Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/dlkey.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// dlkey.c   Dlkey functions
3
//
4
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
5
//
6
//
7
8
#include "precomp.h"
9
10
PSYMCRYPT_DLKEY
11
SYMCRYPT_CALL
12
SymCryptDlkeyAllocate( _In_ PCSYMCRYPT_DLGROUP pDlgroup )
13
0
{
14
0
    PVOID               p;
15
0
    SIZE_T              cb;
16
0
    PSYMCRYPT_DLKEY     res = NULL;
17
18
0
    cb = SymCryptSizeofDlkeyFromDlgroup( pDlgroup );
19
20
0
    p = SymCryptCallbackAlloc( cb );
21
22
0
    if ( p==NULL )
23
0
    {
24
0
        goto cleanup;
25
0
    }
26
27
0
    res = SymCryptDlkeyCreate( p, cb, pDlgroup );
28
29
0
cleanup:
30
0
    return res;
31
0
}
32
33
VOID
34
SYMCRYPT_CALL
35
SymCryptDlkeyFree( _Out_ PSYMCRYPT_DLKEY pkObj )
36
0
{
37
0
    SYMCRYPT_CHECK_MAGIC( pkObj );
38
0
    SymCryptDlkeyWipe( pkObj );
39
0
    SymCryptCallbackFree( pkObj );
40
0
}
41
42
UINT32
43
SYMCRYPT_CALL
44
SymCryptSizeofDlkeyFromDlgroup( _In_ PCSYMCRYPT_DLGROUP pDlgroup )
45
0
{
46
    // Always allocate memory for large private keys
47
0
    return sizeof(SYMCRYPT_DLKEY) + SymCryptSizeofModElementFromModulus( pDlgroup->pmP ) + SymCryptSizeofIntFromDigits( pDlgroup->nDigitsOfP );
48
0
}
49
50
PSYMCRYPT_DLKEY
51
SYMCRYPT_CALL
52
SymCryptDlkeyCreate(
53
    _Out_writes_bytes_( cbBuffer )  PBYTE               pbBuffer,
54
                                    SIZE_T              cbBuffer,
55
    _In_                            PCSYMCRYPT_DLGROUP  pDlgroup )
56
0
{
57
0
    PSYMCRYPT_DLKEY pkRes = NULL;
58
0
    UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
59
60
0
    SYMCRYPT_ASSERT( cbBuffer >= SymCryptSizeofDlkeyFromDlgroup( pDlgroup ) );
61
0
    SYMCRYPT_ASSERT( cbBuffer >= sizeof(SYMCRYPT_DLKEY) + cbModElement );
62
0
    UNREFERENCED_PARAMETER( cbBuffer );     // only referenced in above ASSERTs...
63
0
    SYMCRYPT_ASSERT_ASYM_ALIGNED( pbBuffer );
64
65
0
    pkRes = (PSYMCRYPT_DLKEY) pbBuffer;
66
67
    // DLKEY parameters
68
0
    pkRes->fAlgorithmInfo = 0;
69
0
    pkRes->pDlgroup = pDlgroup;
70
0
    pkRes->fHasPrivateKey = FALSE;
71
0
    pkRes->fPrivateModQ = FALSE;            // This will be properly set during generate or setvalue
72
0
    pkRes->nBitsPriv = pDlgroup->nDefaultBitsPriv;
73
74
    // Create SymCrypt objects
75
0
    pbBuffer += sizeof(SYMCRYPT_DLKEY);
76
77
0
    pkRes->pePublicKey = SymCryptModElementCreate( pbBuffer, cbModElement, pDlgroup->pmP );
78
0
    if (pkRes->pePublicKey == NULL)
79
0
    {
80
0
        goto cleanup;
81
0
    }
82
0
    pbBuffer += cbModElement;
83
84
    //
85
    // **** Always defer the creation of the private key until the key generation or
86
    // set value.
87
    //
88
    // In place of the pbPrivate pointer store the pointer to the allocated buffer.
89
    //
90
0
    pkRes->pbPrivate = pbBuffer;
91
0
    pkRes->piPrivateKey = NULL;
92
93
    // Setting the magic
94
0
    SYMCRYPT_SET_MAGIC( pkRes );
95
96
0
cleanup:
97
0
    return pkRes;
98
0
}
99
100
VOID
101
SYMCRYPT_CALL
102
SymCryptDlkeyWipe( _Out_ PSYMCRYPT_DLKEY pkDst )
103
0
{
104
0
    SymCryptWipe( (PBYTE) pkDst, SymCryptSizeofDlkeyFromDlgroup(pkDst->pDlgroup) );
105
0
}
106
107
VOID
108
SYMCRYPT_CALL
109
SymCryptDlkeyCopy(
110
    _In_    PCSYMCRYPT_DLKEY   pkSrc,
111
    _Out_   PSYMCRYPT_DLKEY    pkDst )
