]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/RSA_DSA_keys.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / RSA_DSA_keys.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 * RSA_DSA_Keys.cpp - RSA, DSA related asymmetric key pair classes.
21 */
22
23 #include "RSA_DSA_keys.h"
24 #include <opensslUtils/opensslUtils.h>
25 #include <opensslUtils/opensslAsn1.h>
26 #include <security_cdsa_utilities/cssmdata.h>
27 #include <AppleCSPSession.h>
28 #include <AppleCSPUtils.h>
29 #include <assert.h>
30 #include <security_utilities/debugging.h>
31 #include "RSA_DSA_utils.h"
32 #include <YarrowConnection.h>
33 #include <security_asn1/SecNssCoder.h>
34
35 #define RSA_PUB_EXPONENT 0x10001 /* recommended by RSA */
36
37 #define rsaKeyDebug(args...) secdebug("rsaKey", ## args)
38
39
40 /***
41 *** RSA-style BinaryKey
42 ***/
43
44 /* constructor with optional existing RSA key */
45 /* FIXME how to transmit OAEP params? */
46 RSABinaryKey::RSABinaryKey(RSA *rsaKey)
47 : mRsaKey(rsaKey),
48 mOaep(false),
49 mLabel(Allocator::standard())
50 {
51 }
52
53 RSABinaryKey::~RSABinaryKey()
54 {
55 if(mRsaKey) {
56 RSA_free(mRsaKey);
57 mRsaKey = NULL;
58 }
59 }
60
61 void RSABinaryKey::setOaep(
62 const CSSM_DATA &label)
63 {
64 mLabel.copy(label);
65 mOaep = true;
66 }
67
68 void RSABinaryKey::generateKeyBlob(
69 Allocator &allocator,
70 CssmData &blob,
71 CSSM_KEYBLOB_FORMAT &format, /* IN/OUT */
72 AppleCSPSession &session,
73 const CssmKey *paramKey, /* optional, unused here */
74 CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */
75 {
76 bool isPub;
77 CSSM_RETURN crtn;
78
79 /* FIXME get label from context here for OAEP */
80
81 /*
82 * Here, the incoming default of CSSM_KEYBLOB_RAW_FORMAT_NONE
83 * is translated to our AppleCSP-custom defaults. App can override.
84 */
85 switch(mKeyHeader.KeyClass) {
86 case CSSM_KEYCLASS_PUBLIC_KEY:
87 isPub = true;
88 switch(format) {
89 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
90 format = RSA_PUB_KEY_FORMAT; // default
91 break;
92 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
93 if(mOaep) {
94 /* have to take digest of the whole thing including label */
95 format = CSSM_KEYBLOB_RAW_FORMAT_X509;
96 }
97 else {
98 /* calculate digest on PKCS1 blob */
99 format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
100 }
101 break;
102 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
103 case CSSM_KEYBLOB_RAW_FORMAT_X509:
104 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
105 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2:
106 break;
107 default:
108 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
109 }
110 break;
111 case CSSM_KEYCLASS_PRIVATE_KEY:
112 isPub = false;
113 switch(format) {
114 case CSSM_KEYBLOB_RAW_FORMAT_NONE: // default
115 format = RSA_PRIV_KEY_FORMAT;
116 break;
117 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
118 if(mOaep) {
119 /* have to take digest of the whole thing including label */
120 format = CSSM_KEYBLOB_RAW_FORMAT_X509;
121 }
122 else {
123 /* calculate digest on PKCS1 blob */
124 format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
125 }
126 isPub = true;
127 break;
128 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
129 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
130 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
131 break;
132 default:
133 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
134 }
135 break;
136 default:
137 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
138 }
139
140 CssmAutoData encodedKey(allocator);
141 if(mOaep) {
142 CSSM_DATA label = mLabel;
143 if(isPub) {
144 crtn = RSAOAEPPublicKeyEncode(mRsaKey, &label, encodedKey);
145 }
146 else {
147 crtn = RSAOAEPPrivateKeyEncode(mRsaKey, &label, encodedKey);
148 }
149 }
150 else {
151 if(isPub) {
152 crtn = RSAPublicKeyEncode(mRsaKey, format, descData(), encodedKey);
153 }
154 else {
155 crtn = RSAPrivateKeyEncode(mRsaKey, format, descData(), encodedKey);
156 }
157 }
158 if(crtn) {
159 CssmError::throwMe(crtn);
160 }
161 blob = encodedKey.release();
162 }
163
164 /***
165 *** RSA-style AppleKeyPairGenContext
166 ***/
167
168 /*
169 * This one is specified in, and called from, CSPFullPluginSession. Our
170 * only job is to prepare two subclass-specific BinaryKeys and call up to
171 * AppleKeyPairGenContext.
172 */
173 void RSAKeyPairGenContext::generate(
174 const Context &context,
175 CssmKey &pubKey,
176 CssmKey &privKey)
177 {
178 RSABinaryKey *pubBinKey = new RSABinaryKey();
179 RSABinaryKey *privBinKey = new RSABinaryKey();
180
181 try {
182 AppleKeyPairGenContext::generate(context,
183 session(),
184 pubKey,
185 pubBinKey,
186 privKey,
187 privBinKey);
188 }
189 catch (...) {
190 delete pubBinKey;
191 delete privBinKey;
192 throw;
193 }
194
195 }
196
197 // this one is specified in, and called from, AppleKeyPairGenContext
198 void RSAKeyPairGenContext::generate(
199 const Context &context,
200 BinaryKey &pubBinKey,
201 BinaryKey &privBinKey,
202 uint32 &keyBits)
203 {
204 /*
205 * These casts throw exceptions if the keys are of the
206 * wrong classes, which would be a major bogon, since we created
207 * the keys in the above generate() function.
208 */
209 RSABinaryKey &rPubBinKey =
210 dynamic_cast<RSABinaryKey &>(pubBinKey);
211 RSABinaryKey &rPrivBinKey =
212 dynamic_cast<RSABinaryKey &>(privBinKey);
213
214 /*
215 * One parameter from context: Key size in bits is required.
216 * FIXME - get public exponent from context?
217 */
218 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
219 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
220 if(keyBits > rsaMaxKeySize()) {
221 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
222 }
223
224 /* generate the private key */
225 rPrivBinKey.mRsaKey = RSA_generate_key(keyBits,
226 RSA_PUB_EXPONENT,
227 NULL, // no callback
228 NULL);
229 if(rPrivBinKey.mRsaKey == NULL) {
230 rsaKeyDebug("RSA_generate_key returned NULL");
231 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); // ???
232 }
233
234 /* public key is subset of private key */
235 rPubBinKey.mRsaKey = RSA_new();
236 if(rPrivBinKey.mRsaKey == NULL) {
237 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
238 }
239 RSA *pub = rPubBinKey.mRsaKey;
240 RSA *priv = rPrivBinKey.mRsaKey;
241 pub->n = BN_dup(priv->n);
242 pub->e = BN_dup(priv->e);
243 if((pub->n == NULL) || (pub->e == NULL)) {
244 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
245 }
246 }
247
248
249 /***
250 *** RSA-style CSPKeyInfoProvider.
251 ***/
252 RSAKeyInfoProvider::RSAKeyInfoProvider(
253 const CssmKey &cssmKey,
254 AppleCSPSession &session) :
255 CSPKeyInfoProvider(cssmKey, session)
256 {
257 }
258
259 CSPKeyInfoProvider *RSAKeyInfoProvider::provider(
260 const CssmKey &cssmKey,
261 AppleCSPSession &session)
262 {
263 switch(cssmKey.algorithm()) {
264 case CSSM_ALGID_RSA:
265 case CSSM_ALGMODE_PKCS1_EME_OAEP:
266 break;
267 default:
268 return NULL;
269 }
270 switch(cssmKey.keyClass()) {
271 case CSSM_KEYCLASS_PUBLIC_KEY:
272 case CSSM_KEYCLASS_PRIVATE_KEY:
273 break;
274 default:
275 return NULL;
276 }
277 /* OK, we'll handle this one */
278 return new RSAKeyInfoProvider(cssmKey, session);
279 }
280
281 /* Given a raw key, cook up a Binary key */
282 void RSAKeyInfoProvider::CssmKeyToBinary(
283 CssmKey *paramKey, // ignored
284 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT, unused here
285 BinaryKey **binKey)
286 {
287 *binKey = NULL;
288 RSA *rsaKey = NULL;
289 CSSM_DATA label = {0, NULL};
290
291 /* first cook up an RSA key */
292 rsaKey = rawCssmKeyToRsa(mKey, label);
293
294 /* now drop that into a BinaryKey */
295 RSABinaryKey *rsaBinKey = new RSABinaryKey(rsaKey);
296 *binKey = rsaBinKey;
297 if(label.Data) {
298 rsaBinKey->setOaep(label);
299 free(label.Data);
300 }
301 }
302
303 /*
304 * Obtain key size in bits.
305 */
306 void RSAKeyInfoProvider::QueryKeySizeInBits(
307 CSSM_KEY_SIZE &keySize)
308 {
309 RSA *rsaKey = NULL;
310 CSSM_DATA label = {0, NULL};
311
312 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
313 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
314 }
315 rsaKey = rawCssmKeyToRsa(mKey, label);
316 keySize.LogicalKeySizeInBits = RSA_size(rsaKey) * 8;
317 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
318 RSA_free(rsaKey);
319 if(label.Data) {
320 free(label.Data);
321 }
322 }
323
324 /*
325 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
326 * passthrough.
327 */
328 bool RSAKeyInfoProvider::getHashableBlob(
329 Allocator &allocator,
330 CssmData &blob) // blob to hash goes here
331 {
332 /*
333 * The optimized case, a raw key in the "proper" format already.
334 * Only public keys in PKCS1 format fit this bill.
335 */
336 assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
337 bool useAsIs = false;
338
339 switch(mKey.keyClass()) {
340 case CSSM_KEYCLASS_PUBLIC_KEY:
341 if(mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
342 useAsIs = true;
343 }
344 break;
345 case CSSM_KEYCLASS_PRIVATE_KEY:
346 break;
347 default:
348 /* shouldn't be here */
349 assert(0);
350 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
351 }
352 if(useAsIs) {
353 const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
354 copyCssmData(keyBlob, blob, allocator);
355 return true;
356 }
357
358 /* caller converts to binary and proceeds */
359 return false;
360 }
361
362 /***
363 *** DSA key support
364 ***/
365
366
367 /***
368 *** DSA-style BinaryKey
369 ***/
370
371 /* constructor with optional existing DSA key */
372 DSABinaryKey::DSABinaryKey(DSA *dsaKey)
373 : mDsaKey(dsaKey)
374 {
375 }
376
377 DSABinaryKey::~DSABinaryKey()
378 {
379 if(mDsaKey) {
380 DSA_free(mDsaKey);
381 mDsaKey = NULL;
382 }
383 }
384
385 void DSABinaryKey::generateKeyBlob(
386 Allocator &allocator,
387 CssmData &blob,
388 CSSM_KEYBLOB_FORMAT &format,
389 AppleCSPSession &session,
390 const CssmKey *paramKey, /* optional */
391 CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */
392 {
393 bool isPub;
394 CSSM_RETURN crtn;
395
396 /*
397 * Here, the incoming default of CSSM_KEYBLOB_RAW_FORMAT_NONE
398 * is translated to our AppleCSP-custom defaults. App can override.
399 */
400 switch(mKeyHeader.KeyClass) {
401 case CSSM_KEYCLASS_PUBLIC_KEY:
402 isPub = true;
403 switch(format) {
404 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
405 format = DSA_PUB_KEY_FORMAT; // default
406 break;
407 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
408 case CSSM_KEYBLOB_RAW_FORMAT_X509:
409 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
410 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2:
411 break;
412 default:
413 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
414 }
415 break;
416 case CSSM_KEYCLASS_PRIVATE_KEY:
417 isPub = false;
418 switch(format) {
419 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
420 format = DSA_PRIV_KEY_FORMAT; // default
421 break;
422 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
423 /*
424 * This is calculated on the public key, which
425 * is not always part of a DSA private key's encoding...
426 * so first calculate the public key.
427 */
428 dsaKeyPrivToPub(mDsaKey);
429 isPub = true;
430 break;
431 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
432 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
433 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
434 break;
435 default:
436 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
437 }
438 break;
439 default:
440 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
441 }
442
443 /* possible conversion from partial binary key to fully
444 * formed blob */
445 DSA *dsaToEncode = mDsaKey;
446 DSA *dsaUpgrade = NULL;
447 if(isPub &&
448 (mDsaKey->p == NULL) &&
449 (paramKey != NULL)) {
450 /*
451 * Don't modify BinaryKey; make a copy.
452 */
453 dsaUpgrade = DSA_new();
454 if(dsaUpgrade == NULL) {
455 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
456 }
457 dsaUpgrade->pub_key = BN_dup(mDsaKey->pub_key);
458 crtn = dsaGetParamsFromKey(dsaUpgrade, *paramKey, session);
459 if(crtn) {
460 DSA_free(dsaUpgrade);
461 CssmError::throwMe(crtn);
462 }
463
464 /* success - switch keys and inform caller of attr change */
465 dsaToEncode = dsaUpgrade;
466 attrFlags &= ~CSSM_KEYATTR_PARTIAL;
467 }
468
469 /*
470 * DSA private keys originating from BSAFE form - e.g., DSA private
471 * keys wrapped in a keychain (which have format FIPS186 by default)
472 * have no public key component. Generate the public key if we don't
473 * have one.
474 */
475 if(!isPub && (dsaToEncode->pub_key == NULL)) {
476 dsaKeyPrivToPub(dsaToEncode);
477 }
478
479 CssmAutoData encodedKey(allocator);
480 if(isPub) {
481 crtn = DSAPublicKeyEncode(dsaToEncode, format, descData(), encodedKey);
482 }
483 else {
484 crtn = DSAPrivateKeyEncode(dsaToEncode, format, descData(), encodedKey);
485 }
486 if(dsaUpgrade != NULL) {
487 /* temp key, get rid of it */
488 DSA_free(dsaUpgrade);
489 }
490 if(crtn) {
491 CssmError::throwMe(crtn);
492 }
493 blob = encodedKey.release();
494 }
495
496 /***
497 *** DSA-style AppleKeyPairGenContext
498 ***/
499
500 /*
501 * This one is specified in, and called from, CSPFullPluginSession. Our
502 * only job is to prepare two subclass-specific BinaryKeys and call up to
503 * AppleKeyPairGenContext.
504 */
505 void DSAKeyPairGenContext::generate(
506 const Context &context,
507 CssmKey &pubKey,
508 CssmKey &privKey)
509 {
510 DSABinaryKey *pubBinKey = new DSABinaryKey();
511 DSABinaryKey *privBinKey = new DSABinaryKey();
512
513 try {
514 AppleKeyPairGenContext::generate(context,
515 session(),
516 pubKey,
517 pubBinKey,
518 privKey,
519 privBinKey);
520 }
521 catch (...) {
522 delete pubBinKey;
523 delete privBinKey;
524 throw;
525 }
526
527 }
528
529 /*
530 * This one is specified in, and called from, AppleKeyPairGenContext
531 */
532 void DSAKeyPairGenContext::generate(
533 const Context &context,
534 BinaryKey &pubBinKey,
535 BinaryKey &privBinKey,
536 uint32 &keyBits)
537 {
538 /*
539 * These casts throw exceptions if the keys are of the
540 * wrong classes, which would be a major bogon, since we created
541 * the keys in the above generate() function.
542 */
543 DSABinaryKey &rPubBinKey =
544 dynamic_cast<DSABinaryKey &>(pubBinKey);
545 DSABinaryKey &rPrivBinKey =
546 dynamic_cast<DSABinaryKey &>(privBinKey);
547
548 /*
549 * Parameters from context:
550 * Key size in bits, required;
551 * {p,q,g} from generateParams, optional
552 */
553 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
554 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
555 if(keyBits > DSA_MAX_KEY_SIZE) {
556 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
557 }
558 CssmData *paramData = context.get<CssmData>(CSSM_ATTRIBUTE_ALG_PARAMS);
559
560 NSS_DSAAlgParams algParams;
561 SecNssCoder coder; // generated algParams mallocd from here
562 if(paramData != NULL) {
563 /* this contains the DER encoding of a NSS_DSAAlgParams */
564 CSSM_RETURN crtn = DSADecodeAlgParams(algParams, paramData->Data,
565 (unsigned)paramData->Length, coder);
566 if(crtn) {
567 CssmError::throwMe(crtn);
568 }
569 }
570 else {
571 /* no alg params specified; generate them now using null (random) seed */
572 dsaGenParams(keyBits, NULL, 0, algParams, coder);
573 }
574
575 /* create key, stuff params into it */
576 rPrivBinKey.mDsaKey = DSA_new();
577 if(rPrivBinKey.mDsaKey == NULL) {
578 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
579 }
580 DSA *dsaKey = rPrivBinKey.mDsaKey;
581 dsaKey->p = cssmDataToBn(algParams.p);
582 dsaKey->q = cssmDataToBn(algParams.q);
583 dsaKey->g = cssmDataToBn(algParams.g);
584
585 /* generate the key (both public and private capabilities) */
586 int irtn = DSA_generate_key(dsaKey);
587 if(!irtn) {
588 throwRsaDsa("DSA_generate_key");
589 }
590
591 /* public key is subset of private key */
592 rPubBinKey.mDsaKey = DSA_new();
593 if(rPrivBinKey.mDsaKey == NULL) {
594 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
595 }
596 DSA *pub = rPubBinKey.mDsaKey;
597 DSA *priv = rPrivBinKey.mDsaKey;
598 pub->p = BN_dup(priv->p);
599 pub->q = BN_dup(priv->q);
600 pub->g = BN_dup(priv->g);
601 pub->pub_key = BN_dup(priv->pub_key);
602 if((pub->p == NULL) || (pub->q == NULL) || (pub->g == NULL) ||
603 (pub->pub_key == NULL)) {
604 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
605 }
606 }
607
608 /*
609 * Generate keygen parameters, stash them in a context attr array for later use
610 * when actually generating the keys.
611 */
612 void DSAKeyPairGenContext::generate(
613 const Context &context,
614 uint32 bitSize,
615 CssmData &params,
616 uint32 &attrCount,
617 Context::Attr * &attrs)
618 {
619 void *seed = NULL;
620 unsigned seedLen = 0;
621
622 /* optional seed from context */
623 CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED);
624 if(seedData) {
625 seed = seedData->data();
626 seedLen = (unsigned)seedData->length();
627 }
628
629 /* generate the params, temp alloc from SecNssCoder */
630 NSS_DSAAlgParams algParams;
631 SecNssCoder coder;
632 dsaGenParams(bitSize, seed, seedLen, algParams, coder);
633
634 /*
635 * Here comes the fun part.
636 * We "return" the DER encoding of these generated params in two ways:
637 * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL.
638 * The app must free this.
639 * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr,
640 * a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to
641 * this attr array and free it, the CSSM_DATA it points to, and the DER
642 * encoding *that* points to, in our destructor.
643 *
644 * First, DER encode.
645 */
646 CssmAutoData aDerData(session());
647 DSAEncodeAlgParams(algParams, aDerData);
648
649 /* copy/release that into a mallocd CSSM_DATA. */
650 CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA));
651 *derData = aDerData.release();
652
653 /* stuff that into a one-element Attr array which we keep after returning */
654 freeGenAttrs();
655 mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr));
656 mGenAttrs->AttributeType = CSSM_ATTRIBUTE_ALG_PARAMS;
657 mGenAttrs->AttributeLength = sizeof(CSSM_DATA);
658 mGenAttrs->Attribute.Data = derData;
659
660 /* and "return" this stuff */
661 copyCssmData(CssmData::overlay(*derData), params, session());
662 attrCount = 1;
663 attrs = mGenAttrs;
664 }
665
666 /* free mGenAttrs and its referents if present */
667 void DSAKeyPairGenContext::freeGenAttrs()
668 {
669 if(mGenAttrs == NULL) {
670 return;
671 }
672 if(mGenAttrs->Attribute.Data) {
673 if(mGenAttrs->Attribute.Data->Data) {
674 session().free(mGenAttrs->Attribute.Data->Data);
675 }
676 session().free(mGenAttrs->Attribute.Data);
677 }
678 session().free(mGenAttrs);
679 }
680
681 /*
682 * Generate DSA algorithm parameters from optional seed input, returning result
683 * into NSS_DSAAlgParamss.[pqg]. This is called from both GenerateParameters and from
684 * KeyPairGenerate (if no GenerateParameters has yet been called).
685 */
686 void DSAKeyPairGenContext::dsaGenParams(
687 uint32 keySizeInBits,
688 const void *inSeed, // optional
689 unsigned inSeedLen,
690 NSS_DSAAlgParams &algParams,
691 SecNssCoder &coder) // contents of algParams mallocd from here
692 {
693 unsigned char seedBuf[SHA1_DIGEST_SIZE];
694 void *seedPtr;
695
696 /* validate key size */
697 if((keySizeInBits < DSA_MIN_KEY_SIZE) ||
698 (keySizeInBits > DSA_MAX_KEY_SIZE) ||
699 (keySizeInBits & DSA_KEY_BITS_MASK)) {
700 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
701 }
702
703 /* seed from one of three sources */
704 if(inSeed == NULL) {
705 /* 20 random seed bytes */
706 session().getRandomBytes(SHA1_DIGEST_SIZE, seedBuf);
707 seedPtr = seedBuf;
708 }
709 else if(inSeedLen == SHA1_DIGEST_SIZE) {
710 /* perfect */
711 seedPtr = (void *)inSeed;
712 }
713 else {
714 /* hash caller's seed */
715 cspGenSha1Hash(inSeed, inSeedLen, seedBuf);
716 seedPtr = seedBuf;
717 }
718
719 DSA *dsaKey = DSA_generate_parameters(keySizeInBits,
720 (unsigned char *)seedPtr,
721 SHA1_DIGEST_SIZE,
722 NULL, // counter_ret
723 NULL, // h_ret
724 NULL,
725 NULL);
726 if(dsaKey == NULL) {
727 throwRsaDsa("DSA_generate_parameters");
728 }
729
730 /* stuff dsaKey->[pqg] into a caller's NSS_DSAAlgParams */
731 bnToCssmData(dsaKey->p, algParams.p, coder);
732 bnToCssmData(dsaKey->q, algParams.q, coder);
733 bnToCssmData(dsaKey->g, algParams.g, coder);
734
735 DSA_free(dsaKey);
736 }
737
738 /***
739 *** DSA-style CSPKeyInfoProvider.
740 ***/
741 DSAKeyInfoProvider::DSAKeyInfoProvider(
742 const CssmKey &cssmKey,
743 AppleCSPSession &session) :
744 CSPKeyInfoProvider(cssmKey, session)
745 {
746
747 }
748 CSPKeyInfoProvider *DSAKeyInfoProvider::provider(
749 const CssmKey &cssmKey,
750 AppleCSPSession &session)
751 {
752 switch(cssmKey.algorithm()) {
753 case CSSM_ALGID_DSA:
754 break;
755 default:
756 return NULL;
757 }
758 switch(cssmKey.keyClass()) {
759 case CSSM_KEYCLASS_PUBLIC_KEY:
760 case CSSM_KEYCLASS_PRIVATE_KEY:
761 break;
762 default:
763 return NULL;
764 }
765 /* OK, we'll handle this one */
766 return new DSAKeyInfoProvider(cssmKey, session);
767 }
768
769 /* Given a raw key, cook up a Binary key */
770 void DSAKeyInfoProvider::CssmKeyToBinary(
771 CssmKey *paramKey, // optional
772 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT
773 BinaryKey **binKey)
774 {
775 *binKey = NULL;
776 DSA *dsaKey = NULL;
777
778 /* first cook up an DSA key, then drop that into a BinaryKey */
779 dsaKey = rawCssmKeyToDsa(mKey, mSession, paramKey);
780 if(dsaKey->p == NULL) {
781 attrFlags |= CSSM_KEYATTR_PARTIAL;
782 }
783 else {
784 attrFlags &= ~CSSM_KEYATTR_PARTIAL;
785 }
786 DSABinaryKey *dsaBinKey = new DSABinaryKey(dsaKey);
787 *binKey = dsaBinKey;
788 }
789
790 /*
791 * Obtain key size in bits.
792 */
793 void DSAKeyInfoProvider::QueryKeySizeInBits(
794 CSSM_KEY_SIZE &keySize)
795 {
796 DSA *dsaKey = NULL;
797
798 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
799 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
800 }
801 dsaKey = rawCssmKeyToDsa(mKey,
802 mSession,
803 NULL); // no param key allowed here
804 if(dsaKey->p != NULL) {
805 /* normal fully-formed key */
806 keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->p);
807 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
808 DSA_free(dsaKey);
809 }
810 else {
811 /* partial key, get an approximation from pub_key */
812 keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->pub_key);
813 DSA_free(dsaKey);
814 /* and indicate this anomaly like so */
815 CssmError::throwMe(CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE);
816 }
817 }
818
819 /*
820 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
821 * passthrough.
822 */
823 bool DSAKeyInfoProvider::getHashableBlob(
824 Allocator &allocator,
825 CssmData &blob) // blob to hash goes here
826 {
827 /* No optimized case for DSA keys */
828 return false;
829 }