]> git.saurik.com Git - apple/security.git/blob - AppleCSP/RSA_DSA/RSA_DSA_keys.cpp
Security-30.1.tar.gz
[apple/security.git] / AppleCSP / RSA_DSA / RSA_DSA_keys.cpp
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
23 #include "RSA_DSA_Keys.h"
24 #include <opensslUtils/opensslUtils.h>
25 #include <opensslUtils/openRsaSnacc.h>
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>
33 #include <Security/appleoids.h>
34 #include <Security/cdsaUtils.h>
35
36 #define RSA_PUB_EXPONENT 0x10001 /* recommended by RSA */
37
38 #define rsaKeyDebug(args...) debug("rsaKey", ## args)
39
40 /***
41 *** RSA-style BinaryKey
42 ***/
43
44 /* constructor with optional existing RSA key */
45 RSABinaryKey::RSABinaryKey(RSA *rsaKey)
46 : mRsaKey(rsaKey)
47 {
48 }
49
50 RSABinaryKey::~RSABinaryKey()
51 {
52 if(mRsaKey) {
53 RSA_free(mRsaKey);
54 mRsaKey = NULL;
55 }
56 }
57
58 void RSABinaryKey::generateKeyBlob(
59 CssmAllocator &allocator,
60 CssmData &blob,
61 CSSM_KEYBLOB_FORMAT &format)
62 {
63 bool isPub;
64 CSSM_RETURN crtn;
65
66 switch(mKeyHeader.KeyClass) {
67 case CSSM_KEYCLASS_PUBLIC_KEY:
68 isPub = true;
69 format = RSA_PUB_KEY_FORMAT;
70 break;
71 case CSSM_KEYCLASS_PRIVATE_KEY:
72 isPub = false;
73 format = RSA_PRIV_KEY_FORMAT;
74 break;
75 default:
76 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
77 }
78
79 CssmAutoData encodedKey(allocator);
80 if(isPub) {
81 crtn = RSAPublicKeyEncode(mRsaKey, encodedKey);
82 }
83 else {
84 crtn = RSAPrivateKeyEncode(mRsaKey, encodedKey);
85 }
86 if(crtn) {
87 CssmError::throwMe(crtn);
88 }
89 blob = encodedKey.release();
90 }
91
92 /***
93 *** RSA-style AppleKeyPairGenContext
94 ***/
95
96 /*
97 * This one is specified in, and called from, CSPFullPluginSession. Our
98 * only job is to prepare two subclass-specific BinaryKeys and call up to
99 * AppleKeyPairGenContext.
100 */
101 void RSAKeyPairGenContext::generate(
102 const Context &context,
103 CssmKey &pubKey,
104 CssmKey &privKey)
105 {
106 RSABinaryKey *pubBinKey = new RSABinaryKey();
107 RSABinaryKey *privBinKey = new RSABinaryKey();
108
109 try {
110 AppleKeyPairGenContext::generate(context,
111 session(),
112 pubKey,
113 pubBinKey,
114 privKey,
115 privBinKey);
116 }
117 catch (...) {
118 delete pubBinKey;
119 delete privBinKey;
120 throw;
121 }
122
123 }
124
125 // this one is specified in, and called from, AppleKeyPairGenContext
126 void RSAKeyPairGenContext::generate(
127 const Context &context,
128 BinaryKey &pubBinKey,
129 BinaryKey &privBinKey,
130 uint32 &keyBits)
131 {
132 /*
133 * These casts throw exceptions if the keys are of the
134 * wrong classes, which would be a major bogon, since we created
135 * the keys in the above generate() function.
136 */
137 RSABinaryKey &rPubBinKey =
138 dynamic_cast<RSABinaryKey &>(pubBinKey);
139 RSABinaryKey &rPrivBinKey =
140 dynamic_cast<RSABinaryKey &>(privBinKey);
141
142 /*
143 * One parameter from context: Key size in bits is required.
144 * FIXME - get public exponent from context?
145 */
146 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
147 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
148
149 /* generate the private key */
150 rPrivBinKey.mRsaKey = RSA_generate_key(keyBits,
151 RSA_PUB_EXPONENT,
152 NULL, // no callback
153 NULL);
154 if(rPrivBinKey.mRsaKey == NULL) {
155 rsaKeyDebug("RSA_generate_key returned NULL");
156 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); // ???
157 }
158
159 /* public key is subset of private key */
160 rPubBinKey.mRsaKey = RSA_new();
161 if(rPrivBinKey.mRsaKey == NULL) {
162 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
163 }
164 RSA *pub = rPubBinKey.mRsaKey;
165 RSA *priv = rPrivBinKey.mRsaKey;
166 pub->n = BN_dup(priv->n);
167 pub->e = BN_dup(priv->e);
168 if((pub->n == NULL) || (pub->e == NULL)) {
169 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
170 }
171 }
172
173
174 /***
175 *** RSA-style CSPKeyInfoProvider.
176 ***/
177 RSAKeyInfoProvider::RSAKeyInfoProvider(
178 const CssmKey &cssmKey) :
179 CSPKeyInfoProvider(cssmKey)
180 {
181 switch(cssmKey.algorithm()) {
182 case CSSM_ALGID_RSA:
183 break;
184 default:
185 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
186 }
187 switch(cssmKey.keyClass()) {
188 case CSSM_KEYCLASS_PUBLIC_KEY:
189 case CSSM_KEYCLASS_PRIVATE_KEY:
190 break;
191 default:
192 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
193 }
194 /* OK, we'll handle this one */
195 return;
196 }
197
198 /* Given a raw key, cook up a Binary key */
199 void RSAKeyInfoProvider::CssmKeyToBinary(
200 BinaryKey **binKey)
201 {
202 *binKey = NULL;
203 RSA *rsaKey = NULL;
204
205 /* first cook up an RSA key, then drop that into a BinaryKey */
206 rsaKey = rawCssmKeyToRsa(mKey);
207 RSABinaryKey *rsaBinKey = new RSABinaryKey(rsaKey);
208 *binKey = rsaBinKey;
209 }
210
211 /*
212 * Obtain key size in bits.
213 */
214 void RSAKeyInfoProvider::QueryKeySizeInBits(
215 CSSM_KEY_SIZE &keySize)
216 {
217 RSA *rsaKey = NULL;
218
219 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
220 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
221 }
222 rsaKey = rawCssmKeyToRsa(mKey);
223 keySize.LogicalKeySizeInBits = RSA_size(rsaKey) * 8;
224 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
225 RSA_free(rsaKey);
226 }
227
228 /***
229 *** DSA key support
230 ***/
231
232
233 /***
234 *** DSA-style BinaryKey
235 ***/
236
237 /* constructor with optional existing DSA key */
238 DSABinaryKey::DSABinaryKey(DSA *dsaKey)
239 : mDsaKey(dsaKey)
240 {
241 }
242
243 DSABinaryKey::~DSABinaryKey()
244 {
245 if(mDsaKey) {
246 DSA_free(mDsaKey);
247 mDsaKey = NULL;
248 }
249 }
250
251 void DSABinaryKey::generateKeyBlob(
252 CssmAllocator &allocator,
253 CssmData &blob,
254 CSSM_KEYBLOB_FORMAT &format)
255 {
256 bool isPub;
257 CSSM_RETURN crtn;
258
259 switch(mKeyHeader.KeyClass) {
260 case CSSM_KEYCLASS_PUBLIC_KEY:
261 isPub = true;
262 format = DSA_PUB_KEY_FORMAT;
263 break;
264 case CSSM_KEYCLASS_PRIVATE_KEY:
265 isPub = false;
266 format = DSA_PRIV_KEY_FORMAT;
267 break;
268 default:
269 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
270 }
271
272 CssmAutoData encodedKey(allocator);
273 if(isPub) {
274 crtn = DSAPublicKeyEncode(mDsaKey, encodedKey);
275 }
276 else {
277 crtn = DSAPrivateKeyEncode(mDsaKey, encodedKey);
278 }
279 if(crtn) {
280 CssmError::throwMe(crtn);
281 }
282 blob = encodedKey.release();
283 }
284
285 /***
286 *** DSA-style AppleKeyPairGenContext
287 ***/
288
289 /*
290 * This one is specified in, and called from, CSPFullPluginSession. Our
291 * only job is to prepare two subclass-specific BinaryKeys and call up to
292 * AppleKeyPairGenContext.
293 */
294 void DSAKeyPairGenContext::generate(
295 const Context &context,
296 CssmKey &pubKey,
297 CssmKey &privKey)
298 {
299 DSABinaryKey *pubBinKey = new DSABinaryKey();
300 DSABinaryKey *privBinKey = new DSABinaryKey();
301
302 try {
303 AppleKeyPairGenContext::generate(context,
304 session(),
305 pubKey,
306 pubBinKey,
307 privKey,
308 privBinKey);
309 }
310 catch (...) {
311 delete pubBinKey;
312 delete privBinKey;
313 throw;
314 }
315
316 }
317
318 /*
319 * This one is specified in, and called from, AppleKeyPairGenContext
320 */
321 void DSAKeyPairGenContext::generate(
322 const Context &context,
323 BinaryKey &pubBinKey,
324 BinaryKey &privBinKey,
325 uint32 &keyBits)
326 {
327 /*
328 * These casts throw exceptions if the keys are of the
329 * wrong classes, which would be a major bogon, since we created
330 * the keys in the above generate() function.
331 */
332 DSABinaryKey &rPubBinKey =
333 dynamic_cast<DSABinaryKey &>(pubBinKey);
334 DSABinaryKey &rPrivBinKey =
335 dynamic_cast<DSABinaryKey &>(privBinKey);
336
337 /*
338 * Parameters from context:
339 * Key size in bits, required;
340 * {p,q,g} from generateParams, optional
341 */
342 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
343 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
344 CssmData *paramData = context.get<CssmData>(CSSM_ATTRIBUTE_ALG_PARAMS);
345
346 DSAAlgParams algParams;
347 if(paramData != NULL) {
348 /* this contains the DER encoding of a DSAAlgParams */
349 try {
350 SC_decodeAsnObj(*paramData, algParams);
351 }
352 catch(...) {
353 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
354 }
355 }
356 else {
357 /* no alg params specified; generate them now using null (random) seed */
358 dsaGenParams(keyBits, NULL, 0, algParams);
359 }
360
361 /* create key, stuff params into it */
362 rPrivBinKey.mDsaKey = DSA_new();
363 if(rPrivBinKey.mDsaKey == NULL) {
364 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
365 }
366 DSA *dsaKey = rPrivBinKey.mDsaKey;
367 dsaKey->p = bigIntStrToBn(algParams.p);
368 dsaKey->q = bigIntStrToBn(algParams.q);
369 dsaKey->g = bigIntStrToBn(algParams.g);
370
371 /* generate the key (both public and private capabilities) */
372 int irtn = DSA_generate_key(dsaKey);
373 if(!irtn) {
374 throwRsaDsa("DSA_generate_key");
375 }
376
377 /* public key is subset of private key */
378 rPubBinKey.mDsaKey = DSA_new();
379 if(rPrivBinKey.mDsaKey == NULL) {
380 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
381 }
382 DSA *pub = rPubBinKey.mDsaKey;
383 DSA *priv = rPrivBinKey.mDsaKey;
384 pub->p = BN_dup(priv->p);
385 pub->q = BN_dup(priv->q);
386 pub->g = BN_dup(priv->g);
387 pub->pub_key = BN_dup(priv->pub_key);
388 if((pub->p == NULL) || (pub->q == NULL) || (pub->g == NULL) ||
389 (pub->pub_key == NULL)) {
390 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
391 }
392 }
393
394 /*
395 * Generate keygen parameters, stash them in a context attr array for later use
396 * when actually generating the keys.
397 */
398 void DSAKeyPairGenContext::generate(
399 const Context &context,
400 uint32 bitSize,
401 CssmData &params,
402 uint32 &attrCount,
403 Context::Attr * &attrs)
404 {
405 void *seed = NULL;
406 unsigned seedLen = 0;
407
408 /* optional seed from context */
409 CssmData *seedData = context.get<CssmData>(CSSM_ATTRIBUTE_SEED);
410 if(seedData) {
411 seed = seedData->data();
412 seedLen = seedData->length();
413 }
414
415 /* generate the params */
416 DSAAlgParams algParams;
417 dsaGenParams(bitSize, seed, seedLen, algParams);
418
419 /*
420 * Here comes the fun part.
421 * We "return" the DER encoding of these generated params in two ways:
422 * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL.
423 * The app must free this.
424 * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr,
425 * a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to
426 * this attr array and free it, the CSSM_DATA it points to, and the DER
427 * encoding *that* points to, in our destructor.
428 *
429 * First, DER encode.
430 */
431 size_t maxSize = sizeofBigInt(algParams.p) +
432 sizeofBigInt(algParams.q) +
433 sizeofBigInt(algParams.g) +
434 10;
435 CssmAutoData aDerData(session());
436 SC_encodeAsnObj(algParams, aDerData, maxSize);
437
438 /* copy/release that into a mallocd CSSM_DATA. */
439 CSSM_DATA_PTR derData = (CSSM_DATA_PTR)session().malloc(sizeof(CSSM_DATA));
440 *derData = aDerData.release();
441
442 /* stuff that into a one-element Attr array which we keep after returning */
443 freeGenAttrs();
444 mGenAttrs = (Context::Attr *)session().malloc(sizeof(Context::Attr));
445 mGenAttrs->AttributeType = CSSM_ATTRIBUTE_ALG_PARAMS;
446 mGenAttrs->AttributeLength = sizeof(CSSM_DATA);
447 mGenAttrs->Attribute.Data = derData;
448
449 /* and "return" this stuff */
450 copyCssmData(CssmData::overlay(*derData), params, session());
451 attrCount = 1;
452 attrs = mGenAttrs;
453 }
454
455 /* free mGenAttrs and its referents if present */
456 void DSAKeyPairGenContext::freeGenAttrs()
457 {
458 if(mGenAttrs == NULL) {
459 return;
460 }
461 if(mGenAttrs->Attribute.Data) {
462 if(mGenAttrs->Attribute.Data->Data) {
463 session().free(mGenAttrs->Attribute.Data->Data);
464 }
465 session().free(mGenAttrs->Attribute.Data);
466 }
467 session().free(mGenAttrs);
468 }
469
470 /*
471 * Generate DSA algorithm parameters from optional seed input, returning result
472 * into DSAAlgParams.[pqg]. This is called from both GenerateParameters and from
473 * KeyPairGenerate (if no GenerateParameters has yet been called).
474 */
475 void DSAKeyPairGenContext::dsaGenParams(
476 uint32 keySizeInBits,
477 const void *inSeed, // optional
478 unsigned inSeedLen,
479 DSAAlgParams &algParams)
480 {
481 unsigned char seedBuf[SHA1_DIGEST_SIZE];
482 void *seedPtr;
483
484 /* validate key size */
485 if((keySizeInBits < DSA_MIN_KEY_SIZE) ||
486 (keySizeInBits > DSA_MAX_KEY_SIZE) ||
487 (keySizeInBits & DSA_KEY_BITS_MASK)) {
488 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
489 }
490
491 /* seed from one of three sources */
492 if(inSeed == NULL) {
493 /* 20 random seed bytes */
494 session().getRandomBytes(SHA1_DIGEST_SIZE, seedBuf);
495 seedPtr = seedBuf;
496 }
497 else if(inSeedLen == SHA1_DIGEST_SIZE) {
498 /* perfect */
499 seedPtr = (void *)inSeed;
500 }
501 else {
502 /* hash caller's seed */
503 cspGenSha1Hash(inSeed, inSeedLen, seedBuf);
504 seedPtr = seedBuf;
505 }
506
507 DSA *dsaKey = DSA_generate_parameters(keySizeInBits,
508 (unsigned char *)seedPtr,
509 SHA1_DIGEST_SIZE,
510 NULL, // counter_ret
511 NULL, // h_ret
512 NULL,
513 NULL);
514 if(dsaKey == NULL) {
515 throwRsaDsa("DSA_generate_parameters");
516 }
517
518 /* stuff dsaKey->[pqg] into a caller's DSAAlgParams */
519 bnToBigIntStr(dsaKey->p, algParams.p);
520 bnToBigIntStr(dsaKey->q, algParams.q);
521 bnToBigIntStr(dsaKey->g, algParams.g);
522
523 DSA_free(dsaKey);
524 }
525
526 /***
527 *** DSA-style CSPKeyInfoProvider.
528 ***/
529 DSAKeyInfoProvider::DSAKeyInfoProvider(
530 const CssmKey &cssmKey) :
531 CSPKeyInfoProvider(cssmKey)
532 {
533 switch(cssmKey.algorithm()) {
534 case CSSM_ALGID_DSA:
535 break;
536 default:
537 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
538 }
539 switch(cssmKey.keyClass()) {
540 case CSSM_KEYCLASS_PUBLIC_KEY:
541 case CSSM_KEYCLASS_PRIVATE_KEY:
542 break;
543 default:
544 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
545 }
546 /* OK, we'll handle this one */
547 return;
548 }
549
550 /* Given a raw key, cook up a Binary key */
551 void DSAKeyInfoProvider::CssmKeyToBinary(
552 BinaryKey **binKey)
553 {
554 *binKey = NULL;
555 DSA *dsaKey = NULL;
556
557 /* first cook up an DSA key, then drop that into a BinaryKey */
558 dsaKey = rawCssmKeyToDsa(mKey);
559 DSABinaryKey *dsaBinKey = new DSABinaryKey(dsaKey);
560 *binKey = dsaBinKey;
561 }
562
563 /*
564 * Obtain key size in bits.
565 */
566 void DSAKeyInfoProvider::QueryKeySizeInBits(
567 CSSM_KEY_SIZE &keySize)
568 {
569 DSA *dsaKey = NULL;
570
571 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
572 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
573 }
574 dsaKey = rawCssmKeyToDsa(mKey);
575 keySize.LogicalKeySizeInBits = BN_num_bits(dsaKey->p);
576 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
577 DSA_free(dsaKey);
578 }