112
0
{
113
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkSrc->pDlgroup;
114
115
    //
116
    // in-place copy is somewhat common...
117
    //
118
0
    if( pkSrc != pkDst )
119
0
    {
120
0
        pkDst->fAlgorithmInfo = pkSrc->fAlgorithmInfo;
121
0
        pkDst->fHasPrivateKey = pkSrc->fHasPrivateKey;
122
0
        pkDst->fPrivateModQ = pkSrc->fPrivateModQ;
123
0
        pkDst->nBitsPriv = pkSrc->nBitsPriv;
124
125
        // Copy the public key
126
0
        SymCryptModElementCopy( pDlgroup->pmP, pkSrc->pePublicKey, pkDst->pePublicKey );
127
128
        // Copy the private key
129
0
        SymCryptIntCopy( pkSrc->piPrivateKey, pkDst->piPrivateKey );
130
0
    }
131
0
}
132
133
134
// DLKEY specific functions
135
136
SYMCRYPT_ERROR
137
SYMCRYPT_CALL
138
SymCryptDlkeySetPrivateKeyLength( _Inout_ PSYMCRYPT_DLKEY pkDlkey, UINT32 nBitsPriv, UINT32 flags )
139
0
{
140
0
    if( nBitsPriv > pkDlkey->pDlgroup->nBitsOfQ ||
141
0
        nBitsPriv < pkDlkey->pDlgroup->nMinBitsPriv ||
142
0
        flags != 0 )
143
0
    {
144
0
        return SYMCRYPT_INVALID_ARGUMENT;
145
0
    }
146
147
0
    pkDlkey->nBitsPriv = nBitsPriv;
148
0
    return SYMCRYPT_NO_ERROR;
149
0
}
150
151
PCSYMCRYPT_DLGROUP
152
SYMCRYPT_CALL
153
SymCryptDlkeyGetGroup( _In_ PCSYMCRYPT_DLKEY pkDlkey )
154
0
{
155
0
    return pkDlkey->pDlgroup;
156
0
}
157
158
UINT32
159
SYMCRYPT_CALL
160
SymCryptDlkeySizeofPublicKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
161
0
{
162
0
    return pkDlkey->pDlgroup->cbPrimeP;
163
0
}
164
165
UINT32
166
SYMCRYPT_CALL
167
SymCryptDlkeySizeofPrivateKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
168
0
{
169
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
170
171
0
    if (pkDlkey->fPrivateModQ)
172
0
    {
173
0
        if (pDlgroup->fHasPrimeQ)
174
0
        {
175
0
            if (pkDlkey->nBitsPriv != pDlgroup->nBitsOfQ)
176
0
            {
177
0
                return (pkDlkey->nBitsPriv + 7) / 8;
178
0
            }
179
0
            else
180
0
            {
181
0
                return pDlgroup->cbPrimeQ;
182
0
            }
183
0
        }
184
0
        else
185
0
        {
186
0
            return pDlgroup->cbPrimeP;  // Somehow the group has no prime Q but the key was set with prime Q, return the safe option
187
0
        }
188
0
    }
189
0
    else
190
0
    {
191
0
        return pDlgroup->cbPrimeP;
192
0
    }
193
0
}
194
195
BOOLEAN
196
SYMCRYPT_CALL
197
SymCryptDlkeyHasPrivateKey( _In_ PCSYMCRYPT_DLKEY pkDlkey )
198
0
{
199
0
    return pkDlkey->fHasPrivateKey;
200
0
}
201
202
0
#define SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION (0x1)
203
204
SYMCRYPT_ERROR
205
SYMCRYPT_CALL
206
SymCryptDlkeyPerformPublicKeyValidation(
207
    _In_                            PCSYMCRYPT_DLKEY        pkDlkey,
208
    _In_                            UINT32                  flags,
209
    _Out_writes_bytes_( cbScratch ) PBYTE                   pbScratch,
210
                                    SIZE_T                  cbScratch )
211
0
{
212
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
213
214
0
    PSYMCRYPT_MODELEMENT peTmp = NULL;
215
0
    PSYMCRYPT_MODELEMENT peTmpPublicKeyExpQ = NULL;
216
0
    UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
217
218
0
    SYMCRYPT_ASSERT( cbScratch >= (2 * cbModElement) +
219
0
                                    SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP) );
220
221
    // Check if Public key is 0
222
0
    if ( SymCryptModElementIsZero( pDlgroup->pmP, pkDlkey->pePublicKey ) )
223
0
    {
224
0
        return SYMCRYPT_INVALID_ARGUMENT;
225
0
    }
226
227
0
    peTmp = SymCryptModElementCreate( pbScratch, cbModElement, pDlgroup->pmP);
228
0
    pbScratch += cbModElement;
229
0
    cbScratch -= cbModElement;
230
231
    // Check if Public key is P-1
232
0
    SymCryptModElementSetValueNegUint32( 1, pDlgroup->pmP, peTmp, pbScratch, cbScratch );
233
0
    if ( SymCryptModElementIsEqual( pDlgroup->pmP, pkDlkey->pePublicKey, peTmp ) )
234
0
    {
235
0
        return SYMCRYPT_INVALID_ARGUMENT;
236
0
    }
237
238
    // Check if Public key is 1 (do this check second as we may reuse 1 element in next check)
239
0
    SymCryptModElementSetValueUint32( 1, pDlgroup->pmP, peTmp, pbScratch, cbScratch );
240
0
    if ( SymCryptModElementIsEqual( pDlgroup->pmP, pkDlkey->pePublicKey, peTmp ) )
