2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
20 * RSA_DSA_Keys.cpp - RSA, DSA related asymmetric key pair classes.
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>
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>
36 #define RSA_PUB_EXPONENT 0x10001 /* recommended by RSA */
38 #define rsaKeyDebug(args...) debug("rsaKey", ## args)
41 *** RSA-style BinaryKey
44 /* constructor with optional existing RSA key */
45 RSABinaryKey::RSABinaryKey(RSA
*rsaKey
)
50 RSABinaryKey::~RSABinaryKey()
58 void RSABinaryKey::generateKeyBlob(
59 CssmAllocator
&allocator
,
61 CSSM_KEYBLOB_FORMAT
&format
)
66 switch(mKeyHeader
.KeyClass
) {
67 case CSSM_KEYCLASS_PUBLIC_KEY
:
69 format
= RSA_PUB_KEY_FORMAT
;
71 case CSSM_KEYCLASS_PRIVATE_KEY
:
73 format
= RSA_PRIV_KEY_FORMAT
;
76 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
79 CssmAutoData
encodedKey(allocator
);
81 crtn
= RSAPublicKeyEncode(mRsaKey
, encodedKey
);
84 crtn
= RSAPrivateKeyEncode(mRsaKey
, encodedKey
);
87 CssmError::throwMe(crtn
);
89 blob
= encodedKey
.release();
93 *** RSA-style AppleKeyPairGenContext
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.
101 void RSAKeyPairGenContext::generate(
102 const Context
&context
,
106 RSABinaryKey
*pubBinKey
= new RSABinaryKey();
107 RSABinaryKey
*privBinKey
= new RSABinaryKey();
110 AppleKeyPairGenContext::generate(context
,
125 // this one is specified in, and called from, AppleKeyPairGenContext
126 void RSAKeyPairGenContext::generate(
127 const Context
&context
,
128 BinaryKey
&pubBinKey
,
129 BinaryKey
&privBinKey
,
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.
137 RSABinaryKey
&rPubBinKey
=
138 dynamic_cast<RSABinaryKey
&>(pubBinKey
);
139 RSABinaryKey
&rPrivBinKey
=
140 dynamic_cast<RSABinaryKey
&>(privBinKey
);
143 * One parameter from context: Key size in bits is required.
144 * FIXME - get public exponent from context?
146 keyBits
= context
.getInt(CSSM_ATTRIBUTE_KEY_LENGTH
,
147 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH
);
149 /* generate the private key */
150 rPrivBinKey
.mRsaKey
= RSA_generate_key(keyBits
,
154 if(rPrivBinKey
.mRsaKey
== NULL
) {
155 rsaKeyDebug("RSA_generate_key returned NULL");
156 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
); // ???
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
);
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
);
175 *** RSA-style CSPKeyInfoProvider.
177 RSAKeyInfoProvider::RSAKeyInfoProvider(
178 const CssmKey
&cssmKey
) :
179 CSPKeyInfoProvider(cssmKey
)
183 CSPKeyInfoProvider
*RSAKeyInfoProvider::provider(
184 const CssmKey
&cssmKey
)
186 switch(cssmKey
.algorithm()) {
192 switch(cssmKey
.keyClass()) {
193 case CSSM_KEYCLASS_PUBLIC_KEY
:
194 case CSSM_KEYCLASS_PRIVATE_KEY
:
199 /* OK, we'll handle this one */
200 return new RSAKeyInfoProvider(cssmKey
);
203 /* Given a raw key, cook up a Binary key */
204 void RSAKeyInfoProvider::CssmKeyToBinary(
210 /* first cook up an RSA key, then drop that into a BinaryKey */
211 rsaKey
= rawCssmKeyToRsa(mKey
);
212 RSABinaryKey
*rsaBinKey
= new RSABinaryKey(rsaKey
);
217 * Obtain key size in bits.
219 void RSAKeyInfoProvider::QueryKeySizeInBits(
220 CSSM_KEY_SIZE
&keySize
)
224 if(mKey
.blobType() != CSSM_KEYBLOB_RAW
) {
225 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
227 rsaKey
= rawCssmKeyToRsa(mKey
);
228 keySize
.LogicalKeySizeInBits
= RSA_size(rsaKey
) * 8;
229 keySize
.EffectiveKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
239 *** DSA-style BinaryKey
242 /* constructor with optional existing DSA key */
243 DSABinaryKey::DSABinaryKey(DSA
*dsaKey
)
248 DSABinaryKey::~DSABinaryKey()
256 void DSABinaryKey::generateKeyBlob(
257 CssmAllocator
&allocator
,
259 CSSM_KEYBLOB_FORMAT
&format
)
264 switch(mKeyHeader
.KeyClass
) {
265 case CSSM_KEYCLASS_PUBLIC_KEY
:
267 format
= DSA_PUB_KEY_FORMAT
;
269 case CSSM_KEYCLASS_PRIVATE_KEY
:
271 format
= DSA_PRIV_KEY_FORMAT
;
274 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
277 CssmAutoData
encodedKey(allocator
);
279 crtn
= DSAPublicKeyEncode(mDsaKey
, encodedKey
);
282 crtn
= DSAPrivateKeyEncode(mDsaKey
, encodedKey
);
285 CssmError::throwMe(crtn
);
287 blob
= encodedKey
.release();
291 *** DSA-style AppleKeyPairGenContext
295 * This one is specified in, and called from, CSPFullPluginSession. Our
296 * only job is to prepare two subclass-specific BinaryKeys and call up to
297 * AppleKeyPairGenContext.
299 void DSAKeyPairGenContext::generate(
300 const Context
&context
,
304 DSABinaryKey
*pubBinKey
= new DSABinaryKey();
305 DSABinaryKey
*privBinKey
= new DSABinaryKey();
308 AppleKeyPairGenContext::generate(context
,
324 * This one is specified in, and called from, AppleKeyPairGenContext
326 void DSAKeyPairGenContext::generate(
327 const Context
&context
,
328 BinaryKey
&pubBinKey
,
329 BinaryKey
&privBinKey
,
333 * These casts throw exceptions if the keys are of the
334 * wrong classes, which would be a major bogon, since we created
335 * the keys in the above generate() function.
337 DSABinaryKey
&rPubBinKey
=
338 dynamic_cast<DSABinaryKey
&>(pubBinKey
);
339 DSABinaryKey
&rPrivBinKey
=
340 dynamic_cast<DSABinaryKey
&>(privBinKey
);
343 * Parameters from context:
344 * Key size in bits, required;
345 * {p,q,g} from generateParams, optional
347 keyBits
= context
.getInt(CSSM_ATTRIBUTE_KEY_LENGTH
,
348 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH
);
349 CssmData
*paramData
= context
.get
<CssmData
>(CSSM_ATTRIBUTE_ALG_PARAMS
);
351 DSAAlgParams algParams
;
352 if(paramData
!= NULL
) {
353 /* this contains the DER encoding of a DSAAlgParams */
355 SC_decodeAsnObj(*paramData
, algParams
);
358 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS
);
362 /* no alg params specified; generate them now using null (random) seed */
363 dsaGenParams(keyBits
, NULL
, 0, algParams
);
366 /* create key, stuff params into it */
367 rPrivBinKey
.mDsaKey
= DSA_new();
368 if(rPrivBinKey
.mDsaKey
== NULL
) {
369 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
371 DSA
*dsaKey
= rPrivBinKey
.mDsaKey
;
372 dsaKey
->p
= bigIntStrToBn(algParams
.p
);
373 dsaKey
->q
= bigIntStrToBn(algParams
.q
);
374 dsaKey
->g
= bigIntStrToBn(algParams
.g
);
376 /* generate the key (both public and private capabilities) */
377 int irtn
= DSA_generate_key(dsaKey
);
379 throwRsaDsa("DSA_generate_key");
382 /* public key is subset of private key */
383 rPubBinKey
.mDsaKey
= DSA_new();
384 if(rPrivBinKey
.mDsaKey
== NULL
) {
385 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
387 DSA
*pub
= rPubBinKey
.mDsaKey
;
388 DSA
*priv
= rPrivBinKey
.mDsaKey
;
389 pub
->p
= BN_dup(priv
->p
);
390 pub
->q
= BN_dup(priv
->q
);
391 pub
->g
= BN_dup(priv
->g
);
392 pub
->pub_key
= BN_dup(priv
->pub_key
);
393 if((pub
->p
== NULL
) || (pub
->q
== NULL
) || (pub
->g
== NULL
) ||
394 (pub
->pub_key
== NULL
)) {
395 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
400 * Generate keygen parameters, stash them in a context attr array for later use
401 * when actually generating the keys.
403 void DSAKeyPairGenContext::generate(
404 const Context
&context
,
408 Context::Attr
* &attrs
)
411 unsigned seedLen
= 0;
413 /* optional seed from context */
414 CssmData
*seedData
= context
.get
<CssmData
>(CSSM_ATTRIBUTE_SEED
);
416 seed
= seedData
->data();
417 seedLen
= seedData
->length();
420 /* generate the params */
421 DSAAlgParams algParams
;
422 dsaGenParams(bitSize
, seed
, seedLen
, algParams
);
425 * Here comes the fun part.
426 * We "return" the DER encoding of these generated params in two ways:
427 * 1. Copy out to app via the params argument, mallocing if Data ptr is NULL.
428 * The app must free this.
429 * 2. Cook up a 1-element Context::attr array containing one ALG_PARAM attr,
430 * a CSSM_DATA_PTR containing the DER encoding. We have to save a ptr to
431 * this attr array and free it, the CSSM_DATA it points to, and the DER
432 * encoding *that* points to, in our destructor.
436 size_t maxSize
= sizeofBigInt(algParams
.p
) +
437 sizeofBigInt(algParams
.q
) +
438 sizeofBigInt(algParams
.g
) +
440 CssmAutoData
aDerData(session());
441 SC_encodeAsnObj(algParams
, aDerData
, maxSize
);
443 /* copy/release that into a mallocd CSSM_DATA. */
444 CSSM_DATA_PTR derData
= (CSSM_DATA_PTR
)session().malloc(sizeof(CSSM_DATA
));
445 *derData
= aDerData
.release();
447 /* stuff that into a one-element Attr array which we keep after returning */
449 mGenAttrs
= (Context::Attr
*)session().malloc(sizeof(Context::Attr
));
450 mGenAttrs
->AttributeType
= CSSM_ATTRIBUTE_ALG_PARAMS
;
451 mGenAttrs
->AttributeLength
= sizeof(CSSM_DATA
);
452 mGenAttrs
->Attribute
.Data
= derData
;
454 /* and "return" this stuff */
455 copyCssmData(CssmData::overlay(*derData
), params
, session());
460 /* free mGenAttrs and its referents if present */
461 void DSAKeyPairGenContext::freeGenAttrs()
463 if(mGenAttrs
== NULL
) {
466 if(mGenAttrs
->Attribute
.Data
) {
467 if(mGenAttrs
->Attribute
.Data
->Data
) {
468 session().free(mGenAttrs
->Attribute
.Data
->Data
);
470 session().free(mGenAttrs
->Attribute
.Data
);
472 session().free(mGenAttrs
);
476 * Generate DSA algorithm parameters from optional seed input, returning result
477 * into DSAAlgParams.[pqg]. This is called from both GenerateParameters and from
478 * KeyPairGenerate (if no GenerateParameters has yet been called).
480 void DSAKeyPairGenContext::dsaGenParams(
481 uint32 keySizeInBits
,
482 const void *inSeed
, // optional
484 DSAAlgParams
&algParams
)
486 unsigned char seedBuf
[SHA1_DIGEST_SIZE
];
489 /* validate key size */
490 if((keySizeInBits
< DSA_MIN_KEY_SIZE
) ||
491 (keySizeInBits
> DSA_MAX_KEY_SIZE
) ||
492 (keySizeInBits
& DSA_KEY_BITS_MASK
)) {
493 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH
);
496 /* seed from one of three sources */
498 /* 20 random seed bytes */
499 session().getRandomBytes(SHA1_DIGEST_SIZE
, seedBuf
);
502 else if(inSeedLen
== SHA1_DIGEST_SIZE
) {
504 seedPtr
= (void *)inSeed
;
507 /* hash caller's seed */
508 cspGenSha1Hash(inSeed
, inSeedLen
, seedBuf
);
512 DSA
*dsaKey
= DSA_generate_parameters(keySizeInBits
,
513 (unsigned char *)seedPtr
,
520 throwRsaDsa("DSA_generate_parameters");
523 /* stuff dsaKey->[pqg] into a caller's DSAAlgParams */
524 bnToBigIntStr(dsaKey
->p
, algParams
.p
);
525 bnToBigIntStr(dsaKey
->q
, algParams
.q
);
526 bnToBigIntStr(dsaKey
->g
, algParams
.g
);
532 *** DSA-style CSPKeyInfoProvider.
534 DSAKeyInfoProvider::DSAKeyInfoProvider(
535 const CssmKey
&cssmKey
) :
536 CSPKeyInfoProvider(cssmKey
)
540 CSPKeyInfoProvider
*DSAKeyInfoProvider::provider(
541 const CssmKey
&cssmKey
)
543 switch(cssmKey
.algorithm()) {
549 switch(cssmKey
.keyClass()) {
550 case CSSM_KEYCLASS_PUBLIC_KEY
:
551 case CSSM_KEYCLASS_PRIVATE_KEY
:
556 /* OK, we'll handle this one */
557 return new DSAKeyInfoProvider(cssmKey
);
560 /* Given a raw key, cook up a Binary key */
561 void DSAKeyInfoProvider::CssmKeyToBinary(
567 /* first cook up an DSA key, then drop that into a BinaryKey */
568 dsaKey
= rawCssmKeyToDsa(mKey
);
569 DSABinaryKey
*dsaBinKey
= new DSABinaryKey(dsaKey
);
574 * Obtain key size in bits.
576 void DSAKeyInfoProvider::QueryKeySizeInBits(
577 CSSM_KEY_SIZE
&keySize
)
581 if(mKey
.blobType() != CSSM_KEYBLOB_RAW
) {
582 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
584 dsaKey
= rawCssmKeyToDsa(mKey
);
585 keySize
.LogicalKeySizeInBits
= BN_num_bits(dsaKey
->p
);
586 keySize
.EffectiveKeySizeInBits
= keySize
.LogicalKeySizeInBits
;