]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/RSA_DSA_keys.cpp
Security-57740.1.18.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...) secinfo("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 void RSAKeyPairGenContext::generate(const Context &context, uint32, CssmData &params, uint32 &attrCount, Context::Attr * &attrs) {
198 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
199 }
200
201 // this one is specified in, and called from, AppleKeyPairGenContext
202 void RSAKeyPairGenContext::generate(
203 const Context &context,
204 BinaryKey &pubBinKey,
205 BinaryKey &privBinKey,
206 uint32 &keyBits)
207 {
208 /*
209 * These casts throw exceptions if the keys are of the
210 * wrong classes, which would be a major bogon, since we created
211 * the keys in the above generate() function.
212 */
213 RSABinaryKey &rPubBinKey =
214 dynamic_cast<RSABinaryKey &>(pubBinKey);
215 RSABinaryKey &rPrivBinKey =
216 dynamic_cast<RSABinaryKey &>(privBinKey);
217
218 /*
219 * One parameter from context: Key size in bits is required.
220 * FIXME - get public exponent from context?
221 */
222 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
223 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
224 if(keyBits > rsaMaxKeySize()) {
225 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
226 }
227
228 /* generate the private key */
229 rPrivBinKey.mRsaKey = RSA_generate_key(keyBits,
230 RSA_PUB_EXPONENT,
231 NULL, // no callback
232 NULL);
233 if(rPrivBinKey.mRsaKey == NULL) {
234 rsaKeyDebug("RSA_generate_key returned NULL");
235 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); // ???
236 }
237
238 /* public key is subset of private key */
239 rPubBinKey.mRsaKey = RSA_new();
240 if(rPrivBinKey.mRsaKey == NULL) {
241 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
242 }
243 RSA *pub = rPubBinKey.mRsaKey;
244 RSA *priv = rPrivBinKey.mRsaKey;
245 pub->n = BN_dup(priv->n);
246 pub->e = BN_dup(priv->e);
247 if((pub->n == NULL) || (pub->e == NULL)) {
248 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
249 }
250 }
251
252
253 /***
254 *** RSA-style CSPKeyInfoProvider.
255 ***/
256 RSAKeyInfoProvider::RSAKeyInfoProvider(
257 const CssmKey &cssmKey,
258 AppleCSPSession &session) :
259 CSPKeyInfoProvider(cssmKey, session)
260 {
261 }
262
263 CSPKeyInfoProvider *RSAKeyInfoProvider::provider(
264 const CssmKey &cssmKey,
265 AppleCSPSession &session)
266 {
267 switch(cssmKey.algorithm()) {
268 case CSSM_ALGID_RSA:
269 case CSSM_ALGMODE_PKCS1_EME_OAEP:
270 break;
271 default:
272 return NULL;
273 }
274 switch(cssmKey.keyClass()) {
275 case CSSM_KEYCLASS_PUBLIC_KEY:
276 case CSSM_KEYCLASS_PRIVATE_KEY:
277 break;
278 default:
279 return NULL;
280 }
281 /* OK, we'll handle this one */
282 return new RSAKeyInfoProvider(cssmKey, session);
283 }
284
285 /* Given a raw key, cook up a Binary key */
286 void RSAKeyInfoProvider::CssmKeyToBinary(
287 CssmKey *paramKey, // ignored
288 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT, unused here
289 BinaryKey **binKey)
290 {
291 *binKey = NULL;
292 RSA *rsaKey = NULL;
293 CSSM_DATA label = {0, NULL};
294
295 /* first cook up an RSA key */
296 rsaKey = rawCssmKeyToRsa(mKey, label);
297
298 /* now drop that into a BinaryKey */
299 RSABinaryKey *rsaBinKey = new RSABinaryKey(rsaKey);
300 *binKey = rsaBinKey;
301 if(label.Data) {
302 rsaBinKey->setOaep(label);
303 free(label.Data);
304 }
305 }
306
307 /*
308 * Obtain key size in bits.
309 */
310 void RSAKeyInfoProvider::QueryKeySizeInBits(
311 CSSM_KEY_SIZE &keySize)
312 {
313 RSA *rsaKey = NULL;
314 CSSM_DATA label = {0, NULL};
315
316 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
317 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
318 }
319 rsaKey = rawCssmKeyToRsa(mKey, label);
320 keySize.LogicalKeySizeInBits = RSA_size(rsaKey) * 8;
321 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
322 RSA_free(rsaKey);
323 if(label.Data) {
324 free(label.Data);
325 }
326 }
327
328 /*
329 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
330 * passthrough.
331 */
332 bool RSAKeyInfoProvider::getHashableBlob(
333 Allocator &allocator,
334 CssmData &blob) // blob to hash goes here
335 {
336 /*
337 * The optimized case, a raw key in the "proper" format already.
338 * Only public keys in PKCS1 format fit this bill.
339 */
340 assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
341 bool useAsIs = false;
342
343 switch(mKey.keyClass()) {
344 case CSSM_KEYCLASS_PUBLIC_KEY:
345 if(mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
346 useAsIs = true;
347 }
348 break;
349 case CSSM_KEYCLASS_PRIVATE_KEY:
350 break;
351 default:
352 /* shouldn't be here */
353 assert(0);
354 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
355 }
356 if(useAsIs) {
357 const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
358 copyCssmData(keyBlob, blob, allocator);
359 return true;
360 }
361
362 /* caller converts to binary and proceeds */
363 return false;
364 }
365
366 /***
367 *** DSA key support
368 ***/
369
370
371 /***
372 *** DSA-style BinaryKey
373 ***/
374
375 /* constructor with optional existing DSA key */
376 DSABinaryKey::DSABinaryKey(DSA *dsaKey)
377 : mDsaKey(dsaKey)
378 {
379 }
380
381 DSABinaryKey::~DSABinaryKey()
382 {
383 if(mDsaKey) {
384 DSA_free(mDsaKey);
385 mDsaKey = NULL;
386 }
387 }
388
389 void DSABinaryKey::generateKeyBlob(
390 Allocator &allocator,
391 CssmData &blob,
392 CSSM_KEYBLOB_FORMAT &format,
393 AppleCSPSession &session,
394 const CssmKey *paramKey, /* optional */
395 CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */
396 {
397 bool isPub;
398 CSSM_RETURN crtn;
399
400 /*
401 * Here, the incoming default of CSSM_KEYBLOB_RAW_FORMAT_NONE
402 * is translated to our AppleCSP-custom defaults. App can override.
403 */
404 switch(mKeyHeader.KeyClass) {
405 case CSSM_KEYCLASS_PUBLIC_KEY:
406 isPub = true;
407 switch(format) {
408 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
409 format = DSA_PUB_KEY_FORMAT; // default
410 break;
411 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
412 case CSSM_KEYBLOB_RAW_FORMAT_X509:
413 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
414 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2:
415 break;
416 default:
417 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
418 }
419 break;
420 case CSSM_KEYCLASS_PRIVATE_KEY:
421 isPub = false;
422 switch(format) {
423 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
424 format = DSA_PRIV_KEY_FORMAT; // default
425 break;
426 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
427 /*
428 * This is calculated on the public key, which
429 * is not always part of a DSA private key's encoding...
430 * so first calculate the public key.
431 */
432 dsaKeyPrivToPub(mDsaKey);
433 isPub = true;
434 break;
435 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
436 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
437 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
438 break;
439 default:
440 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_FORMAT);
441 }
442 break;
443 default:
444 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
445 }
446
447 /* possible conversion from partial binary key to fully
448 * formed blob */
449 DSA *dsaToEncode = mDsaKey;
450 DSA *dsaUpgrade = NULL;
451 if(isPub &&
452 (mDsaKey->p == NULL) &&
453 (paramKey != NULL)) {
454 /*
455 * Don't modify BinaryKey; make a copy.
456 */
457 dsaUpgrade = DSA_new();
458 if(dsaUpgrade == NULL) {
459 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
460 }
461 dsaUpgrade->pub_key = BN_dup(mDsaKey->pub_key);
462 crtn = dsaGetParamsFromKey(dsaUpgrade, *paramKey, session);
463 if(crtn) {
464 DSA_free(dsaUpgrade);
465 CssmError::throwMe(crtn);
466 }
467
468 /* success - switch keys and inform caller of attr change */
469 dsaToEncode = dsaUpgrade;
470 attrFlags &= ~CSSM_KEYATTR_PARTIAL;
471 }
472
473 /*
474 * DSA private keys originating from BSAFE form - e.g., DSA private
475 * keys wrapped in a keychain (which have format FIPS186 by default)
476 * have no public key component. Generate the public key if we don't
477 * have one.
478 */
479 if(!isPub && (dsaToEncode->pub_key == NULL)) {
480 dsaKeyPrivToPub(dsaToEncode);
481 }
482
483 CssmAutoData encodedKey(allocator);
484 if(isPub) {
485 crtn = DSAPublicKeyEncode(dsaToEncode, format, descData(), encodedKey);
486 }
487 else {
488 crtn = DSAPrivateKeyEncode(dsaToEncode, format, descData(), encodedKey);
489 }
490 if(dsaUpgrade != NULL) {
491 /* temp key, get rid of it */
492 DSA_free(dsaUpgrade);
493 }
494 if(crtn) {
495 CssmError::throwMe(crtn);
496 }
497 blob = encodedKey.release();
498 }
499
500 /***
501 *** DSA-style AppleKeyPairGenContext
502 ***/
503
504 /*
505 * This one is specified in, and called from, CSPFullPluginSession. Our
506 * only job is to prepare two subclass-specific BinaryKeys and call up to
507 * AppleKeyPairGenContext.
508 */
509 void DSAKeyPairGenContext::generate(
510 const Context &context,
511 CssmKey &pubKey,
512 CssmKey &privKey)
513 {
514 DSABinaryKey *pubBinKey = new DSABinaryKey();
515 DSABinaryKey *privBinKey = new DSABinaryKey();
516
517 try {
518 AppleKeyPairGenContext::generate(context,
519 session(),
520 pubKey,
521 pubBinKey,
522 privKey,
523 privBinKey);
524 }
525 catch (...) {
526 delete pubBinKey;
527 delete privBinKey;
528 throw;
529 }
530
531 }
532
533 /*
534 * This one is specified in, and called from, AppleKeyPairGenContext
535 */
536 void DSAKeyPairGenContext::generate(
537 const Context &context,
538 BinaryKey &pubBinKey,
539 BinaryKey &privBinKey,
540 uint32 &keyBits)
541 {
542 /*
543 * These casts throw exceptions if the keys are of the
544 * wrong classes, which would be a major bogon, since we created
545 * the keys in the above generate() function.
546 */
547 DSABinaryKey &rPubBinKey =
548 dynamic_cast<DSABinaryKey &>(pubBinKey);
549 DSABinaryKey &rPrivBinKey =
550 dynamic_cast<DSABinaryKey &>(privBinKey);
551
552 /*
553 * Parameters from context:
554 * Key size in bits, required;
555 * {p,q,g} from generateParams, optional
556 */
557 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
558 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
559 if(keyBits > DSA_MAX_KEY_SIZE) {
560 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
561 }
562 CssmData *paramData = context.get<CssmData>(CSSM_ATTRIBUTE_ALG_PARAMS);
563
564 NSS_DSAAlgParams algParams;
565 SecNssCoder coder; // generated algParams mallocd from here
566 if(paramData != NULL) {
567 /* this contains the DER encoding of a NSS_DSAAlgParams */
568 CSSM_RETURN crtn = DSADecodeAlgParams(algParams, paramData->Data,
569 (unsigned)paramData->Length, coder);
570 if(crtn) {
571 CssmError::throwMe(crtn);
572 }
573 }
574 else {
575 /* no alg params specified; generate them now using null (random) seed */
576 dsaGenParams(keyBits, NULL, 0, algParams, coder);
577 }
578
579 /* create key, stuff params into it */
580 rPrivBinKey.mDsaKey = DSA_new();
581 if(rPrivBinKey.mDsaKey == NULL) {
582 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
583 }
584 DSA *dsaKey = rPrivBinKey.mDsaKey;
585 dsaKey->p = cssmDataToBn(algParams.p);
586 dsaKey->q = cssmDataToBn(algParams.q);
587 dsaKey->g = cssmDataToBn(algParams.g);
588
589 /* generate the key (both public and private capabilities) */
590 int irtn = DSA_generate_key(dsaKey);
591 if(!irtn) {
592 throwRsaDsa("DSA_generate_key");
593 }
594
595 /* public key is subset of private key */
596 rPubBinKey.mDsaKey = DSA_new();
597 if(rPrivBinKey.mDsaKey == NULL) {
598 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
599 }
600 DSA *pub = rPubBinKey.mDsaKey;
601 DSA *priv = rPrivBinKey.mDsaKey;
602 pub->p = BN_dup(priv->p);
603 pub->q = BN_dup(priv->q);
604 pub->g = BN_dup(priv->g);
605 pub->pub_key = BN_dup(priv->pub_key);
606 if((pub->p == NULL) || (pub->q == NULL) || (pub->g == NULL) ||
607 (pub->pub_key == NULL)) {
608 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
609 }
610 }
611
612 /*
613 * Generate keygen parameters, stash them in a context attr array for later use
614 * when actually generating the keys.
615 */
616 void DSAKeyPairGenContext::generate(
617 const Context &context,
618 uint32 bitSize,
619 CssmData &params,
620 uint32 &attrCount,
621 Context::Attr * &attrs)
622 {
623 void *seed = NULL;
624 unsigned seedLen = 0;
625
626 /* optional seed from context */
627 CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED);
628 if(seedData) {
629 seed = seedData->data();
630 seedLen = (unsigned)seedData->length();
631 }
632
633 /* generate the params, temp alloc from SecNssCoder */
634 NSS_DSAAlgParams algParams;
635 SecNssCoder coder;
636 dsaGenParams(bitSize, seed, seedLen, algParams, coder);
637
638 /*
639 * Here comes the fun part.
640 * We "return" the DER encoding of these generated params in two ways:
641 * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL.
642 * The app must free this.
643 * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr,
644 * a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to
645 * this attr array and free it, the CSSM_DATA it points to, and the DER
646 * encoding *that* points to, in our destructor.
647 *
648 * First, DER encode.
649 */
650 CssmAutoData aDerData(session());
651 DSAEncodeAlgParams(algParams, aDerData);
652
653 /* copy/release that into a mallocd CSSM_DATA. */
654 CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA));
655 *derData = aDerData.release();
656
657 /* stuff that into a one-element Attr array which we keep after returning */
658 freeGenAttrs();
659 mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr));
660 mGenAttrs->AttributeType = CSSM_ATTRIBUTE_ALG_PARAMS;
661 mGenAttrs->AttributeLength = sizeof(CSSM_DATA);
662 mGenAttrs->Attribute.Data = derData;
663
664 /* and "return" this stuff */
665 copyCssmData(CssmData::overlay(*derData), params, session());
666 attrCount = 1;
667 attrs = mGenAttrs;
668 }
669
670 /* free mGenAttrs and its referents if present */
671 void DSAKeyPairGenContext::freeGenAttrs()
672 {
673 if(mGenAttrs == NULL) {
674 return;
675 }
676 if(mGenAttrs->Attribute.Data) {
677 if(mGenAttrs->Attribute.Data->Data) {
678 session().free(mGenAttrs->Attribute.Data->Data);
679 }
680 session().free(mGenAttrs->Attribute.Data);
681 }
682 session().free(mGenAttrs);
683 }
684
685 /*
686 * Generate DSA algorithm parameters from optional seed input, returning result
687 * into NSS_DSAAlgParamss.[pqg]. This is called from both GenerateParameters and from
688 * KeyPairGenerate (if no GenerateParameters has yet been called).
689 */
690 void DSAKeyPairGenContext::dsaGenParams(
691 uint32 keySizeInBits,
692 const void *inSeed, // optional
693 unsigned inSeedLen,
694 NSS_DSAAlgParams &algParams,
695 SecNssCoder &coder) // contents of algParams mallocd from here
696 {
697 unsigned char seedBuf[SHA1_DIGEST_SIZE];
698 void *seedPtr;
699
700 /* validate key size */
701 if((keySizeInBits < DSA_MIN_KEY_SIZE) ||
702 (keySizeInBits > DSA_MAX_KEY_SIZE) ||
703 (keySizeInBits & DSA_KEY_BITS_MASK)) {
704 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
705 }
706
707 /* seed from one of three sources */
708 if(inSeed == NULL) {
709 /* 20 random seed bytes */
710 session().getRandomBytes(SHA1_DIGEST_SIZE, seedBuf);
711 seedPtr = seedBuf;
712 }
713 else if(inSeedLen == SHA1_DIGEST_SIZE) {
714 /* perfect */
715 seedPtr = (void *)inSeed;
716 }
717 else {
718 /* hash caller's seed */
719 cspGenSha1Hash(inSeed, inSeedLen, seedBuf);
720 seedPtr = seedBuf;
721 }
722
723 DSA *dsaKey = DSA_generate_parameters(keySizeInBits,
724 (unsigned char *)seedPtr,
725 SHA1_DIGEST_SIZE,
726 NULL, // counter_ret
727 NULL, // h_ret
728 NULL,
729 NULL);
730 if(dsaKey == NULL) {
731 throwRsaDsa("DSA_generate_parameters");
732 }
733
734 /* stuff dsaKey->[pqg] into a caller's NSS_DSAAlgParams */
735 bnToCssmData(dsaKey->p, algParams.p, coder);
736 bnToCssmData(dsaKey->q, algParams.q, coder);
737 bnToCssmData(dsaKey->g, algParams.g, coder);
738
739 DSA_free(dsaKey);
740 }
741
742 /***
743 *** DSA-style CSPKeyInfoProvider.
744 ***/
745 DSAKeyInfoProvider::DSAKeyInfoProvider(
746 const CssmKey &cssmKey,
747 AppleCSPSession &session) :
748 CSPKeyInfoProvider(cssmKey, session)
749 {
750
751 }
752 CSPKeyInfoProvider *DSAKeyInfoProvider::provider(
753 const CssmKey &cssmKey,
754 AppleCSPSession &session)
755 {
756 switch(cssmKey.algorithm()) {
757 case CSSM_ALGID_DSA:
758 break;
759 default:
760 return NULL;
761 }
762 switch(cssmKey.keyClass()) {
763 case CSSM_KEYCLASS_PUBLIC_KEY:
764 case CSSM_KEYCLASS_PRIVATE_KEY:
765 break;
766 default:
767 return NULL;
768 }
769 /* OK, we'll handle this one */
770 return new DSAKeyInfoProvider(cssmKey, session);
771 }
772
773 /* Given a raw key, cook up a Binary key */
774 void DSAKeyInfoProvider::CssmKeyToBinary(
775 CssmKey *paramKey, // optional
776 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT
777 BinaryKey **binKey)
778 {
779 *binKey = NULL;
780 DSA *dsaKey = NULL;
781
782 /* first cook up an DSA key, then drop that into a BinaryKey */
783 dsaKey = rawCssmKeyToDsa(mKey, mSession, paramKey);
784 if(dsaKey->p == NULL) {
785 attrFlags |= CSSM_KEYATTR_PARTIAL;
786 }
787 else {
788 attrFlags &= ~CSSM_KEYATTR_PARTIAL;
789 }
790 DSABinaryKey *dsaBinKey = new DSABinaryKey(dsaKey);
791 *binKey = dsaBinKey;
792 }
793
794 /*
795 * Obtain key size in bits.
796 */
797 void DSAKeyInfoProvider::QueryKeySizeInBits(
798 CSSM_KEY_SIZE &keySize)
799 {
800 DSA *dsaKey = NULL;
801
802 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
803 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
804 }
805 dsaKey = rawCssmKeyToDsa(mKey,
806 mSession,
807 NULL); // no param key allowed here
808 if(dsaKey->p != NULL) {
809 /* normal fully-formed key */
810 keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->p);
811 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
812 DSA_free(dsaKey);
813 }
814 else {
815 /* partial key, get an approximation from pub_key */
816 keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->pub_key);
817 DSA_free(dsaKey);
818 /* and indicate this anomaly like so */
819 CssmError::throwMe(CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE);
820 }
821 }
822
823 /*
824 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
825 * passthrough.
826 */
827 bool DSAKeyInfoProvider::getHashableBlob(
828 Allocator &allocator,
829 CssmData &blob) // blob to hash goes here
830 {
831 /* No optimized case for DSA keys */
832 return false;
833 }