241
0
    {
242
0
        return SYMCRYPT_INVALID_ARGUMENT;
243
0
    }
244
245
    // Perform validation that Public key is in a subgroup of order Q.
246
0
    if ( (flags & SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION) != 0 )
247
0
    {
248
0
        peTmpPublicKeyExpQ = SymCryptModElementCreate( pbScratch, cbModElement, pDlgroup->pmP);
249
0
        pbScratch += cbModElement;
250
0
        cbScratch -= cbModElement;
251
252
        // Ensure that Q is specified in the Dlgroup
253
0
        if ( !pDlgroup->fHasPrimeQ )
254
0
        {
255
0
            return SYMCRYPT_INVALID_ARGUMENT;
256
0
        }
257
258
        // Calculate peTmpPublicKeyExpQ = (Public key)^Q
259
0
        SymCryptModExp(
260
0
            pDlgroup->pmP,
261
0
            pkDlkey->pePublicKey,
262
0
            SymCryptIntFromModulus( pDlgroup->pmQ ),
263
0
            pDlgroup->nBitsOfQ,
264
0
            SYMCRYPT_FLAG_DATA_PUBLIC, // No need for side-channel safety for public key validation
265
0
            peTmpPublicKeyExpQ,
266
0
            pbScratch,
267
0
            cbScratch );
268
269
        // Ensure (Public key)^Q == 1 mod P
270
0
        if ( !SymCryptModElementIsEqual( pDlgroup->pmP, peTmpPublicKeyExpQ, peTmp ) )
271
0
        {
272
0
            return SYMCRYPT_INVALID_ARGUMENT;
273
0
        }
274
0
    }
275
276
0
    return SYMCRYPT_NO_ERROR;
277
0
}
278
279
0
#define DLKEY_GEN_RANDOM_GENERIC_LIMIT   (1000)
280
281
SYMCRYPT_ERROR
282
SYMCRYPT_CALL
283
SymCryptDlkeyGenerate(
284
    _In_    UINT32                  flags,
285
    _Inout_ PSYMCRYPT_DLKEY         pkDlkey )
286
0
{
287
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
288
0
    PBYTE pbScratch = NULL;
289
0
    SIZE_T cbScratch = 0;
290
0
    PBYTE pbScratchInternal = NULL;
291
0
    SIZE_T cbScratchInternal = 0;
292
293
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
294
295
0
    PSYMCRYPT_MODELEMENT pePrivateKey = NULL;
296
0
    UINT32 cbPrivateKey = 0;
297
298
0
    PSYMCRYPT_MODULUS pmPriv = NULL;
299
0
    UINT32 nDigitsPriv = 0;
300
0
    UINT32 nBitsPriv = 0;
301
0
    UINT32 fFlagsForModSetRandom = 0;
302
303
0
    BOOLEAN useModSetRandom = TRUE;
304
0
    UINT32 nBytesPriv = 0;
305
0
    UINT32 dwShiftBits;
306
0
    BYTE   privMask;
307
0
    UINT32 cntr;
308
309
0
    PSYMCRYPT_MODELEMENT peTmp = NULL;
310
0
    UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
311
312
    // Ensure caller has specified what algorithm(s) the key will be used with
313
0
    UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
314
    // Make sure only allowed flags are specified
315
0
    UINT32 allowedFlags = SYMCRYPT_FLAG_DLKEY_GEN_MODP | SYMCRYPT_FLAG_KEY_NO_FIPS | algorithmFlags;
316
317
0
    if ( ( ( flags & ~allowedFlags ) != 0 ) || 
318
0
         ( ( flags & algorithmFlags ) == 0 ) )
319
0
    {
320
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
321
0
        goto cleanup;
322
0
    }
323
324
    // Extra sanity checks when running with FIPS
325
    // Either Dlgroup is named SafePrime group and key is for DH,
326
    // or Dlgroup is not named SafePrime group and key is for DSA
327
0
    if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && 
328
0
         ( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) ||
329
0
           (!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) )
330
0
    {
331
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
332
0
        goto cleanup;
333
0
    }
334
335
0
    pkDlkey->fPrivateModQ = (((flags & SYMCRYPT_FLAG_DLKEY_GEN_MODP)==0) && (pDlgroup->fHasPrimeQ));
336
337
0
    if (pkDlkey->fPrivateModQ)
338
0
    {
339
0
        pmPriv = pDlgroup->pmQ;
340
0
        nDigitsPriv = pDlgroup->nDigitsOfQ;
341
0
        nBitsPriv = pDlgroup->nBitsOfQ;
342
0
        fFlagsForModSetRandom = SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE | SYMCRYPT_FLAG_MODRANDOM_ALLOW_MINUSONE; // 1 to Q-1
343
344
0
        if ( pDlgroup->isSafePrimeGroup && (pkDlkey->nBitsPriv != pDlgroup->nBitsOfQ) )
345
0
        {
346
0
            useModSetRandom = FALSE;
347
0
            SYMCRYPT_ASSERT( pkDlkey->nBitsPriv < pDlgroup->nBitsOfQ );     // 2^nBitsPriv < Q
348
349
0
            nBitsPriv = pkDlkey->nBitsPriv;                                 // 1 to (2^nBitsPriv)-1
350
0
            nBytesPriv = (pkDlkey->nBitsPriv + 7) / 8;
351
0
        }
352
0
    }
