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