]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/RSA_DSA_utils.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / RSA_DSA_utils.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_utils.cpp
21 */
22
23 #include "RSA_DSA_utils.h"
24 #include "RSA_DSA_keys.h"
25 #include <opensslUtils/opensslAsn1.h>
26 #include <opensslUtils/opensslUtils.h>
27 #include <security_utilities/logging.h>
28 #include <security_utilities/debugging.h>
29 #include <openssl/bn_legacy.h>
30 #include <openssl/rsa_legacy.h>
31 #include <openssl/dsa_legacy.h>
32 #include <openssl/opensslerr.h>
33 #include <security_utilities/simpleprefs.h>
34 #include <security_utilities/threading.h>
35 #include <security_utilities/globalizer.h>
36 #include <CoreFoundation/CFNumber.h>
37
38 #define rsaMiscDebug(args...) secinfo("rsaMisc", ## args)
39
40 /*
41 * Obtain and cache max key sizes. System preferences only consulted
42 * at most once per process.
43 */
44
45 /*
46 * Do dictionary lookup, convert possible CFNumber to uint32.
47 * Does not alter val if valid number is not found.
48 */
49 static void rsaLookupVal(
50 Dictionary &prefs,
51 CFStringRef key,
52 uint32 &val)
53 {
54 CFNumberRef cfVal = (CFNumberRef)prefs.getValue(key);
55 if(cfVal == NULL) {
56 return;
57 }
58 if(CFGetTypeID(cfVal) != CFNumberGetTypeID()) {
59 return;
60 }
61
62 /* ensure the number is positive, not relying on gcc 64-bit arithmetic */
63 SInt32 s32 = 0;
64 CFNumberRef cfLimit = CFNumberCreate(NULL, kCFNumberSInt32Type, &s32);
65 CFComparisonResult result = CFNumberCompare(cfVal, cfLimit, NULL);
66 CFRelease(cfLimit);
67 if(result == kCFCompareLessThan) {
68 /* negative value in preference */
69 return;
70 }
71
72 /* ensure the number fits in 31 bits (the useful size of a SInt32 for us) */
73 s32 = 0x7fffffff;
74 cfLimit = CFNumberCreate(NULL, kCFNumberSInt32Type, &s32);
75 result = CFNumberCompare(cfVal, cfLimit, NULL);
76 CFRelease(cfLimit);
77 if(result == kCFCompareGreaterThan) {
78 /* too large; discard it */
79 return;
80 }
81 SInt64 s64;
82 if(!CFNumberGetValue(cfVal, kCFNumberSInt64Type, &s64)) {
83 /* impossible, right? We already range checked */
84 return;
85 }
86 val = (uint32)s64;
87 }
88
89 struct RSAKeySizes {
90 uint32 maxKeySize;
91 uint32 maxPubExponentSize;
92 RSAKeySizes();
93 };
94
95 /* one-time only prefs lookup */
96 RSAKeySizes::RSAKeySizes()
97 {
98 /* set defaults, these might get overridden */
99 maxKeySize = RSA_MAX_KEY_SIZE;
100 maxPubExponentSize = RSA_MAX_PUB_EXPONENT_SIZE;
101
102 /* now see if there are prefs set for either of these */
103 Dictionary* d = NULL;
104 try {
105 d = Dictionary::CreateDictionary(kRSAKeySizePrefsDomain, Dictionary::US_System, true);
106 } catch(...) {
107 return;
108 }
109
110 if (!d)
111 {
112 return;
113 }
114
115 if (d->dict())
116 {
117 unique_ptr<Dictionary>apd(d);
118 rsaLookupVal(*apd, kRSAMaxKeySizePref, maxKeySize);
119 rsaLookupVal(*apd, kRSAMaxPublicExponentPref, maxPubExponentSize);
120 }
121 else
122 {
123 delete d;
124 }
125 }
126
127 static ModuleNexus<RSAKeySizes> rsaKeySizes;
128
129 /*
130 * Public functions to obtain the currently configured max sizes of
131 * RSA key and public exponent.
132 */
133 uint32 rsaMaxKeySize()
134 {
135 return rsaKeySizes().maxKeySize;
136 }
137
138 uint32 rsaMaxPubExponentSize()
139 {
140 return rsaKeySizes().maxPubExponentSize;
141 }
142
143 /*
144 * Given a Context:
145 * -- obtain CSSM key (there must only be one)
146 * -- validate keyClass
147 * -- validate keyUsage
148 * -- convert to RSA *, allocating the RSA key if necessary
149 */
150 RSA *contextToRsaKey(
151 const Context &context,
152 AppleCSPSession &session,
153 CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY
154 CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc.
155 bool &mallocdKey, // RETURNED
156 CSSM_DATA &label) // mallocd and RETURNED for OAEP
157 {
158 CssmKey &cssmKey =
159 context.get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
160 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
161 if(hdr.AlgorithmId != CSSM_ALGID_RSA) {
162 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
163 }
164 if(hdr.KeyClass != keyClass) {
165 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
166 }
167 cspValidateIntendedKeyUsage(&hdr, usage);
168 cspVerifyKeyTimes(hdr);
169 return cssmKeyToRsa(cssmKey, session, mallocdKey, label);
170 }
171 /*
172 * Convert a CssmKey to an RSA * key. May result in the creation of a new
173 * RSA (when cssmKey is a raw key); allocdKey is true in that case
174 * in which case the caller generally has to free the allocd key).
175 */
176 RSA *cssmKeyToRsa(
177 const CssmKey &cssmKey,
178 AppleCSPSession &session,
179 bool &allocdKey, // RETURNED
180 CSSM_DATA &label) // mallocd and RETURNED for OAEP
181 {
182 RSA *rsaKey = NULL;
183 allocdKey = false;
184
185 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
186 if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
187 // someone else's key (should never happen)
188 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
189 }
190 switch(hdr->BlobType) {
191 case CSSM_KEYBLOB_RAW:
192 rsaKey = rawCssmKeyToRsa(cssmKey, label);
193 allocdKey = true;
194 break;
195 case CSSM_KEYBLOB_REFERENCE:
196 {
197 BinaryKey &binKey = session.lookupRefKey(cssmKey);
198 RSABinaryKey *rsaBinKey = dynamic_cast<RSABinaryKey *>(&binKey);
199 /* this cast failing means that this is some other
200 * kind of binary key */
201 if(rsaBinKey == NULL) {
202 rsaMiscDebug("cssmKeyToRsa: wrong BinaryKey subclass\n");
203 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
204 }
205 assert(rsaBinKey->mRsaKey != NULL);
206 rsaKey = rsaBinKey->mRsaKey;
207 break;
208 }
209 default:
210 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
211 }
212 return rsaKey;
213 }
214
215 /*
216 * Convert a raw CssmKey to a newly alloc'd RSA key.
217 */
218 RSA *rawCssmKeyToRsa(
219 const CssmKey &cssmKey,
220 CSSM_DATA &label) // mallocd and RETURNED for OAEP keys
221 {
222 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
223 bool isPub;
224 bool isOaep = false;
225
226 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
227
228 switch(hdr->AlgorithmId) {
229 case CSSM_ALGID_RSA:
230 break;
231 case CSSM_ALGMODE_PKCS1_EME_OAEP:
232 isOaep = true;
233 break;
234 default:
235 // someone else's key (should never happen)
236 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
237 }
238
239 /* validate and figure out what we're dealing with */
240 switch(hdr->KeyClass) {
241 case CSSM_KEYCLASS_PUBLIC_KEY:
242 switch(hdr->Format) {
243 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1:
244 case CSSM_KEYBLOB_RAW_FORMAT_X509:
245 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
246 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2:
247 break;
248 default:
249 CssmError::throwMe(
250 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
251 }
252 if(isOaep && (hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509)) {
253 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
254 }
255 isPub = true;
256 break;
257 case CSSM_KEYCLASS_PRIVATE_KEY:
258 switch(hdr->Format) {
259 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: // default
260 case CSSM_KEYBLOB_RAW_FORMAT_PKCS1: // openssl style
261 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
262 break;
263 default:
264 CssmError::throwMe(
265 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT);
266 }
267 if(isOaep && (hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_PKCS8)) {
268 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT);
269 }
270 isPub = false;
271 break;
272 default:
273 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
274 }
275
276 RSA *rsaKey = RSA_new();
277 if(rsaKey == NULL) {
278 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
279 }
280 CSSM_RETURN crtn;
281 if(isOaep) {
282 if(isPub) {
283 crtn = RSAOAEPPublicKeyDecode(rsaKey,
284 cssmKey.KeyData.Data, cssmKey.KeyData.Length,
285 &label);
286 }
287 else {
288 crtn = RSAOAEPPrivateKeyDecode(rsaKey,
289 cssmKey.KeyData.Data, cssmKey.KeyData.Length,
290 &label);
291 }
292 }
293 else {
294 if(isPub) {
295 crtn = RSAPublicKeyDecode(rsaKey, hdr->Format,
296 cssmKey.KeyData.Data, cssmKey.KeyData.Length);
297 }
298 else {
299 crtn = RSAPrivateKeyDecode(rsaKey, hdr->Format,
300 cssmKey.KeyData.Data, cssmKey.KeyData.Length);
301 }
302 }
303 if(crtn) {
304 RSA_free(rsaKey);
305 CssmError::throwMe(crtn);
306 }
307
308 /* enforce max key size and max public exponent size */
309 bool badKey = false;
310 uint32 keySize = RSA_size(rsaKey) * 8;
311 if(keySize > rsaMaxKeySize()) {
312 rsaMiscDebug("rawCssmKeyToRsa: key size exceeded");
313 badKey = true;
314 }
315 else {
316 keySize = BN_num_bytes(rsaKey->e) * 8;
317 if(keySize > rsaMaxPubExponentSize()) {
318 badKey = true;
319 rsaMiscDebug("rawCssmKeyToRsa: pub exponent size exceeded");
320 }
321 }
322 if (BN_is_one(rsaKey->e)) {
323 badKey = true;
324 rsaMiscDebug("rawCssmKeyToRsa: e = 1");
325 }
326 if(badKey) {
327 RSA_free(rsaKey);
328 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
329 }
330 return rsaKey;
331 }
332
333 /*
334 * Given a partially formed DSA public key (with no p, q, or g) and a
335 * CssmKey representing a supposedly fully-formed DSA key, populate
336 * the public key's p, g, and q with values from the fully formed key.
337 */
338 CSSM_RETURN dsaGetParamsFromKey(
339 DSA *partialKey,
340 const CssmKey &paramKey,
341 AppleCSPSession &session)
342 {
343 bool allocdKey;
344 DSA *dsaParamKey = cssmKeyToDsa(paramKey, session, allocdKey);
345 if(dsaParamKey == NULL) {
346 errorLog0("dsaGetParamsFromKey: bad paramKey\n");
347 return CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE;
348 }
349 CSSM_RETURN crtn = CSSM_OK;
350
351 /* require fully formed other key of course... */
352 if((dsaParamKey->p == NULL) ||
353 (dsaParamKey->q == NULL) ||
354 (dsaParamKey->g == NULL)) {
355 errorLog0("dsaGetParamsFromKey: incomplete paramKey\n");
356 crtn = CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE;
357 goto abort;
358 }
359 rsaMiscDebug("dsaGetParamsFromKey: partialKey %p paramKey %p",
360 partialKey, dsaParamKey);
361
362 partialKey->q = BN_dup(dsaParamKey->q);
363 partialKey->p = BN_dup(dsaParamKey->p);
364 partialKey->g = BN_dup(dsaParamKey->g);
365
366 abort:
367 if(allocdKey) {
368 DSA_free(dsaParamKey);
369 }
370 return crtn;
371 }
372
373 /*
374 * Given a Context:
375 * -- obtain CSSM key (there must only be one)
376 * -- validate keyClass
377 * -- validate keyUsage
378 * -- convert to DSA *, allocating the DSA key if necessary
379 */
380 DSA *contextToDsaKey(
381 const Context &context,
382 AppleCSPSession &session,
383 CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY
384 CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc.
385 bool &mallocdKey) // RETURNED
386 {
387 CssmKey &cssmKey =
388 context.get<CssmKey>(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY);
389 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
390 if(hdr.AlgorithmId != CSSM_ALGID_DSA) {
391 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
392 }
393 if(hdr.KeyClass != keyClass) {
394 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
395 }
396 cspValidateIntendedKeyUsage(&hdr, usage);
397 cspVerifyKeyTimes(hdr);
398 DSA *rtnDsa = cssmKeyToDsa(cssmKey, session, mallocdKey);
399 if((keyClass == CSSM_KEYCLASS_PUBLIC_KEY) &&
400 (rtnDsa->p == NULL)) {
401 /*
402 * Special case: this specific key is only partially formed;
403 * it's missing the DSA parameters p, g, and q. To proceed with this
404 * key, the caller must pass in another fully formned DSA public key
405 * in raw form in the context. If it's there we use those parameters.
406 */
407 rsaMiscDebug("contextToDsaKey; partial DSA key %p", rtnDsa);
408 CssmKey *paramKey = context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY);
409 if(paramKey == NULL) {
410 rsaMiscDebug("contextToDsaKey: missing DSA params, no pub key in "
411 "context");
412 if(mallocdKey) {
413 DSA_free(rtnDsa);
414 mallocdKey = false;
415 }
416 CssmError::throwMe(CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE);
417 }
418
419 /*
420 * If this is a ref key, we have to cook up a new DSA key to
421 * avoid modifying the existing key. If we started with a raw key,
422 * we can modify it directly since the underlying DSA key has
423 * a lifetime only as long as this context (and since the context
424 * contains the parameter-bearing key, the params are valid
425 * as long as the DSA key).
426 */
427 if(!mallocdKey) {
428 DSA *existKey = rtnDsa;
429 rtnDsa = DSA_new();
430 if(rtnDsa == NULL) {
431 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
432 }
433 rtnDsa->pub_key = BN_dup(existKey->pub_key);
434 rsaMiscDebug("contextToDsaKey; temp partial copy %p", rtnDsa);
435 mallocdKey = true;
436 }
437
438 /*
439 * Add params from paramKey into rtnDsa
440 */
441 CSSM_RETURN crtn = dsaGetParamsFromKey(rtnDsa, *paramKey, session);
442 if(crtn) {
443 if(mallocdKey) {
444 DSA_free(rtnDsa);
445 mallocdKey = false;
446 }
447 CssmError::throwMe(crtn);
448 }
449 }
450 return rtnDsa;
451 }
452
453 /*
454 * Convert a CssmKey to an DSA * key. May result in the creation of a new
455 * DSA (when cssmKey is a raw key); allocdKey is true in that case
456 * in which case the caller generally has to free the allocd key).
457 */
458 DSA *cssmKeyToDsa(
459 const CssmKey &cssmKey,
460 AppleCSPSession &session,
461 bool &allocdKey) // RETURNED
462 {
463 DSA *dsaKey = NULL;
464 allocdKey = false;
465
466 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
467 if(hdr->AlgorithmId != CSSM_ALGID_DSA) {
468 // someone else's key (should never happen)
469 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
470 }
471 switch(hdr->BlobType) {
472 case CSSM_KEYBLOB_RAW:
473 dsaKey = rawCssmKeyToDsa(cssmKey, session, NULL);
474 allocdKey = true;
475 break;
476 case CSSM_KEYBLOB_REFERENCE:
477 {
478 BinaryKey &binKey = session.lookupRefKey(cssmKey);
479 DSABinaryKey *dsaBinKey = dynamic_cast<DSABinaryKey *>(&binKey);
480 /* this cast failing means that this is some other
481 * kind of binary key */
482 if(dsaBinKey == NULL) {
483 rsaMiscDebug("cssmKeyToDsa: wrong BinaryKey subclass\n");
484 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
485 }
486 assert(dsaBinKey->mDsaKey != NULL);
487 dsaKey = dsaBinKey->mDsaKey;
488 break;
489 }
490 default:
491 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
492 }
493 return dsaKey;
494 }
495
496 /*
497 * Convert a raw CssmKey to a newly alloc'd DSA key.
498 */
499 DSA *rawCssmKeyToDsa(
500 const CssmKey &cssmKey,
501 AppleCSPSession &session,
502 const CssmKey *paramKey) // optional
503 {
504 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
505 bool isPub;
506
507 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
508
509 if(hdr->AlgorithmId != CSSM_ALGID_DSA) {
510 // someone else's key (should never happen)
511 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
512 }
513 /* validate and figure out what we're dealing with */
514 switch(hdr->KeyClass) {
515 case CSSM_KEYCLASS_PUBLIC_KEY:
516 switch(hdr->Format) {
517 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186:
518 case CSSM_KEYBLOB_RAW_FORMAT_X509:
519 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH2:
520 break;
521 default:
522 CssmError::throwMe(
523 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
524 }
525 isPub = true;
526 break;
527 case CSSM_KEYCLASS_PRIVATE_KEY:
528 switch(hdr->Format) {
529 case CSSM_KEYBLOB_RAW_FORMAT_FIPS186: // default
530 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: // openssl style
531 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: // SMIME style
532 break;
533 /* openssh real soon now */
534 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSH:
535 default:
536 CssmError::throwMe(
537 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT);
538 }
539 isPub = false;
540 break;
541 default:
542 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
543 }
544
545 CSSM_RETURN crtn;
546 DSA *dsaKey = DSA_new();
547
548 if (dsaKey == NULL) {
549 crtn = CSSMERR_CSP_MEMORY_ERROR;
550 }
551 else {
552 if(dsaKey == NULL) {
553 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
554 }
555 if(isPub) {
556 crtn = DSAPublicKeyDecode(dsaKey, hdr->Format,
557 cssmKey.KeyData.Data,
558 cssmKey.KeyData.Length);
559 }
560 else {
561 crtn = DSAPrivateKeyDecode(dsaKey, hdr->Format,
562 cssmKey.KeyData.Data,
563 cssmKey.KeyData.Length);
564 }
565 }
566
567 if(crtn) {
568 if (dsaKey != NULL) {
569 DSA_free(dsaKey);
570 }
571
572 CssmError::throwMe(crtn);
573 }
574 /*
575 * Add in optional external parameters if this is not fully formed.
576 * This path is only taken from DSAKeyInfoProvider::CssmKeyToBinary,
577 * e.g., when doing a NULL unwrap of a partially formed DSA public
578 * key with the "complete the key with these params" option.
579 */
580 if(isPub && (dsaKey->p == NULL) && (paramKey != NULL)) {
581 rsaMiscDebug("rawCssmKeyToDsa; updating dsaKey %p", dsaKey);
582 crtn = dsaGetParamsFromKey(dsaKey, *paramKey, session);
583 if(crtn) {
584 DSA_free(dsaKey);
585 CssmError::throwMe(crtn);
586 }
587 }
588
589 if(dsaKey->p != NULL) {
590 /* avoid use of provided DSA key which exceeds the max size */
591 uint32 keySize = BN_num_bits(dsaKey->p);
592 if(keySize > DSA_MAX_KEY_SIZE) {
593 DSA_free(dsaKey);
594 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
595 }
596 }
597 return dsaKey;
598 }
599
600 /*
601 * Given a DSA private key, calculate its public component if it
602 * doesn't already exist. Used for calculating the key digest of
603 * an incoming raw private key.
604 */
605 void dsaKeyPrivToPub(
606 DSA *dsaKey)
607 {
608 assert(dsaKey != NULL);
609 assert(dsaKey->priv_key != NULL);
610
611 if(dsaKey->pub_key != NULL) {
612 return;
613 }
614
615 /* logic copied from DSA_generate_key() */
616 dsaKey->pub_key = BN_new();
617 if(dsaKey->pub_key == NULL) {
618 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
619 }
620 BN_CTX *ctx = BN_CTX_new();
621 if (ctx == NULL) {
622 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
623 }
624 int rtn = BN_mod_exp(dsaKey->pub_key,
625 dsaKey->g,
626 dsaKey->priv_key,
627 dsaKey->p,
628 ctx);
629 BN_CTX_free(ctx);
630 if(rtn == 0) {
631 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
632 }
633 }