int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { if (out_len == 0) { return 1; } OPENSSL_memset(out, 0, out_len); if (digest == EVP_md5_sha1()) { /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and * MD5, MD5 first. */ size_t secret_half = secret_len - (secret_len / 2); if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, (const uint8_t *)label, label_len, seed1, seed1_len, seed2, seed2_len)) { return 0; } /* Note that, if |secret_len| is odd, the two halves share a byte. */ secret = secret + (secret_len - secret_half); secret_len = secret_half; digest = EVP_sha1(); } if (!tls1_P_hash(out, out_len, digest, secret, secret_len, (const uint8_t *)label, label_len, seed1, seed1_len, seed2, seed2_len)) { return 0; } return 1; }
int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { if (out_len == 0) { return 1; } memset(out, 0, out_len); uint32_t algorithm_prf = ssl_get_algorithm_prf(s); if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) { /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and * MD5, MD5 first. */ size_t secret_half = secret_len - (secret_len / 2); if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, (const uint8_t *)label, label_len, seed1, seed1_len, seed2, seed2_len)) { return 0; } /* Note that, if |secret_len| is odd, the two halves share a byte. */ secret = secret + (secret_len - secret_half); secret_len = secret_half; } if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf), secret, secret_len, (const uint8_t *)label, label_len, seed1, seed1_len, seed2, seed2_len)) { return 0; } return 1; }
int CRYPTO_tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { if (out_len == 0) { return 1; } OPENSSL_memset(out, 0, out_len); if (digest == EVP_md5_sha1()) { // If using the MD5/SHA1 PRF, |secret| is partitioned between MD5 and SHA-1. size_t secret_half = secret_len - (secret_len / 2); if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, label, label_len, seed1, seed1_len, seed2, seed2_len)) { return 0; } // Note that, if |secret_len| is odd, the two halves share a byte. secret += secret_len - secret_half; secret_len = secret_half; digest = EVP_sha1(); } return tls1_P_hash(out, out_len, digest, secret, secret_len, label, label_len, seed1, seed1_len, seed2, seed2_len); }
int tls1_PRF( const u_char* secret, uint32_t secret_len, const char* label, u_char* random1, uint32_t random1_len, u_char* random2, uint32_t random2_len, u_char *out, uint32_t out_len ) { uint32_t len; uint32_t i; const u_char *S1,*S2; u_char* out_tmp; u_char* seed; uint32_t seed_len; u_char* p; if( !label || !out || out_len == 0 ) { _ASSERT( FALSE); return NM_ERROR( DSSL_E_INVALID_PARAMETER ); } /* allocate a temporary buffer for second output stream */ out_tmp = (u_char*) malloc( out_len ); if( !out_tmp ) return NM_ERROR( DSSL_E_OUT_OF_MEMORY ); /* allocate and initialize the seed */ seed_len = (uint32_t)strlen( label ) + random1_len + random2_len; seed = (u_char*) malloc( seed_len ); if( !seed ) { free( out_tmp ); return NM_ERROR( DSSL_E_OUT_OF_MEMORY ); } p = seed; memcpy( p, label, strlen( label ) ); p+= strlen( label ); memcpy( p, random1, random1_len ); p+= random1_len; memcpy( p, random2, random2_len ); /* split the secret into halves */ len = (secret_len / 2) + (secret_len % 2); S1 = secret; S2 = secret + secret_len - len; DEBUG_TRACE_BUF("secret", secret, secret_len); DEBUG_TRACE_BUF("seed", seed, seed_len); tls1_P_hash( EVP_md5(), S1, len, seed, seed_len, out, out_len ); tls1_P_hash( EVP_sha1(), S2, len, seed, seed_len, out_tmp, out_len ); for( i=0; i < out_len; i++ ) out[i] ^= out_tmp[i]; DEBUG_TRACE_BUF("result", out, out_len); free( seed ); free( out_tmp ); return DSSL_RC_OK; }
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]; }
int tls12_PRF( const EVP_MD *md, const u_char* secret, uint32_t secret_len, const char* label, u_char* random1, uint32_t random1_len, u_char* random2, uint32_t random2_len, u_char *out, uint32_t out_len ) { uint32_t len; uint32_t i; const u_char *S1,*S2; u_char* out_tmp; u_char* seed; uint32_t seed_len; u_char* p; if( !label || !out || out_len == 0 ) { _ASSERT( FALSE); return NM_ERROR( DSSL_E_INVALID_PARAMETER ); } /* 'sha256' is the default for TLS 1.2. * also, do not allow anything less secure... */ if ( !md ) md = EVP_sha256(); else if ( EVP_MD_size( md ) < EVP_MD_size( EVP_sha256() ) ) md = EVP_sha256(); /* allocate a temporary buffer for second output stream */ out_tmp = (u_char*) malloc( out_len ); if( !out_tmp ) return NM_ERROR( DSSL_E_OUT_OF_MEMORY ); /* allocate and initialize the seed */ seed_len = (uint32_t)strlen( label ) + random1_len + random2_len; seed = (u_char*) malloc( seed_len ); if( !seed ) { free( out_tmp ); return NM_ERROR( DSSL_E_OUT_OF_MEMORY ); } p = seed; memcpy( p, label, strlen( label ) ); p+= strlen( label ); memcpy( p, random1, random1_len ); p+= random1_len; memcpy( p, random2, random2_len ); DEBUG_TRACE_BUF("secret", secret, secret_len); DEBUG_TRACE_BUF("seed", seed, seed_len); tls1_P_hash( md, secret, secret_len, seed, seed_len, out_tmp, out_len ); DEBUG_TRACE_BUF("result", out_tmp, out_len); DEBUG_TRACE3( "\nsecret(%d) + seed(%u)=out(%u)\n", secret_len, seed_len, out_len); for( i=0; i < out_len; i++ ) out[i] = out_tmp[i]; free( seed ); free( out_tmp ); return DSSL_RC_OK; }
/* 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; }
int tls1_prf(SSL *s, uint8_t *out, size_t out_len, const uint8_t *secret, size_t secret_len, const char *label, size_t label_len, const uint8_t *seed1, size_t seed1_len, const uint8_t *seed2, size_t seed2_len) { size_t idx, len, count, i; const uint8_t *S1; long m; const EVP_MD *md; int ret = 0; uint8_t *tmp; if (out_len == 0) { return 1; } /* Allocate a temporary buffer. */ tmp = OPENSSL_malloc(out_len); if (tmp == NULL) { OPENSSL_PUT_ERROR(SSL, tls1_prf, ERR_R_MALLOC_FAILURE); return 0; } /* Count number of digests and partition |secret| evenly. */ count = 0; for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { count++; } } /* TODO(davidben): The only case where count isn't 1 is the old MD5/SHA-1 * combination. The logic around multiple handshake digests can probably be * simplified. */ assert(count == 1 || count == 2); len = secret_len / count; if (count == 1) { secret_len = 0; } S1 = secret; memset(out, 0, out_len); for (idx = 0; ssl_get_handshake_digest(idx, &m, &md); idx++) { if ((m << TLS1_PRF_DGST_SHIFT) & ssl_get_algorithm2(s)) { /* If |count| is 2 and |secret_len| is odd, |secret| is partitioned into * two halves with an overlapping byte. */ if (!tls1_P_hash(tmp, out_len, md, S1, len + (secret_len & 1), (const uint8_t *)label, label_len, seed1, seed1_len, seed2, seed2_len)) { goto err; } S1 += len; for (i = 0; i < out_len; i++) { out[i] ^= tmp[i]; } } } ret = 1; err: OPENSSL_cleanse(tmp, out_len); OPENSSL_free(tmp); return ret; }