diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 0100fb956..70afbd425 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -382,6 +382,7 @@ struct ssl_method_st * Peer SHA256 [13] EXPLICIT OCTET STRING, -- optional SHA256 hash of Peer certifiate * original handshake hash [14] EXPLICIT OCTET STRING, -- optional original handshake hash * tlsext_signed_cert_timestamp_list [15] EXPLICIT OCTET STRING, -- optional signed cert timestamp list extension + * ocsp_response [16] EXPLICIT OCTET STRING, -- optional saved OCSP response from the server * } * Look in ssl/ssl_asn1.c for more details * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-). @@ -449,8 +450,14 @@ struct ssl_session_st uint8_t *tlsext_tick; /* Session ticket */ size_t tlsext_ticklen; /* Session ticket length */ uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ + size_t tlsext_signed_cert_timestamp_list_length; uint8_t *tlsext_signed_cert_timestamp_list; /* Server's list. */ + + /* The OCSP response that came with the session. */ + size_t ocsp_response_length; + uint8_t *ocsp_response; + char peer_sha256_valid; /* Non-zero if peer_sha256 is valid */ unsigned char peer_sha256[SHA256_DIGEST_LENGTH]; /* SHA256 of peer certificate */ @@ -1023,6 +1030,9 @@ struct ssl_ctx_st /* If true, a client will request certificate timestamps. */ char signed_cert_timestamps_enabled; + + /* If true, a client will request a stapled OCSP response. */ + char ocsp_stapling_enabled; }; #endif @@ -1099,6 +1109,15 @@ OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); * client SSL objects created from |ctx|. */ OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); +/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end + * of a connection) to request a stapled OCSP response from the server. Returns + * 1 on success. */ +OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); + +/* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects + * created from |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); + /* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to * |*out_len| bytes of SCT information from the server. This is only valid if * |ssl| is a client. The SCT information is a SignedCertificateTimestampList @@ -1109,6 +1128,13 @@ OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); * WARNING: the returned data is not guaranteed to be well formed. */ OPENSSL_EXPORT void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t *out_len); +/* SSL_get0_ocsp_response sets |*out| and |*out_len| to point to |*out_len| + * bytes of an OCSP response from the server. This is the DER encoding of an + * OCSPResponse type as defined in RFC 2560. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, uint8_t **out, size_t *out_len); + OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *s, int (*cb) (SSL *ssl, const unsigned char **out, @@ -1354,17 +1380,6 @@ struct ssl_st 1 : prepare 2, allow last ack just after in server callback. 2 : don't call servername callback, no ack in server hello */ - /* certificate status request info */ - /* Status type or -1 if no status type */ - int tlsext_status_type; - /* Expect OCSP CertificateStatus message */ - int tlsext_status_expected; - /* OCSP status request only */ - STACK_OF(OCSP_RESPID) *tlsext_ocsp_ids; - X509_EXTENSIONS *tlsext_ocsp_exts; - /* OCSP response received or to be sent */ - uint8_t *tlsext_ocsp_resp; - int tlsext_ocsp_resplen; /* RFC4507 session ticket expected to be received or sent */ int tlsext_ticket_expected; @@ -1409,6 +1424,11 @@ struct ssl_st /* Enable signed certificate time stamps. Currently client only. */ char signed_cert_timestamps_enabled; + /* Enable OCSP stapling. Currently client only. + * TODO(davidben): Add a server-side implementation when it becomes + * necesary. */ + char ocsp_stapling_enabled; + /* For a client, this contains the list of supported protocols in wire * format. */ unsigned char* alpn_client_proto_list; @@ -1648,13 +1668,6 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 #define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB 63 #define SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG 64 -#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE 65 -#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS 66 -#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS 67 -#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS 68 -#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS 69 -#define SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP 70 -#define SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP 71 #define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 2e9b8cc26..44f93677a 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -469,6 +469,11 @@ typedef struct ssl3_state_st /* Server-only: cert_request is true if a client certificate was * requested. */ int cert_request; + + /* certificate_status_expected is true if OCSP stapling was + * negotiated and the server is expected to send a + * CertificateStatus message. */ + char certificate_status_expected; } tmp; /* Connection binding to prevent renegotiation attacks */ diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index b8dd7ae5f..08ad8e894 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -333,27 +333,6 @@ SSL_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_CB,(void (*)(void))cb) #define SSL_set_tlsext_debug_arg(ssl, arg) \ SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_DEBUG_ARG,0, (void *)arg) -#define SSL_set_tlsext_status_type(ssl, type) \ -SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE,type, NULL) - -#define SSL_get_tlsext_status_exts(ssl, arg) \ -SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) - -#define SSL_set_tlsext_status_exts(ssl, arg) \ -SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS,0, (void *)arg) - -#define SSL_get_tlsext_status_ids(ssl, arg) \ -SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) - -#define SSL_set_tlsext_status_ids(ssl, arg) \ -SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS,0, (void *)arg) - -#define SSL_get_tlsext_status_ocsp_resp(ssl, arg) \ -SSL_ctrl(ssl,SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP,0, (void *)arg) - -#define SSL_set_tlsext_status_ocsp_resp(ssl, arg, arglen) \ -SSL_ctrl(ssl,SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP,arglen, (void *)arg) - #define SSL_CTX_set_tlsext_servername_callback(ctx, cb) \ SSL_CTX_callback_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SERVERNAME_CB,(void (*)(void))cb) diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c index 4fcf0c34e..b781d8875 100644 --- a/ssl/d1_clnt.c +++ b/ssl/d1_clnt.c @@ -309,7 +309,7 @@ int dtls1_connect(SSL *s) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) s->state=SSL3_ST_CR_CERT_STATUS_A; else s->state=SSL3_ST_CR_KEY_EXCH_A; diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 102d442a8..79da484f5 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -359,7 +359,7 @@ int dtls1_accept(SSL *s) dtls1_start_timer(s); ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) s->state=SSL3_ST_SW_CERT_STATUS_A; else s->state=SSL3_ST_SW_KEY_EXCH_A; @@ -522,6 +522,8 @@ int dtls1_accept(SSL *s) s->init_num=0; break; +#if 0 + // TODO(davidben): Implement OCSP stapling on the server. case SSL3_ST_SW_CERT_STATUS_A: case SSL3_ST_SW_CERT_STATUS_B: ret=ssl3_send_cert_status(s); @@ -529,7 +531,7 @@ int dtls1_accept(SSL *s) s->state=SSL3_ST_SW_KEY_EXCH_A; s->init_num=0; break; - +#endif case SSL3_ST_SW_CHANGE_A: case SSL3_ST_SW_CHANGE_B: diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 63fbbeb54..44d26a78b 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -299,7 +299,7 @@ int ssl3_connect(SSL *s) { ret=ssl3_get_server_certificate(s); if (ret <= 0) goto end; - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) s->state=SSL3_ST_CR_CERT_STATUS_A; else s->state=SSL3_ST_CR_KEY_EXCH_A; @@ -1798,7 +1798,6 @@ int ssl3_get_cert_status(SSL *s) long n; CBS certificate_status, ocsp_response; uint8_t status_type; - size_t resplen; n=s->method->ssl_get_message(s, SSL3_ST_CR_CERT_STATUS_A, @@ -1822,34 +1821,13 @@ int ssl3_get_cert_status(SSL *s) goto f_err; } - /* TODO(davidben): Make tlsext_ocsp_resplen a - * size_t. Currently it uses -1 to signal no response. The - * spec does not allow ocsp_response to be zero-length, so - * using 0 should be fine. */ - if (!CBS_stow(&ocsp_response, &s->tlsext_ocsp_resp, &resplen)) + if (!CBS_stow(&ocsp_response, + &s->session->ocsp_response, &s->session->ocsp_response_length)) { al = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE); goto f_err; } - s->tlsext_ocsp_resplen = resplen; - if (s->ctx->tlsext_status_cb) - { - int ret; - ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); - if (ret == 0) - { - al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, SSL_R_INVALID_STATUS_RESPONSE); - goto f_err; - } - if (ret < 0) - { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, ssl3_get_cert_status, ERR_R_MALLOC_FAILURE); - goto f_err; - } - } return 1; f_err: ssl3_send_alert(s,SSL3_AL_FATAL,al); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 50aa4bdd3..479b6de82 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -1252,44 +1252,6 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) ret = 1; break; - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: - s->tlsext_status_type=larg; - ret = 1; - break; - - case SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS: - *(STACK_OF(X509_EXTENSION) **)parg = s->tlsext_ocsp_exts; - ret = 1; - break; - - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS: - s->tlsext_ocsp_exts = parg; - ret = 1; - break; - - case SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS: - *(STACK_OF(OCSP_RESPID) **)parg = s->tlsext_ocsp_ids; - ret = 1; - break; - - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS: - s->tlsext_ocsp_ids = parg; - ret = 1; - break; - - case SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: - *(unsigned char **)parg = s->tlsext_ocsp_resp; - return s->tlsext_ocsp_resplen; - - case SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: - if (s->tlsext_ocsp_resp) - OPENSSL_free(s->tlsext_ocsp_resp); - s->tlsext_ocsp_resp = parg; - s->tlsext_ocsp_resplen = larg; - ret = 1; - break; - - case SSL_CTRL_CHAIN: if (larg) return ssl_cert_set1_chain(s->cert, diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 1017f4aa8..0e9c7d565 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -352,7 +352,7 @@ int ssl3_accept(SSL *s) { ret=ssl3_send_server_certificate(s); if (ret <= 0) goto end; - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) s->state=SSL3_ST_SW_CERT_STATUS_A; else s->state=SSL3_ST_SW_KEY_EXCH_A; @@ -569,6 +569,8 @@ int ssl3_accept(SSL *s) s->init_num=0; break; +#if 0 + // TODO(davidben): Implement OCSP stapling on the server. case SSL3_ST_SW_CERT_STATUS_A: case SSL3_ST_SW_CERT_STATUS_B: ret=ssl3_send_cert_status(s); @@ -576,6 +578,7 @@ int ssl3_accept(SSL *s) s->state=SSL3_ST_SW_KEY_EXCH_A; s->init_num=0; break; +#endif case SSL3_ST_SW_CHANGE_A: case SSL3_ST_SW_CHANGE_B: @@ -1137,16 +1140,6 @@ int ssl3_get_client_hello(SSL *s) * s->tmp.new_cipher - the new cipher to use. */ - /* Handles TLS extensions that we couldn't check earlier */ - if (s->version >= SSL3_VERSION) - { - if (ssl_check_clienthello_tlsext_late(s) <= 0) - { - OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_CLIENTHELLO_TLSEXT); - goto err; - } - } - if (ret < 0) ret=-ret; if (0) { @@ -2651,6 +2644,7 @@ int ssl3_send_new_session_ticket(SSL *s) return ssl_do_write(s); } +#if 0 int ssl3_send_cert_status(SSL *s) { if (s->state == SSL3_ST_SW_CERT_STATUS_A) @@ -2685,6 +2679,7 @@ int ssl3_send_cert_status(SSL *s) /* SSL3_ST_SW_CERT_STATUS_B */ return(ssl3_do_write(s,SSL3_RT_HANDSHAKE)); } +#endif /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It * sets the next_proto member in s if found */ diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 05c646264..8acd0eb95 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -120,12 +120,13 @@ typedef struct ssl_session_asn1_st ASN1_OCTET_STRING peer_sha256; ASN1_OCTET_STRING original_handshake_hash; ASN1_OCTET_STRING tlsext_signed_cert_timestamp_list; + ASN1_OCTET_STRING ocsp_response; } SSL_SESSION_ASN1; int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) { #define LSIZE2 (sizeof(long)*2) - int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0; + int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0,v16=0; unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2]; unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2]; int v6=0,v9=0,v10=0; @@ -269,6 +270,13 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) in->tlsext_signed_cert_timestamp_list; } + if (in->ocsp_response_length > 0) + { + a.ocsp_response.length = in->ocsp_response_length; + a.ocsp_response.type = V_ASN1_OCTET_STRING; + a.ocsp_response.data = in->ocsp_response; + } + M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER); M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER); M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING); @@ -303,6 +311,8 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->tlsext_signed_cert_timestamp_list_length > 0) M_ASN1_I2D_len_EXP_opt(&(a.tlsext_signed_cert_timestamp_list), i2d_ASN1_OCTET_STRING, 15, v15); + if (in->ocsp_response_length > 0) + M_ASN1_I2D_len_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16); M_ASN1_I2D_seq_total(); @@ -340,6 +350,8 @@ int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) if (in->tlsext_signed_cert_timestamp_list_length > 0) M_ASN1_I2D_put_EXP_opt(&(a.tlsext_signed_cert_timestamp_list), i2d_ASN1_OCTET_STRING, 15, v15); + if (in->ocsp_response > 0) + M_ASN1_I2D_put_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16); M_ASN1_I2D_finish(); } @@ -600,6 +612,18 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, os.data = NULL; } + os.length = 0; + os.data = NULL; + M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 16); + if (os.data) + { + if (ret->ocsp_response) + OPENSSL_free(ret->ocsp_response); + ret->ocsp_response = os.data; + ret->ocsp_response_length = os.length; + os.data = NULL; + } + M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION); } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 01d59c47f..58684b0e2 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -336,12 +336,6 @@ SSL *SSL_new(SSL_CTX *ctx) s->tlsext_debug_cb = 0; s->tlsext_debug_arg = NULL; s->tlsext_ticket_expected = 0; - s->tlsext_status_type = -1; - s->tlsext_status_expected = 0; - s->tlsext_ocsp_ids = NULL; - s->tlsext_ocsp_exts = NULL; - s->tlsext_ocsp_resp = NULL; - s->tlsext_ocsp_resplen = -1; CRYPTO_add(&ctx->references,1,CRYPTO_LOCK_SSL_CTX); s->initial_ctx=ctx; if (ctx->tlsext_ecpointformatlist) @@ -401,7 +395,10 @@ SSL *SSL_new(SSL_CTX *ctx) s->psk_server_callback=ctx->psk_server_callback; if (!s->server) + { s->signed_cert_timestamps_enabled = s->ctx->signed_cert_timestamps_enabled; + s->ocsp_stapling_enabled = s->ctx->ocsp_stapling_enabled; + } return(s); err: @@ -670,16 +667,6 @@ void SSL_free(SSL *s) if (s->initial_ctx) SSL_CTX_free(s->initial_ctx); if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist); if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist); - if (s->tlsext_ocsp_exts) - sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, - X509_EXTENSION_free); - /* TODO(fork): OCSP support */ -#if 0 - if (s->tlsext_ocsp_ids) - sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); -#endif - if (s->tlsext_ocsp_resp) - OPENSSL_free(s->tlsext_ocsp_resp); if (s->alpn_client_proto_list) OPENSSL_free(s->alpn_client_proto_list); if (s->tlsext_channel_id_private) @@ -1677,7 +1664,7 @@ void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx) int SSL_enable_signed_cert_timestamps(SSL *ssl) { - /* Currently not implemented server side */ + /* Currently not implemented server-side. */ if (ssl->server) return 0; @@ -1685,6 +1672,20 @@ int SSL_enable_signed_cert_timestamps(SSL *ssl) return 1; } +void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx) + { + ctx->ocsp_stapling_enabled = 1; + } + +int SSL_enable_ocsp_stapling(SSL *ssl) + { + /* Currently not implemented server-side. */ + if (ssl->server) + return 0; + ssl->ocsp_stapling_enabled = 1; + return 1; + } + void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t *out_len) { SSL_SESSION *session = ssl->session; @@ -1699,6 +1700,20 @@ void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, uint8_t **out, size_t * *out_len = session->tlsext_signed_cert_timestamp_list_length; } +void SSL_get0_ocsp_response(const SSL *ssl, uint8_t **out, size_t *out_len) + { + SSL_SESSION *session = ssl->session; + + *out_len = 0; + *out = NULL; + if (ssl->server) + return; + if (!session || !session->ocsp_response) + return; + *out = session->ocsp_response; + *out_len = session->ocsp_response_length; + } + /* SSL_select_next_proto implements the standard protocol selection. It is * expected that this function is called from the callback set by * SSL_CTX_set_next_proto_select_cb. diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 0aefaa444..ad2d8431c 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1069,7 +1069,6 @@ int tls1_shared_list(SSL *s, unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, size_t header_len); unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit); int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs); -int ssl_check_clienthello_tlsext_late(SSL *s); int ssl_parse_serverhello_tlsext(SSL *s, CBS *cbs); int ssl_prepare_clienthello_tlsext(SSL *s); int ssl_prepare_serverhello_tlsext(SSL *s); diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index c48c64bdc..7fd17248f 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -716,6 +716,8 @@ void SSL_SESSION_free(SSL_SESSION *ss) if (ss->tlsext_ellipticcurvelist != NULL) OPENSSL_free(ss->tlsext_ellipticcurvelist); if (ss->tlsext_signed_cert_timestamp_list != NULL) OPENSSL_free(ss->tlsext_signed_cert_timestamp_list); + if (ss->ocsp_response != NULL) + OPENSSL_free(ss->ocsp_response); if (ss->psk_identity_hint != NULL) OPENSSL_free(ss->psk_identity_hint); if (ss->psk_identity != NULL) diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index cafcfa29d..8fdd8137b 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -121,8 +121,8 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, int ticklen, const unsigned char *sess_id, int sesslen, SSL_SESSION **psess); -static int ssl_check_clienthello_tlsext_early(SSL *s); -int ssl_check_serverhello_tlsext(SSL *s); +static int ssl_check_clienthello_tlsext(SSL *s); +static int ssl_check_serverhello_tlsext(SSL *s); SSL3_ENC_METHOD TLSv1_enc_data={ tls1_enc, @@ -1025,56 +1025,23 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c ret += salglen; } - /* TODO(fork): we probably want OCSP stapling, but it currently pulls in a lot of code. */ -#if 0 - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) + if (s->ocsp_stapling_enabled) { - int i; - long extlen, idlen, itmp; - OCSP_RESPID *id; + /* The status_request extension is excessively extensible at + * every layer. On the client, only support requesting OCSP + * responses with an empty responder_id_list and no + * extensions. */ + if (limit - ret - 4 - 1 - 2 - 2 < 0) return NULL; - idlen = 0; - for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) - { - id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); - itmp = i2d_OCSP_RESPID(id, NULL); - if (itmp <= 0) - return NULL; - idlen += itmp + 2; - } - - if (s->tlsext_ocsp_exts) - { - extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); - if (extlen < 0) - return NULL; - } - else - extlen = 0; - - if ((long)(limit - ret - 7 - extlen - idlen) < 0) return NULL; s2n(TLSEXT_TYPE_status_request, ret); - if (extlen + idlen > 0xFFF0) - return NULL; - s2n(extlen + idlen + 5, ret); + s2n(1 + 2 + 2, ret); + /* status_type */ *(ret++) = TLSEXT_STATUSTYPE_ocsp; - s2n(idlen, ret); - for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) - { - /* save position of id len */ - unsigned char *q = ret; - id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); - /* skip over id len */ - ret += 2; - itmp = i2d_OCSP_RESPID(id, &ret); - /* write id len */ - s2n(itmp, q); - } - s2n(extlen, ret); - if (extlen > 0) - i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); + /* responder_id_list - empty */ + s2n(0, ret); + /* request_extensions - empty */ + s2n(0, ret); } -#endif if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) { @@ -1311,7 +1278,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c s2n(0,ret); } - if (s->tlsext_status_expected) + if (s->s3->tmp.certificate_status_expected) { if ((long)(limit - ret - 4) < 0) return NULL; s2n(TLSEXT_TYPE_status_request,ret); @@ -1452,8 +1419,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) size_t i; s->servername_done = 0; - s->tlsext_status_type = -1; s->s3->next_proto_neg_seen = 0; + s->s3->tmp.certificate_status_expected = 0; if (s->s3->alpn_selected) { @@ -1480,23 +1447,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) s->cert->pkeys[i].valid_flags = 0; } - /* TODO(fork): we probably want OCSP stapling support, but this pulls in - * a lot of code. */ -#if 0 - /* Clear OCSP state. */ - s->tlsext_status_type = -1; - if (s->tlsext_ocsp_ids) - { - sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); - s->tlsext_ocsp_ids = NULL; - } - if (s->tlsext_ocsp_exts) - { - sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, X509_EXTENSION_free); - s->tlsext_ocsp_exts = NULL; - } -#endif - /* There may be no extensions. */ if (CBS_len(cbs) == 0) { @@ -1745,119 +1695,6 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) } } - /* TODO(fork): we probably want OCSP stapling support, but this pulls in a lot of code. */ -#if 0 - else if (type == TLSEXT_TYPE_status_request) - { - uint8_t status_type; - CBS responder_id_list; - CBS request_extensions; - - if (!CBS_get_u8(&extension, &status_type)) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - /* Only OCSP is supported. */ - if (status_type != TLSEXT_STATUSTYPE_ocsp) - continue; - - s->tlsext_status_type = status_type; - - /* Extension consists of a responder_id_list and - * request_extensions. */ - if (!CBS_get_u16_length_prefixed(&extension, &responder_id_list) || - !CBS_get_u16_length_prefixed(&extension, &request_extensions) || - CBS_len(&extension) != 0) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - if (CBS_len(&responder_id_list) > 0) - { - s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null(); - if (s->tlsext_ocsp_ids == NULL) - { - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - } - - /* Parse out the responder IDs. */ - while (CBS_len(&responder_id_list) > 0) - { - CBS responder_id; - OCSP_RESPID *id; - const uint8_t *data; - - /* Each ResponderID must have size at least 1. */ - if (!CBS_get_u16_length_prefixed(&responder_id_list, &responder_id) || - CBS_len(&responder_id) < 1) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - - /* TODO(fork): Add CBS versions of d2i_FOO_BAR. */ - data = CBS_data(&responder_id); - id = d2i_OCSP_RESPID(NULL, &data, CBS_len(&responder_id)); - if (!id) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - if (!CBS_skip(&responder_id, data - CBS_data(&responder_id))) - { - /* This should never happen. */ - *out_alert = SSL_AD_INTERNAL_ERROR; - OCSP_RESPID_free(id); - return 0; - } - if (CBS_len(&responder_id) != 0) - { - *out_alert = SSL_AD_DECODE_ERROR; - OCSP_RESPID_free(id); - return 0; - } - - if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) - { - *out_alert = SSL_AD_INTERNAL_ERROR; - OCSP_RESPID_free(id); - return 0; - } - } - - /* Parse out request_extensions. */ - if (CBS_len(&request_extensions) > 0) - { - const uint8_t *data; - - data = CBS_data(&request_extensions); - s->tlsext_ocsp_exts = d2i_X509_EXTENSIONS(NULL, - &data, CBS_len(&request_extensions)); - if (s->tlsext_ocsp_exts == NULL) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - if (!CBS_skip(&request_extensions, data - CBS_data(&request_extensions))) - { - /* This should never happen. */ - *out_alert = SSL_AD_INTERNAL_ERROR; - return 0; - } - if (CBS_len(&request_extensions) != 0) - { - *out_alert = SSL_AD_DECODE_ERROR; - return 0; - } - } - } -#endif - else if (type == TLSEXT_TYPE_next_proto_neg && s->s3->tmp.finish_md_len == 0 && s->s3->alpn_selected == NULL) @@ -1960,7 +1797,7 @@ int ssl_parse_clienthello_tlsext(SSL *s, CBS *cbs) return 0; } - if (ssl_check_clienthello_tlsext_early(s) <= 0) + if (ssl_check_clienthello_tlsext(s) <= 0) { OPENSSL_PUT_ERROR(SSL, ssl_parse_clienthello_tlsext, SSL_R_CLIENTHELLO_TLSEXT); return 0; @@ -1993,9 +1830,13 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) int renegotiate_seen = 0; CBS extensions; + /* TODO(davidben): Move all of these to some per-handshake state that + * gets systematically reset on a new handshake; perhaps allocate it + * fresh each time so it's not even kept around post-handshake. */ s->s3->next_proto_neg_seen = 0; - s->tlsext_ticket_expected = 0; + s->tlsext_ticket_expected = 0; + s->s3->tmp.certificate_status_expected = 0; if (s->s3->alpn_selected) { @@ -2101,13 +1942,13 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) *out_alert = SSL_AD_DECODE_ERROR; return 0; } - if (s->tlsext_status_type == -1) + if (!s->ocsp_stapling_enabled) { *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; return 0; } /* Set a flag to expect a CertificateStatus message */ - s->tlsext_status_expected = 1; + s->s3->tmp.certificate_status_expected = 1; } else if (type == TLSEXT_TYPE_next_proto_neg && s->s3->tmp.finish_md_len == 0) { unsigned char *selected; @@ -2281,7 +2122,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s) return 1; } -static int ssl_check_clienthello_tlsext_early(SSL *s) +static int ssl_check_clienthello_tlsext(SSL *s) { int ret=SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -2315,72 +2156,7 @@ static int ssl_check_clienthello_tlsext_early(SSL *s) } } -int ssl_check_clienthello_tlsext_late(SSL *s) - { - int ret = SSL_TLSEXT_ERR_OK; - int al; - - /* If status request then ask callback what to do. - * Note: this must be called after servername callbacks in case - * the certificate has changed, and must be called after the cipher - * has been chosen because this may influence which certificate is sent - */ - if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) - { - int r; - CERT_PKEY *certpkey; - certpkey = ssl_get_server_send_pkey(s); - /* If no certificate can't return certificate status */ - if (certpkey == NULL) - { - s->tlsext_status_expected = 0; - return 1; - } - /* Set current certificate to one we will use so - * SSL_get_certificate et al can pick it up. - */ - s->cert->key = certpkey; - r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); - switch (r) - { - /* We don't want to send a status request response */ - case SSL_TLSEXT_ERR_NOACK: - s->tlsext_status_expected = 0; - break; - /* status request response should be sent */ - case SSL_TLSEXT_ERR_OK: - if (s->tlsext_ocsp_resp) - s->tlsext_status_expected = 1; - else - s->tlsext_status_expected = 0; - break; - /* something bad happened */ - case SSL_TLSEXT_ERR_ALERT_FATAL: - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - al = SSL_AD_INTERNAL_ERROR; - goto err; - } - } - else - s->tlsext_status_expected = 0; - - err: - switch (ret) - { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return -1; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(s, SSL3_AL_WARNING, al); - return 1; - - default: - return 1; - } - } - -int ssl_check_serverhello_tlsext(SSL *s) +static int ssl_check_serverhello_tlsext(SSL *s) { int ret=SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -2421,35 +2197,6 @@ int ssl_check_serverhello_tlsext(SSL *s) else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0) ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg); - /* If we've requested certificate status and we wont get one - * tell the callback - */ - if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected) - && s->ctx && s->ctx->tlsext_status_cb) - { - int r; - /* Set resp to NULL, resplen to -1 so callback knows - * there is no response. - */ - if (s->tlsext_ocsp_resp) - { - OPENSSL_free(s->tlsext_ocsp_resp); - s->tlsext_ocsp_resp = NULL; - } - s->tlsext_ocsp_resplen = -1; - r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg); - if (r == 0) - { - al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE; - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - } - if (r < 0) - { - al = SSL_AD_INTERNAL_ERROR; - ret = SSL_TLSEXT_ERR_ALERT_FATAL; - } - } - switch (ret) { case SSL_TLSEXT_ERR_ALERT_FATAL: