Add X509_self_signed(), extending and improving documenation and tests

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10587)
This commit is contained in:
Dr. David von Oheimb 2019-12-28 12:33:12 +01:00
parent 4cec750c2f
commit 0d8dbb52e3
9 changed files with 107 additions and 51 deletions

View File

@ -218,7 +218,7 @@ int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
}
int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
int no_self_issued, int no_dups, int prepend)
int no_self_signed, int no_dups, int prepend)
/* compiler would allow 'const' for the list of certs, yet they are up-ref'ed */
{
int i;
@ -230,7 +230,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
X509 *cert = sk_X509_value(certs, i);
if (!no_self_issued || X509_check_issued(cert, cert) != X509_V_OK) {
if (!no_self_signed || X509_self_signed(cert, 0) != 1) {
if (!ossl_cmp_sk_X509_add1_cert(sk, cert, no_dups, prepend))
return 0;
}
@ -239,7 +239,7 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
}
int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
int only_self_issued)
int only_self_signed)
{
int i;
@ -252,7 +252,7 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
for (i = 0; i < sk_X509_num(certs); i++) {
X509 *cert = sk_X509_value(certs, i);
if (!only_self_issued || X509_check_issued(cert, cert) == X509_V_OK)
if (!only_self_signed || X509_self_signed(cert, 0) == 1)
if (!X509_STORE_add_cert(store, cert)) /* ups cert ref counter */
return 0;
}

View File

@ -111,25 +111,43 @@ static int null_callback(int ok, X509_STORE_CTX *e)
return ok;
}
/*
/*-
* Return 1 if given cert is considered self-signed, 0 if not, or -1 on error.
* This does not verify self-signedness but relies on x509v3_cache_extensions()
* matching issuer and subject names (i.e., the cert being self-issued) and any
* present authority key identifier matching the subject key identifier, etc.
* This actually verifies self-signedness only if requested.
* It calls X509v3_cache_extensions()
* to match issuer and subject names (i.e., the cert being self-issued) and any
* present authority key identifier to match the subject key identifier, etc.
*/
static int cert_self_signed(X509_STORE_CTX *ctx, X509 *x)
static int x509_self_signed_ex(X509 *cert, int verify_signature,
OPENSSL_CTX *libctx, const char *propq)
{
if (!X509v3_cache_extensions(x, ctx->libctx, ctx->propq))
return -1;
EVP_PKEY *pkey;
if (x->ex_flags & EXFLAG_SS)
return 1;
else
if ((pkey = X509_get0_pubkey(cert)) == NULL) { /* handles cert == NULL */
X509err(0, X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY);
return -1;
}
if (!X509v3_cache_extensions(cert, libctx, propq))
return -1;
if ((cert->ex_flags & EXFLAG_SS) == 0)
return 0;
if (!verify_signature)
return 1;
return X509_verify_ex(cert, pkey, libctx, propq);
}
/* wrapper for internal use */
static int cert_self_signed(X509_STORE_CTX *ctx, X509 *x, int verify_signature)
{
return x509_self_signed_ex(x, verify_signature, ctx->libctx, ctx->propq);
}
int X509_self_signed(X509 *cert, int verify_signature)
{
return x509_self_signed_ex(cert, verify_signature, NULL, NULL);
}
/* Given a certificate try and find an exact match in the store */
static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x)
{
STACK_OF(X509) *certs;
@ -365,7 +383,6 @@ static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer)
}
/* Alternative lookup method: look from a STACK stored in other_ctx */
static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
{
*issuer = find_issuer(ctx, ctx->other_ctx, x);
@ -2954,7 +2971,7 @@ static int build_chain(X509_STORE_CTX *ctx)
SSL_DANE *dane = ctx->dane;
int num = sk_X509_num(ctx->chain);
X509 *cert = sk_X509_value(ctx->chain, num - 1);
int self_signed = cert_self_signed(ctx, cert);
int self_signed;
STACK_OF(X509) *sktmp = NULL;
unsigned int search;
int may_trusted = 0;
@ -2972,7 +2989,7 @@ static int build_chain(X509_STORE_CTX *ctx)
return 0;
}
self_signed = cert_self_signed(ctx, cert);
self_signed = cert_self_signed(ctx, cert, 0);
if (self_signed < 0) {
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
@ -3150,7 +3167,7 @@ static int build_chain(X509_STORE_CTX *ctx)
search = 0;
continue;
}
self_signed = cert_self_signed(ctx, x);
self_signed = cert_self_signed(ctx, x, 0);
if (self_signed < 0) {
ctx->error = X509_V_ERR_UNSPECIFIED;
return 0;
@ -3276,7 +3293,7 @@ static int build_chain(X509_STORE_CTX *ctx)
x = xtmp;
++ctx->num_untrusted;
self_signed = cert_self_signed(ctx, xtmp);
self_signed = cert_self_signed(ctx, xtmp, 0);
if (self_signed < 0) {
sk_X509_free(sktmp);
ctx->error = X509_V_ERR_UNSPECIFIED;

View File

@ -15,9 +15,9 @@ ossl_cmp_X509_STORE_get1_certs
int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
int no_dup, int prepend);
int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs,
int no_self_issued, int no_dups, int prepend);
int no_self_signed, int no_dups, int prepend);
int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
int only_self_issued);
int only_self_signed);
STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store);
=head1 DESCRIPTION
@ -29,10 +29,10 @@ On success the reference count of the certificate is increased.
ossl_cmp_sk_X509_add1_certs() appends or prepends (depending on the I<prepend>
argument) a list of certificates to the given list,
optionally only if not self-issued and optionally only if not already contained.
optionally only if not self-signed and optionally only if not already contained.
The reference counts of those certificates appended successfully are increased.
ossl_cmp_X509_STORE_add1_certs() adds all or only self-issued certificates from
ossl_cmp_X509_STORE_add1_certs() adds all or only self-signed certificates from
the given stack to given store. The I<certs> parameter may be NULL.
ossl_cmp_X509_STORE_get1_certs() retrieves a copy of all certificates in the

