ReactOS 0.4.17-dev-1005-g171e1de
tlsprf.c
Go to the documentation of this file.
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#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//
62{
63 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
64
65 SIZE_T cbKeySize;
66 SIZE_T cbHalfSecret;
67 SIZE_T cbOdd;
68
69 // Calculating the two halves
70 cbHalfSecret = cbKey / 2;
71 cbOdd = cbKey % 2;
72 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 scError = SymCryptHmacMd5ExpandKey(&pExpandedKey->macMd5Key, pbKey, cbKeySize);
117 if (scError != SYMCRYPT_NO_ERROR)
118 {
119 goto cleanup;
120 }
121
122 // SHA1 Key Expansion
123 scError = SymCryptHmacSha1ExpandKey(&pExpandedKey->macSha1Key, pbKey + cbHalfSecret, cbKeySize);
124 if (scError != SYMCRYPT_NO_ERROR)
125 {
126 SymCryptWipeKnownSize(&pExpandedKey->macMd5Key, sizeof(pExpandedKey->macMd5Key));
127
128 goto cleanup;
129 }
130
131cleanup:
132 return scError;
133}
134
141 SIZE_T cbKey )
142{
144
145 pExpandedKey->macAlg = macAlgorithm;
146 return macAlgorithm->expandKeyFunc( &pExpandedKey->macKey, pbKey, cbKey );
147}
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
158VOID
161 _In_ PCSYMCRYPT_MAC pMacAlgorithm,
162 _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey,
163 _In_reads_(cbAi) PCBYTE pbAi,
164 _In_ SIZE_T cbAi,
168{
169 SYMCRYPT_MAC_STATE macState;
170
171 pMacAlgorithm->initFunc( &macState, pMacExpandedKey );
172 pMacAlgorithm->appendFunc(&macState, pbAi, cbAi);
173
174 if (cbSeed > 0)
175 {
176 pMacAlgorithm->appendFunc( &macState, pbSeed, cbSeed );
177 }
178
179 pMacAlgorithm->resultFunc( &macState, pbResult );
180
181 // No need to wipe the state. The resultFunc wipes it.
182}
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
202VOID
205 _In_ PCSYMCRYPT_MAC pMacAlgorithm,
206 _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey,
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{
218 BYTE * pbTmp = pbResult;
219
220 SIZE_T cbMacResultSize = pMacAlgorithm->resultSize;
221 SIZE_T cbBytesToWrite = cbResult;
222
223 if (cbAiIn == 0)
224 {
225 // Build A(1)
227 pMacAlgorithm,
228 pMacExpandedKey,
229 pbSeed, // This is A(0)
230 cbSeed,
231 NULL, // No "seed" part for A(i)'s
232 0,
233 rbAi);
234 }
235 else
236 {
237 // Get the previous Ai
238 memcpy(rbAi, pbAiIn, SYMCRYPT_MIN(SYMCRYPT_MAC_MAX_RESULT_SIZE, cbAiIn));
239 }
240
241 while (cbBytesToWrite > 0)
242 {
243 // Build HMAC( secret, A(i) + seed)
245 pMacAlgorithm,
246 pMacExpandedKey,
247 rbAi, // this is A(i)
248 cbMacResultSize,
249 pbSeed, // the "seed" part
250 cbSeed,
251 rbPartialResult);
252
253 // Store it in the output buffer
254 memcpy(pbTmp, rbPartialResult, SYMCRYPT_MIN(cbBytesToWrite, cbMacResultSize));
255
256 // Build A(i+1)
258 pMacAlgorithm,
259 pMacExpandedKey,
260 rbAi, // This is A(i)
261 cbMacResultSize,
262 NULL, // No "seed" part for A(i)'s
263 0,
264 rbAi);
265
266 if (cbBytesToWrite <= cbMacResultSize)
267 {
268 break;
269 }
270
271 pbTmp += cbMacResultSize;
272 cbBytesToWrite -= cbMacResultSize;
273 }
274
275 // Store the next A(i) if needed
276 if (cbAiOut > 0)
277 {
278 memcpy(pbAiOut, rbAi, SYMCRYPT_MIN(cbAiOut,cbMacResultSize));
279 }
280
281 SymCryptWipeKnownSize(rbAi, sizeof(rbAi));
282 SymCryptWipeKnownSize(rbPartialResult, sizeof(rbPartialResult));
283}
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//
301 _In_reads_opt_(cbLabel) PCBYTE pbLabel,
302 _In_ SIZE_T cbLabel,
305 _Out_writes_(cbResult) PBYTE pbResult,
306 SIZE_T cbResult)
307{
308 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
309
311 SIZE_T cbLabelAndSeed = 0;
312
315
318
319 BYTE * pbTmp = pbResult;
320 SIZE_T cbBytesToWrite = cbResult;
321
322 // Size checks
324 {
325 scError = SYMCRYPT_WRONG_DATA_SIZE;
326 goto cleanup;
327 }
328
329 // Concatenating the label and the seed
330 pbTmp = rbLabelAndSeed;
331 if( cbLabel > 0 )
332 {
333 memcpy(pbTmp, pbLabel, cbLabel);
334 pbTmp += cbLabel;
335 }
336 memcpy(pbTmp, pbSeed, cbSeed);
337 cbLabelAndSeed = cbLabel + cbSeed;
338
339 // Build A(1)'s
343 rbLabelAndSeed, // This is A(0)
344 cbLabelAndSeed,
345 NULL, // No "seed" part for A(i)'s
346 0,
347 rbAiMd5);
348
352 rbLabelAndSeed, // This is A(0)
353 cbLabelAndSeed,
354 NULL, // No "seed" part for A(i)'s
355 0,
356 rbAiSha1);
357
358 // Calculate the output
359 pbTmp = pbResult;
360 while (cbBytesToWrite > 0)
361 {
362 // Calculate the two P_Hashes up to SYMCRYPT_TLS_1_1_CHUNK_SIZE bytes
363
364 // P_MD5
368 rbLabelAndSeed,
369 cbLabelAndSeed,
370 rbAiMd5,
372 rbPartialResultMd5,
374 rbAiMd5,
376
377 // P_SHA1
381 rbLabelAndSeed,
382 cbLabelAndSeed,
383 rbAiSha1,
385 rbPartialResultSha1,
387 rbAiSha1,
389
390 // XOR the two into the output
392 rbPartialResultMd5,
393 rbPartialResultSha1,
394 pbTmp,
396
397 if (cbBytesToWrite <= SYMCRYPT_TLS_1_1_CHUNK_SIZE)
398 {
399 break;
400 }
401
402 cbBytesToWrite -= SYMCRYPT_TLS_1_1_CHUNK_SIZE;
404
405 }
406
407cleanup:
408 SymCryptWipeKnownSize(rbLabelAndSeed, sizeof(rbLabelAndSeed));
409 SymCryptWipeKnownSize(rbAiMd5, sizeof(rbAiMd5));
410 SymCryptWipeKnownSize(rbPartialResultMd5, sizeof(rbPartialResultMd5));
411 SymCryptWipeKnownSize(rbAiSha1, sizeof(rbAiSha1));
412 SymCryptWipeKnownSize(rbPartialResultSha1, sizeof(rbPartialResultSha1));
413
414 return scError;
415}
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//
428 _In_reads_opt_(cbLabel) PCBYTE pbLabel,
429 _In_ SIZE_T cbLabel,
432 _Out_writes_(cbResult) PBYTE pbResult,
433 SIZE_T cbResult)
434{
435 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
436
438 BYTE * pbTmp;
439
440 // Size checks
442 {
443 scError = SYMCRYPT_WRONG_DATA_SIZE;
444 goto cleanup;
445 }
446
447 // Concatenating the label and the seed
448 pbTmp = rbLabelAndSeed;
449 if( cbLabel > 0 )
450 {
451 memcpy(pbTmp, pbLabel, cbLabel);
452 pbTmp += cbLabel;
453 }
454 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 //
462 pExpandedKey->macAlg,
463 &pExpandedKey->macKey,
464 rbLabelAndSeed,
465 cbLabel + cbSeed,
466 NULL,
467 0,
468 pbResult,
469 cbResult,
470 NULL,
471 0);
472
473cleanup:
474 SymCryptWipeKnownSize(rbLabelAndSeed, sizeof(rbLabelAndSeed));
475
476 return scError;
477}
478
479//
480// The full TLS 1.0/1.1 Key Derivation Function
481//
487 _In_reads_opt_(cbLabel) PCBYTE pbLabel,
488 _In_ SIZE_T cbLabel,
491 _Out_writes_(cbResult) PBYTE pbResult,
492 SIZE_T cbResult)
493{
494 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
496
497 // Create the expanded key
499 if (scError != SYMCRYPT_NO_ERROR)
500 {
501 goto cleanup;
502 }
503
504 // Derive the key
505 scError = SymCryptTlsPrf1_1Derive(
506 &key,
507 pbLabel,
508 cbLabel,
509 pbSeed,
510 cbSeed,
511 pbResult,
512 cbResult);
513 if (scError != SYMCRYPT_NO_ERROR)
514 {
515 goto cleanup;
516 }
517
518cleanup:
519 SymCryptWipeKnownSize(&key, sizeof(key));
520
521 return scError;
522}
523
524
525//
526// The full TLS 1.2 Key Derivation Function
527//
531 _In_ PCSYMCRYPT_MAC pMacAlgorithm,
534 _In_reads_opt_(cbLabel) PCBYTE pbLabel,
535 _In_ SIZE_T cbLabel,
538 _Out_writes_(cbResult) PBYTE pbResult,
539 SIZE_T cbResult)
540{
541 SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
543
544 // Create the expanded key
545 scError = SymCryptTlsPrf1_2ExpandKey(&key, pMacAlgorithm, pbKey, cbKey);
546 if (scError != SYMCRYPT_NO_ERROR)
547 {
548 goto cleanup;
549 }
550
551 // Derive the key
552 scError = SymCryptTlsPrf1_2Derive(
553 &key,
554 pbLabel,
555 cbLabel,
556 pbSeed,
557 cbSeed,
558 pbResult,
559 cbResult);
560 if (scError != SYMCRYPT_NO_ERROR)
561 {
562 goto cleanup;
563 }
564
565cleanup:
566 SymCryptWipeKnownSize(&key, sizeof(key));
567
568 return scError;
569}
#define NULL
Definition: types.h:112
static void cleanup(void)
Definition: main.c:1335
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define _In_reads_(s)
Definition: no_sal2.h:168
#define _Out_writes_opt_(s)
Definition: no_sal2.h:226
#define _Out_writes_(s)
Definition: no_sal2.h:176
#define _Out_
Definition: no_sal2.h:160
#define _In_reads_opt_(s)
Definition: no_sal2.h:222
#define _In_
Definition: no_sal2.h:158
BYTE * PBYTE
Definition: pedump.c:66
static const BYTE pbResult[]
PSYMCRYPT_MAC_EXPAND_KEY expandKeyFunc
Definition: copy.c:22
#define SYMCRYPT_ASSERT(_x)
Definition: symcrypt.h:10807
#define SYMCRYPT_HMAC_MD5_RESULT_SIZE
Definition: symcrypt.h:2660
FORCEINLINE VOID SYMCRYPT_CALL SymCryptWipeKnownSize(_Out_writes_bytes_(cbData) PVOID pbData, SIZE_T cbData)
const PCSYMCRYPT_MAC SymCryptHmacSha1Algorithm
Definition: hmacsha1.c:36
const PCSYMCRYPT_MAC SymCryptHmacMd5Algorithm
Definition: hmacmd5.c:29
VOID SYMCRYPT_CALL SymCryptXorBytes(_In_reads_(cbBytes) PCBYTE pbSrc1, _In_reads_(cbBytes) PCBYTE pbSrc2, _Out_writes_(cbBytes) PBYTE pbResult, SIZE_T cbBytes)
Definition: libmain.c:236
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptHmacSha1ExpandKey(_Out_ PSYMCRYPT_HMAC_SHA1_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbKey) PCBYTE pbKey, SIZE_T cbKey)
#define SYMCRYPT_HMAC_SHA1_RESULT_SIZE
Definition: symcrypt.h:2725
#define SYMCRYPT_TLS_MAX_LABEL_SIZE
Definition: symcrypt.h:5671
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptHmacMd5ExpandKey(_Out_ PSYMCRYPT_HMAC_MD5_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbKey) PCBYTE pbKey, SIZE_T cbKey)
#define SYMCRYPT_TLS_MAX_SEED_SIZE
Definition: symcrypt.h:5672
SYMCRYPT_ERROR
Definition: symcrypt.h:227
#define SYMCRYPT_ALIGN
#define SYMCRYPT_CALL
PCBYTE pbKey
PCBYTE SIZE_T cbKey
#define SYMCRYPT_MIN(_a, _b)
UINT32 cbSeed
const BYTE * PCBYTE
#define SYMCRYPT_MAC_MAX_RESULT_SIZE
PCSYMCRYPT_MAC macAlgorithm
PBYTE pbSeed
PCVOID pExpandedKey
VOID SYMCRYPT_CALL SymCryptTlsPrfPHash(_In_ PCSYMCRYPT_MAC pMacAlgorithm, _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey, _In_reads_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _In_reads_opt_(cbAiIn) PCBYTE pbAiIn, _In_ SIZE_T cbAiIn, _Out_writes_(cbResult) PBYTE pbResult, SIZE_T cbResult, _Out_writes_opt_(cbAiOut) PBYTE pbAiOut, SIZE_T cbAiOut)
Definition: tlsprf.c:204
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_1ExpandKey(_Out_ PSYMCRYPT_TLSPRF1_1_EXPANDED_KEY pExpandedKey, _In_reads_(cbKey) PCBYTE pbKey, SIZE_T cbKey)
Definition: tlsprf.c:58
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_1Derive(_In_ PCSYMCRYPT_TLSPRF1_1_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbLabel) PCBYTE pbLabel, _In_ SIZE_T cbLabel, _In_reads_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _Out_writes_(cbResult) PBYTE pbResult, SIZE_T cbResult)
Definition: tlsprf.c:299
VOID SYMCRYPT_CALL SymCryptTlsPrfMac(_In_ PCSYMCRYPT_MAC pMacAlgorithm, _In_ PCSYMCRYPT_MAC_EXPANDED_KEY pMacExpandedKey, _In_reads_(cbAi) PCBYTE pbAi, _In_ SIZE_T cbAi, _In_reads_opt_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _Out_ PBYTE pbResult)
Definition: tlsprf.c:160
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_1(_In_reads_(cbKey) PCBYTE pbKey, _In_ SIZE_T cbKey, _In_reads_opt_(cbLabel) PCBYTE pbLabel, _In_ SIZE_T cbLabel, _In_reads_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _Out_writes_(cbResult) PBYTE pbResult, SIZE_T cbResult)
Definition: tlsprf.c:484
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_2(_In_ PCSYMCRYPT_MAC pMacAlgorithm, _In_reads_(cbKey) PCBYTE pbKey, _In_ SIZE_T cbKey, _In_reads_opt_(cbLabel) PCBYTE pbLabel, _In_ SIZE_T cbLabel, _In_reads_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _Out_writes_(cbResult) PBYTE pbResult, SIZE_T cbResult)
Definition: tlsprf.c:530
#define SYMCRYPT_TLS_1_1_CHUNK_SIZE
Definition: tlsprf.c:23
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_2Derive(_In_ PCSYMCRYPT_TLSPRF1_2_EXPANDED_KEY pExpandedKey, _In_reads_opt_(cbLabel) PCBYTE pbLabel, _In_ SIZE_T cbLabel, _In_reads_(cbSeed) PCBYTE pbSeed, _In_ SIZE_T cbSeed, _Out_writes_(cbResult) PBYTE pbResult, SIZE_T cbResult)
Definition: tlsprf.c:426
#define SYMCRYPT_TLS_MAX_LABEL_AND_SEED_SIZE
Definition: tlsprf.c:19
SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptTlsPrf1_2ExpandKey(_Out_ PSYMCRYPT_TLSPRF1_2_EXPANDED_KEY pExpandedKey, _In_ PCSYMCRYPT_MAC macAlgorithm, _In_reads_(cbKey) PCBYTE pbKey, SIZE_T cbKey)
Definition: tlsprf.c:137
ULONG_PTR SIZE_T
Definition: typedefs.h:80
unsigned char BYTE
Definition: xxhash.c:193