353
0
    else
354
0
    {
355
        // We perform Private key range validation by construction
356
        // The Private key is constructed in the range [1,min(2^nBitsPriv,Q)-1] precisely when pkDlkey->fPrivateModQ
357
0
        if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
358
0
        {
359
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
360
0
            goto cleanup;
361
0
        }
362
363
0
        pmPriv = pDlgroup->pmP;
364
0
        nDigitsPriv = pDlgroup->nDigitsOfP;
365
0
        nBitsPriv = pDlgroup->nBitsOfP;
366
0
        fFlagsForModSetRandom = SYMCRYPT_FLAG_MODRANDOM_ALLOW_ONE;                                          // 1 to P-2
367
0
    }
368
369
0
    cbPrivateKey = SymCryptSizeofModElementFromModulus( pmPriv );
370
371
    //
372
    // From symcrypt_internal.h we have:
373
    //      - sizeof results are upper bounded by 2^19
374
    //      - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE)
375
    // Thus the following calculation does not overflow cbScratch.
376
    //
377
0
    cbScratch = SYMCRYPT_MAX( cbPrivateKey + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(nDigitsPriv),
378
0
                    (2 * cbModElement) + SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP));
379
0
    pbScratch = SymCryptCallbackAlloc( cbScratch );
380
0
    if (pbScratch == NULL)
381
0
    {
382
0
        scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
383
0
        goto cleanup;
384
0
    }
385
386
    // Create the private key integer
387
0
    pkDlkey->piPrivateKey = SymCryptIntCreate( pkDlkey->pbPrivate, SymCryptSizeofIntFromDigits(nDigitsPriv), nDigitsPriv );
388
389
0
    if (useModSetRandom)
390
0
    {
391
        // Create the private key modelement
392
0
        pePrivateKey = SymCryptModElementCreate( pbScratch, cbPrivateKey, pmPriv );
393
0
        pbScratchInternal = pbScratch + cbPrivateKey;
394
0
        cbScratchInternal = cbScratch - cbPrivateKey;
395
396
        // Set a modelement from 1 to q-1 (or 1 to p-2)
397
0
        SymCryptModSetRandom(
398
0
            pmPriv,
399
0
            pePrivateKey,
400
0
            fFlagsForModSetRandom,
401
0
            pbScratchInternal,
402
0
            cbScratchInternal );
403
404
        // Set the private key
405
0
        SymCryptModElementToInt(
406
0
            pmPriv,
407
0
            pePrivateKey,
408
0
            pkDlkey->piPrivateKey,
409
0
            pbScratchInternal,
410
0
            cbScratchInternal );
411
0
    }
412
0
    else
413
0
    {
414
        // Set private key from 1 to (2^nBitsPriv)-1
415
        // Wipe any bytes we won't fill with random
416
0
        SymCryptWipe( pbScratch + nBytesPriv, (nDigitsPriv * SYMCRYPT_FDEF_DIGIT_SIZE) - nBytesPriv );
417
418
0
        dwShiftBits = (0u-nBitsPriv) & 7;
419
0
        privMask = (BYTE)(0xff >> dwShiftBits);
420
421
0
        for(cntr=0; cntr<DLKEY_GEN_RANDOM_GENERIC_LIMIT; cntr++)
422
0
        {
423
            // Try random values until we get one we like
424
0
            SymCryptCallbackRandom( pbScratch, nBytesPriv );
425
426
0
            pbScratch[nBytesPriv-1] &= privMask;
427
428
            // If non-zero we have a value in range [1, (2^nBitsPriv)-1]
429
0
            if( !SymCryptFdefRawIsEqualUint32( (PCUINT32)pbScratch, nDigitsPriv, 0 ) )
430
0
            {
431
0
                break;
432
0
            }
433
0
        }
434
435
0
        if (cntr >= DLKEY_GEN_RANDOM_GENERIC_LIMIT)
436
0
        {
437
0
            SymCryptFatal( 'rndl' );
438
0
        }
439
440
0
        scError = SymCryptIntSetValue( pbScratch, nBytesPriv, SYMCRYPT_NUMBER_FORMAT_LSB_FIRST, pkDlkey->piPrivateKey );
441
0
        if ( scError != SYMCRYPT_NO_ERROR )
442
0
        {
443
0
            goto cleanup;
444
0
        }
445
0
    }
446
447
    // Calculate the public key
448
0
    SymCryptModExp(
449
0
        pDlgroup->pmP,
450
0
        pDlgroup->peG,
451
0
        pkDlkey->piPrivateKey,
452
0
        nBitsPriv,
453
0
        0,      // Side-channel safe
454
0
        pkDlkey->pePublicKey,
455
0
        pbScratch, // We can overwrite pePrivateKey now
456
0
        cbScratch );
457
458
    // Perform range validation on generated Public key.
459
0
    if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
