From: Scott Deboy Date: Thu, 12 Sep 2013 19:03:40 +0000 (-0700) Subject: Update custom TLS extension and supplemental data 'generate' callbacks to support... X-Git-Tag: master-pre-reformat~924 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ac20719d994729970eb3b775c7bffa81f0e9f960;p=openssl Update custom TLS extension and supplemental data 'generate' callbacks to support sending an alert. If multiple TLS extensions are expected but not received, the TLS extension and supplemental data 'generate' callbacks are the only chance for the receive-side to trigger a specific TLS alert during the handshake. Removed logic which no-op'd TLS extension generate callbacks (as the generate callbacks need to always be called in order to trigger alerts), and updated the serverinfo-specific custom TLS extension callbacks to track which custom TLS extensions were received by the client, where no-ops for 'generate' callbacks are appropriate. --- diff --git a/apps/s_client.c b/apps/s_client.c index 1e3bc391b5..95c62a7248 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -242,11 +242,11 @@ static int suppdata_cb(SSL *s, unsigned short supp_data_type, static int auth_suppdata_generate_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); static int authz_tlsext_generate_cb(SSL *s, unsigned short ext_type, const unsigned char **out, unsigned short *outlen, - void *arg); + int *al, void *arg); static int authz_tlsext_cb(SSL *s, unsigned short ext_type, const unsigned char *in, @@ -2456,7 +2456,7 @@ static int authz_tlsext_cb(SSL *s, unsigned short ext_type, static int authz_tlsext_generate_cb(SSL *s, unsigned short ext_type, const unsigned char **out, unsigned short *outlen, - void *arg) + int *al, void *arg) { if (c_auth) { @@ -2488,7 +2488,7 @@ static int suppdata_cb(SSL *s, unsigned short supp_data_type, static int auth_suppdata_generate_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (c_auth && server_provided_client_authz && server_provided_server_authz) { diff --git a/apps/s_server.c b/apps/s_server.c index cb68b2cc84..29969200b6 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -337,11 +337,11 @@ static int suppdata_cb(SSL *s, unsigned short supp_data_type, static int auth_suppdata_generate_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); static int authz_tlsext_generate_cb(SSL *s, unsigned short ext_type, const unsigned char **out, unsigned short *outlen, - void *arg); + int *al, void *arg); static int authz_tlsext_cb(SSL *s, unsigned short ext_type, const unsigned char *in, @@ -3602,7 +3602,7 @@ static int authz_tlsext_cb(SSL *s, unsigned short ext_type, static int authz_tlsext_generate_cb(SSL *s, unsigned short ext_type, const unsigned char **out, unsigned short *outlen, - void *arg) + int *al, void *arg) { if (c_auth && client_provided_client_authz && client_provided_server_authz) { @@ -3635,7 +3635,7 @@ static int suppdata_cb(SSL *s, unsigned short supp_data_type, static int auth_suppdata_generate_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (c_auth && client_provided_client_authz && client_provided_server_authz) { diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index fa20c1c3bd..452a19c171 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -553,8 +553,9 @@ static int ssl23_client_hello(SSL *s) SSLerr(SSL_F_SSL23_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); return -1; } - if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, &al)) == NULL) { + ssl3_send_alert(s,SSL3_AL_FATAL,al); SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); return -1; } diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 68d3131b1e..eccfcc3dca 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -891,8 +891,9 @@ int ssl3_client_hello(SSL *s) SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); goto err; } - if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + if ((p = ssl_add_clienthello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, &al)) == NULL) { + ssl3_send_alert(s,SSL3_AL_FATAL,al); SSLerr(SSL_F_SSL3_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); goto err; } @@ -3622,6 +3623,7 @@ int ssl_do_client_cert_cb(SSL *s, X509 **px509, EVP_PKEY **ppkey) #ifndef OPENSSL_NO_TLSEXT int tls1_send_client_supplemental_data(SSL *s, int *skip) { + int al = 0; if (s->ctx->cli_supp_data_records_count) { unsigned char *p = NULL; @@ -3641,14 +3643,14 @@ int tls1_send_client_supplemental_data(SSL *s, int *skip) if (!record->fn2) continue; cb_retval = record->fn2(s, record->supp_data_type, - &out, &outlen, + &out, &outlen, &al, record->arg); if (cb_retval == -1) continue; /* skip this supp data entry */ if (cb_retval == 0) { SSLerr(SSL_F_TLS1_SEND_CLIENT_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB); - return 0; + goto f_err; } if (outlen == 0 || TLSEXT_MAXLEN_supplemental_data < outlen + 4 + length) { @@ -3703,7 +3705,11 @@ int tls1_send_client_supplemental_data(SSL *s, int *skip) s->init_num = 0; s->init_off = 0; return 1; - } + +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + return 0; +} int tls1_get_server_supplemental_data(SSL *s) { diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 82f715bfd0..31074f264a 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -3029,8 +3029,8 @@ void ssl3_free(SSL *s) SSL_SRP_CTX_free(s); #endif #ifndef OPENSSL_NO_TLSEXT - if (s->s3->tlsext_custom_types != NULL) - OPENSSL_free(s->s3->tlsext_custom_types); + if (s->s3->serverinfo_client_tlsext_custom_types != NULL) + OPENSSL_free(s->s3->serverinfo_client_tlsext_custom_types); #endif OPENSSL_cleanse(s->s3,sizeof *s->s3); OPENSSL_free(s->s3); @@ -3076,12 +3076,12 @@ void ssl3_clear(SSL *s) } #endif #ifndef OPENSSL_NO_TLSEXT - if (s->s3->tlsext_custom_types != NULL) + if (s->s3->serverinfo_client_tlsext_custom_types != NULL) { - OPENSSL_free(s->s3->tlsext_custom_types); - s->s3->tlsext_custom_types = NULL; + OPENSSL_free(s->s3->serverinfo_client_tlsext_custom_types); + s->s3->serverinfo_client_tlsext_custom_types = NULL; } - s->s3->tlsext_custom_types_count = 0; + s->s3->serverinfo_client_tlsext_custom_types_count = 0; #ifndef OPENSSL_NO_EC s->s3->is_probably_safari = 0; #endif /* !OPENSSL_NO_EC */ diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 822d9b57ef..54266fb6da 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1504,7 +1504,7 @@ int ssl3_send_server_hello(SSL *s) { unsigned char *buf; unsigned char *p,*d; - int i,sl; + int i,sl,al; unsigned long l; if (s->state == SSL3_ST_SW_SRVR_HELLO_A) @@ -1574,8 +1574,9 @@ int ssl3_send_server_hello(SSL *s) SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,SSL_R_SERVERHELLO_TLSEXT); return -1; } - if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH)) == NULL) + if ((p = ssl_add_serverhello_tlsext(s, p, buf+SSL3_RT_MAX_PLAIN_LENGTH, &al)) == NULL) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); SSLerr(SSL_F_SSL3_SEND_SERVER_HELLO,ERR_R_INTERNAL_ERROR); return -1; } @@ -3703,6 +3704,7 @@ int ssl3_get_next_proto(SSL *s) int tls1_send_server_supplemental_data(SSL *s, int *skip) { + int al = 0; if (s->ctx->srv_supp_data_records_count) { unsigned char *p = NULL; @@ -3722,14 +3724,14 @@ int tls1_send_server_supplemental_data(SSL *s, int *skip) if (!record->fn1) continue; cb_retval = record->fn1(s, record->supp_data_type, - &out, &outlen, + &out, &outlen, &al, record->arg); if (cb_retval == -1) continue; /* skip this supp data entry */ if (cb_retval == 0) { SSLerr(SSL_F_TLS1_SEND_SERVER_SUPPLEMENTAL_DATA,ERR_R_BUF_LIB); - return 0; + goto f_err; } if (outlen == 0 || TLSEXT_MAXLEN_supplemental_data < outlen + 4 + length) { @@ -3791,6 +3793,9 @@ int tls1_send_server_supplemental_data(SSL *s, int *skip) s->init_num = 0; s->init_off = 0; return 1; +f_err: + ssl3_send_alert(s,SSL3_AL_FATAL,al); + return 0; } int tls1_get_client_supplemental_data(SSL *s) diff --git a/ssl/ssl.h b/ssl/ssl.h index 296c1660b1..ede930e3d2 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -410,7 +410,7 @@ typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, S */ typedef int (*custom_cli_ext_first_cb_fn)(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); typedef int (*custom_cli_ext_second_cb_fn)(SSL *s, unsigned short ext_type, const unsigned char *in, unsigned short inlen, int *al, @@ -422,7 +422,7 @@ typedef int (*custom_srv_ext_first_cb_fn)(SSL *s, unsigned short ext_type, void *arg); typedef int (*custom_srv_ext_second_cb_fn)(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); typedef struct { unsigned short ext_type; @@ -461,7 +461,7 @@ typedef struct { */ typedef int (*srv_supp_data_first_cb_fn)(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); typedef int (*srv_supp_data_second_cb_fn)(SSL *s, unsigned short supp_data_type, const unsigned char *in, unsigned short inlen, int *al, @@ -473,7 +473,7 @@ typedef int (*cli_supp_data_first_cb_fn)(SSL *s, unsigned short supp_data_type, void *arg); typedef int (*cli_supp_data_second_cb_fn)(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg); + unsigned short *outlen, int *al, void *arg); typedef struct { unsigned short supp_data_type; diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 8fe6949f6d..8bd201e08b 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -583,14 +583,12 @@ typedef struct ssl3_state_st #endif #ifndef OPENSSL_NO_TLSEXT - /* tlsext_custom_types contains an array of TLS Extension types which - * were advertised by the client in its ClientHello, which were not - * otherwise handled by OpenSSL, and which the server has registered - * a custom_srv_ext_record to handle. + /* serverinfo_client_tlsext_custom_types contains an array of TLS Extension types which + * were advertised by the client in its ClientHello and leveraged by ServerInfo TLS extension callbacks. * The array does not contain any duplicates, and is in the same order * as the types were received in the client hello. */ - unsigned short *tlsext_custom_types; - size_t tlsext_custom_types_count; /* how many tlsext_custom_types */ + unsigned short *serverinfo_client_tlsext_custom_types; + size_t serverinfo_client_tlsext_custom_types_count; /* how many serverinfo_client_tlsext_custom_types */ /* ALPN information * (we are in the process of transitioning from NPN to ALPN.) */ diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index fd6b883943..1a2aef70e4 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1269,8 +1269,8 @@ int tls1_shared_list(SSL *s, const unsigned char *l1, size_t l1len, const unsigned char *l2, size_t l2len, int nmatch); -unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); -unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit); +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al); +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al); int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n); int ssl_check_clienthello_tlsext_late(SSL *s); int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **data, unsigned char *d, int n); diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 7fcd8460a3..063eea5ecb 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -848,20 +848,59 @@ static int serverinfo_srv_first_cb(SSL *s, unsigned short ext_type, unsigned short inlen, int *al, void *arg) { + size_t i = 0; if (inlen != 0) { *al = SSL_AD_DECODE_ERROR; return 0; } + //if already in list, error out + for (i = 0; i < s->s3->serverinfo_client_tlsext_custom_types_count; i++) + { + if (s->s3->serverinfo_client_tlsext_custom_types[i] == ext_type) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + s->s3->serverinfo_client_tlsext_custom_types_count++; + s->s3->serverinfo_client_tlsext_custom_types = OPENSSL_realloc( + s->s3->serverinfo_client_tlsext_custom_types, + s->s3->serverinfo_client_tlsext_custom_types_count * 2); + if (s->s3->serverinfo_client_tlsext_custom_types == NULL) + { + s->s3->serverinfo_client_tlsext_custom_types_count = 0; + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + s->s3->serverinfo_client_tlsext_custom_types[ + s->s3->serverinfo_client_tlsext_custom_types_count - 1] = ext_type; + return 1; } static int serverinfo_srv_second_cb(SSL *s, unsigned short ext_type, const unsigned char **out, unsigned short *outlen, - void *arg) + int *al, void *arg) { const unsigned char *serverinfo = NULL; size_t serverinfo_length = 0; + size_t i = 0; + unsigned int match = 0; + /* Did the client send a TLS extension for this type? */ + for (i = 0; i < s->s3->serverinfo_client_tlsext_custom_types_count; i++) + { + if (s->s3->serverinfo_client_tlsext_custom_types[i] == ext_type) + { + match = 1; + break; + } + } + if (!match) + { + //extension not sent by client...don't send extension + return -1; + } /* Is there serverinfo data for the chosen server cert? */ if ((ssl_get_server_cert_serverinfo(s, &serverinfo, diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 5e2fed8e72..abdb1b893f 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -564,7 +564,7 @@ static int verify_serverinfo() static int custom_ext_0_cli_first_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (ext_type != CUSTOM_EXT_TYPE_0) custom_ext_error = 1; @@ -582,7 +582,7 @@ static int custom_ext_0_cli_second_cb(SSL *s, unsigned short ext_type, static int custom_ext_1_cli_first_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (ext_type != CUSTOM_EXT_TYPE_1) custom_ext_error = 1; @@ -602,7 +602,7 @@ static int custom_ext_1_cli_second_cb(SSL *s, unsigned short ext_type, static int custom_ext_2_cli_first_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (ext_type != CUSTOM_EXT_TYPE_2) custom_ext_error = 1; @@ -625,7 +625,7 @@ static int custom_ext_2_cli_second_cb(SSL *s, unsigned short ext_type, static int custom_ext_3_cli_first_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { if (ext_type != CUSTOM_EXT_TYPE_3) custom_ext_error = 1; @@ -648,7 +648,7 @@ static int custom_ext_3_cli_second_cb(SSL *s, unsigned short ext_type, return 1; } - +//custom_ext_0_cli_first_cb returns -1 - the server won't receive a callback for this extension static int custom_ext_0_srv_first_cb(SSL *s, unsigned short ext_type, const unsigned char *in, unsigned short inlen, int *al, @@ -658,12 +658,12 @@ static int custom_ext_0_srv_first_cb(SSL *s, unsigned short ext_type, return 0; /* Shouldn't be called */ } +//'generate' callbacks are always called, even if the 'receive' callback isn't called static int custom_ext_0_srv_second_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { - custom_ext_error = 1; - return 0; /* Shouldn't be called */ + return -1; /* Don't send an extension */ } static int custom_ext_1_srv_first_cb(SSL *s, unsigned short ext_type, @@ -683,7 +683,7 @@ static int custom_ext_1_srv_first_cb(SSL *s, unsigned short ext_type, static int custom_ext_1_srv_second_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { return -1; /* Don't send an extension */ } @@ -705,7 +705,7 @@ static int custom_ext_2_srv_first_cb(SSL *s, unsigned short ext_type, static int custom_ext_2_srv_second_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { *out = NULL; *outlen = 0; @@ -729,7 +729,7 @@ static int custom_ext_3_srv_first_cb(SSL *s, unsigned short ext_type, static int custom_ext_3_srv_second_cb(SSL *s, unsigned short ext_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { *out = (const unsigned char*)custom_ext_srv_string; *outlen = strlen(custom_ext_srv_string); @@ -738,7 +738,7 @@ static int custom_ext_3_srv_second_cb(SSL *s, unsigned short ext_type, static int supp_data_0_srv_first_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { *out = (const unsigned char*)supp_data_0_string; *outlen = strlen(supp_data_0_string); @@ -765,7 +765,7 @@ static int supp_data_0_srv_second_cb(SSL *s, unsigned short supp_data_type, static int supp_data_1_srv_first_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { return -1; } @@ -806,7 +806,7 @@ static int supp_data_0_cli_first_cb(SSL *s, unsigned short supp_data_type, static int supp_data_0_cli_second_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { *out = (const unsigned char*)supp_data_0_string; *outlen = strlen(supp_data_0_string); @@ -826,7 +826,7 @@ static int supp_data_1_cli_first_cb(SSL *s, unsigned short supp_data_type, static int supp_data_1_cli_second_cb(SSL *s, unsigned short supp_data_type, const unsigned char **out, - unsigned short *outlen, void *arg) + unsigned short *outlen, int *al, void *arg) { return -1; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 44e4c45237..0354e70d89 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1089,7 +1089,7 @@ void ssl_set_client_disabled(SSL *s) c->valid = 1; } -unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) +unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al) { int extdatalen=0; unsigned char *ret = p; @@ -1453,7 +1453,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha { int cb_retval = 0; cb_retval = record->fn1(s, record->ext_type, - &out, &outlen, + &out, &outlen, al, record->arg); if (cb_retval == 0) return NULL; /* error */ @@ -1509,10 +1509,12 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha return ret; } -unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit) +unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit, int *al) { int extdatalen=0; unsigned char *ret = p; + size_t i; + custom_srv_ext_record *record; #ifndef OPENSSL_NO_NEXTPROTONEG int next_proto_neg_seen; #endif @@ -1696,45 +1698,29 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha } #endif - /* If custom types were sent in ClientHello, add ServerHello responses */ - if (s->s3->tlsext_custom_types_count) + for (i = 0; i < s->ctx->custom_srv_ext_records_count; i++) { - size_t i; - - for (i = 0; i < s->s3->tlsext_custom_types_count; i++) - { - size_t j; - custom_srv_ext_record *record; - - for (j = 0; j < s->ctx->custom_srv_ext_records_count; j++) - { - record = &s->ctx->custom_srv_ext_records[j]; - if (s->s3->tlsext_custom_types[i] == record->ext_type) - { - const unsigned char *out = NULL; - unsigned short outlen = 0; - int cb_retval = 0; - - /* NULL callback or -1 omits extension */ - if (!record->fn2) - break; - cb_retval = record->fn2(s, record->ext_type, - &out, &outlen, - record->arg); - if (cb_retval == 0) - return NULL; /* error */ - if (cb_retval == -1) - break; /* skip this extension */ - if (limit < ret + 4 + outlen) - return NULL; - s2n(record->ext_type, ret); - s2n(outlen, ret); - memcpy(ret, out, outlen); - ret += outlen; - break; - } - } - } + record = &s->ctx->custom_srv_ext_records[i]; + const unsigned char *out = NULL; + unsigned short outlen = 0; + int cb_retval = 0; + + /* NULL callback or -1 omits extension */ + if (!record->fn2) + break; + cb_retval = record->fn2(s, record->ext_type, + &out, &outlen, al, + record->arg); + if (cb_retval == 0) + return NULL; /* error */ + if (cb_retval == -1) + break; /* skip this extension */ + if (limit < ret + 4 + outlen) + return NULL; + s2n(record->ext_type, ret); + s2n(outlen, ret); + memcpy(ret, out, outlen); + ret += outlen; } #ifdef TLSEXT_TYPE_encrypt_then_mac if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) @@ -1949,11 +1935,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char } /* Clear observed custom extensions */ - s->s3->tlsext_custom_types_count = 0; - if (s->s3->tlsext_custom_types != NULL) + s->s3->serverinfo_client_tlsext_custom_types_count = 0; + if (s->s3->serverinfo_client_tlsext_custom_types != NULL) { - OPENSSL_free(s->s3->tlsext_custom_types); - s->s3->tlsext_custom_types = NULL; + OPENSSL_free(s->s3->serverinfo_client_tlsext_custom_types); + s->s3->serverinfo_client_tlsext_custom_types = NULL; } #ifndef OPENSSL_NO_HEARTBEATS @@ -2476,35 +2462,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char record = &s->ctx->custom_srv_ext_records[i]; if (type == record->ext_type) { - size_t j; - - /* Error on duplicate TLS Extensions */ - for (j = 0; j < s->s3->tlsext_custom_types_count; j++) - { - if (type == s->s3->tlsext_custom_types[j]) - { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - } - - /* NULL callback still notes the extension */ if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg)) return 0; - - /* Add the (non-duplicated) entry */ - s->s3->tlsext_custom_types_count++; - s->s3->tlsext_custom_types = OPENSSL_realloc( - s->s3->tlsext_custom_types, - s->s3->tlsext_custom_types_count * 2); - if (s->s3->tlsext_custom_types == NULL) - { - s->s3->tlsext_custom_types = 0; - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - s->s3->tlsext_custom_types[ - s->s3->tlsext_custom_types_count - 1] = type; } } }