-static void tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
- int sec_len, unsigned char *seed, int seed_len,
- unsigned char *out, int olen)
- {
- int chunk,n;
- unsigned int j;
- HMAC_CTX ctx;
- HMAC_CTX ctx_tmp;
- unsigned char A1[HMAC_MAX_MD_CBLOCK];
- unsigned int A1_len;
-
- chunk=EVP_MD_size(md);
-
- HMAC_Init(&ctx,sec,sec_len,md);
- HMAC_Update(&ctx,seed,seed_len);
- HMAC_Final(&ctx,A1,&A1_len);
-
- n=0;
- for (;;)
- {
- HMAC_Init(&ctx,NULL,0,NULL); /* re-init */
- HMAC_Update(&ctx,A1,A1_len);
- memcpy(&ctx_tmp,&ctx,sizeof(ctx)); /* Copy for A2 */ /* not needed for last one */
- HMAC_Update(&ctx,seed,seed_len);
-
- if (olen > chunk)
- {
- HMAC_Final(&ctx,out,&j);
- out+=j;
- olen-=j;
- HMAC_Final(&ctx_tmp,A1,&A1_len); /* calc the next A1 value */
- }
- else /* last one */
- {
- HMAC_Final(&ctx,A1,&A1_len);
- memcpy(out,A1,olen);
- break;
- }
- }
- HMAC_cleanup(&ctx);
- HMAC_cleanup(&ctx_tmp);
- memset(A1,0,sizeof(A1));
- }
-
-static void tls1_PRF(const EVP_MD *md5, const EVP_MD *sha1,
- unsigned char *label, int label_len,
- const unsigned char *sec, int slen, unsigned char *out1,
- unsigned char *out2, int olen)
- {
- int len,i;
- const unsigned char *S1,*S2;
-
- len=slen/2;
- S1=sec;
- S2= &(sec[len]);
- len+=(slen&1); /* add for odd, make longer */
-
-
- tls1_P_hash(md5 ,S1,len,label,label_len,out1,olen);
- tls1_P_hash(sha1,S2,len,label,label_len,out2,olen);
-
- for (i=0; i<olen; i++)
- out1[i]^=out2[i];
- }
-
-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->ctx->md5,s->ctx->sha1,buf,(int)(p-buf),
- s->session->master_key,s->session->master_key_length,
- km,tmp,num);
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
+ 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;
+ size_t j;
+ EVP_MD_CTX ctx, ctx_tmp, ctx_init;
+ EVP_PKEY *mac_key;
+ unsigned char A1[EVP_MAX_MD_SIZE];
+ size_t A1_len;
+ int ret = 0;
+
+ chunk = EVP_MD_size(md);
+ OPENSSL_assert(chunk >= 0);
+
+ EVP_MD_CTX_init(&ctx);
+ EVP_MD_CTX_init(&ctx_tmp);
+ EVP_MD_CTX_init(&ctx_init);
+ EVP_MD_CTX_set_flags(&ctx_init, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+ mac_key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, sec, sec_len);
+ if (!mac_key)
+ goto err;
+ if (!EVP_DigestSignInit(&ctx_init, NULL, md, NULL, mac_key))
+ goto err;
+ if (!EVP_MD_CTX_copy_ex(&ctx, &ctx_init))
+ goto err;
+ if (seed1 && !EVP_DigestSignUpdate(&ctx, seed1, seed1_len))
+ goto err;
+ if (seed2 && !EVP_DigestSignUpdate(&ctx, seed2, seed2_len))
+ goto err;
+ if (seed3 && !EVP_DigestSignUpdate(&ctx, seed3, seed3_len))
+ goto err;
+ if (seed4 && !EVP_DigestSignUpdate(&ctx, seed4, seed4_len))
+ goto err;
+ if (seed5 && !EVP_DigestSignUpdate(&ctx, seed5, seed5_len))
+ goto err;
+ if (!EVP_DigestSignFinal(&ctx, A1, &A1_len))
+ goto err;
+
+ for (;;) {
+ /* Reinit mac contexts */
+ if (!EVP_MD_CTX_copy_ex(&ctx, &ctx_init))
+ goto err;
+ if (!EVP_DigestSignUpdate(&ctx, A1, A1_len))
+ goto err;
+ if (olen > chunk && !EVP_MD_CTX_copy_ex(&ctx_tmp, &ctx))
+ goto err;
+ if (seed1 && !EVP_DigestSignUpdate(&ctx, seed1, seed1_len))
+ goto err;
+ if (seed2 && !EVP_DigestSignUpdate(&ctx, seed2, seed2_len))
+ goto err;
+ if (seed3 && !EVP_DigestSignUpdate(&ctx, seed3, seed3_len))
+ goto err;
+ if (seed4 && !EVP_DigestSignUpdate(&ctx, seed4, seed4_len))
+ goto err;
+ if (seed5 && !EVP_DigestSignUpdate(&ctx, seed5, seed5_len))
+ goto err;
+
+ if (olen > chunk) {
+ if (!EVP_DigestSignFinal(&ctx, out, &j))
+ goto err;
+ out += j;
+ olen -= j;
+ /* calc the next A1 value */
+ if (!EVP_DigestSignFinal(&ctx_tmp, A1, &A1_len))
+ goto err;
+ } else { /* last one */
+
+ if (!EVP_DigestSignFinal(&ctx, A1, &A1_len))
+ goto err;
+ memcpy(out, A1, olen);
+ break;
+ }
+ }
+ ret = 1;
+ err:
+ EVP_PKEY_free(mac_key);
+ EVP_MD_CTX_cleanup(&ctx);
+ EVP_MD_CTX_cleanup(&ctx_tmp);
+ EVP_MD_CTX_cleanup(&ctx_init);
+ OPENSSL_cleanse(A1, sizeof(A1));
+ return ret;
+}
+
+/* seed1 through seed5 are virtually concatenated */
+static int tls1_PRF(long digest_mask,
+ 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;
+ const unsigned char *S1;
+ long m;
+ const EVP_MD *md;
+ int ret = 0;
+
+ /* 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++;
+ }
+ len = slen / count;
+ if (count == 1)
+ slen = 0;
+ S1 = sec;
+ memset(out1, 0, olen);
+ for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) {
+ if ((m << TLS1_PRF_DGST_SHIFT) & digest_mask) {
+ if (!md) {
+ SSLerr(SSL_F_TLS1_PRF, SSL_R_UNSUPPORTED_DIGEST_TYPE);
+ goto err;
+ }
+ if (!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))
+ goto err;
+ S1 += len;
+ for (i = 0; i < olen; i++) {
+ out1[i] ^= out2[i];
+ }
+ }
+ }
+ ret = 1;
+ err:
+ return ret;
+}
+
+static int tls1_generate_key_block(SSL *s, unsigned char *km,
+ unsigned char *tmp, int num)
+{
+ int ret;
+ ret = tls1_PRF(ssl_get_algorithm2(s),
+ 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);