460
0
    {
461
        // Perform Public key validation.
462
        // Always perform range validation, and validation that Public key is in subgroup of order Q
463
0
        scError = SymCryptDlkeyPerformPublicKeyValidation(
464
0
            pkDlkey,
465
0
            SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION,
466
0
            pbScratch,
467
0
            cbScratch );
468
0
        if ( scError != SYMCRYPT_NO_ERROR )
469
0
        {
470
0
            goto cleanup;
471
0
        }
472
0
    }
473
474
    // Set the fHasPrivateKey flag
475
0
    pkDlkey->fHasPrivateKey = TRUE;
476
477
0
    pkDlkey->fAlgorithmInfo = flags; // We want to track all of the flags in the Dlkey
478
479
0
    if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
480
0
    {
481
0
        if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 )
482
0
        {
483
            // Ensure DSA algorithm selftest is run before first use of DSA algorithm
484
0
            SYMCRYPT_RUN_SELFTEST_ONCE(
485
0
                SymCryptDsaSelftest,
486
0
                SYMCRYPT_SELFTEST_ALGORITHM_DSA );
487
488
            // Run PCT eagerly as the key can only be used for DSA - there is no value in deferring
489
0
            SYMCRYPT_RUN_KEY_PCT(
490
0
                SymCryptDsaPct,
491
0
                pkDlkey,
492
0
                SYMCRYPT_PCT_DSA );
493
0
        }
494
495
0
        if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 )
496
0
        {
497
            // Ensure we have run the algorithm selftest at least once.
498
0
            SYMCRYPT_RUN_SELFTEST_ONCE(
499
0
                SymCryptDhSecretAgreementSelftest,
500
0
                SYMCRYPT_SELFTEST_ALGORITHM_DH );
501
502
            // Run PCT eagerly as the key can only be used for DH
503
504
            // DH PCT per SP80056a-rev3 5.6.2.1.4 b)
505
            // Recompute the public key from the private key
506
            // Option a) appears to be explicitly overruled by 140-3 IG
507
508
            // Calculate the public key from the private key in scratch
509
0
            pbScratchInternal = pbScratch;
510
0
            cbScratchInternal = cbScratch;
511
512
0
            peTmp = SymCryptModElementCreate( pbScratchInternal, cbModElement, pDlgroup->pmP );
513
0
            pbScratchInternal += cbModElement;
514
0
            cbScratchInternal -= cbModElement;
515
516
0
            SymCryptModExp(
517
0
                    pDlgroup->pmP,
518
0
                    pDlgroup->peG,
519
0
                    pkDlkey->piPrivateKey,
520
0
                    nBitsPriv,  // This is either bits of P, Q, or some caller-defined value i.e. public values
521
0
                    0,          // Side-channel safe
522
0
                    peTmp,
523
0
                    pbScratchInternal,
524
0
                    cbScratchInternal );
525
526
0
            SYMCRYPT_FIPS_ASSERT( SymCryptModElementIsEqual(pDlgroup->pmP, peTmp, pkDlkey->pePublicKey) );
527
0
        }
528
0
    }
529
530
0
cleanup:
531
0
    if (pbScratch!=NULL)
532
0
    {
533
0
        SymCryptWipe( pbScratch, cbScratch );
534
0
        SymCryptCallbackFree( pbScratch );
535
0
    }
536
0
    return scError;
537
0
}
538
539
SYMCRYPT_ERROR
540
SYMCRYPT_CALL
541
SymCryptDlkeySetValue(
542
    _In_reads_bytes_( cbPrivateKey )    PCBYTE                  pbPrivateKey,
543
                                        SIZE_T                  cbPrivateKey,
544
    _In_reads_bytes_( cbPublicKey )     PCBYTE                  pbPublicKey,
545
                                        SIZE_T                  cbPublicKey,
546
                                        SYMCRYPT_NUMBER_FORMAT  numFormat,
547
                                        UINT32                  flags,
548
    _Inout_                             PSYMCRYPT_DLKEY         pkDlkey )
549
0
{
550
0
    SYMCRYPT_ERROR      scError = SYMCRYPT_NO_ERROR;
551
0
    PBYTE               pbScratch = NULL;
552
0
    UINT32              cbScratch = 0;
553
0
    PBYTE               pbScratchInternal = NULL;
554
0
    UINT32              cbScratchInternal = 0;
555
556
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
557
558
0
    UINT32 nDigitsPriv = 0;
559
0
    UINT32 nBitsPriv = 0;
560
561
0
    PSYMCRYPT_MODELEMENT peTmp = NULL;
562
0
    UINT32 cbModElement = SymCryptSizeofModElementFromModulus( pDlgroup->pmP );
563
0
    UINT32 fValidatePublicKeyOrder = SYMCRYPT_FLAG_DLKEY_PUBLIC_KEY_ORDER_VALIDATION;
564
565
0
    if ( ((pbPrivateKey==NULL) && (cbPrivateKey!=0)) ||
566
0
         ((pbPublicKey==NULL) && (cbPublicKey!=0)) ||
567
0
         ((pbPrivateKey==NULL) && (pbPublicKey==NULL)) )
568
0
    {
569
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
570
0
        goto cleanup;
571
0
    }
572
573
    // Ensure caller has specified what algorithm(s) the key will be used with
574
0
    UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
575
    // Make sure only allowed flags are specified
576
0
    UINT32 allowedFlags = SYMCRYPT_FLAG_KEY_NO_FIPS | SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION | algorithmFlags;
577
578
0
    if ( ( ( flags & ~allowedFlags ) != 0 ) || 
579
0
         ( ( flags & algorithmFlags ) == 0 ) )
580
0
    {
581
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
582
0
        goto cleanup;
583
0
    }
584
585
    // Extra sanity checks when running with FIPS
586
    // Either Dlgroup is named SafePrime group and key is for DH,
587
    // or Dlgroup is not named SafePrime group and key is for DSA
588
0
    if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) && 
