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