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