diff options
author | Bodo Möller <bodo@openssl.org> | 2007-09-21 06:54:24 +0000 |
---|---|---|
committer | Bodo Möller <bodo@openssl.org> | 2007-09-21 06:54:24 +0000 |
commit | 761772d7e19145fa9afb2a0c830ead69a33f3fa5 (patch) | |
tree | f6fbfed11e54a5286025bf235889cca1cb87d503 /ssl | |
parent | 54ef01b54bd64fdf5820d3860f4c458a9c2fa4f0 (diff) |
Implement the Opaque PRF Input TLS extension
(draft-rescorla-tls-opaque-prf-input-00.txt), and do some cleanups and
bugfixes on the way. In particular, this fixes the buffer bounds
checks in ssl_add_clienthello_tlsext() and in ssl_add_serverhello_tlsext().
Note that the opaque PRF Input TLS extension is not compiled by default;
see CHANGES.
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/s23_clnt.c | 19 | ||||
-rw-r--r-- | ssl/s3_clnt.c | 7 | ||||
-rw-r--r-- | ssl/s3_lib.c | 55 | ||||
-rw-r--r-- | ssl/ssl.h | 16 | ||||
-rw-r--r-- | ssl/ssl3.h | 8 | ||||
-rw-r--r-- | ssl/ssl_err.c | 5 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 1 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 12 | ||||
-rw-r--r-- | ssl/ssltest.c | 26 | ||||
-rw-r--r-- | ssl/t1_enc.c | 163 | ||||
-rw-r--r-- | ssl/t1_lib.c | 225 | ||||
-rw-r--r-- | ssl/tls1.h | 21 |
12 files changed, 469 insertions, 89 deletions
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c index 1181d055bb..c500a932a7 100644 --- a/ssl/s23_clnt.c +++ b/ssl/s23_clnt.c @@ -277,6 +277,19 @@ static int ssl23_client_hello(SSL *s) version = SSL2_VERSION; } + if (version != SSL2_VERSION) + { + /* have to disable SSL 2.0 compatibility if we need TLS extensions */ + + if (s->tlsext_hostname != NULL) + ssl2_compat = 0; + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->ctx->tlsext_opaque_prf_input_callback != 0 || s->tlsext_opaque_prf_input != NULL) + ssl2_compat = 0; +#endif + } + buf=(unsigned char *)s->init_buf->data; if (s->state == SSL23_ST_CW_CLNT_HELLO_A) { @@ -420,6 +433,12 @@ static int ssl23_client_hello(SSL *s) *(p++)=0; /* Add the NULL method */ #ifndef OPENSSL_NO_TLSEXT + /* TLS extensions*/ + if (ssl_prepare_clienthello_tlsext(s) <= 0) + { + 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) { SSLerr(SSL_F_SSL23_CLIENT_HELLO,ERR_R_INTERNAL_ERROR); diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 2d1b1a5c69..f8f43eb938 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -656,7 +656,9 @@ int ssl3_client_hello(SSL *s) } #endif *(p++)=0; /* Add the NULL method */ + #ifndef OPENSSL_NO_TLSEXT + /* TLS extensions*/ if (ssl_prepare_clienthello_tlsext(s) <= 0) { SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT); @@ -853,6 +855,7 @@ int ssl3_get_server_hello(SSL *s) s->s3->tmp.new_compression=comp; } #endif + #ifndef OPENSSL_NO_TLSEXT /* TLS extensions*/ if (s->version > SSL3_VERSION) @@ -1768,7 +1771,7 @@ int ssl3_get_new_session_ticket(SSL *s) if (ticklen + 6 != n) { al = SSL3_AL_FATAL,SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH); + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,SSL_R_LENGTH_MISMATCH); goto f_err; } if (s->session->tlsext_tick) @@ -1779,7 +1782,7 @@ int ssl3_get_new_session_ticket(SSL *s) s->session->tlsext_tick = OPENSSL_malloc(ticklen); if (!s->session->tlsext_tick) { - SSLerr(SSL_F_SSL3_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE); + SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET,ERR_R_MALLOC_FAILURE); goto err; } memcpy(s->session->tlsext_tick, p, ticklen); diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index b2d1fefc31..476d27a7b2 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -2083,6 +2083,13 @@ void ssl3_free(SSL *s) if(s == NULL) return; +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + OPENSSL_free(s->s3->client_opaque_prf_input); + if (s->s3->server_opaque_prf_input != NULL) + OPENSSL_free(s->s3->server_opaque_prf_input); +#endif + ssl3_cleanup_key_block(s); if (s->s3->rbuf.buf != NULL) OPENSSL_free(s->s3->rbuf.buf); @@ -2115,6 +2122,15 @@ void ssl3_clear(SSL *s) unsigned char *rp,*wp; size_t rlen, wlen; +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + OPENSSL_free(s->s3->client_opaque_prf_input); + s->s3->client_opaque_prf_input = NULL; + if (s->s3->server_opaque_prf_input != NULL) + OPENSSL_free(s->s3->server_opaque_prf_input); + s->s3->server_opaque_prf_input = NULL; +#endif + ssl3_cleanup_key_block(s); if (s->s3->tmp.ca_names != NULL) sk_X509_NAME_pop_free(s->s3->tmp.ca_names,X509_NAME_free); @@ -2337,11 +2353,33 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) SSLerr(SSL_F_SSL3_CTRL, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE); return 0; } - s->options |= SSL_OP_NO_SSLv2; /* can't use extension w/ SSL 2.0 format */ break; case SSL_CTRL_SET_TLSEXT_DEBUG_ARG: s->tlsext_debug_arg=parg; + ret = 1; break; + +#ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT: + if (larg > 12288) /* actual internal limit is 2^16 for the complete hello message + * (including the cert chain and everything) */ + { + SSLerr(SSL_F_SSL3_CTRL, SSL_R_OPAQUE_PRF_INPUT_TOO_LONG); + break; + } + if (s->tlsext_opaque_prf_input != NULL) + OPENSSL_free(s->tlsext_opaque_prf_input); + s->tlsext_opaque_prf_input = BUF_memdup(parg, (size_t)larg); + if (s->tlsext_opaque_prf_input != NULL) + { + s->tlsext_opaque_prf_input_len = (size_t)larg; + ret = 1; + } + else + s->tlsext_opaque_prf_input_len = 0; + break; +#endif + #endif /* !OPENSSL_NO_TLSEXT */ default: break; @@ -2562,7 +2600,15 @@ long ssl3_ctx_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) } return 1; } + +#ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG: + ctx->tlsext_opaque_prf_input_callback_arg = parg; + return 1; +#endif + #endif /* !OPENSSL_NO_TLSEXT */ + /* A Thawte special :-) */ case SSL_CTRL_EXTRA_CHAIN_CERT: if (ctx->extra_certs == NULL) @@ -2612,6 +2658,13 @@ long ssl3_ctx_callback_ctrl(SSL_CTX *ctx, int cmd, void (*fp)(void)) case SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: ctx->tlsext_servername_callback=(int (*)(SSL *,int *,void *))fp; break; + +#ifdef TLSEXT_TYPE_opaque_prf_input + case SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB: + ctx->tlsext_opaque_prf_input_callback = (int (*)(SSL *,void *, size_t, void *))fp; + break; +#endif + #endif default: return(0); @@ -799,7 +799,12 @@ struct ssl_ctx_st unsigned char tlsext_tick_key_name[16]; unsigned char tlsext_tick_hmac_key[16]; unsigned char tlsext_tick_aes_key[16]; + + /* draft-rescorla-tls-opaque-prf-input-00.txt information */ + int (*tlsext_opaque_prf_input_callback)(SSL *, void *peerinput, size_t len, void *arg); + void *tlsext_opaque_prf_input_callback_arg; #endif + #ifndef OPENSSL_NO_PSK char *psk_identity_hint; unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, char *identity, @@ -1086,11 +1091,16 @@ struct ssl_st size_t tlsext_ellipticcurvelist_length; unsigned char *tlsext_ellipticcurvelist; /* our list */ #endif /* OPENSSL_NO_EC */ + + /* draft-rescorla-tls-opaque-prf-input-00.txt information to be used for handshakes */ + void *tlsext_opaque_prf_input; + size_t tlsext_opaque_prf_input_len; + SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */ #define session_ctx initial_ctx #else #define session_ctx ctx -#endif +#endif /* OPENSSL_NO_TLSEXT */ }; #ifdef __cplusplus @@ -1304,6 +1314,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_CTRL_SET_TLSEXT_DEBUG_ARG 57 #define SSL_CTRL_GET_TLSEXT_TICKET_KEYS 58 #define SSL_CTRL_SET_TLSEXT_TICKET_KEYS 59 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT 60 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61 +#define SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62 #endif #define SSL_session_reused(ssl) \ @@ -2009,6 +2022,7 @@ void ERR_load_SSL_strings(void); #define SSL_R_NULL_SSL_METHOD_PASSED 196 #define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 197 #define SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE 297 +#define SSL_R_OPAQUE_PRF_INPUT_TOO_LONG 327 #define SSL_R_PACKET_LENGTH_TOO_LONG 198 #define SSL_R_PARSE_TLSEXT 227 #define SSL_R_PATH_TOO_LONG 270 diff --git a/ssl/ssl3.h b/ssl/ssl3.h index 0543cb287e..29cd3da860 100644 --- a/ssl/ssl3.h +++ b/ssl/ssl3.h @@ -443,6 +443,14 @@ typedef struct ssl3_state_st int in_read_app_data; + /* Opaque PRF input as used for the current handshake. + * These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined + * (otherwise, they are merely present to improve binary compatibility) */ + void *client_opaque_prf_input; + size_t client_opaque_prf_input_len; + void *server_opaque_prf_input; + size_t server_opaque_prf_input_len; + struct { /* actually only needs to be 16+20 */ unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2]; diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 18a64e9e82..3121e0e70c 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -249,13 +249,13 @@ static ERR_STRING_DATA SSL_str_functs[]= {ERR_FUNC(SSL_F_SSL_USE_RSAPRIVATEKEY_FILE), "SSL_use_RSAPrivateKey_file"}, {ERR_FUNC(SSL_F_SSL_VERIFY_CERT_CHAIN), "SSL_VERIFY_CERT_CHAIN"}, {ERR_FUNC(SSL_F_SSL_WRITE), "SSL_write"}, -{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "tls1_cert_verify_mac"}, +{ERR_FUNC(SSL_F_TLS1_CERT_VERIFY_MAC), "TLS1_CERT_VERIFY_MAC"}, {ERR_FUNC(SSL_F_TLS1_CHANGE_CIPHER_STATE), "TLS1_CHANGE_CIPHER_STATE"}, {ERR_FUNC(SSL_F_TLS1_CHECK_SERVERHELLO_TLSEXT), "TLS1_CHECK_SERVERHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"}, {ERR_FUNC(SSL_F_TLS1_PREPARE_CLIENTHELLO_TLSEXT), "TLS1_PREPARE_CLIENTHELLO_TLSEXT"}, {ERR_FUNC(SSL_F_TLS1_PREPARE_SERVERHELLO_TLSEXT), "TLS1_PREPARE_SERVERHELLO_TLSEXT"}, -{ERR_FUNC(SSL_F_TLS1_PRF), "tls1_prf"}, +{ERR_FUNC(SSL_F_TLS1_PRF), "TLS1_PRF"}, {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"}, {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"}, {0,NULL} @@ -399,6 +399,7 @@ static ERR_STRING_DATA SSL_str_reasons[]= {ERR_REASON(SSL_R_NULL_SSL_METHOD_PASSED),"null ssl method passed"}, {ERR_REASON(SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),"old session cipher not returned"}, {ERR_REASON(SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE),"only tls allowed in fips mode"}, +{ERR_REASON(SSL_R_OPAQUE_PRF_INPUT_TOO_LONG),"opaque PRF input too long"}, {ERR_REASON(SSL_R_PACKET_LENGTH_TOO_LONG),"packet length too long"}, {ERR_REASON(SSL_R_PARSE_TLSEXT) ,"parse tlsext"}, {ERR_REASON(SSL_R_PATH_TOO_LONG) ,"path too long"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 575cf7c69a..00a93eeee9 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -542,6 +542,7 @@ void SSL_free(SSL *s) if (s->tlsext_ecpointformatlist) OPENSSL_free(s->tlsext_ecpointformatlist); if (s->tlsext_ellipticcurvelist) OPENSSL_free(s->tlsext_ellipticcurvelist); #endif /* OPENSSL_NO_EC */ + if (s->tlsext_opaque_prf_input) OPENSSL_free(s->tlsext_opaque_prf_input); #endif if (s->client_CA != NULL) diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 2f8f0f837d..50a8acc015 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -330,24 +330,30 @@ #define SSL_SSLV3 0x00000002L #define SSL_TLSV1 SSL_SSLV3 /* for now */ -/* Bits for algorithm2 (handshake digests) */ + +/* Bits for algorithm2 (handshake digests and other extra flags) */ #define SSL_HANDSHAKE_MAC_MD5 0x10 #define SSL_HANDSHAKE_MAC_SHA 0x20 #define SSL_HANDSHAKE_MAC_GOST94 0x40 #define SSL_HANDSHAKE_MAC_DEFAULT (SSL_HANDSHAKE_MAC_MD5 | SSL_HANDSHAKE_MAC_SHA) - /* When adding new digest in the ssl_ciph.c and increment SSM_MD_NUM_IDX * make sure to update this constant too */ #define SSL_MAX_DIGEST 4 - #define TLS1_PRF_DGST_SHIFT 8 #define TLS1_PRF_MD5 (SSL_HANDSHAKE_MAC_MD5 << TLS1_PRF_DGST_SHIFT) #define TLS1_PRF_SHA1 (SSL_HANDSHAKE_MAC_SHA << TLS1_PRF_DGST_SHIFT) #define TLS1_PRF_GOST94 (SSL_HANDSHAKE_MAC_GOST94 << TLS1_PRF_DGST_SHIFT) #define TLS1_PRF (TLS1_PRF_MD5 | TLS1_PRF_SHA1) + +/* Stream MAC for GOST ciphersuites from cryptopro draft + * (currently this also goes into algorithm2) */ +#define TLS1_STREAM_MAC 0x04 + + + /* * Export and cipher strength information. For each cipher we have to decide * whether it is exportable or not. This information is likely to change diff --git a/ssl/ssltest.c b/ssl/ssltest.c index 0be921f7f2..83a571d69b 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -422,6 +422,25 @@ static void lock_dbg_cb(int mode, int type, const char *file, int line) } } +#ifdef TLSEXT_TYPE_opaque_prf_input +struct cb_info_st { void *input; size_t len; int ret; }; +struct cb_info_st co1 = { "C", 1, 1 }; /* try to negotiate oqaque PRF input */ +struct cb_info_st co2 = { "C", 1, 2 }; /* insist on oqaque PRF input */ +struct cb_info_st so1 = { "S", 1, 1 }; /* try to negotiate oqaque PRF input */ +struct cb_info_st so2 = { "S", 1, 2 }; /* insist on oqaque PRF input */ + +int opaque_prf_input_cb(SSL *ssl, void *peerinput, size_t len, void *arg_) + { + struct cb_info_st *arg = arg_; + + if (arg == NULL) + return 1; + + if (!SSL_set_tlsext_opaque_prf_input(ssl, arg->input, arg->len)) + return 0; + return arg->ret; + } +#endif int main(int argc, char *argv[]) { @@ -836,6 +855,13 @@ bad: SSL_CTX_set_tmp_rsa_callback(s_ctx,tmp_rsa_cb); #endif +#ifdef TLSEXT_TYPE_opaque_prf_input + SSL_CTX_set_tlsext_opaque_prf_input_callback(c_ctx, opaque_prf_input_cb); + SSL_CTX_set_tlsext_opaque_prf_input_callback(s_ctx, opaque_prf_input_cb); + SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(c_ctx, &co1); /* or &co2 or NULL */ + SSL_CTX_set_tlsext_opaque_prf_input_callback_arg(s_ctx, &so1); /* or &so2 or NULL */ +#endif + if (!SSL_CTX_use_certificate_file(s_ctx,server_cert,SSL_FILETYPE_PEM)) { ERR_print_errors(bio_err); diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 80cfe44a02..3509f62b18 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -142,8 +142,14 @@ #include <openssl/hmac.h> #include <openssl/md5.h> +/* seed1 through seed5 are virtually concatenated */ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec, - int sec_len, unsigned char *seed, int seed_len, + int sec_len, + const void *seed1, int seed1_len, + const void *seed2, int seed2_len, + const void *seed3, int seed3_len, + const void *seed4, int seed4_len, + const void *seed5, int seed5_len, unsigned char *out, int olen) { int chunk,n; @@ -159,7 +165,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec, HMAC_CTX_init(&ctx_tmp); HMAC_Init_ex(&ctx,sec,sec_len,md, NULL); HMAC_Init_ex(&ctx_tmp,sec,sec_len,md, NULL); - HMAC_Update(&ctx,seed,seed_len); + if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len); + if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len); + if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len); + if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len); + if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len); HMAC_Final(&ctx,A1,&A1_len); n=0; @@ -169,7 +179,11 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec, HMAC_Init_ex(&ctx_tmp,NULL,0,NULL,NULL); /* re-init */ HMAC_Update(&ctx,A1,A1_len); HMAC_Update(&ctx_tmp,A1,A1_len); - HMAC_Update(&ctx,seed,seed_len); + if (seed1 != NULL) HMAC_Update(&ctx,seed1,seed1_len); + if (seed2 != NULL) HMAC_Update(&ctx,seed2,seed2_len); + if (seed3 != NULL) HMAC_Update(&ctx,seed3,seed3_len); + if (seed4 != NULL) HMAC_Update(&ctx,seed4,seed4_len); + if (seed5 != NULL) HMAC_Update(&ctx,seed5,seed5_len); if (olen > chunk) { @@ -190,9 +204,15 @@ static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec, OPENSSL_cleanse(A1,sizeof(A1)); } +/* seed1 through seed5 are virtually concatenated */ static void tls1_PRF(long digest_mask, - unsigned char *label, int label_len, - const unsigned char *sec, int slen, unsigned char *out1, + const void *seed1, int seed1_len, + const void *seed2, int seed2_len, + const void *seed3, int seed3_len, + const void *seed4, int seed4_len, + const void *seed5, int seed5_len, + const unsigned char *sec, int slen, + unsigned char *out1, unsigned char *out2, int olen) { int len,i,idx,count; @@ -200,7 +220,7 @@ static void tls1_PRF(long digest_mask, long m; const EVP_MD *md; - /* Count number of digests and divide sec evenly */ + /* Count number of digests and partition sec evenly */ count=0; for (idx=0;ssl_get_handshake_digest(idx,&m,&md);idx++) { if ((m<<TLS1_PRF_DGST_SHIFT) & digest_mask) count++; @@ -215,7 +235,9 @@ static void tls1_PRF(long digest_mask, SSL_R_UNSUPPORTED_DIGEST_TYPE); return; } - tls1_P_hash(md ,S1,len+(slen&1),label,label_len,out2,olen); + tls1_P_hash(md ,S1,len+(slen&1), + seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len, + out2,olen); S1+=len; for (i=0; i<olen; i++) { @@ -228,20 +250,11 @@ static void tls1_PRF(long digest_mask, static void tls1_generate_key_block(SSL *s, unsigned char *km, unsigned char *tmp, int num) { - unsigned char *p; - unsigned char buf[SSL3_RANDOM_SIZE*2+ - TLS_MD_MAX_CONST_SIZE]; - p=buf; - - memcpy(p,TLS_MD_KEY_EXPANSION_CONST, - TLS_MD_KEY_EXPANSION_CONST_SIZE); - p+=TLS_MD_KEY_EXPANSION_CONST_SIZE; - memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - - tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf), + tls1_PRF(s->s3->tmp.new_cipher->algorithm2, + TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE, + s->s3->server_random,SSL3_RANDOM_SIZE, + s->s3->client_random,SSL3_RANDOM_SIZE, + NULL,0,NULL,0, s->session->master_key,s->session->master_key_length, km,tmp,num); #ifdef KSSL_DEBUG @@ -261,8 +274,7 @@ int tls1_change_cipher_state(SSL *s, int which) { static const unsigned char empty[]=""; unsigned char *p,*key_block,*mac_secret; - unsigned char *exp_label,buf[TLS_MD_MAX_CONST_SIZE+ - SSL3_RANDOM_SIZE*2]; + unsigned char *exp_label; unsigned char tmp1[EVP_MAX_KEY_LENGTH]; unsigned char tmp2[EVP_MAX_KEY_LENGTH]; unsigned char iv1[EVP_MAX_IV_LENGTH*2]; @@ -443,29 +455,22 @@ printf("which = %04X\nmac key=",which); /* In here I set both the read and write key/iv to the * same value since only the correct one will be used :-). */ - p=buf; - memcpy(p,exp_label,exp_label_len); - p+=exp_label_len; - memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(p-buf),key,j, - tmp1,tmp2,EVP_CIPHER_key_length(c)); + tls1_PRF(s->s3->tmp.new_cipher->algorithm2, + exp_label,exp_label_len, + s->s3->client_random,SSL3_RANDOM_SIZE, + s->s3->server_random,SSL3_RANDOM_SIZE, + NULL,0,NULL,0, + key,j,tmp1,tmp2,EVP_CIPHER_key_length(c)); key=tmp1; if (k > 0) { - p=buf; - memcpy(p,TLS_MD_IV_BLOCK_CONST, - TLS_MD_IV_BLOCK_CONST_SIZE); - p+=TLS_MD_IV_BLOCK_CONST_SIZE; - memcpy(p,s->s3->client_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - memcpy(p,s->s3->server_random,SSL3_RANDOM_SIZE); - p+=SSL3_RANDOM_SIZE; - tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,p-buf,empty,0, - iv1,iv2,k*2); + tls1_PRF(s->s3->tmp.new_cipher->algorithm2, + TLS_MD_IV_BLOCK_CONST,TLS_MD_IV_BLOCK_CONST_SIZE, + s->s3->client_random,SSL3_RANDOM_SIZE, + s->s3->server_random,SSL3_RANDOM_SIZE, + NULL,0,NULL,0, + empty,0,iv1,iv2,k*2); if (client_write) iv=iv1; else @@ -767,35 +772,51 @@ int tls1_final_finish_mac(SSL *s, { unsigned int i; EVP_MD_CTX ctx; - unsigned char buf[TLS_MD_MAX_CONST_SIZE+MD5_DIGEST_LENGTH+SHA_DIGEST_LENGTH]; + unsigned char buf[2*EVP_MAX_MD_SIZE]; unsigned char *q,buf2[12]; int idx; long mask; + int err=0; const EVP_MD *md; q=buf; - memcpy(q,str,slen); - q+=slen; EVP_MD_CTX_init(&ctx); if (s->s3->handshake_buffer) ssl3_digest_cached_records(s); - for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) { - if (mask & s->s3->tmp.new_cipher->algorithm2) { - EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); - EVP_DigestFinal_ex(&ctx,q,&i); - q+=i; + for (idx=0;ssl_get_handshake_digest(idx,&mask,&md);idx++) + { + if (mask & s->s3->tmp.new_cipher->algorithm2) + { + int hashsize = EVP_MD_size(md); + if ((size_t)hashsize > (sizeof buf - (size_t)(q-buf))) + { + /* internal error: 'buf' is too small for this cipersuite! */ + err = 1; + } + else + { + EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); + EVP_DigestFinal_ex(&ctx,q,&i); + if (i != hashsize) /* can't really happen */ + err = 1; + q+=i; + } + } } - } - - tls1_PRF(s->s3->tmp.new_cipher->algorithm2,buf,(int)(q-buf), - s->session->master_key,s->session->master_key_length, - out,buf2,sizeof buf2); + + tls1_PRF(s->s3->tmp.new_cipher->algorithm2, + str,slen, buf,(int)(q-buf), NULL,0, NULL,0, NULL,0, + s->session->master_key,s->session->master_key_length, + out,buf2,sizeof buf2); EVP_MD_CTX_cleanup(&ctx); - return sizeof buf2; + if (err) + return 0; + else + return sizeof buf2; } int tls1_mac(SSL *ssl, unsigned char *md, int send) @@ -876,23 +897,35 @@ printf("rec="); int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len) { - unsigned char buf[SSL3_RANDOM_SIZE*2+TLS_MD_MASTER_SECRET_CONST_SIZE]; unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH]; + const void *co = NULL, *so = NULL; + int col = 0, sol = NULL; #ifdef KSSL_DEBUG printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len); #endif /* KSSL_DEBUG */ - /* Setup the stuff to munge */ - memcpy(buf,TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE); - memcpy(&(buf[TLS_MD_MASTER_SECRET_CONST_SIZE]), - s->s3->client_random,SSL3_RANDOM_SIZE); - memcpy(&(buf[SSL3_RANDOM_SIZE+TLS_MD_MASTER_SECRET_CONST_SIZE]), - s->s3->server_random,SSL3_RANDOM_SIZE); +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL && s->s3->server_opaque_prf_input != NULL && + s->s3->client_opaque_prf_input_len > 0 && + s->s3->client_opaque_prf_input_len == s->s3->server_opaque_prf_input_len) + { + co = s->s3->client_opaque_prf_input; + col = s->s3->server_opaque_prf_input_len; + so = s->s3->server_opaque_prf_input; + sol = s->s3->client_opaque_prf_input_len; /* must be same as col (see draft-rescorla-tls-opaque-prf-input-00.txt, section 3.1) */ + } +#endif + tls1_PRF(s->s3->tmp.new_cipher->algorithm2, - buf,TLS_MD_MASTER_SECRET_CONST_SIZE+SSL3_RANDOM_SIZE*2,p,len, + TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE, + s->s3->client_random,SSL3_RANDOM_SIZE, + co, col, + s->s3->server_random,SSL3_RANDOM_SIZE, + so, sol, + p,len, s->session->master_key,buff,sizeof buff); + #ifdef KSSL_DEBUG printf ("tls1_generate_master_secret() complete\n"); #endif /* KSSL_DEBUG */ diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index b5eab2cb68..0c7841402d 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -284,8 +284,8 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha + hostname length */ - if ((lenmax = limit - p - 9) < 0 - || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) + if ((lenmax = limit - ret - 9) < 0 + || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) return NULL; /* extension type and length */ @@ -300,15 +300,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha s2n(size_str,ret); memcpy(ret, s->tlsext_hostname, size_str); ret+=size_str; - } + #ifndef OPENSSL_NO_EC if (s->tlsext_ecpointformatlist != NULL) { /* Add TLS extension ECPointFormats to the ClientHello message */ long lenmax; - if ((lenmax = limit - p - 5) < 0) return NULL; + if ((lenmax = limit - ret - 5) < 0) return NULL; if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ecpointformatlist_length > 255) { @@ -327,7 +327,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Add TLS extension EllipticCurves to the ClientHello message */ long lenmax; - if ((lenmax = limit - p - 6) < 0) return NULL; + if ((lenmax = limit - ret - 6) < 0) return NULL; if (s->tlsext_ellipticcurvelist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ellipticcurvelist_length > 65532) { @@ -359,8 +359,7 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Check for enough room 2 for extension type, 2 for len * rest for ticket */ - if (limit - p - 4 - ticklen < 0) - return NULL; + if ((long)(limit - ret - 4 - ticklen) < 0) return NULL; s2n(TLSEXT_TYPE_session_ticket,ret); s2n(ticklen,ret); if (ticklen) @@ -370,6 +369,24 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned cha } } +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->client_opaque_prf_input != NULL) + { + size_t col = s->s3->client_opaque_prf_input_len; + + if ((long)(limit - ret - 6 - col < 0)) + return NULL; + if (col > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(col + 2, ret); + s2n(col, ret); + memcpy(ret, s->s3->client_opaque_prf_input, col); + ret += col; + } +#endif + if ((extdatalen = ret-p-2)== 0) return p; @@ -387,7 +404,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha if (!s->hit && s->servername_done == 1 && s->session->tlsext_hostname != NULL) { - if (limit - p - 4 < 0) return NULL; + if ((long)(limit - ret - 4) < 0) return NULL; s2n(TLSEXT_TYPE_server_name,ret); s2n(0,ret); @@ -398,7 +415,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha /* Add TLS extension ECPointFormats to the ServerHello message */ long lenmax; - if ((lenmax = limit - p - 5) < 0) return NULL; + if ((lenmax = limit - ret - 5) < 0) return NULL; if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax) return NULL; if (s->tlsext_ecpointformatlist_length > 255) { @@ -419,11 +436,29 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned cha if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) { - if (limit - p - 4 < 0) return NULL; + if ((long)(limit - ret - 4) < 0) return NULL; s2n(TLSEXT_TYPE_session_ticket,ret); s2n(0,ret); } + +#ifdef TLSEXT_TYPE_opaque_prf_input + if (s->s3->server_opaque_prf_input != NULL) + { + size_t sol = s->s3->server_opaque_prf_input_len; + if ((long)(limit - ret - 6 - sol) < 0) + return NULL; + if (sol > 0xFFFD) /* can't happen */ + return NULL; + + s2n(TLSEXT_TYPE_opaque_prf_input, ret); + s2n(sol + 2, ret); + s2n(sol, ret); + memcpy(ret, s->s3->server_opaque_prf_input, sol); + ret += sol; + } +#endif + if ((extdatalen = ret-p-2)== 0) return p; @@ -610,6 +645,35 @@ int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in #endif } #endif /* OPENSSL_NO_EC */ +#ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) + { + unsigned char *sdata = data; + + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input_len != size - 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + + s->s3->client_opaque_prf_input = BUF_memdup(sdata, s->s3->client_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +#endif + /* session ticket processed earlier */ data+=size; } @@ -694,6 +758,35 @@ int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, in } s->tlsext_ticket_expected = 1; } +#ifdef TLSEXT_TYPE_opaque_prf_input + else if (type == TLSEXT_TYPE_opaque_prf_input) + { + unsigned char *sdata = data; + + if (size < 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + n2s(sdata, s->s3->server_opaque_prf_input_len); + if (s->s3->server_opaque_prf_input_len != size - 2) + { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->server_opaque_prf_input); + s->s3->server_opaque_prf_input = BUF_memdup(sdata, s->s3->server_opaque_prf_input_len); + + if (s->s3->server_opaque_prf_input == NULL) + { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } +#endif + data+=size; } @@ -780,6 +873,38 @@ int ssl_prepare_clienthello_tlsext(SSL *s) s2n(i,j); } #endif /* OPENSSL_NO_EC */ + +#ifdef TLSEXT_TYPE_opaque_prf_input + { + int r = 1; + + if (s->ctx->tlsext_opaque_prf_input_callback != 0) + { + r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg); + if (!r) + return -1; + } + + if (s->tlsext_opaque_prf_input != NULL) + { + if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */ + OPENSSL_free(s->s3->client_opaque_prf_input); + + s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len); + if (s->s3->client_opaque_prf_input == NULL) + { + SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE); + return -1; + } + s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; + } + + if (r == 2) + /* at callback's request, insist on receiving an appropriate server opaque PRF input */ + s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len; + } +#endif + return 1; } @@ -810,6 +935,7 @@ int ssl_prepare_serverhello_tlsext(SSL *s) s->tlsext_ecpointformatlist[2] = TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2; } #endif /* OPENSSL_NO_EC */ + return 1; } @@ -832,6 +958,62 @@ int ssl_check_clienthello_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); + +#ifdef TLSEXT_TYPE_opaque_prf_input + { + /* This sort of belongs into ssl_prepare_serverhello_tlsext(), + * but we might be sending an alert in response to the client hello, + * so this has to happen here in ssl_check_clienthello_tlsext(). */ + + int r = 1; |