Coverage Report

Created: 2024-11-21 07:03

/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