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/t1_enc.c | |
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/t1_enc.c')
-rw-r--r-- | ssl/t1_enc.c | 163 |
1 files changed, 98 insertions, 65 deletions
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 */ |