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