tlsprfalg.c (3977B)
1 /* tlsprfalg.c - TLS Pseudo Random Function (PRF) implementation 2 * 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifdef FREEBL_NO_DEPEND 8 #include "stubs.h" 9 #endif 10 11 #include "blapi.h" 12 #include "hasht.h" 13 #include "alghmac.h" 14 15 #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX 16 17 /* TLS P_hash function */ 18 SECStatus 19 TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, 20 SECItem *seed, SECItem *result, PRBool isFIPS) 21 { 22 unsigned char state[PHASH_STATE_MAX_LEN]; 23 unsigned char outbuf[PHASH_STATE_MAX_LEN]; 24 unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size; 25 unsigned int remaining; 26 unsigned char *res; 27 SECStatus status; 28 HMACContext *cx; 29 SECStatus rv = SECFailure; 30 const SECHashObject *hashObj = HASH_GetRawHashObject(hashType); 31 32 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); 33 PORT_Assert((seed != NULL) && (seed->data != NULL)); 34 PORT_Assert((result != NULL) && (result->data != NULL)); 35 36 remaining = result->len; 37 res = result->data; 38 39 if (label != NULL) 40 label_len = PORT_Strlen(label); 41 42 cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS); 43 if (cx == NULL) 44 goto loser; 45 46 /* initialize the state = A(1) = HMAC_hash(secret, seed) */ 47 HMAC_Begin(cx); 48 HMAC_Update(cx, (unsigned char *)label, label_len); 49 HMAC_Update(cx, seed->data, seed->len); 50 status = HMAC_Finish(cx, state, &state_len, sizeof(state)); 51 if (status != SECSuccess) 52 goto loser; 53 54 /* generate a block at a time until we're done */ 55 while (remaining > 0) { 56 57 HMAC_Begin(cx); 58 HMAC_Update(cx, state, state_len); 59 if (label_len) 60 HMAC_Update(cx, (unsigned char *)label, label_len); 61 HMAC_Update(cx, seed->data, seed->len); 62 status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf)); 63 if (status != SECSuccess) 64 goto loser; 65 66 /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */ 67 HMAC_Begin(cx); 68 HMAC_Update(cx, state, state_len); 69 status = HMAC_Finish(cx, state, &state_len, sizeof(state)); 70 if (status != SECSuccess) 71 goto loser; 72 73 chunk_size = PR_MIN(outbuf_len, remaining); 74 PORT_Memcpy(res, &outbuf, chunk_size); 75 res += chunk_size; 76 remaining -= chunk_size; 77 } 78 79 rv = SECSuccess; 80 81 loser: 82 /* clear out state so it's not left on the stack */ 83 if (cx) 84 HMAC_Destroy(cx, PR_TRUE); 85 PORT_SafeZero(state, sizeof(state)); 86 PORT_SafeZero(outbuf, sizeof(outbuf)); 87 return rv; 88 } 89 90 SECStatus 91 TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, 92 SECItem *result, PRBool isFIPS) 93 { 94 SECStatus rv = SECFailure, status; 95 unsigned int i; 96 SECItem tmp = { siBuffer, NULL, 0 }; 97 SECItem S1; 98 SECItem S2; 99 100 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); 101 PORT_Assert((seed != NULL) && (seed->data != NULL)); 102 PORT_Assert((result != NULL) && (result->data != NULL)); 103 104 S1.type = siBuffer; 105 S1.len = (secret->len / 2) + (secret->len & 1); 106 S1.data = secret->data; 107 108 S2.type = siBuffer; 109 S2.len = S1.len; 110 S2.data = secret->data + (secret->len - S2.len); 111 112 tmp.data = (unsigned char *)PORT_Alloc(result->len); 113 if (tmp.data == NULL) 114 goto loser; 115 tmp.len = result->len; 116 117 status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS); 118 if (status != SECSuccess) 119 goto loser; 120 121 status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS); 122 if (status != SECSuccess) 123 goto loser; 124 125 for (i = 0; i < result->len; i++) 126 result->data[i] ^= tmp.data[i]; 127 128 rv = SECSuccess; 129 130 loser: 131 if (tmp.data != NULL) 132 PORT_ZFree(tmp.data, tmp.len); 133 return rv; 134 }