diff options
author | Viktor Dukhovni <openssl-users@dukhovni.org> | 2015-12-29 19:28:28 +0100 |
---|---|---|
committer | Viktor Dukhovni <openssl-users@dukhovni.org> | 2016-01-06 01:31:49 +0100 |
commit | 919ba009429b3617e975933f37a23be996a33b8d (patch) | |
tree | ffe91f4f27fd4d8b3d3401f1e860212f15c8b993 /ssl | |
parent | Fix X509_STORE_CTX_cleanup() (diff) | |
download | openssl-919ba009429b3617e975933f37a23be996a33b8d.tar.xz openssl-919ba009429b3617e975933f37a23be996a33b8d.zip |
DANE support structures, constructructors and accessors
Also tweak some of the code in demos/bio, to enable interactive
testing of BIO_s_accept's use of SSL_dup. Changed the sconnect
client to authenticate the server, which now exercises the new
SSL_set1_host() function.
Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/record/rec_layer_s3.c | 9 | ||||
-rw-r--r-- | ssl/record/record.h | 1 | ||||
-rw-r--r-- | ssl/ssl_cert.c | 15 | ||||
-rw-r--r-- | ssl/ssl_err.c | 22 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 517 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 8 |
6 files changed, 531 insertions, 41 deletions
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index ae31f5dd66..53989125d6 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -208,15 +208,6 @@ int RECORD_LAYER_set_data(RECORD_LAYER *rl, const unsigned char *buf, int len) return 1; } -void RECORD_LAYER_dup(RECORD_LAYER *dst, RECORD_LAYER *src) -{ - /* - * Currently only called from SSL_dup...which only seems to expect the - * rstate to be duplicated and nothing else from the RECORD_LAYER??? - */ - dst->rstate = src->rstate; -} - void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl) { memset(rl->read_sequence, 0, sizeof(rl->read_sequence)); diff --git a/ssl/record/record.h b/ssl/record/record.h index 96370710c4..af10166a88 100644 --- a/ssl/record/record.h +++ b/ssl/record/record.h @@ -321,7 +321,6 @@ void RECORD_LAYER_release(RECORD_LAYER *rl); int RECORD_LAYER_read_pending(RECORD_LAYER *rl); int RECORD_LAYER_write_pending(RECORD_LAYER *rl); int RECORD_LAYER_set_data(RECORD_LAYER *rl, const unsigned char *buf, int len); -void RECORD_LAYER_dup(RECORD_LAYER *dst, RECORD_LAYER *src); void RECORD_LAYER_reset_read_sequence(RECORD_LAYER *rl); void RECORD_LAYER_reset_write_sequence(RECORD_LAYER *rl); int RECORD_LAYER_setup_comp_buffer(RECORD_LAYER *rl); diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 597de0ad6c..7f01bcc641 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -486,6 +486,7 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) int i; X509_STORE *verify_store; X509_STORE_CTX ctx; + X509_VERIFY_PARAM *param; if (s->cert->verify_store) verify_store = s->cert->verify_store; @@ -500,10 +501,16 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_X509_LIB); return (0); } + param = X509_STORE_CTX_get0_param(&ctx); + /* Set suite B flags if needed */ X509_STORE_CTX_set_flags(&ctx, tls1_suiteb(s)); X509_STORE_CTX_set_ex_data(&ctx, SSL_get_ex_data_X509_STORE_CTX_idx(), s); + /* Verify via DANE if enabled */ + if (DANETLS_ENABLED(&s->dane)) + X509_STORE_CTX_set0_dane(&ctx, &s->dane); + /* * We need to inherit the verify parameters. These can be determined by * the context: if its a server it will verify SSL client certificates or @@ -512,9 +519,9 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) X509_STORE_CTX_set_default(&ctx, s->server ? "ssl_client" : "ssl_server"); /* - * Anything non-default in "param" should overwrite anything in the ctx. + * Anything non-default in "s->param" should overwrite anything in the ctx. */ - X509_VERIFY_PARAM_set1(X509_STORE_CTX_get0_param(&ctx), s->param); + X509_VERIFY_PARAM_set1(param, s->param); if (s->verify_callback) X509_STORE_CTX_set_verify_cb(&ctx, s->verify_callback); @@ -534,6 +541,10 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) } s->verify_result = ctx.error; + + /* Move peername from the store context params to the SSL handle's */ + X509_VERIFY_PARAM_move_peername(s->param, param); + X509_STORE_CTX_cleanup(&ctx); return (i); diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index d9dbf99391..cfa4179a40 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -72,6 +72,9 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"}, {ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"}, + {ERR_FUNC(SSL_F_DANE_CTX_ENABLE), "dane_ctx_enable"}, + {ERR_FUNC(SSL_F_DANE_MTYPE_SET), "dane_mtype_set"}, + {ERR_FUNC(SSL_F_DANE_TLSA_ADD), "dane_tlsa_add"}, {ERR_FUNC(SSL_F_DO_DTLS1_WRITE), "do_dtls1_write"}, {ERR_FUNC(SSL_F_DO_SSL3_WRITE), "DO_SSL3_WRITE"}, {ERR_FUNC(SSL_F_DTLS1_ACCEPT), "dtls1_accept"}, @@ -262,6 +265,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO), "SSL_CTX_use_serverinfo"}, {ERR_FUNC(SSL_F_SSL_CTX_USE_SERVERINFO_FILE), "SSL_CTX_use_serverinfo_file"}, + {ERR_FUNC(SSL_F_SSL_DANE_ENABLE), "SSL_dane_enable"}, {ERR_FUNC(SSL_F_SSL_DO_CONFIG), "ssl_do_config"}, {ERR_FUNC(SSL_F_SSL_DO_HANDSHAKE), "SSL_do_handshake"}, {ERR_FUNC(SSL_F_SSL_GET_NEW_SESSION), "ssl_get_new_session"}, @@ -491,9 +495,25 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_COMPRESSION_LIBRARY_ERROR), "compression library error"}, {ERR_REASON(SSL_R_CONNECTION_TYPE_NOT_SET), "connection type not set"}, + {ERR_REASON(SSL_R_CONTEXT_NOT_DANE_ENABLED), "context not dane enabled"}, {ERR_REASON(SSL_R_COOKIE_GEN_CALLBACK_FAILURE), "cookie gen callback failure"}, {ERR_REASON(SSL_R_COOKIE_MISMATCH), "cookie mismatch"}, + {ERR_REASON(SSL_R_DANE_ALREADY_ENABLED), "dane already enabled"}, + {ERR_REASON(SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL), + "dane cannot override mtype full"}, + {ERR_REASON(SSL_R_DANE_NOT_ENABLED), "dane not enabled"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_CERTIFICATE), "dane tlsa bad certificate"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE), + "dane tlsa bad certificate usage"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_DATA_LENGTH), "dane tlsa bad data length"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH), + "dane tlsa bad digest length"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_MATCHING_TYPE), + "dane tlsa bad matching type"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_PUBLIC_KEY), "dane tlsa bad public key"}, + {ERR_REASON(SSL_R_DANE_TLSA_BAD_SELECTOR), "dane tlsa bad selector"}, + {ERR_REASON(SSL_R_DANE_TLSA_NULL_DATA), "dane tlsa null data"}, {ERR_REASON(SSL_R_DATA_BETWEEN_CCS_AND_FINISHED), "data between ccs and finished"}, {ERR_REASON(SSL_R_DATA_LENGTH_TOO_LONG), "data length too long"}, @@ -524,6 +544,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = { "encrypted length too long"}, {ERR_REASON(SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST), "error in received cipher list"}, + {ERR_REASON(SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN), + "error setting tlsa base domain"}, {ERR_REASON(SSL_R_EXCESSIVE_MESSAGE_SIZE), "excessive message size"}, {ERR_REASON(SSL_R_EXTRA_DATA_IN_MESSAGE), "extra data in message"}, {ERR_REASON(SSL_R_FAILED_TO_INIT_ASYNC), "failed to init async"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 760014d739..f0f1264cdf 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -197,6 +197,333 @@ struct ssl_async_args { } f; }; +static const struct { + uint8_t mtype; + uint8_t ord; + int nid; +} dane_mds[] = { + { DANETLS_MATCHING_FULL, 0, NID_undef }, + { DANETLS_MATCHING_2256, 1, NID_sha256 }, + { DANETLS_MATCHING_2512, 2, NID_sha512 }, +}; + +static int dane_ctx_enable(struct dane_ctx_st *dctx) +{ + const EVP_MD **mdevp; + uint8_t *mdord; + uint8_t mdmax = DANETLS_MATCHING_LAST; + int n = ((int) mdmax) + 1; /* int to handle PrivMatch(255) */ + size_t i; + + mdevp = OPENSSL_zalloc(n * sizeof(*mdevp)); + mdord = OPENSSL_zalloc(n * sizeof(*mdord)); + + if (mdord == NULL || mdevp == NULL) { + OPENSSL_free(mdevp); + SSLerr(SSL_F_DANE_CTX_ENABLE, ERR_R_MALLOC_FAILURE); + return 0; + } + + /* Install default entries */ + for (i = 0; i < OSSL_NELEM(dane_mds); ++i) { + const EVP_MD *md; + + if (dane_mds[i].nid == NID_undef || + (md = EVP_get_digestbynid(dane_mds[i].nid)) == NULL) + continue; + mdevp[dane_mds[i].mtype] = md; + mdord[dane_mds[i].mtype] = dane_mds[i].ord; + } + + dctx->mdevp = mdevp; + dctx->mdord = mdord; + dctx->mdmax = mdmax; + + return 1; +} + +static void dane_ctx_final(struct dane_ctx_st *dctx) +{ + OPENSSL_free(dctx->mdevp); + dctx->mdevp = NULL; + + OPENSSL_free(dctx->mdord); + dctx->mdord = NULL; + dctx->mdmax = 0; +} + +static void tlsa_free(danetls_record *t) +{ + if (t == NULL) + return; + OPENSSL_free(t->data); + EVP_PKEY_free(t->spki); + OPENSSL_free(t); +} + +static void dane_final(struct dane_st *dane) +{ + sk_danetls_record_pop_free(dane->trecs, tlsa_free); + dane->trecs = NULL; + + sk_X509_pop_free(dane->certs, X509_free); + dane->certs = NULL; + + X509_free(dane->mcert); + dane->mcert = NULL; + dane->mtlsa = NULL; + dane->mdpth = -1; + dane->pdpth = -1; +} + +/* + * dane_copy - Copy dane configuration, sans verification state. + */ +static int ssl_dane_dup(SSL *to, SSL *from) +{ + int num; + int i; + + if (!DANETLS_ENABLED(&from->dane)) + return 1; + + dane_final(&to->dane); + + num = sk_danetls_record_num(from->dane.trecs); + for (i = 0; i < num; ++i) { + danetls_record *t = sk_danetls_record_value(from->dane.trecs, i); + if (SSL_dane_tlsa_add(to, t->usage, t->selector, t->mtype, + t->data, t->dlen) <= 0) + return 0; + } + return 1; +} + +static int dane_mtype_set( + struct dane_ctx_st *dctx, + const EVP_MD *md, + uint8_t mtype, + uint8_t ord) +{ + int i; + + if (mtype == DANETLS_MATCHING_FULL && md != NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, + SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL); + return 0; + } + + if (mtype > dctx->mdmax) { + const EVP_MD **mdevp; + uint8_t *mdord; + int n = ((int) mtype) + 1; + + mdevp = OPENSSL_realloc(dctx->mdevp, n * sizeof(*mdevp)); + if (mdevp == NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE); + return -1; + } + dctx->mdevp = mdevp; + + mdord = OPENSSL_realloc(dctx->mdord, n * sizeof(*mdord)); + if (mdord == NULL) { + SSLerr(SSL_F_DANE_MTYPE_SET, ERR_R_MALLOC_FAILURE); + return -1; + } + dctx->mdord = mdord; + + /* Zero-fill any gaps */ + for (i = dctx->mdmax+1; i < mtype; ++i) { + mdevp[i] = NULL; + mdord[i] = 0; + } + + dctx->mdmax = mtype; + } + + dctx->mdevp[mtype] = md; + /* Coerce ordinal of disabled matching types to 0 */ + dctx->mdord[mtype] = (md == NULL) ? 0 : ord; + + return 1; +} + +static const EVP_MD *tlsa_md_get(struct dane_st *dane, uint8_t mtype) +{ + if (mtype > dane->dctx->mdmax) + return NULL; + return dane->dctx->mdevp[mtype]; +} + +static int dane_tlsa_add( + struct dane_st *dane, + uint8_t usage, + uint8_t selector, + uint8_t mtype, + unsigned char *data, + size_t dlen) +{ + danetls_record *t; + const EVP_MD *md = NULL; + int ilen = (int)dlen; + int i; + + if (dane->trecs == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_NOT_ENABLED); + return -1; + } + + if (ilen < 0 || dlen != (size_t)ilen) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DATA_LENGTH); + return 0; + } + + if (usage > DANETLS_USAGE_LAST) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE); + return 0; + } + + if (selector > DANETLS_SELECTOR_LAST) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_SELECTOR); + return 0; + } + + if (mtype != DANETLS_MATCHING_FULL) { + md = tlsa_md_get(dane, mtype); + if (md == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE); + return 0; + } + } + + if (md != NULL && dlen != (size_t)EVP_MD_size(md)) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH); + return 0; + } + if (!data) { + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_NULL_DATA); + return 0; + } + + if ((t = OPENSSL_zalloc(sizeof(*t))) == NULL) { + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + + t->usage = usage; + t->selector = selector; + t->mtype = mtype; + t->data = OPENSSL_malloc(ilen); + if (t->data == NULL) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + memcpy(t->data, data, ilen); + t->dlen = ilen; + + /* Validate and cache full certificate or public key */ + if (mtype == DANETLS_MATCHING_FULL) { + const unsigned char *p = data; + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + + switch (selector) { + case DANETLS_SELECTOR_CERT: + if (!d2i_X509(&cert, &p, dlen) || p < data || + dlen != (size_t)(p - data)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE); + return 0; + } + if (X509_get0_pubkey(cert) == NULL) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_CERTIFICATE); + return 0; + } + + if ((DANETLS_USAGE_BIT(usage) & DANETLS_TA_MASK) == 0) { + X509_free(cert); + break; + } + + /* + * For usage DANE-TA(2), we support authentication via "2 0 0" TLSA + * records that contain full certificates of trust-anchors that are + * not present in the wire chain. For usage PKIX-TA(0), we augment + * the chain with untrusted Full(0) certificates from DNS, in case + * they are missing from the chain. + */ + if ((dane->certs == NULL && + (dane->certs = sk_X509_new_null()) == NULL) || + !sk_X509_push(dane->certs, cert)) { + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + X509_free(cert); + tlsa_free(t); + return -1; + } + break; + + case DANETLS_SELECTOR_SPKI: + if (!d2i_PUBKEY(&pkey, &p, dlen) || p < data || + dlen != (size_t)(p - data)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY); + return 0; + } + + /* + * For usage DANE-TA(2), we support authentication via "2 1 0" TLSA + * records that contain full bare keys of trust-anchors that are + * not present in the wire chain. + */ + if (usage == DANETLS_USAGE_DANE_TA) + t->spki = pkey; + else + EVP_PKEY_free(pkey); + break; + } + } + + /*- + * Find the right insertion point for the new record. + * + * See crypto/x509/x509_vfy.c. We sort DANE-EE(3) records first, so that + * they can be processed first, as they require no chain building, and no + * expiration or hostname checks. Because DANE-EE(3) is numerically + * largest, this is accomplished via descending sort by "usage". + * + * We also sort in descending order by matching ordinal to simplify + * the implementation of digest agility in the verification code. + * + * The choice of order for the selector is not significant, so we + * use the same descending order for consistency. + */ + for (i = 0; i < sk_danetls_record_num(dane->trecs); ++i) { + danetls_record *rec = sk_danetls_record_value(dane->trecs, i); + if (rec->usage > usage) + continue; + if (rec->usage < usage) + break; + if (rec->selector > selector) + continue; + if (rec->selector < selector) + break; + if (dane->dctx->mdord[rec->mtype] > dane->dctx->mdord[mtype]) + continue; + break; + } + + if (!sk_danetls_record_insert(dane->trecs, t, i)) { + tlsa_free(t); + SSLerr(SSL_F_DANE_TLSA_ADD, ERR_R_MALLOC_FAILURE); + return -1; + } + dane->umask |= DANETLS_USAGE_BIT(usage); + + return 1; +} + static void clear_ciphers(SSL *s) { /* clear the current cipher */ @@ -237,6 +564,16 @@ int SSL_clear(SSL *s) clear_ciphers(s); s->first_packet = 0; + /* Reset DANE verification result state */ + s->dane.mdpth = -1; + s->dane.pdpth = -1; + X509_free(s->dane.mcert); + s->dane.mcert = NULL; + s->dane.mtlsa = NULL; + + /* Clear the verification result peername */ + X509_VERIFY_PARAM_move_peername(s->param, NULL); + /* * Check to see if we were changed into a different method, if so, revert * back if we are not doing session-id reuse. @@ -497,6 +834,121 @@ int SSL_set_trust(SSL *s, int trust) return X509_VERIFY_PARAM_set_trust(s->param, trust); } +int SSL_set1_host(SSL *s, const char *hostname) +{ + return X509_VERIFY_PARAM_set1_host(s->param, hostname, 0); +} + +int SSL_add1_host(SSL *s, const char *hostname) +{ + return X509_VERIFY_PARAM_add1_host(s->param, hostname, 0); +} + +void SSL_set_hostflags(SSL *s, unsigned int flags) +{ + X509_VERIFY_PARAM_set_hostflags(s->param, flags); +} + +const char *SSL_get0_peername(SSL *s) +{ + return X509_VERIFY_PARAM_get0_peername(s->param); +} + +int SSL_CTX_dane_enable(SSL_CTX *ctx) +{ + return dane_ctx_enable(&ctx->dane); +} + +int SSL_dane_enable(SSL *s, const char *basedomain) +{ + struct dane_st *dane = &s->dane; + + if (s->ctx->dane.mdmax == 0) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_CONTEXT_NOT_DANE_ENABLED); + return 0; + } + if (dane->trecs != NULL) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_DANE_ALREADY_ENABLED); + return 0; + } + + /* Primary RFC6125 reference identifier */ + if (!X509_VERIFY_PARAM_set1_host(s->param, basedomain, 0)) { + SSLerr(SSL_F_SSL_DANE_ENABLE, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN); + return -1; + } + + /* Default SNI name */ + if (s->tlsext_hostname == NULL) { + if (!SSL_set_tlsext_host_name(s, basedomain)) + return -1; + } + + dane->mdpth = -1; + dane->pdpth = -1; + dane->dctx = &s->ctx->dane; + dane->trecs = sk_danetls_record_new_null(); + + if (dane->trecs == NULL) { + SSLerr(SSL_F_SSL_DANE_ENABLE, ERR_R_MALLOC_FAILURE); + return -1; + } + return 1; +} + +int SSL_get0_dane_authority(SSL *s, X509 **mcert, EVP_PKEY **mspki) +{ + struct dane_st *dane = &s->dane; + + if (!DANETLS_ENABLED(dane)) + return -1; + if (dane->mtlsa) { + if (mcert) + *mcert = dane->mcert; + if (mspki) + *mspki = (dane->mcert == NULL) ? dane->mtlsa->spki : NULL; + } + return dane->mdpth; +} + +int SSL_get0_dane_tlsa(SSL *s, uint8_t *usage, uint8_t *selector, + uint8_t *mtype, unsigned const char **data, size_t *dlen) +{ + struct dane_st *dane = &s->dane; + + if (!DANETLS_ENABLED(dane)) + return -1; + if (dane->mtlsa) { + if (usage) + *usage = dane->mtlsa->usage; + if (selector) + *selector = dane->mtlsa->selector; + if (mtype) + *mtype = dane->mtlsa->mtype; + if (data) + *data = dane->mtlsa->data; + if (dlen) + *dlen = dane->mtlsa->dlen; + } + return dane->mdpth; +} + +struct dane_st *SSL_get0_dane(SSL *s) +{ + return &s->dane; +} + +int SSL_dane_tlsa_add(SSL *s, uint8_t usage, uint8_t selector, + uint8_t mtype, unsigned char *data, size_t dlen) +{ + return dane_tlsa_add(&s->dane, usage, selector, mtype, data, dlen); +} + +int SSL_CTX_dane_mtype_set(SSL_CTX *ctx, const EVP_MD *md, uint8_t mtype, uint8_t ord) +{ + return dane_mtype_set(&ctx->dane, md, mtype, ord); +} + int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm) { return X509_VERIFY_PARAM_set1(ctx->param, vpm); @@ -543,6 +995,7 @@ void SSL_free(SSL *s) #endif X509_VERIFY_PARAM_free(s->param); + dane_final(&s->dane); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL, s, &s->ex_data); if (s->bbio != NULL) { @@ -877,9 +1330,10 @@ int SSL_copy_session_id(SSL *t, const SSL *f) * what if we are setup for one protocol version but want to talk another */ if (t->method != f->method) { - t->method->ssl_free(t); /* cleanup current */ - t->method = f->method; /* change method */ - t->method->ssl_new(t); /* setup new */ + t->method->ssl_free(t); + t->method = f->method; + if (t->method->ssl_new(t) == 0) + return 0; } CRYPTO_add(&f->cert->references, 1, CRYPTO_LOCK_SSL_CERT); @@ -1922,6 +2376,7 @@ void SSL_CTX_free(SSL_CTX *a) #endif X509_VERIFY_PARAM_free(a->param); + dane_ctx_final(&a->dane); /* * Free internal session cache. However: the remove_cb() may reference @@ -2346,24 +2801,23 @@ const SSL_METHOD *SSL_get_ssl_method(SSL *s) int SSL_set_ssl_method(SSL *s, const SSL_METHOD *meth) { - int conn = -1; int ret = 1; if (s->method != meth) { - if (s->handshake_func != NULL) - conn = (s->handshake_func == s->method->ssl_connect); + const SSL_METHOD *sm = s->method; + int (*hf)(SSL *) = s->handshake_func; - if (s->method->version == meth->version) + if (sm->version == meth->version) s->method = meth; else { - s->method->ssl_free(s); + sm->ssl_free(s); s->method = meth; ret = s->method->ssl_new(s); } - if (conn == 1) + if (hf == sm->ssl_connect) s->handshake_func = meth->ssl_connect; - else if (conn == 0) + else if (hf == sm->ssl_accept) s->handshake_func = meth->ssl_accept; } return (ret); @@ -2554,14 +3008,23 @@ SSL *SSL_dup(SSL *s) SSL *ret; int i; + /* If we're not quiescent, just up_ref! */ + if (!SSL_in_init(s) || !SSL_in_before(s)) { + CRYPTO_add(&s->references, 1, CRYPTO_LOCK_SSL); + return s; + } + + /* + * Otherwise, copy configuration state, and session if set. + */ if ((ret = SSL_new(SSL_get_SSL_CTX(s))) == NULL) return (NULL); - ret->version = s->version; - ret->method = s->method; - if (s->session != NULL) { - /* This copies session-id, SSL_METHOD, sid_ctx, and 'cert' */ + /* + * Arranges to share the same session via up_ref. This "copies" + * session-id, SSL_METHOD, sid_ctx, and 'cert' + */ if (!SSL_copy_session_id(ret, s)) goto err; } else { @@ -2571,10 +3034,8 @@ SSL *SSL_dup(SSL *s) * point to the same object, and thus we can't use * SSL_copy_session_id. */ - - ret->method->ssl_free(ret); - ret->method = s->method; - ret->method->ssl_new(ret); + if (!SSL_set_ssl_method(ret, s->method)) + goto err; if (s->cert != NULL) { ssl_cert_free(ret->cert); @@ -2587,6 +3048,8 @@ SSL *SSL_dup(SSL *s) goto err; } + ssl_dane_dup(ret, s); + ret->version = s->version; ret->options = s->options; ret->mode = s->mode; SSL_set_max_cert_list(ret, SSL_get_max_cert_list(s)); @@ -2617,19 +3080,15 @@ SSL *SSL_dup(SSL *s) } else ret->wbio = ret->rbio; } - ret->rwstate = s->rwstate; - ret->handshake_func = s->handshake_func; + ret->server = s->server; - ret->renegotiate = s->renegotiate; - ret->new_session = s->new_session; - ret->quiet_shutdown = s->quiet_shutdown; + if (s->handshake_func) { + if (s->server) + SSL_set_accept_state(ret); + else + SSL_set_connect_state(ret); + } ret->shutdown = s->shutdown; - ret->statem = s->statem; /* SSL_dup does not really work at any state, - * though */ - RECORD_LAYER_dup(&ret->rlayer, &s->rlayer); - ret->init_num = 0; /* would have to copy ret->init_buf, - * ret->init_msg, ret->init_num, - * ret->init_off */ ret->hit = s->hit; ret->default_passwd_callback = s->default_passwd_callback; diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 7e07297f2f..fee7fa6f15 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -169,6 +169,7 @@ #include "record/record.h" #include "statem/statem.h" #include "packet_locl.h" +#include "internal/dane.h" # ifdef OPENSSL_BUILD_SHLIBSSL # undef OPENSSL_EXTERN @@ -925,6 +926,9 @@ struct ssl_ctx_st { unsigned char *alpn_client_proto_list; unsigned alpn_client_proto_list_len; + /* Shared DANE context */ + struct dane_ctx_st dane; + /* SRTP profiles we are willing to do from RFC 5764 */ STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; /* @@ -1007,6 +1011,10 @@ struct ssl_st { void *msg_callback_arg; int hit; /* reusing a previous session */ X509_VERIFY_PARAM *param; + + /* Per connection DANE state */ + struct dane_st dane; + /* crypto */ STACK_OF(SSL_CIPHER) *cipher_list; STACK_OF(SSL_CIPHER) *cipher_list_by_id; |