/src/SymCrypt/lib/tlsprf.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // tlsprf.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | // |
8 | | // This module contains the routines to implement the two PRF |
9 | | // functions for the TLS protocols 1.1 and 1.2. These are used in |
10 | | // the protocol's key derivation function. |
11 | | // |
12 | | // |
13 | | |
14 | | #include "precomp.h" |
15 | | |
16 | | // |
17 | | // TLS PRF Constants |
18 | | // |
19 | | #define SYMCRYPT_TLS_MAX_LABEL_AND_SEED_SIZE (SYMCRYPT_TLS_MAX_LABEL_SIZE + SYMCRYPT_TLS_MAX_SEED_SIZE) |
20 | | |
21 | | // This **MUST** be a common multiple of MD5 |
22 | | // output size and SHA1 output size. |
23 | 197 | #define SYMCRYPT_TLS_1_1_CHUNK_SIZE 80 |
24 | | |
25 | | // |
26 | | // SymCryptTlsPrf1_1ExpandKey is the key expansion function for versions 1.0 |
27 | | // and 1.1 of the TLS protocol. It takes as inputs a pointer to the expanded TLSPRF1.1 |
28 | | // key, and the key material in pbKey. Regarding the treatment of the key |
29 | | // material (the "secret"), the following is defined in RFCs 2246 and 4346: |
30 | | // |
31 | | // TLS's PRF is created by splitting the secret into two halves and |
32 | | // using one half to generate data with P_MD5 and the other half to |
33 | | // generate data with P_SHA - 1, then exclusive - or'ing the outputs of |
34 | | // these two expansion functions together. |
35 | | // |
36 | | // S1 and S2 are the two halves of the secret and each is the same |
37 | | // length. S1 is taken from the first half of the secret, S2 from the |
38 | | // second half. Their length is created by rounding up the length of the |
39 | | // overall secret divided by two; thus, if the original secret is an odd |
40 | | // number of bytes long, the last byte of S1 will be the same as the |
41 | | // first byte of S2. |
42 | | // |
43 | | // L_S = length in bytes of secret; |
44 | | // L_S1 = L_S2 = ceil(L_S / 2); |
45 | | // |
46 | | // The secret is partitioned into two halves (with the possibility of |
47 | | // one shared byte) as described above, S1 taking the first L_S1 bytes |
48 | | // and S2 the last L_S2 bytes. |
49 | | // |
50 | | // Note: In pre-RS1 Windows if the length of the key material of each half |
51 | | // exceeded HMAC_K_PADSIZE = 64, we truncated the key. This does not comply |
52 | | // with RFC 2014 (HMAC). However, as of April 2016 several cipher suites |
53 | | // used keys (pre-master secret) longer than 128 bytes. To achieve interop |
54 | | // with servers complying to the RFC we use the entire key for the HMAC calculation. |
55 | | // |
56 | | SYMCRYPT_ERROR |
57 | | SYMCRYPT_CALL |
58 | | SymCryptTlsPrf1_1ExpandKey( |
59 | | _Out_ PSYMCRYPT_TLSPRF1_1_EXPANDED_KEY pExpandedKey, |
60 | | _In_reads_(cbKey) PCBYTE pbKey, |
61 | | SIZE_T cbKey) |
62 | 27 | { |
63 | 27 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
64 | | |
65 | 27 | SIZE_T cbKeySize; |
66 | 27 | SIZE_T cbHalfSecret; |
67 | 27 | SIZE_T cbOdd; |
68 | | |
69 | | // Calculating the two halves |
70 | 27 | cbHalfSecret = cbKey / 2; |
71 | 27 | cbOdd = cbKey % 2; |
72 | 27 | cbKeySize = cbHalfSecret + cbOdd; |
73 | | |
74 | | // |
75 | | // The bytes of the key material are split as following: |
76 | | // cbOdd == 0 => cbKeySize == cbHalfSecret |
77 | | // |
78 | | // ******************************************** |
79 | | // <----cbHalfSecret----><----cbHalfSecret----> |
80 | | // <----cbKeySize-------><----cbKeySize-------> |
81 | | // |
82 | | // |
83 | | // cbOdd == 1 => cbKeySize == cbHalfSecret + 1 |
84 | | // |
85 | | // **********************$********************** |
86 | | // <----cbHalfSecret----> <----cbHalfSecret----> |
87 | | // <----cbKeySize--------> |
88 | | // <----cbKeySize--------> |
89 | | // |
90 | | // Note that the middle byte of the key input might be |
91 | | // read twice (when the key length is odd). This violates |
92 | | // the standard rule that input data should only be read |
93 | | // once. In this case, we do this for the following reasons: |
94 | | // - Avoiding the dual-read is difficult; we’d have to buffer |
95 | | // an arbitrary-size input, and SymCrypt avoids memory |
96 | | // allocations for symmetric algorithms. |
97 | | // - The dual-reading of inputs is a problem when the |
98 | | // memory is double-mapped to a different (less trusted) |
99 | | // security context. (E.g. a kernel-mode operation on |
100 | | // memory that is also mapped into a user address space.) |
101 | | // This PRF is used by TLS in LSA where that situation |
102 | | // does not occur. |
103 | | // - This is used for TLS 1.0 and TLS 1.1, both of which |
104 | | // are on the deprecation path. |
105 | | // - In the dual-read attack, the input is typically provided |
106 | | // by the attacker, and then changed whilst the code is |
107 | | // accessing it. But if the attacker is providing the input, |
108 | | // she could just as well have provided an even-length key |
109 | | // input that provides full freedom for choosing both HMAC |
110 | | // keys; there is simply no reason to try and perform the |
111 | | // dual-read attack. |
112 | | // - Even if the dual-read problem were to occur, it does not |
113 | | // seem to help an attacker in any way. |
114 | | |
115 | | // MD5 Key Expansion |
116 | 27 | scError = SymCryptHmacMd5ExpandKey(&pExpandedKey->macMd5Key, pbKey, cbKeySize); |
117 | 27 | if (scError != SYMCRYPT_NO_ERROR) |
118 | 0 | { |
119 | 0 | goto cleanup; |
120 | 0 | } |
121 | | |
122 | | // SHA1 Key Expansion |
123 | 27 | scError = SymCryptHmacSha1ExpandKey(&pExpandedKey->macSha1Key, pbKey + cbHalfSecret, cbKeySize); |
124 | 27 | if (scError != SYMCRYPT_NO_ERROR) |
125 | 0 | { |
126 | 0 | SymCryptWipeKnownSize(&pExpandedKey->macMd5Key, sizeof(pExpandedKey->macMd5Key)); |
127 | |
|
128 | 0 | goto cleanup; |
129 | 0 | } |
130 | | |
131 | 27 | cleanup: |
132 | 27 | return scError; |
133 | 27 | } |
134 | | |
135 | | SYMCRYPT_ERROR |
136 | | SYMCRYPT_CALL |
137 | | SymCryptTlsPrf1_2ExpandKey( |
138 | | _Out_ PSYMCRYPT_TLSPRF1_2_EXPANDED_KEY pExpandedKey, |
139 | | _In_ PCSYMCRYPT_MAC macAlgorithm, |
140 | | _In_reads_(cbKey) PCBYTE pbKey, |
141 | | SIZE_T cbKey ) |
142 | 0 | { |
143 | 0 | SYMCRYPT_ASSERT( macAlgorithm->expandedKeySize <= sizeof( pExpandedKey->macKey ) ); |
144 | |
|
145 | 0 | pExpandedKey->macAlg = macAlgorithm; |
146 | 0 | return macAlgorithm->expandKeyFunc( &pExpandedKey->macKey, pbKey, cbKey ); |
147 | 0 | } |
148 | | |
149 | | // |
150 | | // SymCryptTlsPrfMac uses the expanded key and hashes the concatenated |
151 | | // inputs pbAi and pbSeed. It is used by all the TLS versions per |
152 | | // RFCs 2246, 4346, and 5246. |
153 | | // Remark: |
154 | | // - cbSeed can be 0 and pbSeed NULL. |
155 | | // - pbResult should be of size at least pMacAlgorithm->resultSize |
156 | | // |
157 | | |
158 | | VOID |
159 | | SYMCRYPT_CALL |
160 | | SymCryptTlsPrfMac( |
161 | | _In_ PCSYMCRYPT_MAC pMacAlgorithm, |
162 | | _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey, |
163 | | _In_reads_(cbAi) PCBYTE pbAi, |
164 | | _In_ SIZE_T cbAi, |
165 | | _In_reads_opt_(cbSeed) PCBYTE pbSeed, |
166 | | _In_ SIZE_T cbSeed, |
167 | | _Out_ PBYTE pbResult) |
168 | 1.29k | { |
169 | 1.29k | SYMCRYPT_MAC_STATE macState; |
170 | | |
171 | 1.29k | pMacAlgorithm->initFunc( &macState, pMacExpandedKey ); |
172 | 1.29k | pMacAlgorithm->appendFunc(&macState, pbAi, cbAi); |
173 | | |
174 | 1.29k | if (cbSeed > 0) |
175 | 457 | { |
176 | 457 | pMacAlgorithm->appendFunc( &macState, pbSeed, cbSeed ); |
177 | 457 | } |
178 | | |
179 | 1.29k | pMacAlgorithm->resultFunc( &macState, pbResult ); |
180 | | |
181 | | // No need to wipe the state. The resultFunc wipes it. |
182 | 1.29k | } |
183 | | |
184 | | // |
185 | | // SymCryptTlsPrfPHash is defined in RFCs 2246, 4346, |
186 | | // and 5246 as follows: |
187 | | // |
188 | | // First, we define a data expansion function, P_hash(secret, data) |
189 | | // which uses a single hash function to expand a secret and seed into |
190 | | // an arbitrary quantity of output: |
191 | | // |
192 | | // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) + |
193 | | // HMAC_hash(secret, A(2) + seed) + |
194 | | // HMAC_hash(secret, A(3) + seed) + ... |
195 | | // |
196 | | // Where + indicates concatenation. |
197 | | // A() is defined as: |
198 | | // A(0) = seed |
199 | | // A(i) = HMAC_hash(secret, A(i-1)) |
200 | | // |
201 | | |
202 | | VOID |
203 | | SYMCRYPT_CALL |
204 | | SymCryptTlsPrfPHash( |
205 | | _In_ PCSYMCRYPT_MAC pMacAlgorithm, |
206 | | _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey, |
207 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
208 | | _In_ SIZE_T cbSeed, |
209 | | _In_reads_opt_(cbAiIn) PCBYTE pbAiIn, // Buffer for the previous Ai (used in 1.1) |
210 | | _In_ SIZE_T cbAiIn, |
211 | | _Out_writes_(cbResult) PBYTE pbResult, |
212 | | SIZE_T cbResult, |
213 | | _Out_writes_opt_(cbAiOut) PBYTE pbAiOut, // Buffer for the next Ai (only with AiIn) |
214 | | SIZE_T cbAiOut) |
215 | 146 | { |
216 | 146 | SYMCRYPT_ALIGN BYTE rbAi[SYMCRYPT_MAC_MAX_RESULT_SIZE]; |
217 | 146 | SYMCRYPT_ALIGN BYTE rbPartialResult[SYMCRYPT_MAC_MAX_RESULT_SIZE]; |
218 | 146 | BYTE * pbTmp = pbResult; |
219 | | |
220 | 146 | SIZE_T cbMacResultSize = pMacAlgorithm->resultSize; |
221 | 146 | SIZE_T cbBytesToWrite = cbResult; |
222 | | |
223 | 146 | if (cbAiIn == 0) |
224 | 0 | { |
225 | | // Build A(1) |
226 | 0 | SymCryptTlsPrfMac( |
227 | 0 | pMacAlgorithm, |
228 | 0 | pMacExpandedKey, |
229 | 0 | pbSeed, // This is A(0) |
230 | 0 | cbSeed, |
231 | 0 | NULL, // No "seed" part for A(i)'s |
232 | 0 | 0, |
233 | 0 | rbAi); |
234 | 0 | } |
235 | 146 | else |
236 | 146 | { |
237 | | // Get the previous Ai |
238 | 146 | memcpy(rbAi, pbAiIn, SYMCRYPT_MIN(SYMCRYPT_MAC_MAX_RESULT_SIZE, cbAiIn)); |
239 | 146 | } |
240 | | |
241 | 633 | while (cbBytesToWrite > 0) |
242 | 633 | { |
243 | | // Build HMAC( secret, A(i) + seed) |
244 | 633 | SymCryptTlsPrfMac( |
245 | 633 | pMacAlgorithm, |
246 | 633 | pMacExpandedKey, |
247 | 633 | rbAi, // this is A(i) |
248 | 633 | cbMacResultSize, |
249 | 633 | pbSeed, // the "seed" part |
250 | 633 | cbSeed, |
251 | 633 | rbPartialResult); |
252 | | |
253 | | // Store it in the output buffer |
254 | 633 | memcpy(pbTmp, rbPartialResult, SYMCRYPT_MIN(cbBytesToWrite, cbMacResultSize)); |
255 | | |
256 | | // Build A(i+1) |
257 | 633 | SymCryptTlsPrfMac( |
258 | 633 | pMacAlgorithm, |
259 | 633 | pMacExpandedKey, |
260 | 633 | rbAi, // This is A(i) |
261 | 633 | cbMacResultSize, |
262 | 633 | NULL, // No "seed" part for A(i)'s |
263 | 633 | 0, |
264 | 633 | rbAi); |
265 | | |
266 | 633 | if (cbBytesToWrite <= cbMacResultSize) |
267 | 146 | { |
268 | 146 | break; |
269 | 146 | } |
270 | | |
271 | 487 | pbTmp += cbMacResultSize; |
272 | 487 | cbBytesToWrite -= cbMacResultSize; |
273 | 487 | } |
274 | | |
275 | | // Store the next A(i) if needed |
276 | 146 | if (cbAiOut > 0) |
277 | 146 | { |
278 | 146 | memcpy(pbAiOut, rbAi, SYMCRYPT_MIN(cbAiOut,cbMacResultSize)); |
279 | 146 | } |
280 | | |
281 | 146 | SymCryptWipeKnownSize(rbAi, sizeof(rbAi)); |
282 | 146 | SymCryptWipeKnownSize(rbPartialResult, sizeof(rbPartialResult)); |
283 | 146 | } |
284 | | |
285 | | |
286 | | // |
287 | | // The following PRF is defined in RFC 2246 and 4346: |
288 | | // |
289 | | // The PRF is then defined as the result of mixing the two pseudorandom |
290 | | // streams by exclusive - or'ing them together. |
291 | | // |
292 | | // PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR |
293 | | // P_SHA-1(S2, label + seed); |
294 | | // |
295 | | // Remark: We will do the do the two P_hash computations in parallel |
296 | | // |
297 | | SYMCRYPT_ERROR |
298 | | SYMCRYPT_CALL |
299 | | SymCryptTlsPrf1_1Derive( |
300 | | _In_ PCSYMCRYPT_TLSPRF1_1_EXPANDED_KEY pExpandedKey, |
301 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
302 | | _In_ SIZE_T cbLabel, |
303 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
304 | | _In_ SIZE_T cbSeed, |
305 | | _Out_writes_(cbResult) PBYTE pbResult, |
306 | | SIZE_T cbResult) |
307 | 27 | { |
308 | 27 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
309 | | |
310 | 27 | SYMCRYPT_ALIGN BYTE rbLabelAndSeed[SYMCRYPT_TLS_MAX_LABEL_AND_SEED_SIZE]; |
311 | 27 | SIZE_T cbLabelAndSeed = 0; |
312 | | |
313 | 27 | SYMCRYPT_ALIGN BYTE rbAiMd5[SYMCRYPT_HMAC_MD5_RESULT_SIZE]; |
314 | 27 | SYMCRYPT_ALIGN BYTE rbPartialResultMd5[SYMCRYPT_TLS_1_1_CHUNK_SIZE]; |
315 | | |
316 | 27 | SYMCRYPT_ALIGN BYTE rbAiSha1[SYMCRYPT_HMAC_SHA1_RESULT_SIZE]; |
317 | 27 | SYMCRYPT_ALIGN BYTE rbPartialResultSha1[SYMCRYPT_TLS_1_1_CHUNK_SIZE]; |
318 | | |
319 | 27 | BYTE * pbTmp = pbResult; |
320 | 27 | SIZE_T cbBytesToWrite = cbResult; |
321 | | |
322 | | // Size checks |
323 | 27 | if ((cbLabel > SYMCRYPT_TLS_MAX_LABEL_SIZE) || (cbSeed > SYMCRYPT_TLS_MAX_SEED_SIZE)) |
324 | 13 | { |
325 | 13 | scError = SYMCRYPT_WRONG_DATA_SIZE; |
326 | 13 | goto cleanup; |
327 | 13 | } |
328 | | |
329 | | // Concatenating the label and the seed |
330 | 14 | pbTmp = rbLabelAndSeed; |
331 | 14 | if( cbLabel > 0 ) |
332 | 0 | { |
333 | 0 | memcpy(pbTmp, pbLabel, cbLabel); |
334 | 0 | pbTmp += cbLabel; |
335 | 0 | } |
336 | 14 | memcpy(pbTmp, pbSeed, cbSeed); |
337 | 14 | cbLabelAndSeed = cbLabel + cbSeed; |
338 | | |
339 | | // Build A(1)'s |
340 | 14 | SymCryptTlsPrfMac( |
341 | 14 | SymCryptHmacMd5Algorithm, |
342 | 14 | (PCSYMCRYPT_MAC_EXPANDED_KEY)&pExpandedKey->macMd5Key, |
343 | 14 | rbLabelAndSeed, // This is A(0) |
344 | 14 | cbLabelAndSeed, |
345 | 14 | NULL, // No "seed" part for A(i)'s |
346 | 14 | 0, |
347 | 14 | rbAiMd5); |
348 | | |
349 | 14 | SymCryptTlsPrfMac( |
350 | 14 | SymCryptHmacSha1Algorithm, |
351 | 14 | (PCSYMCRYPT_MAC_EXPANDED_KEY)&pExpandedKey->macSha1Key, |
352 | 14 | rbLabelAndSeed, // This is A(0) |
353 | 14 | cbLabelAndSeed, |
354 | 14 | NULL, // No "seed" part for A(i)'s |
355 | 14 | 0, |
356 | 14 | rbAiSha1); |
357 | | |
358 | | // Calculate the output |
359 | 14 | pbTmp = pbResult; |
360 | 76 | while (cbBytesToWrite > 0) |
361 | 73 | { |
362 | | // Calculate the two P_Hashes up to SYMCRYPT_TLS_1_1_CHUNK_SIZE bytes |
363 | | |
364 | | // P_MD5 |
365 | 73 | SymCryptTlsPrfPHash( |
366 | 73 | SymCryptHmacMd5Algorithm, |
367 | 73 | (PCSYMCRYPT_MAC_EXPANDED_KEY)&pExpandedKey->macMd5Key, |
368 | 73 | rbLabelAndSeed, |
369 | 73 | cbLabelAndSeed, |
370 | 73 | rbAiMd5, |
371 | 73 | SYMCRYPT_HMAC_MD5_RESULT_SIZE, |
372 | 73 | rbPartialResultMd5, |
373 | 73 | SYMCRYPT_MIN(cbBytesToWrite, SYMCRYPT_TLS_1_1_CHUNK_SIZE), |
374 | 73 | rbAiMd5, |
375 | 73 | SYMCRYPT_HMAC_MD5_RESULT_SIZE); |
376 | | |
377 | | // P_SHA1 |
378 | 73 | SymCryptTlsPrfPHash( |
379 | 73 | SymCryptHmacSha1Algorithm, |
380 | 73 | (PCSYMCRYPT_MAC_EXPANDED_KEY)&pExpandedKey->macSha1Key, |
381 | 73 | rbLabelAndSeed, |
382 | 73 | cbLabelAndSeed, |
383 | 73 | rbAiSha1, |
384 | 73 | SYMCRYPT_HMAC_SHA1_RESULT_SIZE, |
385 | 73 | rbPartialResultSha1, |
386 | 73 | SYMCRYPT_MIN(cbBytesToWrite, SYMCRYPT_TLS_1_1_CHUNK_SIZE), |
387 | 73 | rbAiSha1, |
388 | 73 | SYMCRYPT_HMAC_SHA1_RESULT_SIZE); |
389 | | |
390 | | // XOR the two into the output |
391 | 73 | SymCryptXorBytes( |
392 | 73 | rbPartialResultMd5, |
393 | 73 | rbPartialResultSha1, |
394 | 73 | pbTmp, |
395 | 73 | SYMCRYPT_MIN(cbBytesToWrite, SYMCRYPT_TLS_1_1_CHUNK_SIZE)); |
396 | | |
397 | 73 | if (cbBytesToWrite <= SYMCRYPT_TLS_1_1_CHUNK_SIZE) |
398 | 11 | { |
399 | 11 | break; |
400 | 11 | } |
401 | | |
402 | 62 | cbBytesToWrite -= SYMCRYPT_TLS_1_1_CHUNK_SIZE; |
403 | 62 | pbTmp += SYMCRYPT_TLS_1_1_CHUNK_SIZE; |
404 | | |
405 | 62 | } |
406 | | |
407 | 27 | cleanup: |
408 | 27 | SymCryptWipeKnownSize(rbLabelAndSeed, sizeof(rbLabelAndSeed)); |
409 | 27 | SymCryptWipeKnownSize(rbAiMd5, sizeof(rbAiMd5)); |
410 | 27 | SymCryptWipeKnownSize(rbPartialResultMd5, sizeof(rbPartialResultMd5)); |
411 | 27 | SymCryptWipeKnownSize(rbAiSha1, sizeof(rbAiSha1)); |
412 | 27 | SymCryptWipeKnownSize(rbPartialResultSha1, sizeof(rbPartialResultSha1)); |
413 | | |
414 | 27 | return scError; |
415 | 14 | } |
416 | | |
417 | | // |
418 | | // The following PRF is defined in RFC 5246: |
419 | | // |
420 | | // TLS's PRF is created by applying P_hash to the secret as: |
421 | | // |
422 | | // PRF(secret, label, seed) = P_<hash>(secret, label + seed) |
423 | | // |
424 | | SYMCRYPT_ERROR |
425 | | SYMCRYPT_CALL |
426 | | SymCryptTlsPrf1_2Derive( |
427 | | _In_ PCSYMCRYPT_TLSPRF1_2_EXPANDED_KEY pExpandedKey, |
428 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
429 | | _In_ SIZE_T cbLabel, |
430 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
431 | | _In_ SIZE_T cbSeed, |
432 | | _Out_writes_(cbResult) PBYTE pbResult, |
433 | | SIZE_T cbResult) |
434 | 0 | { |
435 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
436 | |
|
437 | 0 | SYMCRYPT_ALIGN BYTE rbLabelAndSeed[SYMCRYPT_TLS_MAX_LABEL_AND_SEED_SIZE]; |
438 | 0 | BYTE * pbTmp; |
439 | | |
440 | | // Size checks |
441 | 0 | if ((cbLabel > SYMCRYPT_TLS_MAX_LABEL_SIZE) || (cbSeed > SYMCRYPT_TLS_MAX_SEED_SIZE)) |
442 | 0 | { |
443 | 0 | scError = SYMCRYPT_WRONG_DATA_SIZE; |
444 | 0 | goto cleanup; |
445 | 0 | } |
446 | | |
447 | | // Concatenating the label and the seed |
448 | 0 | pbTmp = rbLabelAndSeed; |
449 | 0 | if( cbLabel > 0 ) |
450 | 0 | { |
451 | 0 | memcpy(pbTmp, pbLabel, cbLabel); |
452 | 0 | pbTmp += cbLabel; |
453 | 0 | } |
454 | 0 | memcpy(pbTmp, pbSeed, cbSeed); |
455 | | |
456 | | // |
457 | | // According to RFC 2104 (HMAC), hash the secret if its length |
458 | | // exceeds the basic compression block length. This is taken |
459 | | // care by the specific HMAC inside SymCryptTlsPrfPHash. |
460 | | // |
461 | 0 | SymCryptTlsPrfPHash( |
462 | 0 | pExpandedKey->macAlg, |
463 | 0 | &pExpandedKey->macKey, |
464 | 0 | rbLabelAndSeed, |
465 | 0 | cbLabel + cbSeed, |
466 | 0 | NULL, |
467 | 0 | 0, |
468 | 0 | pbResult, |
469 | 0 | cbResult, |
470 | 0 | NULL, |
471 | 0 | 0); |
472 | |
|
473 | 0 | cleanup: |
474 | 0 | SymCryptWipeKnownSize(rbLabelAndSeed, sizeof(rbLabelAndSeed)); |
475 | |
|
476 | 0 | return scError; |
477 | 0 | } |
478 | | |
479 | | // |
480 | | // The full TLS 1.0/1.1 Key Derivation Function |
481 | | // |
482 | | SYMCRYPT_ERROR |
483 | | SYMCRYPT_CALL |
484 | | SymCryptTlsPrf1_1( |
485 | | _In_reads_(cbKey) PCBYTE pbKey, |
486 | | _In_ SIZE_T cbKey, |
487 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
488 | | _In_ SIZE_T cbLabel, |
489 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
490 | | _In_ SIZE_T cbSeed, |
491 | | _Out_writes_(cbResult) PBYTE pbResult, |
492 | | SIZE_T cbResult) |
493 | 27 | { |
494 | 27 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
495 | 27 | SYMCRYPT_TLSPRF1_1_EXPANDED_KEY key; |
496 | | |
497 | | // Create the expanded key |
498 | 27 | scError = SymCryptTlsPrf1_1ExpandKey(&key, pbKey, cbKey); |
499 | 27 | if (scError != SYMCRYPT_NO_ERROR) |
500 | 0 | { |
501 | 0 | goto cleanup; |
502 | 0 | } |
503 | | |
504 | | // Derive the key |
505 | 27 | scError = SymCryptTlsPrf1_1Derive( |
506 | 27 | &key, |
507 | 27 | pbLabel, |
508 | 27 | cbLabel, |
509 | 27 | pbSeed, |
510 | 27 | cbSeed, |
511 | 27 | pbResult, |
512 | 27 | cbResult); |
513 | 27 | if (scError != SYMCRYPT_NO_ERROR) |
514 | 13 | { |
515 | 13 | goto cleanup; |
516 | 13 | } |
517 | | |
518 | 27 | cleanup: |
519 | 27 | SymCryptWipeKnownSize(&key, sizeof(key)); |
520 | | |
521 | 27 | return scError; |
522 | 27 | } |
523 | | |
524 | | |
525 | | // |
526 | | // The full TLS 1.2 Key Derivation Function |
527 | | // |
528 | | SYMCRYPT_ERROR |
529 | | SYMCRYPT_CALL |
530 | | SymCryptTlsPrf1_2( |
531 | | _In_ PCSYMCRYPT_MAC pMacAlgorithm, |
532 | | _In_reads_(cbKey) PCBYTE pbKey, |
533 | | _In_ SIZE_T cbKey, |
534 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
535 | | _In_ SIZE_T cbLabel, |
536 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
537 | | _In_ SIZE_T cbSeed, |
538 | | _Out_writes_(cbResult) PBYTE pbResult, |
539 | | SIZE_T cbResult) |
540 | 0 | { |
541 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
542 | 0 | SYMCRYPT_TLSPRF1_2_EXPANDED_KEY key; |
543 | | |
544 | | // Create the expanded key |
545 | 0 | scError = SymCryptTlsPrf1_2ExpandKey(&key, pMacAlgorithm, pbKey, cbKey); |
546 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
547 | 0 | { |
548 | 0 | goto cleanup; |
549 | 0 | } |
550 | | |
551 | | // Derive the key |
552 | 0 | scError = SymCryptTlsPrf1_2Derive( |
553 | 0 | &key, |
554 | 0 | pbLabel, |
555 | 0 | cbLabel, |
556 | 0 | pbSeed, |
557 | 0 | cbSeed, |
558 | 0 | pbResult, |
559 | 0 | cbResult); |
560 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
561 | 0 | { |
562 | 0 | goto cleanup; |
563 | 0 | } |
564 | | |
565 | 0 | cleanup: |
566 | 0 | SymCryptWipeKnownSize(&key, sizeof(key)); |
567 | |
|
568 | 0 | return scError; |
569 | 0 | } |
570 | | |
571 | | |
572 | | |