589
0
         ( (pDlgroup->isSafePrimeGroup && (flags & SYMCRYPT_FLAG_DLKEY_DSA)) ||
590
0
           (!(pDlgroup->isSafePrimeGroup) && (flags & SYMCRYPT_FLAG_DLKEY_DH)) ) )
591
0
    {
592
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
593
0
        goto cleanup;
594
0
    }
595
596
    // Check that minimal validation flag only specified with no fips
597
0
    if ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
598
0
         ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) != 0 ) )
599
0
    {
600
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
601
0
        goto cleanup;
602
0
    }
603
604
0
    if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) != 0 )
605
0
    {
606
0
        fValidatePublicKeyOrder = 0;
607
0
    }
608
609
    //
610
    // From symcrypt_internal.h we have:
611
    //      - sizeof results are upper bounded by 2^19
612
    //      - SYMCRYPT_SCRATCH_BYTES results are upper bounded by 2^27 (including RSA and ECURVE)
613
    // Thus the following calculation does not overflow cbScratch.
614
    //
615
0
    cbScratch = SYMCRYPT_MAX( cbModElement + SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(pDlgroup->nDigitsOfP),
616
0
                     (2 * cbModElement) + SYMCRYPT_SCRATCH_BYTES_FOR_MODEXP(pDlgroup->nDigitsOfP) );
617
0
    pbScratch = SymCryptCallbackAlloc( cbScratch );
618
0
    if (pbScratch == NULL)
619
0
    {
620
0
        scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
621
0
        goto cleanup;
622
0
    }
623
624
0
    if ( pbPrivateKey != NULL )
625
0
    {
626
        //
627
        // Check the size of the imported private key to detect if it is mod P or mod Q
628
        // If the group does not have a Q assume that the imported key is modulo P as
629
        // it wouldn't help us assume otherwise (the bitsize of the private key should be kept
630
        // secret from SC attacks).
631
        // If the private key has had some non-default value set for nBitsPriv then the caller
632
        // has explicitly opted in to more stringent range checking.
633
        //
634
0
        pkDlkey->fPrivateModQ = ( (pDlgroup->fHasPrimeQ) &&
635
0
            ((cbPrivateKey < pDlgroup->cbPrimeQ) ||
636
0
            ((cbPrivateKey == pDlgroup->cbPrimeQ) && (pDlgroup->cbPrimeQ < pDlgroup->cbPrimeP)) ||
637
0
            (pkDlkey->nBitsPriv != pDlgroup->nDefaultBitsPriv)) );
638
639
0
        if ( pkDlkey->fPrivateModQ )
640
0
        {
641
0
            nDigitsPriv = pDlgroup->nDigitsOfQ;
642
0
            nBitsPriv = pDlgroup->nBitsOfQ;
643
644
0
            if ( pDlgroup->isSafePrimeGroup )
645
0
            {
646
0
                nBitsPriv = pkDlkey->nBitsPriv;
647
0
            }
648
0
        }
649
0
        else
650
0
        {
651
0
            nDigitsPriv = pDlgroup->nDigitsOfP;
652
0
            nBitsPriv = pDlgroup->nBitsOfP;
653
0
        }
654
655
0
        pkDlkey->piPrivateKey = SymCryptIntCreate( pkDlkey->pbPrivate, SymCryptSizeofIntFromDigits(nDigitsPriv), nDigitsPriv );
656
657
0
        scError = SymCryptIntSetValue(
658
0
                        pbPrivateKey,
659
0
                        cbPrivateKey,
660
0
                        numFormat,
661
0
                        pkDlkey->piPrivateKey );
662
0
        if ( scError != SYMCRYPT_NO_ERROR )
663
0
        {
664
0
            goto cleanup;
665
0
        }
666
667
        // Perform range validation on imported Private key.
668
        // Check if Private key is 0 - perform unconditionally as it is cheap
669
        // and it never makes sense for private key to be 0 intentionally
670
0
        if ( SymCryptIntIsEqualUint32( pkDlkey->piPrivateKey, 0 ) )
671
0
        {
672
0
            scError = SYMCRYPT_INVALID_ARGUMENT;
673
0
            goto cleanup;
674
0
        }
675
676
        // Continue range validation on imported Private key.
677
0
        if ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 )