View File

@ -31,7 +31,7 @@ or some B<X509_V_ERR*> constant to indicate an error.
=head1 SEE ALSO
L<X509_verify_cert(3)>, L<X509_verify(3)>, L<X509_check_ca(3)>,
L<openssl-verify(1)>
L<openssl-verify(1)>, L<X509_self_signed(3)>
=head1 COPYRIGHT

View File

@ -2,7 +2,7 @@
=head1 NAME
X509_verify_ex, X509_verify,
X509_verify_ex, X509_verify, X509_self_signed,
X509_REQ_verify_ex, X509_REQ_verify,
X509_CRL_verify -
verify certificate, certificate request, or CRL signature
@ -14,6 +14,7 @@ verify certificate, certificate request, or CRL signature
int X509_verify_ex(X509 *x, EVP_PKEY *pkey,
OPENSSL_CTX *libctx, const char *propq);
int X509_verify(X509 *x, EVP_PKEY *pkey);
int X509_self_signed(X509 *cert, int verify_signature);
int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *pkey,
OPENSSL_CTX *libctx, const char *propq);
@ -31,6 +32,12 @@ no other checks (such as certificate chain validity) are performed.
X509_verify() is the same as X509_verify_ex() except that the default library
context and property query string are used.
X509_self_signed() checks whether a certificate is self-signed.
For success the issuer and subject names must match, the components of the
authority key identifier (if present) must match the subject key identifier etc.
The signature itself is actually verified only if B<verify_signature> is 1, as
for explicitly trusted certificates this verification is not worth the effort.
X509_REQ_verify_ex(), X509_REQ_verify() and X509_CRL_verify()
verify the signatures of certificate requests and CRLs, respectively.
@ -42,6 +49,9 @@ return 1 if the signature is valid and 0 if the signature check fails.
If the signature could not be checked at all because it was ill-formed
or some other error occurred then -1 is returned.
X509_self_signed() returns the same values but also returns 1
if all respective fields match and B<verify_signature> is 0.
=head1 SEE ALSO
L<d2i_X509(3)>,
@ -65,7 +75,7 @@ L<OPENSSL_CTX(3)>
The X509_verify(), X509_REQ_verify(), and X509_CRL_verify()
functions are available in all versions of OpenSSL.
X509_verify_ex() and X509_REQ_verify_ex()
X509_verify_ex(), X509_REQ_verify_ex(), and X509_self_signed()
were added in OpenSSL 3.0.
=head1 COPYRIGHT

View File

@ -345,6 +345,7 @@ const char *X509_verify_cert_error_string(long n);
int X509_verify_ex(X509 *a, EVP_PKEY *r, OPENSSL_CTX *libctx, const char *propq);
int X509_verify(X509 *a, EVP_PKEY *r);
int X509_self_signed(X509 *cert, int verify_signature);
int X509_REQ_verify_ex(X509_REQ *a, EVP_PKEY *r, OPENSSL_CTX *libctx,
const char *propq);

View File

@ -14,6 +14,7 @@ setup("test_verify_extra");
plan tests => 1;
ok(run(test(["verify_extra_test",
srctop_file("test", "certs", "rootCA.pem"),
srctop_file("test", "certs", "roots.pem"),
srctop_file("test", "certs", "untrusted.pem"),
srctop_file("test", "certs", "bad.pem"),

View File

@ -18,11 +18,24 @@
DEFINE_STACK_OF(X509)
static const char *root_f;
static const char *roots_f;
static const char *untrusted_f;
static const char *bad_f;
static const char *req_f;
static X509 *load_cert_from_file(const char *filename)
{
X509 *cert = NULL;
BIO *bio;
bio = BIO_new_file(filename, "r");
if (bio != NULL)
cert = PEM_read_bio_X509(bio, NULL, 0, NULL);
BIO_free(bio);
return cert;
}
static STACK_OF(X509) *load_certs_from_file(const char *filename)
{
STACK_OF(X509) *certs;
@ -97,7 +110,6 @@ static int test_alt_chains_cert_forgery(void)
int i;
X509 *x = NULL;
STACK_OF(X509) *untrusted = NULL;
BIO *bio = NULL;
X509_STORE_CTX *sctx = NULL;
X509_STORE *store = NULL;
X509_LOOKUP *lookup = NULL;
@ -114,10 +126,7 @@ static int test_alt_chains_cert_forgery(void)
untrusted = load_certs_from_file(untrusted_f);
if ((bio = BIO_new_file(bad_f, "r")) == NULL)
goto err;
if ((x = PEM_read_bio_X509(bio, NULL, 0, NULL)) == NULL)
if ((x = load_cert_from_file(bad_f)) == NULL)
goto err;
sctx = X509_STORE_CTX_new();
@ -136,7 +145,6 @@ static int test_alt_chains_cert_forgery(void)
err:
X509_STORE_CTX_free(sctx);
X509_free(x);
BIO_free(bio);
sk_X509_pop_free(untrusted, X509_free);
X509_STORE_free(store);
return ret;
@ -146,14 +154,9 @@ static int test_store_ctx(void)
{
X509_STORE_CTX *sctx = NULL;
X509 *x = NULL;
BIO *bio = NULL;
int testresult = 0, ret;
bio = BIO_new_file(bad_f, "r");
if (bio == NULL)
goto err;
x = PEM_read_bio_X509(bio, NULL, 0, NULL);
x = load_cert_from_file(bad_f);
if (x == NULL)
goto err;
@ -175,7 +178,6 @@ static int test_store_ctx(void)
err:
X509_STORE_CTX_free(sctx);
X509_free(x);
BIO_free(bio);
return testresult;
}
@ -184,16 +186,11 @@ OPT_TEST_DECLARE_USAGE("roots.pem untrusted.pem bad.pem\n")
static int test_distinguishing_id(void)
{
X509 *x = NULL;
BIO *bio = NULL;
int ret = 0;
ASN1_OCTET_STRING *v = NULL, *v2 = NULL;
char *distid = "this is an ID";
bio = BIO_new_file(bad_f, "r");
if (bio == NULL)
goto err;
x = PEM_read_bio_X509(bio, NULL, 0, NULL);
x = load_cert_from_file(bad_f);
if (x == NULL)
goto err;
@ -217,7 +214,6 @@ static int test_distinguishing_id(void)
ret = 1;
err:
X509_free(x);
BIO_free(bio);
return ret;
}
@ -261,6 +257,32 @@ static int test_req_distinguishing_id(void)
return ret;
}
static int test_self_signed(const char *filename, int expected)
{
X509 *cert;
int ret;
cert = load_cert_from_file(filename); /* may result in NULL */
ret = TEST_int_eq(X509_self_signed(cert, 1), expected);
X509_free(cert);
return ret;
}
static int test_self_signed_good(void)
{
return test_self_signed(root_f, 1);
}
static int test_self_signed_bad(void)
{
return test_self_signed(bad_f, 0);
}
static int test_self_signed_error(void)
{
return test_self_signed("nonexistent file name", -1);
}
int setup_tests(void)
{
if (!test_skip_common_options()) {
@ -268,15 +290,19 @@ int setup_tests(void)
return 0;
}
if (!TEST_ptr(roots_f = test_get_argument(0))
|| !TEST_ptr(untrusted_f = test_get_argument(1))
|| !TEST_ptr(bad_f = test_get_argument(2))
|| !TEST_ptr(req_f = test_get_argument(3)))
if (!TEST_ptr(root_f = test_get_argument(0))
|| !TEST_ptr(roots_f = test_get_argument(1))
|| !TEST_ptr(untrusted_f = test_get_argument(2))
|| !TEST_ptr(bad_f = test_get_argument(3))
|| !TEST_ptr(req_f = test_get_argument(4)))
return 0;
ADD_TEST(test_alt_chains_cert_forgery);
ADD_TEST(test_store_ctx);
ADD_TEST(test_distinguishing_id);
ADD_TEST(test_req_distinguishing_id);
ADD_TEST(test_self_signed_good);
ADD_TEST(test_self_signed_bad);
ADD_TEST(test_self_signed_error);
return 1;
}

View File

@ -4681,6 +4681,7 @@ ERR_set_error ? 3_0_0 EXIST::FUNCTION:
ERR_vset_error ? 3_0_0 EXIST::FUNCTION:
X509_get0_authority_issuer ? 3_0_0 EXIST::FUNCTION:
X509_get0_authority_serial ? 3_0_0 EXIST::FUNCTION:
X509_self_signed ? 3_0_0 EXIST::FUNCTION:
EC_GROUP_new_by_curve_name_ex ? 3_0_0 NOEXIST::FUNCTION:EC
EC_KEY_new_ex ? 3_0_0 NOEXIST::FUNCTION:EC
EC_KEY_new_by_curve_name_ex ? 3_0_0 NOEXIST::FUNCTION:EC