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
TLS_P_hash(HASH_HashType hashType,const SECItem * secret,const char * label,SECItem * seed,SECItem * result,PRBool isFIPS)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_Memset(state, 0, sizeof(state));
86 PORT_Memset(outbuf, 0, sizeof(outbuf));
87 return rv;
88 }
89
90 SECStatus
TLS_PRF(const SECItem * secret,const char * label,SECItem * seed,SECItem * result,PRBool isFIPS)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 }
135