678
0
        {
679
            // Ensure that Q is specified in the Dlgroup
680
0
            if ( !pDlgroup->fHasPrimeQ )
681
0
            {
682
0
                scError = SYMCRYPT_INVALID_ARGUMENT;
683
0
                goto cleanup;
684
0
            }
685
686
            // If nBitsPriv is specified, check if Private key is greater than or equal to 2^nBitsPriv
687
            // Otherwise, check if Private key is greater than or equal to Q
688
0
            if ( ( ( (nBitsPriv <  pDlgroup->nBitsOfQ) &&
689
0
                    SymCryptIntBitsizeOfValue( pkDlkey->piPrivateKey ) > nBitsPriv ) ) ||
690
0
                   ( (nBitsPriv >= pDlgroup->nBitsOfQ) &&
691
0
                    !SymCryptIntIsLessThan( pkDlkey->piPrivateKey, SymCryptIntFromModulus( pDlgroup->pmQ ) ) ) )
692
0
            {
693
0
                scError = SYMCRYPT_INVALID_ARGUMENT;
694
0
                goto cleanup;
695
0
            }
696
0
        }
697
698
0
        pkDlkey->fHasPrivateKey = TRUE;
699
0
    }
700
701
0
    if ( pbPublicKey != NULL )
702
0
    {
703
0
        scError = SymCryptModElementSetValue(
704
0
                        pbPublicKey,
705
0
                        cbPublicKey,
706
0
                        numFormat,
707
0
                        pDlgroup->pmP,
708
0
                        pkDlkey->pePublicKey,
709
0
                        pbScratch,
710
0
                        cbScratch );
711
0
        if ( scError != SYMCRYPT_NO_ERROR )
712
0
        {
713
0
            goto cleanup;
714
0
        }
715
716
        // Perform range validation on imported Public key.
717
0
        if ( (flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION) == 0 )
718
0
        {
719
            // Perform Public key validation.
720
            // Always perform range validation
721
            // May also perform validation that Public key is in subgroup of order Q, depending on flags
722
0
            scError = SymCryptDlkeyPerformPublicKeyValidation(
723
0
                pkDlkey,
724
0
                fValidatePublicKeyOrder,
725
0
                pbScratch,
726
0
                cbScratch );
727
0
            if ( scError != SYMCRYPT_NO_ERROR )
728
0
            {
729
0
                goto cleanup;
730
0
            }
731
0
        }
732
0
    }
733
734
    // Calculating the public key if no key was provided
735
    // or if needed for keypair regeneration validation
736
0
    if ( (pbPublicKey==NULL) ||
737
0
         ( ( ( flags & SYMCRYPT_FLAG_KEY_NO_FIPS ) == 0 ) &&
738
0
          (pbPrivateKey!=NULL) && (pbPublicKey!=NULL) ) )
739
0
    {
740
        // Calculate the public key from the private key
741
0
        pbScratchInternal = pbScratch;
742
0
        cbScratchInternal = cbScratch;
743
744
        // By default calculate the public key directly where it will be persisted
745
0
        peTmp = pkDlkey->pePublicKey;
746
747
0
        if ( pbPublicKey != NULL )
748
0
        {
749
            // If doing regeneration validation calculate the public key in scratch
750
0
            peTmp = SymCryptModElementCreate( pbScratchInternal, cbModElement, pDlgroup->pmP);
751
0
            pbScratchInternal += cbModElement;
752
0
            cbScratchInternal -= cbModElement;
753
0
        }
754
755
0
        SymCryptModExp(
756
0
                pDlgroup->pmP,
757
0
                pDlgroup->peG,
758
0
                pkDlkey->piPrivateKey,
759
0
                nBitsPriv,  // This is either bits of P, Q, or some caller-defined value i.e. public values
760
0
                0,          // Side-channel safe
761
0
                peTmp,
762
0
                pbScratchInternal,
763
0
                cbScratchInternal );
764
765
0
        if ( pbPublicKey != NULL )
766
0
        {
767
0
            if ( !SymCryptModElementIsEqual(pDlgroup->pmP, peTmp, pkDlkey->pePublicKey) )
768
0
            {
769
0
                scError = SYMCRYPT_AUTHENTICATION_FAILURE;
770
0
                goto cleanup;
771
0
            }
772
0
        }
773
0
        else if ( ( flags & SYMCRYPT_FLAG_KEY_MINIMAL_VALIDATION ) == 0 )
774
0
        {
775
            // Perform Public key validation on generated public key.
776
            // Always perform range validation
777
            // May also perform validation that Public key is in subgroup of order Q, depending on flags
778
0
            scError = SymCryptDlkeyPerformPublicKeyValidation(
779
0
                pkDlkey,
780
0
                fValidatePublicKeyOrder,
781
0
                pbScratch,
782
0
                cbScratch );
783
0
            if ( scError != SYMCRYPT_NO_ERROR )
784
0
            {
785
0
                goto cleanup;
786
0
            }
787
0
        }
788
0
    }
789
790
0
    pkDlkey->fAlgorithmInfo = flags; // We want to track all of the flags in the Dlkey
791
792
0
    if ( (flags & SYMCRYPT_FLAG_KEY_NO_FIPS) == 0 )
