|
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 |
|
16 #define PHASH_STATE_MAX_LEN HASH_LENGTH_MAX |
|
17 |
|
18 /* TLS P_hash function */ |
|
19 SECStatus |
|
20 TLS_P_hash(HASH_HashType hashType, const SECItem *secret, const char *label, |
|
21 SECItem *seed, SECItem *result, PRBool isFIPS) |
|
22 { |
|
23 unsigned char state[PHASH_STATE_MAX_LEN]; |
|
24 unsigned char outbuf[PHASH_STATE_MAX_LEN]; |
|
25 unsigned int state_len = 0, label_len = 0, outbuf_len = 0, chunk_size; |
|
26 unsigned int remaining; |
|
27 unsigned char *res; |
|
28 SECStatus status; |
|
29 HMACContext *cx; |
|
30 SECStatus rv = SECFailure; |
|
31 const SECHashObject *hashObj = HASH_GetRawHashObject(hashType); |
|
32 |
|
33 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); |
|
34 PORT_Assert((seed != NULL) && (seed->data != NULL)); |
|
35 PORT_Assert((result != NULL) && (result->data != NULL)); |
|
36 |
|
37 remaining = result->len; |
|
38 res = result->data; |
|
39 |
|
40 if (label != NULL) |
|
41 label_len = PORT_Strlen(label); |
|
42 |
|
43 cx = HMAC_Create(hashObj, secret->data, secret->len, isFIPS); |
|
44 if (cx == NULL) |
|
45 goto loser; |
|
46 |
|
47 /* initialize the state = A(1) = HMAC_hash(secret, seed) */ |
|
48 HMAC_Begin(cx); |
|
49 HMAC_Update(cx, (unsigned char *)label, label_len); |
|
50 HMAC_Update(cx, seed->data, seed->len); |
|
51 status = HMAC_Finish(cx, state, &state_len, sizeof(state)); |
|
52 if (status != SECSuccess) |
|
53 goto loser; |
|
54 |
|
55 /* generate a block at a time until we're done */ |
|
56 while (remaining > 0) { |
|
57 |
|
58 HMAC_Begin(cx); |
|
59 HMAC_Update(cx, state, state_len); |
|
60 if (label_len) |
|
61 HMAC_Update(cx, (unsigned char *)label, label_len); |
|
62 HMAC_Update(cx, seed->data, seed->len); |
|
63 status = HMAC_Finish(cx, outbuf, &outbuf_len, sizeof(outbuf)); |
|
64 if (status != SECSuccess) |
|
65 goto loser; |
|
66 |
|
67 /* Update the state = A(i) = HMAC_hash(secret, A(i-1)) */ |
|
68 HMAC_Begin(cx); |
|
69 HMAC_Update(cx, state, state_len); |
|
70 status = HMAC_Finish(cx, state, &state_len, sizeof(state)); |
|
71 if (status != SECSuccess) |
|
72 goto loser; |
|
73 |
|
74 chunk_size = PR_MIN(outbuf_len, remaining); |
|
75 PORT_Memcpy(res, &outbuf, chunk_size); |
|
76 res += chunk_size; |
|
77 remaining -= chunk_size; |
|
78 } |
|
79 |
|
80 rv = SECSuccess; |
|
81 |
|
82 loser: |
|
83 /* clear out state so it's not left on the stack */ |
|
84 if (cx) |
|
85 HMAC_Destroy(cx, PR_TRUE); |
|
86 PORT_Memset(state, 0, sizeof(state)); |
|
87 PORT_Memset(outbuf, 0, sizeof(outbuf)); |
|
88 return rv; |
|
89 } |
|
90 |
|
91 SECStatus |
|
92 TLS_PRF(const SECItem *secret, const char *label, SECItem *seed, |
|
93 SECItem *result, PRBool isFIPS) |
|
94 { |
|
95 SECStatus rv = SECFailure, status; |
|
96 unsigned int i; |
|
97 SECItem tmp = { siBuffer, NULL, 0}; |
|
98 SECItem S1; |
|
99 SECItem S2; |
|
100 |
|
101 PORT_Assert((secret != NULL) && (secret->data != NULL || !secret->len)); |
|
102 PORT_Assert((seed != NULL) && (seed->data != NULL)); |
|
103 PORT_Assert((result != NULL) && (result->data != NULL)); |
|
104 |
|
105 S1.type = siBuffer; |
|
106 S1.len = (secret->len / 2) + (secret->len & 1); |
|
107 S1.data = secret->data; |
|
108 |
|
109 S2.type = siBuffer; |
|
110 S2.len = S1.len; |
|
111 S2.data = secret->data + (secret->len - S2.len); |
|
112 |
|
113 tmp.data = (unsigned char*)PORT_Alloc(result->len); |
|
114 if (tmp.data == NULL) |
|
115 goto loser; |
|
116 tmp.len = result->len; |
|
117 |
|
118 status = TLS_P_hash(HASH_AlgMD5, &S1, label, seed, result, isFIPS); |
|
119 if (status != SECSuccess) |
|
120 goto loser; |
|
121 |
|
122 status = TLS_P_hash(HASH_AlgSHA1, &S2, label, seed, &tmp, isFIPS); |
|
123 if (status != SECSuccess) |
|
124 goto loser; |
|
125 |
|
126 for (i = 0; i < result->len; i++) |
|
127 result->data[i] ^= tmp.data[i]; |
|
128 |
|
129 rv = SECSuccess; |
|
130 |
|
131 loser: |
|
132 if (tmp.data != NULL) |
|
133 PORT_ZFree(tmp.data, tmp.len); |
|
134 return rv; |
|
135 } |
|
136 |