From 2c7b4dbc1af9cfae4e4afd7c4a07db95a1133a6a Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Wed, 3 Aug 2016 20:57:52 +0100 Subject: [PATCH] Convert tls_construct_client_hello() to use PACKETW Reviewed-by: Rich Salz --- include/openssl/ssl.h | 3 +- ssl/d1_lib.c | 4 + ssl/d1_srtp.c | 43 ---- ssl/s3_lib.c | 40 +++- ssl/ssl_err.c | 4 +- ssl/ssl_locl.h | 40 +++- ssl/statem/statem_clnt.c | 196 +++++++++------- ssl/statem/statem_dtls.c | 43 ++++ ssl/statem/statem_lib.c | 14 ++ ssl/statem/statem_srvr.c | 4 +- ssl/t1_ext.c | 70 +++++- ssl/t1_lib.c | 490 +++++++++++++++++++++------------------ ssl/t1_reneg.c | 24 -- 13 files changed, 585 insertions(+), 390 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 41cb36e943..af6d9b5ad6 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2120,6 +2120,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_CHECK_PRIVATE_KEY 163 # define SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT 280 # define SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG 279 +# define SSL_F_SSL_CIPHER_LIST_TO_BYTES 425 # define SSL_F_SSL_CIPHER_PROCESS_RULESTR 230 # define SSL_F_SSL_CIPHER_STRENGTH_SORT 231 # define SSL_F_SSL_CLEAR 164 @@ -2456,9 +2457,9 @@ int ERR_load_SSL_strings(void); # define SSL_R_SSL_SECTION_NOT_FOUND 136 # define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 301 # define SSL_R_SSL_SESSION_ID_CONFLICT 302 -# define SSL_R_SSL_SESSION_ID_TOO_LONG 408 # define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273 # define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303 +# define SSL_R_SSL_SESSION_ID_TOO_LONG 408 # define SSL_R_SSL_SESSION_VERSION_MISMATCH 210 # define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 # define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 0ada7edf77..043057f421 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -44,6 +44,8 @@ const SSL3_ENC_METHOD DTLSv1_enc_data = { SSL_ENC_FLAG_DTLS | SSL_ENC_FLAG_EXPLICIT_IV, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, + dtls1_set_handshake_header2, + dtls1_close_construct_packet, dtls1_handshake_write }; @@ -63,6 +65,8 @@ const SSL3_ENC_METHOD DTLSv1_2_enc_data = { | SSL_ENC_FLAG_SHA256_PRF | SSL_ENC_FLAG_TLS1_2_CIPHERS, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, + dtls1_set_handshake_header2, + dtls1_close_construct_packet, dtls1_handshake_write }; diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c index 7e88f17754..b5e5ef3f51 100644 --- a/ssl/d1_srtp.c +++ b/ssl/d1_srtp.c @@ -136,49 +136,6 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) return s->srtp_profile; } -/* - * Note: this function returns 0 length if there are no profiles specified - */ -int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, - int maxlen) -{ - int ct = 0; - int i; - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; - SRTP_PROTECTION_PROFILE *prof; - - clnt = SSL_get_srtp_profiles(s); - ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); /* -1 if clnt == 0 */ - - if (p) { - if (ct == 0) { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT, - SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST); - return 1; - } - - if ((2 + ct * 2 + 1) > maxlen) { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_USE_SRTP_EXT, - SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG); - return 1; - } - - /* Add the length */ - s2n(ct * 2, p); - for (i = 0; i < ct; i++) { - prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); - s2n(prof->id, p); - } - - /* Add an empty use_mki value */ - *p++ = 0; - } - - *len = 2 + ct * 2 + 1; - - return 0; -} - int ssl_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al) { SRTP_PROTECTION_PROFILE *sprof; diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index e94ee83717..9f7c6cc782 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -2751,6 +2751,8 @@ const SSL3_ENC_METHOD SSLv3_enc_data = { 0, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, + ssl3_set_handshake_header2, + tls_close_construct_packet, ssl3_handshake_write }; @@ -2787,6 +2789,22 @@ int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) return 1; } +/* + * Temporary name. To be renamed ssl3_set_handshake_header() once all PACKETW + * conversion is complete. The old ssl3_set_handshake_heder() can be deleted + * at that point. + * TODO - RENAME ME + */ +int ssl3_set_handshake_header2(SSL *s, PACKETW *pkt, PACKETW *body, int htype) +{ + /* Set the content type and 3 bytes for the message len */ + if (!PACKETW_put_bytes(pkt, htype, 1) + || !PACKETW_get_sub_packet_len(pkt, body, 3)) + return 0; + + return 1; +} + int ssl3_handshake_write(SSL *s) { return ssl3_do_write(s, SSL3_RT_HANDSHAKE); @@ -3553,7 +3571,13 @@ const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p) return cp; } -int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) +/* + * Old version of the ssl3_put_cipher_by_char function used by code that has not + * yet been converted to PACKETW yet. It will be deleted once PACKETW conversion + * is complete. + * TODO - DELETE ME + */ +int ssl3_put_cipher_by_char_old(const SSL_CIPHER *c, unsigned char *p) { long l; @@ -3567,6 +3591,20 @@ int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p) return (2); } +int ssl3_put_cipher_by_char(const SSL_CIPHER *c, PACKETW *pkt, size_t *len) +{ + if ((c->id & 0xff000000) != 0x03000000) { + *len = 0; + return 1; + } + + if (!PACKETW_put_bytes(pkt, c->id & 0xffff, 2)) + return 0; + + *len = 2; + return 1; +} + /* * ssl3_choose_cipher - choose a cipher from those offered by the client * @s: SSL connection diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 1fddda612a..f776f61cfa 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -107,6 +107,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { "ssl_check_serverhello_tlsext"}, {ERR_FUNC(SSL_F_SSL_CHECK_SRVR_ECC_CERT_AND_ALG), "ssl_check_srvr_ecc_cert_and_alg"}, + {ERR_FUNC(SSL_F_SSL_CIPHER_LIST_TO_BYTES), "ssl_cipher_list_to_bytes"}, {ERR_FUNC(SSL_F_SSL_CIPHER_PROCESS_RULESTR), "ssl_cipher_process_rulestr"}, {ERR_FUNC(SSL_F_SSL_CIPHER_STRENGTH_SORT), "ssl_cipher_strength_sort"}, @@ -567,10 +568,9 @@ static ERR_STRING_DATA SSL_str_reasons[] = { {ERR_REASON(SSL_R_SSL_SESSION_ID_CONFLICT), "ssl session id conflict"}, {ERR_REASON(SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG), "ssl session id context too long"}, - {ERR_REASON(SSL_R_SSL_SESSION_ID_TOO_LONG), - "ssl session id too long"}, {ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH), "ssl session id has bad length"}, + {ERR_REASON(SSL_R_SSL_SESSION_ID_TOO_LONG), "ssl session id too long"}, {ERR_REASON(SSL_R_SSL_SESSION_VERSION_MISMATCH), "ssl session version mismatch"}, {ERR_REASON(SSL_R_TLSV1_ALERT_ACCESS_DENIED), diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 4079b31637..29ad18d05f 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -457,7 +457,8 @@ struct ssl_method_st { long (*ssl_ctrl) (SSL *s, int cmd, long larg, void *parg); long (*ssl_ctx_ctrl) (SSL_CTX *ctx, int cmd, long larg, void *parg); const SSL_CIPHER *(*get_cipher_by_char) (const unsigned char *ptr); - int (*put_cipher_by_char) (const SSL_CIPHER *cipher, unsigned char *ptr); + int (*put_cipher_by_char) (const SSL_CIPHER *cipher, PACKETW *pkt, + size_t *len); int (*ssl_pending) (const SSL *s); int (*num_ciphers) (void); const SSL_CIPHER *(*get_cipher) (unsigned ncipher); @@ -1584,6 +1585,11 @@ typedef struct ssl3_enc_method { unsigned int hhlen; /* Set the handshake header */ int (*set_handshake_header) (SSL *s, int type, unsigned long len); + /* Set the handshake header */ + int (*set_handshake_header2) (SSL *s, PACKETW *pkt, PACKETW *body, + int type); + /* Close construction of the handshake message */ + int (*close_construct_packet) (SSL *s, PACKETW *pkt); /* Write out handshake message */ int (*do_write) (SSL *s); } SSL3_ENC_METHOD; @@ -1593,6 +1599,10 @@ typedef struct ssl3_enc_method { (((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen) # define ssl_set_handshake_header(s, htype, len) \ s->method->ssl3_enc->set_handshake_header(s, htype, len) +# define ssl_set_handshake_header2(s, pkt, body, htype) \ + s->method->ssl3_enc->set_handshake_header2((s), (pkt), (body), (htype)) +# define ssl_close_construct_packet(s, pkt) \ + s->method->ssl3_enc->close_construct_packet((s), (pkt)) # define ssl_do_write(s) s->method->ssl3_enc->do_write(s) /* Values for enc_flags */ @@ -1854,7 +1864,9 @@ __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey); __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh); __owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p); -__owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, unsigned char *p); +__owur int ssl3_put_cipher_by_char_old(const SSL_CIPHER *c, unsigned char *p); +__owur int ssl3_put_cipher_by_char(const SSL_CIPHER *c, PACKETW *pkt, + size_t *len); int ssl3_init_finished_mac(SSL *s); __owur int ssl3_setup_key_block(SSL *s); __owur int ssl3_change_cipher_state(SSL *s, int which); @@ -1894,6 +1906,12 @@ __owur int ssl3_do_change_cipher_spec(SSL *ssl); __owur long ssl3_default_timeout(void); __owur int ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); +__owur int ssl3_set_handshake_header2(SSL *s, PACKETW *pkt, PACKETW *body, + int htype); +__owur int tls_close_construct_packet(SSL *s, PACKETW *pkt); +__owur int dtls1_set_handshake_header2(SSL *s, PACKETW *pkt, PACKETW *body, + int htype); +__owur int dtls1_close_construct_packet(SSL *s, PACKETW *pkt); __owur int ssl3_handshake_write(SSL *s); __owur int ssl_allow_compression(SSL *s); @@ -2002,8 +2020,7 @@ __owur EVP_PKEY *ssl_generate_pkey_curve(int id); __owur int tls1_shared_list(SSL *s, const unsigned char *l1, size_t l1len, const unsigned char *l2, size_t l2len, int nmatch); -__owur unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, - unsigned char *limit, int *al); +__owur int ssl_add_clienthello_tlsext(SSL *s, PACKETW *pkt, int *al); __owur unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned char *limit, int *al); __owur int ssl_parse_clienthello_tlsext(SSL *s, PACKET *pkt); @@ -2054,12 +2071,12 @@ void ssl_clear_hash_ctx(EVP_MD_CTX **hash); __owur int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len, int maxlen); __owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al); -__owur int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, - int *len, int maxlen); __owur int ssl_parse_clienthello_renegotiate_ext(SSL *s, PACKET *pkt, int *al); __owur long ssl_get_algorithm2(SSL *s); -__owur size_t tls12_copy_sigalgs(SSL *s, unsigned char *out, - const unsigned char *psig, size_t psiglen); +__owur size_t tls12_copy_sigalgs_old(SSL *s, unsigned char *out, + const unsigned char *psig, size_t psiglen); +__owur int tls12_copy_sigalgs(SSL *s, PACKETW *pkt, + const unsigned char *psig, size_t psiglen); __owur int tls1_save_sigalgs(SSL *s, const unsigned char *data, int dsize); __owur int tls1_process_sigalgs(SSL *s); __owur size_t tls12_get_psigalgs(SSL *s, const unsigned char **psigs); @@ -2068,8 +2085,6 @@ __owur int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, void ssl_set_client_disabled(SSL *s); __owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op); -__owur int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, - int maxlen); __owur int ssl_parse_clienthello_use_srtp_ext(SSL *s, PACKET *pkt, int *al); __owur int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen); @@ -2108,8 +2123,9 @@ __owur int custom_ext_parse(SSL *s, int server, unsigned int ext_type, const unsigned char *ext_data, size_t ext_size, int *al); -__owur int custom_ext_add(SSL *s, int server, unsigned char **pret, - unsigned char *limit, int *al); +__owur int custom_ext_add_old(SSL *s, int server, unsigned char **pret, + unsigned char *limit, int *al); +__owur int custom_ext_add(SSL *s, int server, PACKETW *pkt, int *al); __owur int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index ff42858ff3..0fdcfa2b59 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -63,7 +63,7 @@ static ossl_inline int cert_req_allowed(SSL *s); static int key_exchange_expected(SSL *s); static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b); static int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, - unsigned char *p); + PACKETW *pkt); /* * Is a CertificateRequest message allowed at the moment or not? @@ -689,19 +689,22 @@ WORK_STATE ossl_statem_client_post_process_message(SSL *s, WORK_STATE wst) int tls_construct_client_hello(SSL *s) { - unsigned char *buf; - unsigned char *p, *d; + unsigned char *p; int i; int protverr; - unsigned long l; - int al = 0; + int al = SSL_AD_HANDSHAKE_FAILURE; #ifndef OPENSSL_NO_COMP - int j; SSL_COMP *comp; #endif SSL_SESSION *sess = s->session; + PACKETW pkt, body, spkt; - buf = (unsigned char *)s->init_buf->data; + if (!PACKETW_init(&pkt, s->init_buf) + || !PACKETW_set_max_size(&pkt, SSL3_RT_MAX_PLAIN_LENGTH)) { + /* Should not happen */ + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } /* Work out what SSL/TLS/DTLS version to use */ protverr = ssl_set_client_hello_version(s); @@ -743,8 +746,11 @@ int tls_construct_client_hello(SSL *s) if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)) <= 0) goto err; - /* Do the message type and length last */ - d = p = ssl_handshake_start(s); + if (!ssl_set_handshake_header2(s, &pkt, &body, SSL3_MT_CLIENT_HELLO)) { + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } /*- * version indicates the negotiated version: for example from @@ -776,90 +782,92 @@ int tls_construct_client_hello(SSL *s) * client_version in client hello and not resetting it to * the negotiated version. */ - *(p++) = s->client_version >> 8; - *(p++) = s->client_version & 0xff; - - /* Random stuff */ - memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE); - p += SSL3_RANDOM_SIZE; + if (!PACKETW_put_bytes(&body, s->client_version, 2) + || !PACKETW_memcpy(&body, s->s3->client_random, SSL3_RANDOM_SIZE)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } /* Session ID */ if (s->new_session) i = 0; else i = s->session->session_id_length; - *(p++) = i; - if (i != 0) { - if (i > (int)sizeof(s->session->session_id)) { - SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); - goto err; - } - memcpy(p, s->session->session_id, i); - p += i; + if (i > (int)sizeof(s->session->session_id) + || !PACKETW_get_sub_packet_len(&body, &spkt, 1) + || (i != 0 && !PACKETW_memcpy(&spkt, s->session->session_id, i)) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; } /* cookie stuff for DTLS */ if (SSL_IS_DTLS(s)) { - if (s->d1->cookie_len > sizeof(s->d1->cookie)) { + if (s->d1->cookie_len > sizeof(s->d1->cookie) + || !PACKETW_get_sub_packet_len(&body, &spkt, 1) + || !PACKETW_memcpy(&spkt, s->d1->cookie, s->d1->cookie_len) + || !PACKETW_close(&spkt)) { SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } - *(p++) = s->d1->cookie_len; - memcpy(p, s->d1->cookie, s->d1->cookie_len); - p += s->d1->cookie_len; } /* Ciphers supported */ - i = ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &(p[2])); - if (i == 0) { - SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_NO_CIPHERS_AVAILABLE); + if (!PACKETW_get_sub_packet_len(&body, &spkt, 2)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + /* ssl_cipher_list_to_bytes() raises SSLerr if appropriate */ + if (!ssl_cipher_list_to_bytes(s, SSL_get_ciphers(s), &spkt)) + goto err; + if (!PACKETW_close(&spkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } -#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH - /* - * Some servers hang if client hello > 256 bytes as hack workaround - * chop number of supported ciphers to keep it well below this if we - * use TLS v1.2 - */ - if (TLS1_get_version(s) >= TLS1_2_VERSION - && i > OPENSSL_MAX_TLS1_2_CIPHER_LENGTH) - i = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; -#endif - s2n(i, p); - p += i; /* COMPRESSION */ -#ifdef OPENSSL_NO_COMP - *(p++) = 1; -#else - - if (!ssl_allow_compression(s) || !s->ctx->comp_methods) - j = 0; - else - j = sk_SSL_COMP_num(s->ctx->comp_methods); - *(p++) = 1 + j; - for (i = 0; i < j; i++) { - comp = sk_SSL_COMP_value(s->ctx->comp_methods, i); - *(p++) = comp->id; + if (!PACKETW_get_sub_packet_len(&body, &spkt, 1)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } +#ifndef OPENSSL_NO_COMP + if (ssl_allow_compression(s) && s->ctx->comp_methods) { + int compnum = sk_SSL_COMP_num(s->ctx->comp_methods); + for (i = 0; i < compnum; i++) { + comp = sk_SSL_COMP_value(s->ctx->comp_methods, i); + if (!PACKETW_put_bytes(&spkt, comp->id, 1)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } + } } #endif - *(p++) = 0; /* Add the NULL method */ + /* Add the NULL method */ + if (!PACKETW_put_bytes(&spkt, 0, 1) || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); + goto err; + } /* TLS extensions */ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); goto err; } - if ((p = - ssl_add_clienthello_tlsext(s, p, buf + SSL3_RT_MAX_PLAIN_LENGTH, - &al)) == NULL) { + if (!PACKETW_get_sub_packet_len(&body, &spkt, 2) + /* + * If extensions are of zero length then we don't even add the + * extensions length bytes + */ + || !PACKETW_set_flags(&spkt, + OPENSSL_PACKETW_FLAGS_ABANDON_ON_ZERO_LENGTH) + || !ssl_add_clienthello_tlsext(s, &spkt, &al) + || !PACKETW_close(&spkt)) { ssl3_send_alert(s, SSL3_AL_FATAL, al); SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } - l = p - d; - if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) { + if (!PACKETW_close(&body) || !ssl_close_construct_packet(s, &pkt)) { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; @@ -2909,47 +2917,79 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) return i; } -int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, unsigned char *p) +int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, PACKETW *pkt) { - int i, j = 0; - const SSL_CIPHER *c; - unsigned char *q; + int i; + size_t totlen = 0, len, maxlen; int empty_reneg_info_scsv = !s->renegotiate; /* Set disabled masks for this session */ ssl_set_client_disabled(s); if (sk == NULL) return (0); - q = p; - for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { +#ifdef OPENSSL_MAX_TLS1_2_CIPHER_LENGTH +# if OPENSSL_MAX_TLS1_2_CIPHER_LENGTH < 6 +# error Max cipher length too short +# endif + /* + * Some servers hang if client hello > 256 bytes as hack workaround + * chop number of supported ciphers to keep it well below this if we + * use TLS v1.2 + */ + if (TLS1_get_version(s) >= TLS1_2_VERSION) + maxlen = OPENSSL_MAX_TLS1_2_CIPHER_LENGTH & ~1; + else +#endif + /* Maximum length that can be stored in 2 bytes. Length must be even */ + maxlen = 0xfffe; + + if (empty_reneg_info_scsv) + maxlen -= 2; + if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) + maxlen -= 2; + + for (i = 0; i < sk_SSL_CIPHER_num(sk) && totlen < maxlen; i++) { + const SSL_CIPHER *c; + c = sk_SSL_CIPHER_value(sk, i); /* Skip disabled ciphers */ if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_SUPPORTED)) continue; - j = s->method->put_cipher_by_char(c, p); - p += j; + + if (!s->method->put_cipher_by_char(c, pkt, &len)) { + SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR); + return 0; + } + + totlen += len; } - /* - * If p == q, no ciphers; caller indicates an error. Otherwise, add - * applicable SCSVs. - */ - if (p != q) { + + if (totlen == 0) { + SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, SSL_R_NO_CIPHERS_AVAILABLE); + return 0; + } + + if (totlen != 0) { if (empty_reneg_info_scsv) { static SSL_CIPHER scsv = { 0, NULL, SSL3_CK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - j = s->method->put_cipher_by_char(&scsv, p); - p += j; + if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) { + SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR); + return 0; + } } if (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) { static SSL_CIPHER scsv = { 0, NULL, SSL3_CK_FALLBACK_SCSV, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - j = s->method->put_cipher_by_char(&scsv, p); - p += j; + if (!s->method->put_cipher_by_char(&scsv, pkt, &len)) { + SSLerr(SSL_F_SSL_CIPHER_LIST_TO_BYTES, ERR_R_INTERNAL_ERROR); + return 0; + } } } - return (p - q); + return 1; } diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c index de2de09796..6d6c5a3aa6 100644 --- a/ssl/statem/statem_dtls.c +++ b/ssl/statem/statem_dtls.c @@ -1190,3 +1190,46 @@ void dtls1_get_message_header(unsigned char *data, struct hm_header_st *msg_hdr) n2l3(data, msg_hdr->frag_off); n2l3(data, msg_hdr->frag_len); } + +/* + * Temporary name. To be renamed dtls1_set_handshake_header() once all PACKETW + * conversion is complete. The old dtls1_set_handshake_heder() can be deleted + * at that point. + * TODO - RENAME ME + */ +int dtls1_set_handshake_header2(SSL *s, PACKETW *pkt, PACKETW *body, int htype) +{ + unsigned char *header; + dtls1_set_message_header(s, htype, 0, 0, 0); + + /* + * We allocate space at the start for the message header. This gets filled + * in later + */ + if (!PACKETW_allocate_bytes(pkt, DTLS1_HM_HEADER_LENGTH, &header) + || !PACKETW_get_sub_packet(pkt, body)) + return 0; + + return 1; +} + +int dtls1_close_construct_packet(SSL *s, PACKETW *pkt) +{ + size_t msglen; + + if (!PACKETW_get_length(pkt, &msglen) + || msglen > INT_MAX + || !PACKETW_close(pkt)) + return 0; + s->d1->w_msg_hdr.msg_len = msglen - DTLS1_HM_HEADER_LENGTH; + s->d1->w_msg_hdr.frag_len = msglen - DTLS1_HM_HEADER_LENGTH; + s->init_num = (int)msglen; + s->init_off = 0; + + /* Buffer the message to handle re-xmits */ + + if (!dtls1_buffer_message(s, 0)) + return 0; + + return 1; +} diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 19b75a7ac7..2eaa2c0b1a 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -57,6 +57,20 @@ int ssl3_do_write(SSL *s, int type) return (0); } +int tls_close_construct_packet(SSL *s, PACKETW *pkt) +{ + size_t msglen; + + if (!PACKETW_get_length(pkt, &msglen) + || msglen > INT_MAX + || !PACKETW_close(pkt)) + return 0; + s->init_num = (int)msglen; + s->init_off = 0; + + return 1; +} + int tls_construct_finished(SSL *s, const char *sender, int slen) { unsigned char *p; diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index a6b8a87092..818f48d2e3 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1551,7 +1551,7 @@ int tls_construct_server_hello(SSL *s) p += sl; /* put the cipher */ - i = ssl3_put_cipher_by_char(s->s3->tmp.new_cipher, p); + i = ssl3_put_cipher_by_char_old(s->s3->tmp.new_cipher, p); p += i; /* put the compression method */ @@ -2002,7 +2002,7 @@ int tls_construct_certificate_request(SSL *s) nl = tls12_get_psigalgs(s, &psigs); /* Skip over length for now */ p += 2; - nl = tls12_copy_sigalgs(s, p, psigs, nl); + nl = tls12_copy_sigalgs_old(s, p, psigs, nl); /* Now fill in length */ s2n(nl, etmp); p += nl; diff --git a/ssl/t1_ext.c b/ssl/t1_ext.c index a8e9f9a9cd..1ccd4c8b15 100644 --- a/ssl/t1_ext.c +++ b/ssl/t1_ext.c @@ -72,10 +72,13 @@ int custom_ext_parse(SSL *s, int server, /* * Request custom extension data from the application and add to the return - * buffer. + * buffer. This is the old style function signature prior to PACKETW. This is + * here temporarily until the conversion to PACKETW is completed, i.e. it is + * used by code that hasn't been converted yet. + * TODO - REMOVE THIS FUNCTION */ -int custom_ext_add(SSL *s, int server, - unsigned char **pret, unsigned char *limit, int *al) +int custom_ext_add_old(SSL *s, int server, + unsigned char **pret, unsigned char *limit, int *al) { custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext; custom_ext_method *meth; @@ -131,6 +134,67 @@ int custom_ext_add(SSL *s, int server, return 1; } + +/* + * Request custom extension data from the application and add to the return + * buffer. + */ +int custom_ext_add(SSL *s, int server, PACKETW *pkt, int *al) +{ + custom_ext_methods *exts = server ? &s->cert->srv_ext : &s->cert->cli_ext; + custom_ext_method *meth; + size_t i; + + for (i = 0; i < exts->meths_count; i++) { + const unsigned char *out = NULL; + size_t outlen = 0; + PACKETW spkt; + + meth = exts->meths + i; + + if (server) { + /* + * For ServerHello only send extensions present in ClientHello. + */ + if (!(meth->ext_flags & SSL_EXT_FLAG_RECEIVED)) + continue; + /* If callback absent for server skip it */ + if (!meth->add_cb) + continue; + } + if (meth->add_cb) { + int cb_retval = 0; + cb_retval = meth->add_cb(s, meth->ext_type, + &out, &outlen, al, meth->add_arg); + if (cb_retval < 0) + return 0; /* error */ + if (cb_retval == 0) + continue; /* skip this extension */ + } + + if (!PACKETW_put_bytes(pkt, meth->ext_type, 2) + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || (outlen > 0 && !PACKETW_memcpy(&spkt, out, outlen)) + || !PACKETW_close(&spkt)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + /* + * We can't send duplicates: code logic should prevent this. + */ + OPENSSL_assert(!(meth->ext_flags & SSL_EXT_FLAG_SENT)); + /* + * Indicate extension has been sent: this is both a sanity check to + * ensure we don't send duplicate extensions and indicates that it is + * not an error if the extension is present in ServerHello. + */ + meth->ext_flags |= SSL_EXT_FLAG_SENT; + if (meth->free_cb) + meth->free_cb(s, meth->ext_type, out, meth->add_arg); + } + return 1; +} + /* Copy table of custom extensions */ int custom_exts_copy(custom_ext_methods *dst, const custom_ext_methods *src) { diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b8f8fd22fe..6e047918fd 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -41,6 +41,8 @@ SSL3_ENC_METHOD const TLSv1_enc_data = { 0, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, + ssl3_set_handshake_header2, + tls_close_construct_packet, ssl3_handshake_write }; @@ -59,6 +61,8 @@ SSL3_ENC_METHOD const TLSv1_1_enc_data = { SSL_ENC_FLAG_EXPLICIT_IV, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, + ssl3_set_handshake_header2, + tls_close_construct_packet, ssl3_handshake_write }; @@ -78,6 +82,8 @@ SSL3_ENC_METHOD const TLSv1_2_enc_data = { | SSL_ENC_FLAG_TLS1_2_CIPHERS, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, + ssl3_set_handshake_header2, + tls_close_construct_packet, ssl3_handshake_write }; @@ -1007,12 +1013,9 @@ static int tls1_check_duplicate_extensions(const PACKET *packet) return ret; } -unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, - unsigned char *limit, int *al) +int ssl_add_clienthello_tlsext(SSL *s, PACKETW *pkt, int *al) { - int extdatalen = 0; - unsigned char *orig = buf; - unsigned char *ret = buf; + PACKETW spkt; #ifndef OPENSSL_NO_EC /* See if we support any ECC ciphersuites */ int using_ecc = 0; @@ -1035,32 +1038,16 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, } #endif - ret += 2; - - if (ret >= limit) - return NULL; /* this really never occurs, but ... */ - /* Add RI if renegotiating */ if (s->renegotiate) { - int el; - - if (!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0)) { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; - } - - if ((limit - ret - 4 - el) < 0) - return NULL; - - s2n(TLSEXT_TYPE_renegotiate, ret); - s2n(el, ret); - - if (!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el)) { + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_renegotiate, 2) + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_memcpy(&spkt, s->s3->previous_client_finished, + s->s3->previous_client_finished_len) + || !PACKETW_close(&spkt)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - - ret += el; } /* Only add RI for SSLv3 */ if (s->client_version == SSL3_VERSION) @@ -1068,124 +1055,102 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, if (s->tlsext_hostname != NULL) { /* Add TLS extension servername to the Client Hello message */ - unsigned long size_str; - long lenmax; - - /*- - * check for enough space. - * 4 for the servername type and extension length - * 2 for servernamelist length - * 1 for the hostname type - * 2 for hostname length - * + hostname length - */ - - if ((lenmax = limit - ret - 9) < 0 - || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) - return NULL; - - /* extension type and length */ - s2n(TLSEXT_TYPE_server_name, ret); - s2n(size_str + 5, ret); - - /* length of servername list */ - s2n(size_str + 3, ret); - - /* hostname type, length and hostname */ - *(ret++) = (unsigned char)TLSEXT_NAMETYPE_host_name; - s2n(size_str, ret); - memcpy(ret, s->tlsext_hostname, size_str); - ret += size_str; + PACKETW slistpkt, hostpkt; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_server_name, 2) + /* Sub-packet for server_name extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + /* Sub-packet for servername list (always 1 hostname)*/ + || !PACKETW_get_sub_packet_len(&spkt, &slistpkt, 2) + || !PACKETW_put_bytes(&slistpkt, TLSEXT_NAMETYPE_host_name, 1) + /* Sub-packet for a single hostname host name */ + || !PACKETW_get_sub_packet_len(&slistpkt, &hostpkt, 2) + || !PACKETW_memcpy(&hostpkt, s->tlsext_hostname, + strlen(s->tlsext_hostname)) + || !PACKETW_close(&hostpkt) + || !PACKETW_close(&slistpkt) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #ifndef OPENSSL_NO_SRP /* Add SRP username if there is one */ - if (s->srp_ctx.login != NULL) { /* Add TLS extension SRP username to the - * Client Hello message */ - - int login_len = strlen(s->srp_ctx.login); - if (login_len > 255 || login_len == 0) { + if (s->srp_ctx.login != NULL) { + PACKETW loginpkt; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_srp, 2) + /* Sub-packet for SRP extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_get_sub_packet_len(&spkt, &loginpkt, 1) + /* login must not be zero...internal error if so */ + || !PACKETW_set_flags(&loginpkt, + OPENSSL_PACKETW_FLAGS_NON_ZERO_LENGTH) + || !PACKETW_memcpy(&loginpkt, s->srp_ctx.login, + strlen(s->srp_ctx.login)) + || !PACKETW_close(&loginpkt) + || !PACKETW_close(&spkt)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - - /*- - * check for enough space. - * 4 for the srp type type and extension length - * 1 for the srp user identity - * + srp user identity length - */ - if ((limit - ret - 5 - login_len) < 0) - return NULL; - - /* fill in the extension */ - s2n(TLSEXT_TYPE_srp, ret); - s2n(login_len + 1, ret); - (*ret++) = (unsigned char)login_len; - memcpy(ret, s->srp_ctx.login, login_len); - ret += login_len; } #endif #ifndef OPENSSL_NO_EC if (using_ecc) { + PACKETW formatspkt, curveslistpkt; + /* * Add TLS extension ECPointFormats to the ClientHello message */ - long lenmax; const unsigned char *pcurves, *pformats; - size_t num_curves, num_formats, curves_list_len; + size_t num_curves, num_formats; size_t i; - unsigned char *etmp; tls1_get_formatlist(s, &pformats, &num_formats); - if ((lenmax = limit - ret - 5) < 0) - return NULL; - if (num_formats > (size_t)lenmax) - return NULL; - if (num_formats > 255) { + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_ec_point_formats, 2) + /* Sub-packet for formats extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_get_sub_packet_len(&spkt, &formatspkt, 1) + || !PACKETW_memcpy(&formatspkt, pformats, num_formats) + || !PACKETW_close(&formatspkt) + || !PACKETW_close(&spkt)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - s2n(TLSEXT_TYPE_ec_point_formats, ret); - /* The point format list has 1-byte length. */ - s2n(num_formats + 1, ret); - *(ret++) = (unsigned char)num_formats; - memcpy(ret, pformats, num_formats); - ret += num_formats; - /* * Add TLS extension EllipticCurves to the ClientHello message */ pcurves = s->tlsext_ellipticcurvelist; - if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) - return NULL; - - if ((lenmax = limit - ret - 6) < 0) - return NULL; - if (num_curves > (size_t)lenmax / 2) - return NULL; - if (num_curves > 65532 / 2) { + if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - s2n(TLSEXT_TYPE_elliptic_curves, ret); - etmp = ret + 4; + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_elliptic_curves, 2) + /* Sub-packet for curves extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_get_sub_packet_len(&spkt, &curveslistpkt, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } /* Copy curve ID if supported */ for (i = 0; i < num_curves; i++, pcurves += 2) { if (tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) { - *etmp++ = pcurves[0]; - *etmp++ = pcurves[1]; + if (!PACKETW_put_bytes(&curveslistpkt, pcurves[0], 1) + || !PACKETW_put_bytes(&curveslistpkt, pcurves[1], 1)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, + ERR_R_INTERNAL_ERROR); + return 0; + } } } - - curves_list_len = etmp - ret - 4; - - s2n(curves_list_len + 2, ret); - s2n(curves_list_len, ret); - ret += curves_list_len; + if (!PACKETW_close(&curveslistpkt) || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #endif /* OPENSSL_NO_EC */ @@ -1197,8 +1162,10 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, s->tlsext_session_ticket->data) { ticklen = s->tlsext_session_ticket->length; s->session->tlsext_tick = OPENSSL_malloc(ticklen); - if (s->session->tlsext_tick == NULL) - return NULL; + if (s->session->tlsext_tick == NULL) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } memcpy(s->session->tlsext_tick, s->tlsext_session_ticket->data, ticklen); s->session->tlsext_ticklen = ticklen; @@ -1207,17 +1174,14 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, if (ticklen == 0 && s->tlsext_session_ticket && s->tlsext_session_ticket->data == NULL) goto skip_ext; - /* - * Check for enough room 2 for extension type, 2 for len rest for - * ticket - */ - if ((long)(limit - ret - 4 - ticklen) < 0) - return NULL; - s2n(TLSEXT_TYPE_session_ticket, ret); - s2n(ticklen, ret); - if (ticklen) { - memcpy(ret, s->session->tlsext_tick, ticklen); - ret += ticklen; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_session_ticket, 2) + /* Sub-packet for ticket extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_memcpy(&spkt, s->session->tlsext_tick, ticklen) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; } } skip_ext: @@ -1225,81 +1189,102 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, if (SSL_CLIENT_USE_SIGALGS(s)) { size_t salglen; const unsigned char *salg; - unsigned char *etmp; + PACKETW salgslistpkt; + salglen = tls12_get_psigalgs(s, &salg); - if ((size_t)(limit - ret) < salglen + 6) - return NULL; - s2n(TLSEXT_TYPE_signature_algorithms, ret); - etmp = ret; - /* Skip over lengths for now */ - ret += 4; - salglen = tls12_copy_sigalgs(s, ret, salg, salglen); - /* Fill in lengths */ - s2n(salglen + 2, etmp); - s2n(salglen, etmp); - ret += salglen; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_signature_algorithms, 2) + /* Sub-packet for sig-algs extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + /* Sub-packet for the actual list */ + || !PACKETW_get_sub_packet_len(&spkt, &salgslistpkt, 2) + || !tls12_copy_sigalgs(s, &salgslistpkt, salg, salglen) + || !PACKETW_close(&salgslistpkt) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #ifndef OPENSSL_NO_OCSP if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) { + PACKETW idspkt, extpkt; int i; - long extlen, idlen, itmp; - OCSP_RESPID *id; - idlen = 0; + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_status_request, 2) + /* Sub-packet for status request extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_put_bytes(&spkt, TLSEXT_STATUSTYPE_ocsp, 1) + /* Sub-packet for the ids */ + || !PACKETW_get_sub_packet_len(&spkt, &idspkt, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) { + unsigned char *idbytes; + int idlen; + OCSP_RESPID *id; + PACKETW idpkt; + id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i); - itmp = i2d_OCSP_RESPID(id, NULL); - if (itmp <= 0) - return NULL; - idlen += itmp + 2; + idlen = i2d_OCSP_RESPID(id, NULL); + if (idlen <= 0 + /* Sub-packet for an individual id */ + || !PACKETW_get_sub_packet_len(&idspkt, &idpkt, 1) + || !PACKETW_allocate_bytes(&idpkt, idlen, &idbytes) + || i2d_OCSP_RESPID(id, &idbytes) != idlen + || !PACKETW_close(&idpkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + } + if (!PACKETW_close(&idspkt) + || !PACKETW_get_sub_packet_len(&spkt, &extpkt, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; } - if (s->tlsext_ocsp_exts) { - extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); - if (extlen < 0) - return NULL; - } else - extlen = 0; + unsigned char *extbytes; + int extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL); - 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); - *(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); + if (extlen < 0) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + if (!PACKETW_allocate_bytes(&extpkt, extlen, &extbytes) + || i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &extbytes) + != extlen) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + } + if (!PACKETW_close(&extpkt) || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; } - s2n(extlen, ret); - if (extlen > 0) - i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret); } #endif #ifndef OPENSSL_NO_HEARTBEATS if (SSL_IS_DTLS(s)) { - /* Add Heartbeat extension */ - if ((limit - ret - 4 - 1) < 0) - return NULL; - s2n(TLSEXT_TYPE_heartbeat, ret); - s2n(1, ret); + unsigned int mode; + /*- * Set mode: * 1: peer may send requests * 2: peer not allowed to send requests */ if (s->tlsext_heartbeat & SSL_DTLSEXT_HB_DONT_RECV_REQUESTS) - *(ret++) = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS; + mode = SSL_DTLSEXT_HB_DONT_SEND_REQUESTS; else - *(ret++) = SSL_DTLSEXT_HB_ENABLED; + mode = SSL_DTLSEXT_HB_ENABLED; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_heartbeat, 2) + /* Sub-packet for Hearbeat extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_put_bytes(&spkt, mode, 1) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #endif @@ -1309,10 +1294,11 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, * The client advertises an empty extension to indicate its support * for Next Protocol Negotiation */ - if (limit - ret - 4 < 0) - return NULL; - s2n(TLSEXT_TYPE_next_proto_neg, ret); - s2n(0, ret); + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_next_proto_neg, 2) + || !PACKETW_put_bytes(pkt, 0, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #endif @@ -1322,52 +1308,80 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, * (see longer comment below) */ if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len) { - if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len) - return NULL; - s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret); - s2n(2 + s->alpn_client_proto_list_len, ret); - s2n(s->alpn_client_proto_list_len, ret); - memcpy(ret, s->alpn_client_proto_list, s->alpn_client_proto_list_len); - ret += s->alpn_client_proto_list_len; + PACKETW plistpkt; + + if (!PACKETW_put_bytes(pkt, + TLSEXT_TYPE_application_layer_protocol_negotiation, 2) + /* Sub-packet ALPN extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + /* Sub-packet for ALPN proto list */ + || !PACKETW_get_sub_packet_len(&spkt, &plistpkt, 2) + || !PACKETW_memcpy(&plistpkt, s->alpn_client_proto_list, + s->alpn_client_proto_list_len) + || !PACKETW_close(&plistpkt) + || !PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } s->s3->alpn_sent = 1; } #ifndef OPENSSL_NO_SRTP if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) { - int el; - - /* Returns 0 on success!! */ - if (ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0)) { + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt = 0; + SRTP_PROTECTION_PROFILE *prof; + int i, ct; + PACKETW plistpkt; + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_use_srtp, 2) + /* Sub-packet for SRTP extension */ + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + /* Sub-packet for the protection profile list */ + || !PACKETW_get_sub_packet_len(&spkt, &plistpkt, 2)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - - if ((limit - ret - 4 - el) < 0) - return NULL; - - s2n(TLSEXT_TYPE_use_srtp, ret); - s2n(el, ret); - - if (ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) { + ct = sk_SRTP_PROTECTION_PROFILE_num(clnt); + for (i = 0; i < ct; i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); + if (prof == NULL || !PACKETW_put_bytes(&plistpkt, prof->id, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + } + if (!PACKETW_close(&plistpkt) || !PACKETW_close(&spkt)) { SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return NULL; + return 0; } - ret += el; } #endif custom_ext_init(&s->cert->cli_ext); /* Add custom TLS Extensions to ClientHello */ - if (!custom_ext_add(s, 0, &ret, limit, al)) - return NULL; - s2n(TLSEXT_TYPE_encrypt_then_mac, ret); - s2n(0, ret); + if (!custom_ext_add(s, 0, pkt, al)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_encrypt_then_mac, 2) + || !PACKETW_put_bytes(pkt, 0, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + #ifndef OPENSSL_NO_CT if (s->ct_validation_callback != NULL) { - s2n(TLSEXT_TYPE_signed_certificate_timestamp, ret); - s2n(0, ret); + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_signed_certificate_timestamp, 2) + || !PACKETW_put_bytes(pkt, 0, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } #endif - s2n(TLSEXT_TYPE_extended_master_secret, ret); - s2n(0, ret); + + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_extended_master_secret, 2) + || !PACKETW_put_bytes(pkt, 0, 2)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } /* * Add padding to workaround bugs in F5 terminators. See @@ -1376,7 +1390,13 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, * appear last. */ if (s->options & SSL_OP_TLSEXT_PADDING) { - int hlen = ret - (unsigned char *)s->init_buf->data; + unsigned char *padbytes; + size_t hlen; + + if (!PACKETW_get_total_written(pkt, &hlen)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } if (hlen > 0xff && hlen < 0x200) { hlen = 0x200 - hlen; @@ -1385,20 +1405,22 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, else hlen = 0; - s2n(TLSEXT_TYPE_padding, ret); - s2n(hlen, ret); - memset(ret, 0, hlen); - ret += hlen; + if (!PACKETW_put_bytes(pkt, TLSEXT_TYPE_padding, 2) + || !PACKETW_get_sub_packet_len(pkt, &spkt, 2) + || !PACKETW_allocate_bytes(&spkt, hlen, &padbytes)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + memset(padbytes, 0, hlen); + if (!PACKETW_close(&spkt)) { + SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } } } done: - - if ((extdatalen = ret - orig - 2) == 0) - return orig; - - s2n(extdatalen, orig); - return ret; + return 1; } unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, @@ -1589,7 +1611,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, } } #endif - if (!custom_ext_add(s, 1, &ret, limit, al)) + if (!custom_ext_add_old(s, 1, &ret, limit, al)) return NULL; if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) { /* @@ -3311,7 +3333,13 @@ void ssl_set_sig_mask(uint32_t *pmask_a, SSL *s, int op) *pmask_a |= SSL_aECDSA; } -size_t tls12_copy_sigalgs(SSL *s, unsigned char *out, +/* + * Old version of the tls12_copy_sigalgs function used by code that has not + * yet been converted to PACKETW yet. It will be deleted once PACKETW conversion + * is complete. + * TODO - DELETE ME + */ +size_t tls12_copy_sigalgs_old(SSL *s, unsigned char *out, const unsigned char *psig, size_t psiglen) { unsigned char *tmpout = out; @@ -3325,6 +3353,20 @@ size_t tls12_copy_sigalgs(SSL *s, unsigned char *out, return tmpout - out; } +int tls12_copy_sigalgs(SSL *s, PACKETW *pkt, + const unsigned char *psig, size_t psiglen) +{ + size_t i; + for (i = 0; i < psiglen; i += 2, psig += 2) { + if (tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, psig)) { + if (!PACKETW_put_bytes(pkt, psig[0], 1) + || !PACKETW_put_bytes(pkt, psig[1], 1)) + return 0; + } + } + return 1; +} + /* Given preference and allowed sigalgs set shared sigalgs */ static int tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig, const unsigned char *pref, size_t preflen, diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c index 01dc403bdb..f5136e26cd 100644 --- a/ssl/t1_reneg.c +++ b/ssl/t1_reneg.c @@ -11,30 +11,6 @@ #include #include "ssl_locl.h" -/* Add the client's renegotiation binding */ -int ssl_add_clienthello_renegotiate_ext(SSL *s, unsigned char *p, int *len, - int maxlen) -{ - if (p) { - if ((s->s3->previous_client_finished_len + 1) > maxlen) { - SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATE_EXT_TOO_LONG); - return 0; - } - - /* Length byte */ - *p = s->s3->previous_client_finished_len; - p++; - - memcpy(p, s->s3->previous_client_finished, - s->s3->previous_client_finished_len); - } - - *len = s->s3->previous_client_finished_len + 1; - - return 1; -} - /* * Parse the client's renegotiation binding and abort if it's not right */ -- 2.25.1