diff options
author | Viktor Dukhovni <openssl-users@dukhovni.org> | 2015-12-29 14:12:36 -0500 |
---|---|---|
committer | Viktor Dukhovni <openssl-users@dukhovni.org> | 2016-01-07 13:48:59 -0500 |
commit | 170b735820ac6a3857733fccf889cde9d723ddc8 (patch) | |
tree | a0d55c48d1117bd156bb9dbbba7629b221f3db91 | |
parent | a8eba56ef62af2f9a5b46825c994665cd3789c2e (diff) |
DANE support for X509_verify_cert()
Reviewed-by: Richard Levitte <levitte@openssl.org>
-rw-r--r-- | crypto/x509/x509_err.c | 2 | ||||
-rw-r--r-- | crypto/x509/x509_vfy.c | 408 | ||||
-rw-r--r-- | include/openssl/x509.h | 2 | ||||
-rw-r--r-- | include/openssl/x509_vfy.h | 2 | ||||
-rw-r--r-- | test/Makefile | 27 | ||||
-rw-r--r-- | test/danetest.c | 543 | ||||
-rw-r--r-- | test/danetest.in | 1675 | ||||
-rw-r--r-- | test/danetest.pem | 14 | ||||
-rw-r--r-- | test/recipes/80-test_dane.t | 13 |
9 files changed, 2674 insertions, 12 deletions
diff --git a/crypto/x509/x509_err.c b/crypto/x509/x509_err.c index 668af28cba..114affc440 100644 --- a/crypto/x509/x509_err.c +++ b/crypto/x509/x509_err.c @@ -74,6 +74,7 @@ static ERR_STRING_DATA X509_str_functs[] = { {ERR_FUNC(X509_F_BUILD_CHAIN), "build_chain"}, {ERR_FUNC(X509_F_BY_FILE_CTRL), "by_file_ctrl"}, {ERR_FUNC(X509_F_CHECK_POLICY), "check_policy"}, + {ERR_FUNC(X509_F_DANE_I2D), "dane_i2d"}, {ERR_FUNC(X509_F_DIR_CTRL), "dir_ctrl"}, {ERR_FUNC(X509_F_GET_CERT_BY_SUBJECT), "get_cert_by_subject"}, {ERR_FUNC(X509_F_NETSCAPE_SPKI_B64_DECODE), "NETSCAPE_SPKI_b64_decode"}, @@ -134,6 +135,7 @@ static ERR_STRING_DATA X509_str_functs[] = { static ERR_STRING_DATA X509_str_reasons[] = { {ERR_REASON(X509_R_AKID_MISMATCH), "akid mismatch"}, + {ERR_REASON(X509_R_BAD_SELECTOR), "bad selector"}, {ERR_REASON(X509_R_BAD_X509_FILETYPE), "bad x509 filetype"}, {ERR_REASON(X509_R_BASE64_DECODE_ERROR), "base64 decode error"}, {ERR_REASON(X509_R_CANT_CHECK_DH_KEY), "cant check dh key"}, diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 1c509a9961..73339f3fd4 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -114,6 +114,7 @@ static int build_chain(X509_STORE_CTX *ctx); static int verify_chain(X509_STORE_CTX *ctx); +static int dane_verify(X509_STORE_CTX *ctx); static int null_callback(int ok, X509_STORE_CTX *e); static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x); @@ -125,6 +126,7 @@ static int check_revocation(X509_STORE_CTX *ctx); static int check_cert(X509_STORE_CTX *ctx); static int check_policy(X509_STORE_CTX *ctx); static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); +static int check_dane_issuer(X509_STORE_CTX *ctx, int depth); static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, unsigned int *preasons, X509_CRL *crl, X509 *x); @@ -237,6 +239,7 @@ static int verify_chain(X509_STORE_CTX *ctx) int X509_verify_cert(X509_STORE_CTX *ctx) { + struct dane_st *dane = (struct dane_st *)ctx->dane; if (ctx->cert == NULL) { X509err(X509_F_X509_VERIFY_CERT, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); @@ -264,6 +267,14 @@ int X509_verify_cert(X509_STORE_CTX *ctx) X509_up_ref(ctx->cert); ctx->num_untrusted = 1; + /* + * If dane->trecs is an empty stack, we'll fail, since the user enabled + * DANE. If none of the TLSA records were usable, and it makes sense to + * keep going with an unauthenticated handshake, they can handle that in + * the verify callback, or not set SSL_VERIFY_PEER. + */ + if (DANETLS_ENABLED(dane)) + return dane_verify(ctx); return verify_chain(ctx); } @@ -565,9 +576,18 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted) X509 *x = NULL; X509 *mx; int (*cb) (int xok, X509_STORE_CTX *xctx) = ctx->verify_cb; + struct dane_st *dane = (struct dane_st *)ctx->dane; int num = sk_X509_num(ctx->chain); int trust; + if (DANETLS_HAS_TA(dane) && num_untrusted > 0) { + switch (trust = check_dane_issuer(ctx, num_untrusted)) { + case X509_TRUST_TRUSTED: + case X509_TRUST_REJECTED: + return trust; + } + } + /* * Check trusted certificates in chain at depth num_untrusted and up. * Note, that depths 0..num_untrusted-1 may also contain trusted @@ -637,7 +657,14 @@ static int check_trust(X509_STORE_CTX *ctx, int num_untrusted) return X509_TRUST_UNTRUSTED; trusted: - return X509_TRUST_TRUSTED; + if (!DANETLS_ENABLED(dane)) + return X509_TRUST_TRUSTED; + if (dane->pdpth < 0) + dane->pdpth = num_untrusted; + /* With DANE, PKIX alone is not trusted until we have both */ + if (dane->mdpth >= 0) + return X509_TRUST_TRUSTED; + return X509_TRUST_UNTRUSTED; } static int check_revocation(X509_STORE_CTX *ctx) @@ -1524,6 +1551,17 @@ static int internal_verify(X509_STORE_CTX *ctx) ctx->error_depth = n; xi = sk_X509_value(ctx->chain, n); + /* + * With DANE-verified bare public key TA signatures, it remains only to + * check the timestamps of the top certificate. We report the issuer as + * NULL, since all we have is a bare key. + */ + if (ctx->bare_ta_signed) { + xs = xi; + xi = NULL; + goto check_cert; + } + if (ctx->check_issued(ctx, xi, xi)) xs = xi; else { @@ -2074,6 +2112,7 @@ int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, ctx->tree = NULL; ctx->parent = NULL; ctx->dane = NULL; + ctx->bare_ta_signed = 0; /* Zero ex_data to make sure we're cleanup-safe */ memset(&ctx->ex_data, 0, sizeof(ctx->ex_data)); @@ -2270,15 +2309,311 @@ void X509_STORE_CTX_set0_dane(X509_STORE_CTX *ctx, struct dane_st *dane) ctx->dane = dane; } +static unsigned char *dane_i2d( + X509 *cert, + uint8_t selector, + unsigned int *i2dlen) +{ + unsigned char *buf = NULL; + int len; + + /* + * Extract ASN.1 DER form of certificate or public key. + */ + switch (selector) { + case DANETLS_SELECTOR_CERT: + len = i2d_X509(cert, &buf); + break; + case DANETLS_SELECTOR_SPKI: + len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf); + break; + default: + X509err(X509_F_DANE_I2D, X509_R_BAD_SELECTOR); + return NULL; + } + + if (len < 0 || buf == NULL) { + X509err(X509_F_DANE_I2D, ERR_R_MALLOC_FAILURE); + return NULL; + } + + *i2dlen = (unsigned int)len; + return buf; +} + +#define DANETLS_NONE 256 /* impossible uint8_t */ + +static int dane_match(X509_STORE_CTX *ctx, X509 *cert, int depth) +{ + struct dane_st *dane = (struct dane_st *)ctx->dane; + unsigned usage = DANETLS_NONE; + unsigned selector = DANETLS_NONE; + unsigned ordinal = DANETLS_NONE; + unsigned mtype = DANETLS_NONE; + unsigned char *i2dbuf = NULL; + unsigned int i2dlen = 0; + unsigned char mdbuf[EVP_MAX_MD_SIZE]; + unsigned char *cmpbuf = NULL; + unsigned int cmplen = 0; + int i; + int recnum; + int matched = 0; + danetls_record *t = NULL; + uint32_t mask; + + mask = (depth == 0) ? DANETLS_EE_MASK : DANETLS_TA_MASK; + + /* + * The trust store is not applicable with DANE-TA(2) + */ + if (depth >= ctx->num_untrusted) + mask &= DANETLS_PKIX_MASK; + + /* + * If we've previously matched a PKIX-?? record, no need to test any + * furher PKIX-?? records, it remains to just build the PKIX chain. + * Had the match been a DANE-?? record, we'd be done already. + */ + if (dane->mdpth >= 0) + mask &= ~DANETLS_PKIX_MASK; + + /*- + * https://tools.ietf.org/html/rfc7671#section-5.1 + * https://tools.ietf.org/html/rfc7671#section-5.2 + * https://tools.ietf.org/html/rfc7671#section-5.3 + * https://tools.ietf.org/html/rfc7671#section-5.4 + * + * We handle DANE-EE(3) records first as they require no chain building + * and no expiration or hostname checks. We also process digests with + * higher ordinals first and ignore lower priorities except Full(0) which + * is always processed (last). If none match, we then process PKIX-EE(1). + * + * NOTE: This relies on DANE usages sorting before the corresponding PKIX + * usages in SSL_dane_tlsa_add(), and also on descending sorting of digest + * priorities. See twin comment in ssl/ssl_lib.c. + * + * We expect that most TLSA RRsets will have just a single usage, so we + * don't go out of our way to cache multiple selector-specific i2d buffers + * across usages, but if the selector happens to remain the same as switch + * usages, that's OK. Thus, a set of "3 1 1", "3 0 1", "1 1 1", "1 0 1", + * records would result in us generating each of the certificate and public + * key DER forms twice, but more typically we'd just see multiple "3 1 1" + * or multiple "3 0 1" records. + * + * As soon as we find a match at any given depth, we stop, because either + * we've matched a DANE-?? record and the peer is authenticated, or, after + * exhausing all DANE-?? records, we've matched a PKIX-?? record, which is + * sufficient for DANE, and what remains to do is ordinary PKIX validation. + */ + recnum = (dane->umask & mask) ? sk_danetls_record_num(dane->trecs) : 0; + for (i = 0; matched == 0 && i < recnum; ++i) { + t = sk_danetls_record_value(dane->trecs, i); + if ((DANETLS_USAGE_BIT(t->usage) & mask) == 0) + continue; + if (t->usage != usage) { + usage = t->usage; + + /* Reset digest agility for each usage/selector pair */ + mtype = DANETLS_NONE; + ordinal = dane->dctx->mdord[t->mtype]; + } + if (t->selector != selector) { + selector = t->selector; + + /* Update per-selector state */ + OPENSSL_free(i2dbuf); + i2dbuf = dane_i2d(cert, selector, &i2dlen); + if (i2dbuf == NULL) + return -1; + + /* Reset digest agility for each usage/selector pair */ + mtype = DANETLS_NONE; + ordinal = dane->dctx->mdord[t->mtype]; + } else if (t->mtype != DANETLS_MATCHING_FULL) { + /*- + * Digest agility: + * + * <https://tools.ietf.org/html/rfc7671#section-9> + * + * For a fixed selector, after processing all records with the + * highest mtype ordinal, ignore all mtypes with lower ordinals + * other than "Full". + */ + if (dane->dctx->mdord[t->mtype] < ordinal) + continue; + } + + /* + * Each time we hit a (new selector or) mtype, re-compute the relevant + * digest, more complex caching is not worth the code space. + */ + if (t->mtype != mtype) { + const EVP_MD *md = dane->dctx->mdevp[mtype = t->mtype]; + cmpbuf = i2dbuf; + cmplen = i2dlen; + + if (md != NULL) { + cmpbuf = mdbuf; + if (!EVP_Digest(i2dbuf, i2dlen, cmpbuf, &cmplen, md, 0)) { + matched = -1; + break; + } + } + } + + /* + * Squirrel away the certificate and depth if we have a match. Any + * DANE match is dispositive, but with PKIX we still need to build a + * full chain. + */ + if (cmplen == t->dlen && + memcmp(cmpbuf, t->data, cmplen) == 0) { + if (DANETLS_USAGE_BIT(usage) & DANETLS_DANE_MASK) + matched = 1; + if (matched || dane->mdpth < 0) { + dane->mdpth = depth; + dane->mtlsa = t; + OPENSSL_free(dane->mcert); + dane->mcert = cert; + X509_up_ref(cert); + } + break; + } + } + + /* Clear the one-element DER cache */ + OPENSSL_free(i2dbuf); + return matched; +} + +static int check_dane_issuer(X509_STORE_CTX *ctx, int depth) +{ + struct dane_st *dane = (struct dane_st *)ctx->dane; + int matched = 0; + X509 *cert; + + if (!DANETLS_HAS_TA(dane) || depth == 0) + return X509_TRUST_UNTRUSTED; + + /* + * Record any DANE trust anchor matches, for the first depth to test, if + * there's one at that depth. (This'll be false for length 1 chains looking + * for an exact match for the leaf certificate). + */ + cert = sk_X509_value(ctx->chain, depth); + if (cert != NULL && (matched = dane_match(ctx, cert, depth)) < 0) + return X509_TRUST_REJECTED; + if (matched > 0) { + ctx->num_untrusted = depth - 1; + return X509_TRUST_TRUSTED; + } + + return X509_TRUST_UNTRUSTED; +} + +static int check_dane_pkeys(X509_STORE_CTX *ctx) +{ + struct dane_st *dane = (struct dane_st *)ctx->dane; + danetls_record *t; + int num = ctx->num_untrusted; + X509 *cert = sk_X509_value(ctx->chain, num - 1); + int recnum = sk_danetls_record_num(dane->trecs); + int i; + + for (i = 0; i < recnum; ++i) { + t = sk_danetls_record_value(dane->trecs, i); + if (t->usage != DANETLS_USAGE_DANE_TA || + t->selector != DANETLS_SELECTOR_SPKI || + t->mtype != DANETLS_MATCHING_FULL || + X509_verify(cert, t->spki) <= 0) + continue; + + /* Clear PKIX-?? matches that failed to panned out to a full chain */ + X509_free(dane->mcert); + dane->mcert = NULL; + + /* Record match via a bare TA public key */ + ctx->bare_ta_signed = 1; + dane->mdpth = num - 1; + dane->mtlsa = t; + + /* Prune any excess chain certificates */ + num = sk_X509_num(ctx->chain); + for (; num > ctx->num_untrusted; --num) + X509_free(sk_X509_pop(ctx->chain)); + + return X509_TRUST_TRUSTED; + } + + return X509_TRUST_UNTRUSTED; +} + +static void dane_reset(struct dane_st *dane) +{ + /* + * Reset state to verify another chain, or clear after failure. + */ + X509_free(dane->mcert); + dane->mcert = NULL; + dane->mtlsa = NULL; + dane->mdpth = -1; + dane->pdpth = -1; +} + +static int dane_verify(X509_STORE_CTX *ctx) +{ + X509 *cert = ctx->cert; + int (*cb)(int xok, X509_STORE_CTX *xctx) = ctx->verify_cb; + struct dane_st *dane = (struct dane_st *)ctx->dane; + int matched; + int done; + + dane_reset(dane); + + matched = dane_match(ctx, ctx->cert, 0); + done = matched != 0 || (!DANETLS_HAS_TA(dane) && dane->mdpth < 0); + + if (done) + X509_get_pubkey_parameters(NULL, ctx->chain); + + if (matched > 0) { + ctx->error_depth = 0; + ctx->current_cert = cert; + return cb(1, ctx); + } + + if (matched < 0) { + ctx->error_depth = 0; + ctx->current_cert = cert; + ctx->error = X509_V_ERR_OUT_OF_MEM; + return -1; + } + + if (done) { + /* Fail early, TA-based success is not possible */ + ctx->current_cert = cert; + ctx->error_depth = 0; + ctx->error = X509_V_ERR_CERT_UNTRUSTED; + return cb(0, ctx); + } + + /* + * Chain verification for usages 0/1/2. TLSA record matching of depth > 0 + * certificates happens in-line with building the rest of the chain. + */ + return verify_chain(ctx); +} + static int build_chain(X509_STORE_CTX *ctx) { + struct dane_st *dane = (struct dane_st *)ctx->dane; int (*cb) (int, X509_STORE_CTX *) = ctx->verify_cb; int num = sk_X509_num(ctx->chain); X509 *cert = sk_X509_value(ctx->chain, num - 1); int ss = cert_self_signed(cert); STACK_OF(X509) *sktmp = NULL; unsigned int search; - int may_trusted = 1; + int may_trusted = 0; int may_alternate = 0; int trust = X509_TRUST_UNTRUSTED; int alt_untrusted = 0; @@ -2294,14 +2629,19 @@ static int build_chain(X509_STORE_CTX *ctx) #define S_DOALTERNATE (1 << 2) /* Retry with pruned alternate chain */ /* * Set up search policy, untrusted if possible, trusted-first if enabled. - * If not trusted-first, and alternate chains are not disabled, try - * building an alternate chain if no luck with untrusted first. + * If we're doing DANE and not doing PKIX-TA/PKIX-EE, we never look in the + * trust_store, otherwise we might look there first. If not trusted-first, + * and alternate chains are not disabled, try building an alternate chain + * if no luck with untrusted first. */ search = (ctx->untrusted != NULL) ? S_DOUNTRUSTED : 0; - if (search == 0 || ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) - search |= S_DOTRUSTED; - else if (!(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) - may_alternate = 1; + if (DANETLS_HAS_PKIX(dane) || !DANETLS_HAS_DANE(dane)) { + if (search == 0 || ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) + search |= S_DOTRUSTED; + else if (!(ctx->param->flags & X509_V_FLAG_NO_ALT_CHAINS)) + may_alternate = 1; + may_trusted = 1; + } /* * Shallow-copy the stack of untrusted certificates (with TLS, this is @@ -2313,6 +2653,17 @@ static int build_chain(X509_STORE_CTX *ctx) return 0; } + /* Include any untrusted full certificates from DNS */ + if (DANETLS_ENABLED(dane) && dane->certs != NULL) { + for (i = 0; i < sk_X509_num(dane->certs); ++i) { + if (!sk_X509_push(sktmp, sk_X509_value(dane->certs, i))) { + sk_X509_free(sktmp); + X509err(X509_F_BUILD_CHAIN, ERR_R_MALLOC_FAILURE); + return 0; + } + } + } + /* * Still absurdly large, but arithmetically safe, a lower hard upper bound * might be reasonable. @@ -2381,6 +2732,10 @@ static int build_chain(X509_STORE_CTX *ctx) * case we may prune some more untrusted certificates and try * again. Thus the S_DOALTERNATE bit may yet be turned on * again with an even shorter untrusted chain! + * + * If in the process we threw away our matching PKIX-TA trust + * anchor, reset DANE trust. We might find a suitable trusted + * certificate among the ones from the trust store. */ if ((search & S_DOALTERNATE) != 0) { OPENSSL_assert(num > i && i > 0 && ss == 0); @@ -2388,6 +2743,16 @@ static int build_chain(X509_STORE_CTX *ctx) for (; num > i; --num) X509_free(sk_X509_pop(ctx->chain)); ctx->num_untrusted = num; + + if (DANETLS_ENABLED(dane) && + dane->mdpth >= ctx->num_untrusted) { + dane->mdpth = -1; + X509_free(dane->mcert); + dane->mcert = NULL; + } + if (DANETLS_ENABLED(dane) && + dane->pdpth >= ctx->num_untrusted) + dane->pdpth = -1; } /* @@ -2426,6 +2791,13 @@ static int build_chain(X509_STORE_CTX *ctx) * trust. If not done, and not self-signed look deeper. * Whether or not we're doing "trusted first", we no longer * look for untrusted certificates from the peer's chain. + * + * At this point ctx->num_trusted and num must reflect the + * correct number of untrusted certificates, since the DANE + * logic in check_trust() depends on distinguishing CAs from + * "the wire" from CAs from the trust store. In particular, the + * certificate at depth "num" should be the new trusted + * certificate with ctx->num_untrusted <= num. */ if (ok) { OPENSSL_assert(ctx->num_untrusted <= num); @@ -2497,14 +2869,27 @@ static int build_chain(X509_STORE_CTX *ctx) * certificates over and over. */ (void) sk_X509_delete_ptr(sktmp, x); + + /* + * Check for DANE-TA trust of the topmost untrusted certificate. + */ + switch (trust = check_dane_issuer(ctx, ctx->num_untrusted - 1)) { + case X509_TRUST_TRUSTED: + case X509_TRUST_REJECTED: + search = 0; + continue; + } } } sk_X509_free(sktmp); /* - * Last chance to make a trusted chain, check for direct leaf PKIX trust. + * Last chance to make a trusted chain, either bare DANE-TA public-key + * signers, or else direct leaf PKIX trust. */ if (sk_X509_num(ctx->chain) <= depth) { + if (trust == X509_TRUST_UNTRUSTED && DANETLS_HAS_DANE_TA(dane)) + trust = check_dane_pkeys(ctx); if (trust == X509_TRUST_UNTRUSTED && sk_X509_num(ctx->chain) == ctx->num_untrusted) trust = check_trust(ctx, 1); @@ -2522,6 +2907,9 @@ static int build_chain(X509_STORE_CTX *ctx) ctx->error_depth = num-1; if (num > depth) ctx->error = X509_V_ERR_CERT_CHAIN_TOO_LONG; + else if (DANETLS_ENABLED(dane) && + (!DANETLS_HAS_PKIX(dane) || dane->pdpth >= 0)) + ctx->error = X509_V_ERR_CERT_UNTRUSTED; else if (ss && sk_X509_num(ctx->chain) == 1) ctx->error = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; else if (ss) @@ -2530,6 +2918,8 @@ static int build_chain(X509_STORE_CTX *ctx) ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; else ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; + if (DANETLS_ENABLED(dane)) + dane_reset(dane); return cb(0, ctx); } } diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 0b00abfc2a..0f66329544 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -1073,6 +1073,7 @@ void ERR_load_X509_strings(void); # define X509_F_BUILD_CHAIN 106 # define X509_F_BY_FILE_CTRL 101 # define X509_F_CHECK_POLICY 145 +# define X509_F_DANE_I2D 107 # define X509_F_DIR_CTRL 102 # define X509_F_GET_CERT_BY_SUBJECT 103 # define X509_F_NETSCAPE_SPKI_B64_DECODE 129 @@ -1119,6 +1120,7 @@ void ERR_load_X509_strings(void); /* Reason codes. */ # define X509_R_AKID_MISMATCH 110 +# define X509_R_BAD_SELECTOR 133 # define X509_R_BAD_X509_FILETYPE 100 # define X509_R_BASE64_DECODE_ERROR 118 # define X509_R_CANT_CHECK_DH_KEY 114 diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h index c96ab6862b..7ea11ea392 100644 --- a/include/openssl/x509_vfy.h +++ b/include/openssl/x509_vfy.h @@ -264,6 +264,8 @@ struct x509_store_ctx_st { /* X509_STORE_CTX */ X509_STORE_CTX *parent; CRYPTO_EX_DATA ex_data; struct dane_st *dane; + /* signed via bare TA public key, rather than CA certificate */ + int bare_ta_signed; } /* X509_STORE_CTX */ ; void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); diff --git a/test/Makefile b/test/Makefile index 3a04fef39a..81035584c5 100644 --- a/test/Makefile +++ b/test/Makefile @@ -59,6 +59,7 @@ RANDTEST= randtest DHTEST= dhtest DSATEST= dsatest SSLTEST= ssltest +DANETEST= danetest RSATEST= rsa_test ENGINETEST= enginetest EVPTEST= evp_test @@ -90,7 +91,7 @@ EXE= $(NPTEST)$(EXE_EXT) $(BNTEST)$(EXE_EXT) $(ECTEST)$(EXE_EXT) \ $(DESTEST)$(EXE_EXT) $(SHA1TEST)$(EXE_EXT) $(SHA256TEST)$(EXE_EXT) $(SHA512TEST)$(EXE_EXT) \ $(MDC2TEST)$(EXE_EXT) $(RMDTEST)$(EXE_EXT) \ $(RANDTEST)$(EXE_EXT) $(DHTEST)$(EXE_EXT) $(ENGINETEST)$(EXE_EXT) \ - $(GOST2814789TEST)$(EXE_EXT) \ + $(GOST2814789TEST)$(EXE_EXT) $(DANETEST)$(EXE_EXT) \ $(BFTEST)$(EXE_EXT) $(CASTTEST)$(EXE_EXT) $(SSLTEST)$(EXE_EXT) \ $(EXPTEST)$(EXE_EXT) $(DSATEST)$(EXE_EXT) $(RSATEST)$(EXE_EXT) \ $(EVPTEST)$(EXE_EXT) $(EVPEXTRATEST)$(EXE_EXT) $(IGETEST)$(EXE_EXT) \ @@ -108,7 +109,7 @@ OBJ= $(NPTEST).o $(BNTEST).o $(ECTEST).o \ $(HMACTEST).o $(WPTEST).o \ $(RC2TEST).o $(RC4TEST).o $(RC5TEST).o \ $(DESTEST).o $(SHA1TEST).o $(SHA256TEST).o $(SHA512TEST).o \ - $(MDC2TEST).o $(RMDTEST).o \ + $(MDC2TEST).o $(RMDTEST).o $(DANETEST).o \ $(RANDTEST).o $(DHTEST).o $(ENGINETEST).o $(CASTTEST).o \ $(BFTEST).o $(SSLTEST).o $(DSATEST).o $(EXPTEST).o $(RSATEST).o \ $(EVPTEST).o $(EVPEXTRATEST).o $(IGETEST).o $(JPAKETEST).o $(V3NAMETEST).o \ @@ -120,7 +121,7 @@ SRC= $(NPTEST).c $(BNTEST).c $(ECTEST).c \ $(ECDSATEST).c $(ECDHTEST).c $(GMDIFFTEST).c $(PBELUTEST).c $(IDEATEST).c \ $(MD2TEST).c $(MD4TEST).c $(MD5TEST).c \ $(HMACTEST).c $(WPTEST).c \ - $(RC2TEST).c $(RC4TEST).c $(RC5TEST).c \ + $(RC2TEST).c $(RC4TEST).c $(RC5TEST).c $(DANETEST).c \ $(DESTEST).c $(SHA1TEST).c $(MDC2TEST).c $(RMDTEST).c \ $(RANDTEST).c $(DHTEST).c $(ENGINETEST).c $(CASTTEST).c \ $(BFTEST).c $(SSLTEST).c $(DSATEST).c $(EXPTEST).c $(RSATEST).c \ @@ -317,6 +318,9 @@ $(METHTEST)$(EXE_EXT): $(METHTEST).o $(DLIBCRYPTO) $(SSLTEST)$(EXE_EXT): $(SSLTEST).o $(DLIBSSL) $(DLIBCRYPTO) @target=$(SSLTEST); $(BUILD_CMD) +$(DANETEST)$(EXE_EXT): $(DANETEST).o $(DLIBSSL) $(DLIBCRYPTO) + @target=$(DANETEST); $(BUILD_CMD) + $(ENGINETEST)$(EXE_EXT): $(ENGINETEST).o $(DLIBCRYPTO) @target=$(ENGINETEST); $(BUILD_CMD) @@ -435,6 +439,23 @@ clienthellotest.o: clienthellotest.c constant_time_test.o: ../e_os.h ../include/internal/constant_time_locl.h constant_time_test.o: ../include/openssl/e_os2.h constant_time_test.o: ../include/openssl/opensslconf.h constant_time_test.c +danetest.o: ../e_os.h ../include/internal/dane.h ../include/openssl/asn1.h +danetest.o: ../include/openssl/bio.h ../include/openssl/buffer.h +danetest.o: ../include/openssl/comp.h ../include/openssl/conf.h +danetest.o: ../include/openssl/crypto.h ../include/openssl/dtls1.h +danetest.o: ../include/openssl/e_os2.h ../include/openssl/ec.h +danetest.o: ../include/openssl/engine.h ../include/openssl/err.h +danetest.o: ../include/openssl/evp.h ../include/openssl/hmac.h +danetest.o: ../include/openssl/lhash.h ../include/openssl/obj_mac.h +danetest.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h +danetest.o: ../include/openssl/opensslv.h ../include/openssl/ossl_typ.h +danetest.o: ../include/openssl/pem.h ../include/openssl/pem2.h +danetest.o: ../include/openssl/pkcs7.h ../include/openssl/safestack.h +danetest.o: ../include/openssl/sha.h ../include/openssl/srtp.h +danetest.o: ../include/openssl/ssl.h ../include/openssl/ssl2.h +danetest.o: ../include/openssl/ssl3.h ../include/openssl/stack.h +danetest.o: ../include/openssl/symhacks.h ../include/openssl/tls1.h +danetest.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h danetest.c destest.o: ../include/openssl/des.h ../include/openssl/e_os2.h destest.o: ../include/openssl/opensslconf.h destest.c dhtest.o: ../e_os.h ../include/openssl/bio.h ../include/openssl/bn.h diff --git a/test/danetest.c b/test/danetest.c new file mode 100644 index 0000000000..063b94470d --- /dev/null +++ b/test/danetest.c @@ -0,0 +1,543 @@ +/* danetest.c */ +/* ==================================================================== + * Copyright (c) 2015 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <limits.h> +#include <errno.h> + +#include <openssl/crypto.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/conf.h> +#ifndef OPENSSL_NO_ENGINE +#include <openssl/engine.h> +#endif + +#include "../e_os.h" + +static const char *progname; + +/* + * Forward declaration, of function that uses internal interfaces, from headers + * included at the end of this module. + */ +static void store_ctx_dane_init(X509_STORE_CTX *, SSL *); + +static int saved_errno; + +static void save_errno(void) +{ + saved_errno = errno; +} + +static int restore_errno(void) +{ + int ret = errno; + errno = saved_errno; + return ret; +} + +static void usage(void) +{ + fprintf(stderr, "usage: %s: danetest basedomain CAfile tlsafile\n", progname); +} + +static void print_errors(void) +{ + unsigned long err; + char buffer[1024]; + const char *file; + const char *data; + int line; + int flags; + + while ((err = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { + ERR_error_string_n(err, buffer, sizeof(buffer)); + if (flags & ERR_TXT_STRING) + fprintf(stderr, "Error: %s:%s:%d:%s\n", buffer, file, line, data); + else + fprintf(stderr, "Error: %s:%s:%d\n", buffer, file, line); + } +} + +static int verify_chain(SSL *ssl, STACK_OF(X509) *chain) +{ + int ret; + X509_STORE_CTX *store_ctx; + SSL_CTX *ssl_ctx = SSL_get_SSL_CTX(ssl); + X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); + int store_ctx_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); + X509 *cert = sk_X509_value(chain, 0); + + if ((store_ctx = X509_STORE_CTX_new()) == NULL) + return -1; + + if (!X509_STORE_CTX_init(store_ctx, store, cert, chain)) + return 0; + X509_STORE_CTX_set_ex_data(store_ctx, store_ctx_idx, ssl); + + X509_STORE_CTX_set_default(store_ctx, + SSL_is_server(ssl) ? "ssl_client" : "ssl_server"); + X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(store_ctx), + SSL_get0_param(ssl)); + store_ctx_dane_init(store_ctx, ssl); + + if (SSL_get_verify_callback(ssl)) + X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl)); + + ret = X509_verify_cert(store_ctx); + + SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(store_ctx)); + X509_STORE_CTX_cleanup(store_ctx); + X509_STORE_CTX_free(store_ctx); + + return (ret); +} + +static STACK_OF(X509) *load_chain(FILE *fp, int nelem) +{ + int count; + char *name = 0; + char *header = 0; + unsigned char *data = 0; + long len; + char *errtype = 0; /* if error: cert or pkey? */ + STACK_OF(X509) *chain; + typedef X509 *(*d2i_X509_t)(X509 **, const unsigned char **, long); + + if ((chain = sk_X509_new_null()) == 0) { + perror("malloc"); + exit(1); + } + + for (count = 0; + count < nelem && errtype == 0 + && PEM_read(fp, &name, &header, &data, &len); + ++count) { + const unsigned char *p = data; + + if (strcmp(name, PEM_STRING_X509) == 0 + || strcmp(name, PEM_STRING_X509_TRUSTED) == 0 + || strcmp(name, PEM_STRING_X509_OLD) == 0) { + d2i_X509_t d = strcmp(name, PEM_STRING_X509_TRUSTED) ? + d2i_X509_AUX : d2i_X509; + X509 *cert = d(0, &p, len); + + if (cert == 0 || (p - data) != len) + errtype = "certificate"; + else if (sk_X509_push(chain, cert) == 0) { + perror("malloc"); + goto err; + } + } else { + fprintf(stderr, "unexpected chain file object: %s\n", name); + goto err; + } + + /* + * If any of these were null, PEM_read() would have failed. + */ + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(data); |