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
)
181 switch(cssmKey
.algorithm()) {
185 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
187 switch(cssmKey
.keyClass()) {
188 case CSSM_KEYCLASS_PUBLIC_KEY
:
189 case CSSM_KEYCLASS_PRIVATE_KEY
:
192 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
194 /* OK, we'll handle this one */
198 /* Given a raw key, cook up a Binary key */
199 void RSAKeyInfoProvider::CssmKeyToBinary(
205 /* first cook up an RSA key, then drop that into a BinaryKey */
206 rsaKey
= rawCssmKeyToRsa(mKey
);
207 RSABinaryKey
*rsaBinKey
= new RSABinaryKey(rsaKey
);
212 * Obtain key size in bits.
214 void RSAKeyInfoProvider::QueryKeySizeInBits(
215 CSSM_KEY_SIZE
&keySize
)
219 if(mKey
.blobType() != CSSM_KEYBLOB_RAW
) {
220 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
222 rsaKey
= rawCssmKeyToRsa(mKey
);
223 keySize
.LogicalKeySizeInBits
= RSA_size(rsaKey
) * 8;
224 keySize
.EffectiveKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
234 *** DSA-style BinaryKey
237 /* constructor with optional existing DSA key */
238 DSABinaryKey::DSABinaryKey(DSA
*dsaKey
)
243 DSABinaryKey::~DSABinaryKey()
251 void DSABinaryKey::generateKeyBlob(
252 CssmAllocator
&allocator
,
254 CSSM_KEYBLOB_FORMAT
&format
)
259 switch(mKeyHeader
.KeyClass
) {
260 case CSSM_KEYCLASS_PUBLIC_KEY
:
262 format
= DSA_PUB_KEY_FORMAT
;
264 case CSSM_KEYCLASS_PRIVATE_KEY
:
266 format
= DSA_PRIV_KEY_FORMAT
;
269 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
272 CssmAutoData
encodedKey(allocator
);
274 crtn
= DSAPublicKeyEncode(mDsaKey
, encodedKey
);
277 crtn
= DSAPrivateKeyEncode(mDsaKey
, encodedKey
);
280 CssmError::throwMe(crtn
);
282 blob
= encodedKey
.release();
286 *** DSA-style AppleKeyPairGenContext
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.
294 void DSAKeyPairGenContext::generate(
295 const Context
&context
,
299 DSABinaryKey
*pubBinKey
= new DSABinaryKey();
300 DSABinaryKey
*privBinKey
= new DSABinaryKey();
303 AppleKeyPairGenContext::generate(context
,
319 * This one is specified in, and called from, AppleKeyPairGenContext
321 void DSAKeyPairGenContext::generate(
322 const Context
&context
,
323 BinaryKey
&pubBinKey
,
324 BinaryKey
&privBinKey
,
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.
332 DSABinaryKey
&rPubBinKey
=
333 dynamic_cast<DSABinaryKey
&>(pubBinKey
);
334 DSABinaryKey
&rPrivBinKey
=
335 dynamic_cast<DSABinaryKey
&>(privBinKey
);
338 * Parameters from context:
339 * Key size in bits, required;
340 * {p,q,g} from generateParams, optional
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
);
346 DSAAlgParams algParams
;
347 if(paramData
!= NULL
) {
348 /* this contains the DER encoding of a DSAAlgParams */
350 SC_decodeAsnObj(*paramData
, algParams
);
353 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS
);
357 /* no alg params specified; generate them now using null (random) seed */
358 dsaGenParams(keyBits
, NULL
, 0, algParams
);
361 /* create key, stuff params into it */
362 rPrivBinKey
.mDsaKey
= DSA_new();
363 if(rPrivBinKey
.mDsaKey
== NULL
) {
364 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
366 DSA
*dsaKey
= rPrivBinKey
.mDsaKey
;
367 dsaKey
->p
= bigIntStrToBn(algParams
.p
);
368 dsaKey
->q
= bigIntStrToBn(algParams
.q
);
369 dsaKey
->g
= bigIntStrToBn(algParams
.g
);
371 /* generate the key (both public and private capabilities) */
372 int irtn
= DSA_generate_key(dsaKey
);
374 throwRsaDsa("DSA_generate_key");
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
);
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
);
395 * Generate keygen parameters, stash them in a context attr array for later use
396 * when actually generating the keys.
398 void DSAKeyPairGenContext::generate(
399 const Context
&context
,
403 Context::Attr
* &attrs
)
406 unsigned seedLen
= 0;
408 /* optional seed from context */
409 CssmData
*seedData
= context
.get
<CssmData
>(CSSM_ATTRIBUTE_SEED
);
411 seed
= seedData
->data();
412 seedLen
= seedData
->length();
415 /* generate the params */
416 DSAAlgParams algParams
;
417 dsaGenParams(bitSize
, seed
, seedLen
, algParams
);
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.
431 size_t maxSize
= sizeofBigInt(algParams
.p
) +
432 sizeofBigInt(algParams
.q
) +
433 sizeofBigInt(algParams
.g
) +
435 CssmAutoData
aDerData(session());
436 SC_encodeAsnObj(algParams
, aDerData
, maxSize
);
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();
442 /* stuff that into a one-element Attr array which we keep after returning */
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
;
449 /* and "return" this stuff */
450 copyCssmData(CssmData::overlay(*derData
), params
, session());
455 /* free mGenAttrs and its referents if present */
456 void DSAKeyPairGenContext::freeGenAttrs()
458 if(mGenAttrs
== NULL
) {
461 if(mGenAttrs
->Attribute
.Data
) {
462 if(mGenAttrs
->Attribute
.Data
->Data
) {
463 session().free(mGenAttrs
->Attribute
.Data
->Data
);
465 session().free(mGenAttrs
->Attribute
.Data
);
467 session().free(mGenAttrs
);
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).
475 void DSAKeyPairGenContext::dsaGenParams(
476 uint32 keySizeInBits
,
477 const void *inSeed
, // optional
479 DSAAlgParams
&algParams
)
481 unsigned char seedBuf
[SHA1_DIGEST_SIZE
];
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
);
491 /* seed from one of three sources */
493 /* 20 random seed bytes */
494 session().getRandomBytes(SHA1_DIGEST_SIZE
, seedBuf
);
497 else if(inSeedLen
== SHA1_DIGEST_SIZE
) {
499 seedPtr
= (void *)inSeed
;
502 /* hash caller's seed */
503 cspGenSha1Hash(inSeed
, inSeedLen
, seedBuf
);
507 DSA
*dsaKey
= DSA_generate_parameters(keySizeInBits
,
508 (unsigned char *)seedPtr
,
515 throwRsaDsa("DSA_generate_parameters");
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
);
527 *** DSA-style CSPKeyInfoProvider.
529 DSAKeyInfoProvider::DSAKeyInfoProvider(
530 const CssmKey
&cssmKey
) :
531 CSPKeyInfoProvider(cssmKey
)
533 switch(cssmKey
.algorithm()) {
537 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
539 switch(cssmKey
.keyClass()) {
540 case CSSM_KEYCLASS_PUBLIC_KEY
:
541 case CSSM_KEYCLASS_PRIVATE_KEY
:
544 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
546 /* OK, we'll handle this one */
550 /* Given a raw key, cook up a Binary key */
551 void DSAKeyInfoProvider::CssmKeyToBinary(
557 /* first cook up an DSA key, then drop that into a BinaryKey */
558 dsaKey
= rawCssmKeyToDsa(mKey
);
559 DSABinaryKey
*dsaBinKey
= new DSABinaryKey(dsaKey
);
564 * Obtain key size in bits.
566 void DSAKeyInfoProvider::QueryKeySizeInBits(
567 CSSM_KEY_SIZE
&keySize
)
571 if(mKey
.blobType() != CSSM_KEYBLOB_RAW
) {
572 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
574 dsaKey
= rawCssmKeyToDsa(mKey
);
575 keySize
.LogicalKeySizeInBits
= BN_num_bits(dsaKey
->p
);
576 keySize
.EffectiveKeySizeInBits
= keySize
.LogicalKeySizeInBits
;