]> git.saurik.com Git - apple/security.git/blob - AppleCSP/BSafeCSP/bsafeKeyGen.cpp
274a158b95de3cb41e60e959f9ef9b03dee03c85
[apple/security.git] / AppleCSP / BSafeCSP / bsafeKeyGen.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 #ifdef BSAFE_CSP_ENABLE
19
20
21 //
22 // bsafeKeyGen.cpp - key generation routines
23 //
24 #include "bsafecspi.h"
25 #include "bsafePKCS1.h"
26 #include "cspdebugging.h"
27
28 /*
29 * Stateless, private function to map a CSSM alg and pub/priv state
30 * to B_INFO_TYPE and format. Returns true on success, false on
31 * "I don't understand this algorithm".
32 */
33 bool BSafe::bsafeAlgToInfoType(
34 CSSM_ALGORITHMS alg,
35 bool isPublic,
36 B_INFO_TYPE &infoType, // RETURNED
37 CSSM_KEYBLOB_FORMAT &format) // RETURNED
38 {
39 switch(alg) {
40 case CSSM_ALGID_RSA:
41 if(isPublic) {
42 infoType = RSA_PUB_KEYINFO_TYPE;
43 format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
44 }
45 else {
46 infoType = RSA_PRIV_KEYINFO_TYPE;
47 format = CSSM_KEYBLOB_RAW_FORMAT_PKCS8;
48 }
49 return true;
50 case CSSM_ALGID_DSA:
51 format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
52 if(isPublic) {
53 infoType = DSA_PUB_KEYINFO_TYPE;
54 }
55 else {
56 infoType = DSA_PRIV_KEYINFO_TYPE;
57 }
58 return true;
59 default:
60 return false;
61 }
62 }
63
64
65 BSafe::BSafeBinaryKey::BSafeBinaryKey(
66 bool isPub,
67 uint32 Alg)
68 : mIsPublic(isPub),
69 mAlg(Alg)
70 {
71 BSafe::check(B_CreateKeyObject(&mBsKey), true);
72 }
73
74 BSafe::BSafeBinaryKey::~BSafeBinaryKey()
75 {
76 B_DestroyKeyObject(&mBsKey);
77 }
78
79 void BSafe::BSafeBinaryKey::generateKeyBlob(
80 CssmAllocator &allocator,
81 CssmData &blob,
82 CSSM_KEYBLOB_FORMAT &format) // input val ignored for now
83 {
84 assert(mBsKey != NULL);
85
86 B_INFO_TYPE bsType;
87 if(!bsafeAlgToInfoType(mAlg, mIsPublic, bsType, format)) {
88 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
89 }
90 if(format == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
91 /* special case, encode the PKCS1 format blob */
92 CssmRemoteData rData(
93 CssmAllocator::standard(CssmAllocator::sensitive), blob);
94 BS_GetKeyPkcs1(mBsKey, rData);
95 rData.release();
96 }
97 else {
98 BSafeItem *info;
99 BSafe::check(
100 B_GetKeyInfo((POINTER *)&info, mBsKey, bsType), true);
101 blob = info->copy<CssmData>(allocator);
102 }
103 }
104
105 //
106 // This is called from CSPFullPluginSession
107 //
108 void BSafe::BSafeKeyPairGenContext::generate(
109 const Context &context,
110 CssmKey &pubKey,
111 CssmKey &privKey)
112 {
113 BSafeBinaryKey *pubBinKey = new BSafeBinaryKey(true,
114 context.algorithm());
115 BSafeBinaryKey *privBinKey = new BSafeBinaryKey(false,
116 context.algorithm());
117
118 try {
119 AppleKeyPairGenContext::generate(context,
120 session(),
121 pubKey,
122 pubBinKey,
123 privKey,
124 privBinKey);
125 }
126 catch (...) {
127 delete pubBinKey;
128 delete privBinKey;
129 throw;
130 }
131 }
132
133 //
134 // Called from AppleKeyPairGenContext
135 //
136 void BSafe::BSafeKeyPairGenContext::generate(
137 const Context &context,
138 BinaryKey &pubBinKey, // valid on successful return
139 BinaryKey &privBinKey, // ditto
140 uint32 &keySize) // ditto
141 {
142 /* these casts throw exceptions if the keys are of the
143 * wrong classes, which is a major bogon, since we created
144 * the keys in the above generate() function */
145 BSafeBinaryKey &bsPubBinKey =
146 dynamic_cast<BSafeBinaryKey &>(pubBinKey);
147 BSafeBinaryKey &bsPrivBinKey =
148 dynamic_cast<BSafeBinaryKey &>(privBinKey);
149
150 if (!initialized) {
151 setupAlgorithm(context, keySize);
152 check(B_GenerateInit(bsAlgorithm, chooser(), bsSurrender), true);
153 initialized = true;
154 }
155
156 setRandom();
157 check(B_GenerateKeypair(bsAlgorithm,
158 bsPubBinKey.bsKey(),
159 bsPrivBinKey.bsKey(),
160 bsRandom,
161 bsSurrender), true);
162 }
163
164 void BSafe::BSafeKeyPairGenContext::setupAlgorithm(
165 const Context &context,
166 uint32 &keySize)
167 {
168 switch(context.algorithm()) {
169 case CSSM_ALGID_RSA:
170 {
171 A_RSA_KEY_GEN_PARAMS genParams;
172 keySize = genParams.modulusBits =
173 context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
174 CSSMERR_CSP_INVALID_ATTR_KEY_LENGTH);
175 if (CssmData *params =
176 context.get<CssmData>(CSSM_ATTRIBUTE_ALG_PARAMS)) {
177 genParams.publicExponent = BSafeItem(*params);
178 } else {
179 static unsigned char exponent[] = { 1, 0, 1 };
180 genParams.publicExponent = BSafeItem(exponent, sizeof(exponent));
181 }
182 /*
183 * For test purposes, we avoid the 'strong' key generate
184 * algorithm if a CSSM_ALGMODE_CUSTOM mode atrtribute
185 * is present in the context. This is not published and
186 * not supported in the real world.
187 */
188 uint32 mode = context.getInt(CSSM_ATTRIBUTE_MODE);
189 if(mode == CSSM_ALGMODE_CUSTOM) {
190 setAlgorithm(AI_RSAKeyGen, &genParams);
191 }
192 else {
193 setAlgorithm(AI_RSAStrongKeyGen, &genParams);
194 }
195 }
196 break;
197 case CSSM_ALGID_DSA:
198 {
199 A_DSA_PARAMS genParams;
200 genParams.prime =
201 BSafeItem(context.get<CssmData>(
202 CSSM_ATTRIBUTE_PRIME,
203 CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS));
204 genParams.subPrime =
205 BSafeItem(context.get<CssmData>(
206 CSSM_ATTRIBUTE_SUBPRIME,
207 CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS));
208 genParams.base =
209 BSafeItem(context.get<CssmData>(
210 CSSM_ATTRIBUTE_BASE,
211 CSSMERR_CSP_MISSING_ATTR_ALG_PARAMS));
212 setAlgorithm(AI_DSAKeyGen, &genParams);
213 keySize = B_IntegerBits(genParams.prime.data, genParams.prime.len);
214 }
215 break;
216 default:
217 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
218 }
219 }
220
221 //
222 // DSA Parameter Generation
223 //
224 void BSafe::BSafeKeyPairGenContext::generate(
225 const Context &context,
226 uint32 bitSize,
227 CssmData &params,
228 uint32 &attrCount,
229 Context::Attr * &attrs)
230 {
231 assert(context.algorithm() == CSSM_ALGID_DSA);
232
233 B_ALGORITHM_OBJ genAlg = NULL;
234 B_ALGORITHM_OBJ result = NULL;
235
236 try {
237 check(B_CreateAlgorithmObject(&genAlg));
238
239 B_DSA_PARAM_GEN_PARAMS genParams;
240 genParams.primeBits = bitSize;
241 check(B_SetAlgorithmInfo(genAlg, AI_DSAParamGen, POINTER(&genParams)));
242 setRandom();
243 check(B_GenerateInit(genAlg, chooser(), bsSurrender), true);
244 check(B_CreateAlgorithmObject(&result));
245 check(B_GenerateParameters(genAlg, result, bsRandom, bsSurrender));
246
247 // get parameters out of algorithm object
248 A_DSA_PARAMS *kParams = NULL;
249 check(B_GetAlgorithmInfo((POINTER *)&kParams, result, AI_DSAKeyGen), true);
250
251 // shred them into context attribute form
252 attrs = normAllocator->alloc<Context::Attr>(3);
253 attrs[0] = Context::Attr(CSSM_ATTRIBUTE_PRIME,
254 *BSafeItem(kParams->prime).copyp<CssmData>(*normAllocator));
255 attrs[1] = Context::Attr(CSSM_ATTRIBUTE_SUBPRIME,
256 *BSafeItem(kParams->subPrime).copyp<CssmData>(*normAllocator));
257 attrs[2] = Context::Attr(CSSM_ATTRIBUTE_BASE,
258 *BSafeItem(kParams->base).copyp<CssmData>(*normAllocator));
259 attrCount = 3;
260
261 // clean up
262 B_DestroyAlgorithmObject(&result);
263 B_DestroyAlgorithmObject(&genAlg);
264 } catch (...) {
265 // clean up
266 B_DestroyAlgorithmObject(&result);
267 B_DestroyAlgorithmObject(&genAlg);
268 throw;
269 }
270 }
271
272 /*
273 * CSPKeyInfoProvider for asymmetric BSAFE keys.
274 */
275 BSafe::BSafeKeyInfoProvider::BSafeKeyInfoProvider(
276 const CssmKey &cssmKey) :
277 CSPKeyInfoProvider(cssmKey)
278 {
279 }
280
281 CSPKeyInfoProvider *BSafe::BSafeKeyInfoProvider::provider(
282 const CssmKey &cssmKey)
283 {
284 switch(cssmKey.keyClass()) {
285 case CSSM_KEYCLASS_PUBLIC_KEY:
286 case CSSM_KEYCLASS_PRIVATE_KEY:
287 break;
288 default:
289 return NULL;
290 }
291 switch(mKey.algorithm()) {
292 case CSSM_ALGID_RSA:
293 case CSSM_ALGID_DSA:
294 break;
295 default:
296 return NULL;
297 }
298 /* OK, we'll handle this one */
299 return new BSafeKeyInfoProvider(cssmKey);
300 }
301
302 /* cook up a Binary key */
303 void BSafe::BSafeKeyInfoProvider::CssmKeyToBinary(
304 BinaryKey **binKey)
305 {
306 *binKey = NULL;
307
308 const CSSM_KEYHEADER *hdr = &mKey.KeyHeader;
309 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
310
311 B_INFO_TYPE bsType;
312 CSSM_KEYBLOB_FORMAT format;
313 bool isPub;
314
315 switch(hdr->KeyClass) {
316 case CSSM_KEYCLASS_PUBLIC_KEY:
317 isPub = true;
318 break;
319 case CSSM_KEYCLASS_PRIVATE_KEY:
320 isPub = false;
321 break;
322 default:
323 // someone else's key
324 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
325 }
326 if(!bsafeAlgToInfoType(hdr->AlgorithmId, isPub, bsType, format)) {
327 // someone else's key
328 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
329 }
330 if(hdr->Format != format) {
331 dprintf0("BSafe::cssmKeyToBinary: format mismatch\n");
332 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
333 }
334
335 BSafeBinaryKey *bsBinKey = new BSafeBinaryKey(isPub,
336 hdr->AlgorithmId);
337
338 // set up key material as appropriate
339 if(format == CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
340 /* special case, decode the PKCS1 format blob */
341 BS_setKeyPkcs1(mKey, bsBinKey->bsKey());
342 }
343 else {
344 /* normal case, use key blob as is */
345 BSafeItem item(mKey.KeyData);
346 BSafe::check(
347 B_SetKeyInfo(bsBinKey->bsKey(), bsType, POINTER(&item)), true);
348 }
349 *binKey = bsBinKey;
350 }
351
352 /*
353 * Obtain key size in bits.
354 */
355 void BSafe::BSafeKeyInfoProvider::QueryKeySizeInBits(
356 CSSM_KEY_SIZE &keySize)
357 {
358 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
359 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
360 }
361
362 /* cook up BSAFE key */
363 B_KEY_OBJ bKey;
364 A_RSA_KEY *rsaKeyInfo = NULL;
365 A_DSA_PUBLIC_KEY *dsaPubKeyInfo = NULL;
366 A_DSA_PRIVATE_KEY *dsaPrivKeyInfo = NULL;
367 ITEM *sizeItem = NULL;
368 BSafe::check(B_CreateKeyObject(&bKey), true);
369 B_INFO_TYPE infoType;
370
371 switch(mKey.algorithm()) {
372 case CSSM_ALGID_RSA:
373 switch(mKey.keyClass()) {
374 case CSSM_KEYCLASS_PUBLIC_KEY:
375 if(mKey.blobFormat() !=
376 CSSM_KEYBLOB_RAW_FORMAT_PKCS1) {
377 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
378 }
379
380 /* convert from PKCS1 blob to raw key */
381 BS_setKeyPkcs1(mKey, bKey);
382 infoType = KI_RSAPublic;
383 /* break to common RSA code */
384 break;
385 case CSSM_KEYCLASS_PRIVATE_KEY:
386 {
387 if(mKey.blobFormat() !=
388 CSSM_KEYBLOB_RAW_FORMAT_PKCS8) {
389 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
390 }
391
392 /* convert from PKCS8 blob to raw key */
393 BSafeItem item(mKey.KeyData);
394 BSafe::check(
395 B_SetKeyInfo(bKey, KI_PKCS_RSAPrivateBER,
396 POINTER(&item)), true);
397 infoType = KI_RSAPrivate;
398 break;
399 }
400 default:
401 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
402 }
403 rsaKeyInfo = getKey<A_RSA_KEY>(bKey, infoType);
404 sizeItem = &rsaKeyInfo->modulus;
405 break;
406
407 case CSSM_ALGID_DSA:
408 /* untested as of 9/11/00 */
409 if(mKey.blobFormat() !=
410 CSSM_KEYBLOB_RAW_FORMAT_FIPS186) {
411 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
412 }
413 switch(mKey.keyClass()) {
414 case CSSM_KEYCLASS_PUBLIC_KEY:
415 {
416 BSafeItem item(mKey.KeyData);
417 BSafe::check(B_SetKeyInfo(bKey,
418 DSA_PUB_KEYINFO_TYPE,
419 (POINTER)&item), true);
420
421 /* get the key bits */
422 dsaPubKeyInfo = getKey<A_DSA_PUBLIC_KEY>(bKey,
423 KI_DSAPublic);
424 sizeItem = &dsaPubKeyInfo->params.prime;
425 break;
426 }
427 case CSSM_KEYCLASS_PRIVATE_KEY:
428 {
429 BSafeItem item(mKey.KeyData);
430 BSafe::check(B_SetKeyInfo(bKey,
431 DSA_PRIV_KEYINFO_TYPE,
432 (POINTER)&item), true);
433
434 /* get the key bits */
435 dsaPrivKeyInfo = getKey<A_DSA_PRIVATE_KEY>(bKey,
436 KI_DSAPrivate);
437 sizeItem = &dsaPrivKeyInfo->params.prime;
438 break;
439 }
440 default:
441 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
442 }
443 break;
444 default:
445 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
446 }
447 uint32 iSize = B_IntegerBits(sizeItem->data, sizeItem->len);
448 keySize.LogicalKeySizeInBits = iSize;
449 keySize.EffectiveKeySizeInBits = iSize;
450 B_DestroyKeyObject(&bKey);
451 }
452
453 #endif /* BSAFE_CSP_ENABLE */
454