1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/freebl/tlsprfalg.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,136 @@ 1.4 +/* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation 1.5 + * 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifdef FREEBL_NO_DEPEND 1.11 +#include "stubs.h" 1.12 +#endif 1.13 + 1.14 +#include "blapi.h" 1.15 +#include "hasht.h" 1.16 +#include "alghmac.h" 1.17 + 1.18 + 1.19 +#define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX 1.20 + 1.21 +/* TLS P_hash function */ 1.22 +SECStatus 1.23 +TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 1.24 + SECItem *seed, SECItem *result, PRBool isFIPS) 1.25 +{ 1.26 + unsigned char state[PHASH_STATE_MAX_LEN]; 1.27 + unsigned char outbuf[PHASH_STATE_MAX_LEN]; 1.28 + unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size; 1.29 + unsigned int remaining; 1.30 + unsigned char *res; 1.31 + SECStatus status; 1.32 + HMACContext *cx; 1.33 + SECStatus rv = SECFailure; 1.34 + const SECHashObject *hashObj = HASH_GetRawHashObject(hashType); 1.35 + 1.36 + PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); 1.37 + PORT_Assert((seed != NULL) && (seed->data != NULL)); 1.38 + PORT_Assert((result != NULL) && (result->data != NULL)); 1.39 + 1.40 + remaining = result->len; 1.41 + res = result->data; 1.42 + 1.43 + if (label != NULL) 1.44 + label_len = PORT_Strlen(label); 1.45 + 1.46 + cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS); 1.47 + if (cx == NULL) 1.48 + goto loser; 1.49 + 1.50 + /* initialize the state = A(1) = HMAC_hash(secret, seed) */ 1.51 + HMAC_Begin(cx); 1.52 + HMAC_Update(cx, (unsigned char *)label, label_len); 1.53 + HMAC_Update(cx, seed->data, seed->len); 1.54 + status = HMAC_Finish(cx, state, &state_len, sizeof(state)); 1.55 + if (status != SECSuccess) 1.56 + goto loser; 1.57 + 1.58 + /* generate a block at a time until we're done */ 1.59 + while (remaining > 0) { 1.60 + 1.61 + HMAC_Begin(cx); 1.62 + HMAC_Update(cx, state, state_len); 1.63 + if (label_len) 1.64 + HMAC_Update(cx, (unsigned char *)label, label_len); 1.65 + HMAC_Update(cx, seed->data, seed->len); 1.66 + status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf)); 1.67 + if (status != SECSuccess) 1.68 + goto loser; 1.69 + 1.70 + /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */ 1.71 + HMAC_Begin(cx); 1.72 + HMAC_Update(cx, state, state_len); 1.73 + status = HMAC_Finish(cx, state, &state_len, sizeof(state)); 1.74 + if (status != SECSuccess) 1.75 + goto loser; 1.76 + 1.77 + chunk_size = PR_MIN(outbuf_len, remaining); 1.78 + PORT_Memcpy(res, &outbuf, chunk_size); 1.79 + res += chunk_size; 1.80 + remaining -= chunk_size; 1.81 + } 1.82 + 1.83 + rv = SECSuccess; 1.84 + 1.85 +loser: 1.86 + /* clear out state so it's not left on the stack */ 1.87 + if (cx) 1.88 + HMAC_Destroy(cx, PR_TRUE); 1.89 + PORT_Memset(state, 0, sizeof(state)); 1.90 + PORT_Memset(outbuf, 0, sizeof(outbuf)); 1.91 + return rv; 1.92 +} 1.93 + 1.94 +SECStatus 1.95 +TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 1.96 + SECItem *result, PRBool isFIPS) 1.97 +{ 1.98 + SECStatus rv = SECFailure, status; 1.99 + unsigned int i; 1.100 + SECItem tmp = { siBuffer, NULL, 0}; 1.101 + SECItem S1; 1.102 + SECItem S2; 1.103 + 1.104 + PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); 1.105 + PORT_Assert((seed != NULL) && (seed->data != NULL)); 1.106 + PORT_Assert((result != NULL) && (result->data != NULL)); 1.107 + 1.108 + S1.type = siBuffer; 1.109 + S1.len = (secret->len / 2) + (secret->len & 1); 1.110 + S1.data = secret->data; 1.111 + 1.112 + S2.type = siBuffer; 1.113 + S2.len = S1.len; 1.114 + S2.data = secret->data + (secret->len - S2.len); 1.115 + 1.116 + tmp.data = (unsigned char*)PORT_Alloc(result->len); 1.117 + if (tmp.data == NULL) 1.118 + goto loser; 1.119 + tmp.len = result->len; 1.120 + 1.121 + status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS); 1.122 + if (status != SECSuccess) 1.123 + goto loser; 1.124 + 1.125 + status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS); 1.126 + if (status != SECSuccess) 1.127 + goto loser; 1.128 + 1.129 + for (i = 0; i < result->len; i++) 1.130 + result->data[i] ^= tmp.data[i]; 1.131 + 1.132 + rv = SECSuccess; 1.133 + 1.134 +loser: 1.135 + if (tmp.data != NULL) 1.136 + PORT_ZFree(tmp.data, tmp.len); 1.137 + return rv; 1.138 +} 1.139 +