793
0
    {
794
0
        if( ( flags & SYMCRYPT_FLAG_DLKEY_DSA ) != 0 )
795
0
        {
796
            // Ensure DSA algorithm selftest is run before first use of DSA algorithm
797
0
            SYMCRYPT_RUN_SELFTEST_ONCE(
798
0
                SymCryptDsaSelftest,
799
0
                SYMCRYPT_SELFTEST_ALGORITHM_DSA );
800
801
0
            if( pkDlkey->fHasPrivateKey )
802
0
            {
803
0
                SYMCRYPT_RUN_KEY_PCT(
804
0
                    SymCryptDsaPct,
805
0
                    pkDlkey,
806
0
                    SYMCRYPT_PCT_DSA );
807
0
            }
808
0
        }
809
        
810
0
        if( ( flags & SYMCRYPT_FLAG_DLKEY_DH ) != 0 )
811
0
        {
812
0
            SYMCRYPT_RUN_SELFTEST_ONCE(
813
0
                SymCryptDhSecretAgreementSelftest,
814
0
                SYMCRYPT_SELFTEST_ALGORITHM_DH );
815
0
        }
816
0
    }
817
818
0
cleanup:
819
0
    if (pbScratch!=NULL)
820
0
    {
821
0
        SymCryptWipe( pbScratch, cbScratch );
822
0
        SymCryptCallbackFree( pbScratch );
823
0
    }
824
0
    return scError;
825
0
}
826
827
828
SYMCRYPT_ERROR
829
SYMCRYPT_CALL
830
SymCryptDlkeyGetValue(
831
    _In_    PCSYMCRYPT_DLKEY        pkDlkey,
832
    _Out_writes_bytes_( cbPrivateKey )
833
            PBYTE                   pbPrivateKey,
834
            SIZE_T                  cbPrivateKey,
835
    _Out_writes_bytes_( cbPublicKey )
836
            PBYTE                   pbPublicKey,
837
            SIZE_T                  cbPublicKey,
838
            SYMCRYPT_NUMBER_FORMAT  numFormat,
839
            UINT32                  flags )
840
0
{
841
0
    SYMCRYPT_ERROR      scError = SYMCRYPT_NO_ERROR;
842
0
    PBYTE               pbScratch = NULL;
843
0
    UINT32              cbScratch = 0;
844
845
0
    PCSYMCRYPT_DLGROUP pDlgroup = pkDlkey->pDlgroup;
846
847
0
    UNREFERENCED_PARAMETER( flags );
848
849
0
    if ( ((pbPrivateKey==NULL) && (cbPrivateKey!=0)) ||
850
0
         ((pbPublicKey==NULL) && (cbPublicKey!=0)) ||
851
0
         ((pbPrivateKey==NULL) && (pbPublicKey==NULL)) ||
852
0
         ((pbPrivateKey!=NULL) && !pkDlkey->fHasPrivateKey) )
853
0
    {
854
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
855
0
        goto cleanup;
856
0
    }
857
858
0
    if (pbPrivateKey != NULL)
859
0
    {
860
0
        scError = SymCryptIntGetValue(
861
0
                        pkDlkey->piPrivateKey,
862
0
                        pbPrivateKey,
863
0
                        cbPrivateKey,
864
0
                        numFormat );
865
0
        if (scError!=SYMCRYPT_NO_ERROR)
866
0
        {
867
0
            goto cleanup;
868
0
        }
869
0
    }
870
871
0
    if (pbPublicKey != NULL)
872
0
    {
873
0
        cbScratch = SYMCRYPT_SCRATCH_BYTES_FOR_COMMON_MOD_OPERATIONS(pDlgroup->nDigitsOfP);
874
0
        pbScratch = SymCryptCallbackAlloc( cbScratch );
875
0
        if (pbScratch == NULL)
876
0
        {
877
0
            scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE;
878
0
            goto cleanup;
879
0
        }
880
881
0
        scError = SymCryptModElementGetValue(
882
0
                        pDlgroup->pmP,
883
0
                        pkDlkey->pePublicKey,
884
0
                        pbPublicKey,
885
0
                        cbPublicKey,
886
0
                        numFormat,
887
0
                        pbScratch,
888
0
                        cbScratch );
889
0
        if (scError!=SYMCRYPT_NO_ERROR)
890
0
        {
891
0
            goto cleanup;
892
0
        }
893
0
    }
894
895
0
cleanup:
896
0
    if (pbScratch!=NULL)
897
0
    {
898
0
        SymCryptWipe( pbScratch, cbScratch );
899
0
        SymCryptCallbackFree( pbScratch );
900
0
    }
901
0
    return scError;
902
0
}
903
904
SYMCRYPT_ERROR
905
SYMCRYPT_CALL
906
SymCryptDlkeyExtendKeyUsage(
907
    _Inout_ PSYMCRYPT_DLKEY pkDlkey,
908
            UINT32          flags )
909
0
{
910
0
    SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
911
912
    // Ensure caller has specified what algorithm(s) the key will be used with
913
0
    UINT32 algorithmFlags = SYMCRYPT_FLAG_DLKEY_DSA | SYMCRYPT_FLAG_DLKEY_DH;
914
915
0
    if ( ( ( flags & ~algorithmFlags ) != 0 ) || 
916
0
         ( ( flags & algorithmFlags ) == 0) )
917
0
    {
918
0
        scError = SYMCRYPT_INVALID_ARGUMENT;
919
0
        goto cleanup;
920
0
    }
921
922
0
    pkDlkey->fAlgorithmInfo |= flags;
923
924
0
cleanup:
925
0
    return scError;
926
0
}