/src/nss-nspr/nss/lib/freebl/hmacct.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | | |
5 | | #ifdef FREEBL_NO_DEPEND |
6 | | #include "stubs.h" |
7 | | #endif |
8 | | |
9 | | #include "secport.h" |
10 | | #include "hasht.h" |
11 | | #include "blapit.h" |
12 | | #include "hmacct.h" |
13 | | #include "secerr.h" |
14 | | |
15 | | /* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length |
16 | | * field. (SHA-384/512 have 128-bit length.) */ |
17 | | #define MAX_HASH_BIT_COUNT_BYTES 16 |
18 | | |
19 | | /* constantTimeGE returns 0xff if a>=b and 0x00 otherwise, where a, b < |
20 | | * MAX_UINT/2. */ |
21 | | static unsigned char |
22 | | constantTimeGE(unsigned int a, unsigned int b) |
23 | 0 | { |
24 | 0 | return PORT_CT_GE(a, b); |
25 | 0 | } |
26 | | |
27 | | /* constantTimeEQ8 returns 0xff if a==b and 0x00 otherwise. */ |
28 | | static unsigned char |
29 | | constantTimeEQ(unsigned char a, unsigned char b) |
30 | 0 | { |
31 | 0 | return PORT_CT_EQ(a, b); |
32 | 0 | } |
33 | | |
34 | | /* MAC performs a constant time SSLv3/TLS MAC of |dataLen| bytes of |data|, |
35 | | * where |dataLen| includes both the authenticated bytes and the MAC tag from |
36 | | * the sender. |dataLen| must be >= the length of the MAC tag. |
37 | | * |
38 | | * |dataTotalLen| is >= |dataLen| and also accounts for any padding bytes |
39 | | * that may follow the sender's MAC. (Only a single block of padding may |
40 | | * follow in SSLv3, or up to 255 bytes in TLS.) |
41 | | * |
42 | | * Since the results of decryption are secret information (otherwise a |
43 | | * padding-oracle is created), this function is constant-time with respect to |
44 | | * |dataLen|. |
45 | | * |
46 | | * |header| contains either the 13-byte TLS header (containing the sequence |
47 | | * number, record type etc), or it contains the SSLv3 header with the SSLv3 |
48 | | * padding bytes etc. */ |
49 | | static SECStatus |
50 | | MAC(unsigned char *mdOut, |
51 | | unsigned int *mdOutLen, |
52 | | unsigned int mdOutMax, |
53 | | const SECHashObject *hashObj, |
54 | | const unsigned char *macSecret, |
55 | | unsigned int macSecretLen, |
56 | | const unsigned char *header, |
57 | | unsigned int headerLen, |
58 | | const unsigned char *data, |
59 | | unsigned int dataLen, |
60 | | unsigned int dataTotalLen, |
61 | | unsigned char isSSLv3) |
62 | 0 | { |
63 | 0 | void *mdState = hashObj->create(); |
64 | 0 | const unsigned int mdSize = hashObj->length; |
65 | 0 | const unsigned int mdBlockSize = hashObj->blocklength; |
66 | | /* mdLengthSize is the number of bytes in the length field that terminates |
67 | | * the hash. |
68 | | * |
69 | | * This assumes that hash functions with a 64 byte block size use a 64-bit |
70 | | * length, and otherwise they use a 128-bit length. This is true of {MD5, |
71 | | * SHA*} (which are all of the hash functions specified for use with TLS |
72 | | * today). */ |
73 | 0 | const unsigned int mdLengthSize = mdBlockSize == 64 ? 8 : 16; |
74 | |
|
75 | 0 | const unsigned int sslv3PadLen = hashObj->type == HASH_AlgMD5 ? 48 : 40; |
76 | | |
77 | | /* varianceBlocks is the number of blocks of the hash that we have to |
78 | | * calculate in constant time because they could be altered by the |
79 | | * padding value. |
80 | | * |
81 | | * In SSLv3, the padding must be minimal so the end of the plaintext |
82 | | * varies by, at most, 15+20 = 35 bytes. (We conservatively assume that |
83 | | * the MAC size varies from 0..20 bytes.) In case the 9 bytes of hash |
84 | | * termination (0x80 + 64-bit length) don't fit in the final block, we |
85 | | * say that the final two blocks can vary based on the padding. |
86 | | * |
87 | | * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not |
88 | | * required to be minimal. Therefore we say that the final six blocks |
89 | | * can vary based on the padding. |
90 | | * |
91 | | * Later in the function, if the message is short and there obviously |
92 | | * cannot be this many blocks then varianceBlocks can be reduced. */ |
93 | 0 | unsigned int varianceBlocks = isSSLv3 ? 2 : 6; |
94 | | /* From now on we're dealing with the MAC, which conceptually has 13 |
95 | | * bytes of `header' before the start of the data (TLS) or 71/75 bytes |
96 | | * (SSLv3) */ |
97 | 0 | const unsigned int len = dataTotalLen + headerLen; |
98 | | /* maxMACBytes contains the maximum bytes of bytes in the MAC, including |
99 | | * |header|, assuming that there's no padding. */ |
100 | 0 | const unsigned int maxMACBytes = len - mdSize - 1; |
101 | | /* numBlocks is the maximum number of hash blocks. */ |
102 | 0 | const unsigned int numBlocks = |
103 | 0 | (maxMACBytes + 1 + mdLengthSize + mdBlockSize - 1) / mdBlockSize; |
104 | | /* macEndOffset is the index just past the end of the data to be |
105 | | * MACed. */ |
106 | 0 | const unsigned int macEndOffset = dataLen + headerLen - mdSize; |
107 | | /* c is the index of the 0x80 byte in the final hash block that |
108 | | * contains application data. */ |
109 | 0 | const unsigned int c = macEndOffset % mdBlockSize; |
110 | | /* indexA is the hash block number that contains the 0x80 terminating |
111 | | * value. */ |
112 | 0 | const unsigned int indexA = macEndOffset / mdBlockSize; |
113 | | /* indexB is the hash block number that contains the 64-bit hash |
114 | | * length, in bits. */ |
115 | 0 | const unsigned int indexB = (macEndOffset + mdLengthSize) / mdBlockSize; |
116 | | /* bits is the hash-length in bits. It includes the additional hash |
117 | | * block for the masked HMAC key, or whole of |header| in the case of |
118 | | * SSLv3. */ |
119 | 0 | unsigned int bits; |
120 | | /* In order to calculate the MAC in constant time we have to handle |
121 | | * the final blocks specially because the padding value could cause the |
122 | | * end to appear somewhere in the final |varianceBlocks| blocks and we |
123 | | * can't leak where. However, |numStartingBlocks| worth of data can |
124 | | * be hashed right away because no padding value can affect whether |
125 | | * they are plaintext. */ |
126 | 0 | unsigned int numStartingBlocks = 0; |
127 | | /* k is the starting byte offset into the conceptual header||data where |
128 | | * we start processing. */ |
129 | 0 | unsigned int k = 0; |
130 | 0 | unsigned char lengthBytes[MAX_HASH_BIT_COUNT_BYTES]; |
131 | | /* hmacPad is the masked HMAC key. */ |
132 | 0 | unsigned char hmacPad[HASH_BLOCK_LENGTH_MAX]; |
133 | 0 | unsigned char firstBlock[HASH_BLOCK_LENGTH_MAX]; |
134 | 0 | unsigned char macOut[HASH_LENGTH_MAX]; |
135 | 0 | unsigned i, j; |
136 | | |
137 | | /* For SSLv3, if we're going to have any starting blocks then we need |
138 | | * at least two because the header is larger than a single block. */ |
139 | 0 | if (numBlocks > varianceBlocks + (isSSLv3 ? 1 : 0)) { |
140 | 0 | numStartingBlocks = numBlocks - varianceBlocks; |
141 | 0 | k = mdBlockSize * numStartingBlocks; |
142 | 0 | } |
143 | |
|
144 | 0 | bits = 8 * macEndOffset; |
145 | 0 | hashObj->begin(mdState); |
146 | 0 | if (!isSSLv3) { |
147 | | /* Compute the initial HMAC block. For SSLv3, the padding and |
148 | | * secret bytes are included in |header| because they take more |
149 | | * than a single block. */ |
150 | 0 | bits += 8 * mdBlockSize; |
151 | 0 | memset(hmacPad, 0, mdBlockSize); |
152 | 0 | PORT_Assert(macSecretLen <= sizeof(hmacPad)); |
153 | 0 | memcpy(hmacPad, macSecret, macSecretLen); |
154 | 0 | for (i = 0; i < mdBlockSize; i++) |
155 | 0 | hmacPad[i] ^= 0x36; |
156 | 0 | hashObj->update(mdState, hmacPad, mdBlockSize); |
157 | 0 | } |
158 | |
|
159 | 0 | j = 0; |
160 | 0 | memset(lengthBytes, 0, sizeof(lengthBytes)); |
161 | 0 | if (mdLengthSize == 16) { |
162 | 0 | j = 8; |
163 | 0 | } |
164 | 0 | if (hashObj->type == HASH_AlgMD5) { |
165 | | /* MD5 appends a little-endian length. */ |
166 | 0 | for (i = 0; i < 4; i++) { |
167 | 0 | lengthBytes[i + j] = bits >> (8 * i); |
168 | 0 | } |
169 | 0 | } else { |
170 | | /* All other TLS hash functions use a big-endian length. */ |
171 | 0 | for (i = 0; i < 4; i++) { |
172 | 0 | lengthBytes[4 + i + j] = bits >> (8 * (3 - i)); |
173 | 0 | } |
174 | 0 | } |
175 | |
|
176 | 0 | if (k > 0) { |
177 | 0 | if (isSSLv3) { |
178 | | /* The SSLv3 header is larger than a single block. |
179 | | * overhang is the number of bytes beyond a single |
180 | | * block that the header consumes: either 7 bytes |
181 | | * (SHA1) or 11 bytes (MD5). */ |
182 | 0 | const unsigned int overhang = headerLen - mdBlockSize; |
183 | 0 | hashObj->update(mdState, header, mdBlockSize); |
184 | 0 | memcpy(firstBlock, header + mdBlockSize, overhang); |
185 | 0 | memcpy(firstBlock + overhang, data, mdBlockSize - overhang); |
186 | 0 | hashObj->update(mdState, firstBlock, mdBlockSize); |
187 | 0 | for (i = 1; i < k / mdBlockSize - 1; i++) { |
188 | 0 | hashObj->update(mdState, data + mdBlockSize * i - overhang, |
189 | 0 | mdBlockSize); |
190 | 0 | } |
191 | 0 | } else { |
192 | | /* k is a multiple of mdBlockSize. */ |
193 | 0 | memcpy(firstBlock, header, 13); |
194 | 0 | memcpy(firstBlock + 13, data, mdBlockSize - 13); |
195 | 0 | hashObj->update(mdState, firstBlock, mdBlockSize); |
196 | 0 | for (i = 1; i < k / mdBlockSize; i++) { |
197 | 0 | hashObj->update(mdState, data + mdBlockSize * i - 13, |
198 | 0 | mdBlockSize); |
199 | 0 | } |
200 | 0 | } |
201 | 0 | } |
202 | |
|
203 | 0 | memset(macOut, 0, sizeof(macOut)); |
204 | | |
205 | | /* We now process the final hash blocks. For each block, we construct |
206 | | * it in constant time. If i == indexA then we'll include the 0x80 |
207 | | * bytes and zero pad etc. For each block we selectively copy it, in |
208 | | * constant time, to |macOut|. */ |
209 | 0 | for (i = numStartingBlocks; i <= numStartingBlocks + varianceBlocks; i++) { |
210 | 0 | unsigned char block[HASH_BLOCK_LENGTH_MAX]; |
211 | 0 | unsigned char isBlockA = constantTimeEQ(i, indexA); |
212 | 0 | unsigned char isBlockB = constantTimeEQ(i, indexB); |
213 | 0 | for (j = 0; j < mdBlockSize; j++) { |
214 | 0 | unsigned char isPastC = isBlockA & constantTimeGE(j, c); |
215 | 0 | unsigned char isPastCPlus1 = isBlockA & constantTimeGE(j, c + 1); |
216 | 0 | unsigned char b = 0; |
217 | 0 | if (k < headerLen) { |
218 | 0 | b = header[k]; |
219 | 0 | } else if (k < dataTotalLen + headerLen) { |
220 | 0 | b = data[k - headerLen]; |
221 | 0 | } |
222 | 0 | k++; |
223 | | |
224 | | /* If this is the block containing the end of the |
225 | | * application data, and we are at the offset for the |
226 | | * 0x80 value, then overwrite b with 0x80. */ |
227 | 0 | b = (b & ~isPastC) | (0x80 & isPastC); |
228 | | /* If this the the block containing the end of the |
229 | | * application data and we're past the 0x80 value then |
230 | | * just write zero. */ |
231 | 0 | b = b & ~isPastCPlus1; |
232 | | /* If this is indexB (the final block), but not |
233 | | * indexA (the end of the data), then the 64-bit |
234 | | * length didn't fit into indexA and we're having to |
235 | | * add an extra block of zeros. */ |
236 | 0 | b &= ~isBlockB | isBlockA; |
237 | | |
238 | | /* The final bytes of one of the blocks contains the length. */ |
239 | 0 | if (j >= mdBlockSize - mdLengthSize) { |
240 | | /* If this is indexB, write a length byte. */ |
241 | 0 | b = (b & ~isBlockB) | |
242 | 0 | (isBlockB & lengthBytes[j - (mdBlockSize - mdLengthSize)]); |
243 | 0 | } |
244 | 0 | block[j] = b; |
245 | 0 | } |
246 | |
|
247 | 0 | hashObj->update(mdState, block, mdBlockSize); |
248 | 0 | hashObj->end_raw(mdState, block, NULL, mdSize); |
249 | | /* If this is indexB, copy the hash value to |macOut|. */ |
250 | 0 | for (j = 0; j < mdSize; j++) { |
251 | 0 | macOut[j] |= block[j] & isBlockB; |
252 | 0 | } |
253 | 0 | } |
254 | |
|
255 | 0 | hashObj->begin(mdState); |
256 | |
|
257 | 0 | if (isSSLv3) { |
258 | | /* We repurpose |hmacPad| to contain the SSLv3 pad2 block. */ |
259 | 0 | for (i = 0; i < sslv3PadLen; i++) |
260 | 0 | hmacPad[i] = 0x5c; |
261 | |
|
262 | 0 | hashObj->update(mdState, macSecret, macSecretLen); |
263 | 0 | hashObj->update(mdState, hmacPad, sslv3PadLen); |
264 | 0 | hashObj->update(mdState, macOut, mdSize); |
265 | 0 | } else { |
266 | | /* Complete the HMAC in the standard manner. */ |
267 | 0 | for (i = 0; i < mdBlockSize; i++) |
268 | 0 | hmacPad[i] ^= 0x6a; |
269 | |
|
270 | 0 | hashObj->update(mdState, hmacPad, mdBlockSize); |
271 | 0 | hashObj->update(mdState, macOut, mdSize); |
272 | 0 | } |
273 | |
|
274 | 0 | hashObj->end(mdState, mdOut, mdOutLen, mdOutMax); |
275 | 0 | hashObj->destroy(mdState, PR_TRUE); |
276 | |
|
277 | 0 | PORT_Memset(lengthBytes, 0, sizeof lengthBytes); |
278 | 0 | PORT_Memset(hmacPad, 0, sizeof hmacPad); |
279 | 0 | PORT_Memset(firstBlock, 0, sizeof firstBlock); |
280 | 0 | PORT_Memset(macOut, 0, sizeof macOut); |
281 | |
|
282 | 0 | return SECSuccess; |
283 | 0 | } |
284 | | |
285 | | SECStatus |
286 | | HMAC_ConstantTime( |
287 | | unsigned char *result, |
288 | | unsigned int *resultLen, |
289 | | unsigned int maxResultLen, |
290 | | const SECHashObject *hashObj, |
291 | | const unsigned char *secret, |
292 | | unsigned int secretLen, |
293 | | const unsigned char *header, |
294 | | unsigned int headerLen, |
295 | | const unsigned char *body, |
296 | | unsigned int bodyLen, |
297 | | unsigned int bodyTotalLen) |
298 | 0 | { |
299 | 0 | if (hashObj->end_raw == NULL) |
300 | 0 | return SECFailure; |
301 | 0 | return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen, |
302 | 0 | header, headerLen, body, bodyLen, bodyTotalLen, |
303 | 0 | 0 /* not SSLv3 */); |
304 | 0 | } |
305 | | |
306 | | SECStatus |
307 | | SSLv3_MAC_ConstantTime( |
308 | | unsigned char *result, |
309 | | unsigned int *resultLen, |
310 | | unsigned int maxResultLen, |
311 | | const SECHashObject *hashObj, |
312 | | const unsigned char *secret, |
313 | | unsigned int secretLen, |
314 | | const unsigned char *header, |
315 | | unsigned int headerLen, |
316 | | const unsigned char *body, |
317 | | unsigned int bodyLen, |
318 | | unsigned int bodyTotalLen) |
319 | 0 | { |
320 | 0 | if (hashObj->end_raw == NULL) |
321 | 0 | return SECFailure; |
322 | 0 | return MAC(result, resultLen, maxResultLen, hashObj, secret, secretLen, |
323 | 0 | header, headerLen, body, bodyLen, bodyTotalLen, |
324 | 0 | 1 /* SSLv3 */); |
325 | 0 | } |