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