]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/FEEKeys.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / FEEKeys.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-2012,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
19 /*
20 * FEEKeys.cpp - FEE-related asymmetric key pair classes.
21 *
22 */
23
24 #ifdef CRYPTKIT_CSP_ENABLE
25
26 #include "FEEKeys.h"
27 #include "FEECSPUtils.h"
28 #include "CryptKitSpace.h"
29 #include <security_cryptkit/feePublicKey.h>
30 #include <security_cryptkit/falloc.h>
31 #include <security_cdsa_utilities/cssmdata.h>
32 #include "AppleCSPSession.h"
33 #include "AppleCSPUtils.h"
34 #include <security_utilities/simulatecrash_assert.h>
35 #include <security_utilities/debugging.h>
36
37 #define feeKeyDebug(args...) secinfo("feeKey", ## args)
38
39 /***
40 *** FEE-style BinaryKey
41 ***/
42
43 /* constructor with optional existing feePubKey */
44 CryptKit::FEEBinaryKey::FEEBinaryKey(feePubKey feeKey)
45 : mFeeKey(feeKey)
46 {
47 if(mFeeKey == NULL) {
48 mFeeKey = feePubKeyAlloc();
49 if(mFeeKey == NULL) {
50 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
51 }
52 }
53 }
54
55 CryptKit::FEEBinaryKey::~FEEBinaryKey()
56 {
57 if(mFeeKey) {
58 feePubKeyFree(mFeeKey);
59 mFeeKey = NULL;
60 }
61 }
62
63 void CryptKit::FEEBinaryKey::generateKeyBlob(
64 Allocator &allocator,
65 CssmData &blob,
66 CSSM_KEYBLOB_FORMAT &format,
67 AppleCSPSession &session,
68 const CssmKey *paramKey, /* optional, unused here */
69 CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */
70 {
71 unsigned char *keyBlob = NULL;
72 unsigned len = 0;
73 feeReturn frtn = FR_Internal;
74 bool freeTheKey = false;
75 feePubKey keyToEncode = mFeeKey;
76
77 assert(mFeeKey != NULL);
78 if((format == CSSM_KEYBLOB_RAW_FORMAT_DIGEST) &&
79 (mKeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)) {
80 /* key digest calculation; special case for private keys: cook
81 * up the associated public key and encode that */
82 keyToEncode = feePubKeyAlloc();
83 if(keyToEncode == NULL) {
84 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
85 }
86 frtn = feePubKeyInitPubKeyFromPriv(mFeeKey, keyToEncode);
87 if(frtn) {
88 feePubKeyFree(keyToEncode);
89 throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv");
90 }
91 freeTheKey = true;
92 }
93
94 bool badFormat = false;
95 int isPrivate = feePubKeyIsPrivate(keyToEncode);
96
97 switch(mKeyHeader.AlgorithmId) {
98 case CSSM_ALGID_FEE:
99 if(isPrivate) {
100 /* FEE private key */
101 switch(format) {
102 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
103 format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
104 /* and drop thru */
105 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
106 frtn = feePubKeyCreateDERPrivBlob(keyToEncode, &keyBlob, &len);
107 break;
108 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
109 frtn = feePubKeyCreatePrivBlob(keyToEncode, &keyBlob, &len);
110 break;
111 default:
112 badFormat = true;
113 break;
114 }
115 }
116 else {
117 /* FEE Public key */
118 switch(format) {
119 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
120 format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
121 /* and drop thru */
122 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
123 frtn = feePubKeyCreateDERPubBlob(keyToEncode, &keyBlob, &len);
124 break;
125 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
126 frtn = feePubKeyCreatePubBlob(keyToEncode, &keyBlob, &len);
127 break;
128 default:
129 badFormat = true;
130 break;
131 }
132 }
133 /* end of base ALGID_FEE */
134 break;
135
136 case CSSM_ALGID_ECDSA:
137 if(isPrivate) {
138 /* ECDSA/ECDH private key */
139 switch(format) {
140 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
141 /* ECDSA private key: PKCS8 */
142 frtn = feePubKeyCreatePKCS8Blob(keyToEncode, &keyBlob, &len);
143 break;
144 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
145 /* set to default format, drop thru */
146 format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
147 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
148 /* ECDSA private key, SEC1/OpenSSL format */
149 frtn = feePubKeyCreateOpenSSLBlob(keyToEncode, &keyBlob, &len);
150 break;
151 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
152 format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
153 /* and drop thru */
154 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
155 /* raw private key bytes */
156 frtn = feeCreateECDSAPrivBlob(keyToEncode, &keyBlob, &len);
157 break;
158 default:
159 badFormat = true;
160 break;
161 }
162 }
163 else {
164 /*
165 * ECDSA public key.
166 * Note there is no OpenSSL case here, that format is only generated for
167 * private keys.
168 */
169 switch(format) {
170 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
171 /* set to default format, drop thru */
172 format = CSSM_KEYBLOB_RAW_FORMAT_X509;
173 case CSSM_KEYBLOB_RAW_FORMAT_X509:
174 /* ECDSA, public key, default: X509 */
175 frtn = feePubKeyCreateX509Blob(keyToEncode, &keyBlob, &len);
176 break;
177 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST:
178 format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
179 /* and drop thru */
180 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
181 /* raw x|y string */
182 frtn = feeCreateECDSAPubBlob(keyToEncode, &keyBlob, &len);
183 break;
184 default:
185 badFormat = true;
186 break;
187 }
188 }
189 /* end of case CSSM_ALGID_ECDSA */
190 break;
191 default:
192 /* not reached */
193 badFormat = true;
194 break;
195 }
196
197 if(badFormat) {
198 CssmError::throwMe(isPrivate ?
199 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT :
200 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
201 }
202 if(frtn) {
203 throwCryptKit(frtn, "feePubKeyCreate*Blob");
204 }
205 setUpCssmData(blob, len, allocator);
206 memmove(blob.data(), keyBlob, len);
207 blob.length(len);
208 ffree(keyBlob);
209 if(freeTheKey) {
210 /* free the temp pub key we created here */
211 feePubKeyFree(keyToEncode);
212 }
213 }
214
215 /***
216 *** FEE-style AppleKeyPairGenContext
217 ***/
218
219 /*
220 * This one is specified in, and called from, CSPFullPluginSession. Our
221 * only job is to prepare two subclass-specific BinaryKeys and call up to
222 * AppleKeyPairGenContext.
223 */
224 void CryptKit::FEEKeyPairGenContext::generate(
225 const Context &context,
226 CssmKey &pubKey,
227 CssmKey &privKey)
228 {
229 FEEBinaryKey *pubBinKey = new FEEBinaryKey();
230 FEEBinaryKey *privBinKey = new FEEBinaryKey();
231
232 try {
233 AppleKeyPairGenContext::generate(context,
234 session(),
235 pubKey,
236 pubBinKey,
237 privKey,
238 privBinKey);
239 }
240 catch (...) {
241 delete pubBinKey;
242 delete privBinKey;
243 throw;
244 }
245
246 }
247
248 void CryptKit::FEEKeyPairGenContext::generate(const Context &context, uint32, CssmData &params, uint32 &attrCount, Context::Attr * &attrs) {
249 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED);
250 }
251
252 // this one is specified in, and called from, AppleKeyPairGenContext
253 void CryptKit::FEEKeyPairGenContext::generate(
254 const Context &context,
255 BinaryKey &pubBinKey,
256 BinaryKey &privBinKey,
257 uint32 &keyBits)
258 {
259 /*
260 * These casts throw exceptions if the keys are of the
261 * wrong classes, which would be a major bogon, since we created
262 * the keys in the above generate() function.
263 */
264 FEEBinaryKey &fPubBinKey =
265 dynamic_cast<FEEBinaryKey &>(pubBinKey);
266 FEEBinaryKey &fPrivBinKey =
267 dynamic_cast<FEEBinaryKey &>(privBinKey);
268
269 /*
270 * Two parameters from context. Key size in bits is required;
271 * seed is optional. If not present, we cook up random private data.
272 */
273 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH,
274 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH);
275 CssmCryptoData *cseed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED);
276 CssmData *seed;
277 bool haveSeed;
278 CssmAutoData aSeed(session()); // malloc on demand
279 if(cseed) {
280 /* caller specified seed */
281 haveSeed = true;
282 seed = &cseed->param();
283 }
284 else {
285 /* generate random seed */
286 haveSeed = false;
287 unsigned keyBytes = ((keyBits + 7) / 8) + 1;
288 aSeed.malloc(keyBytes);
289 session().getRandomBytes(keyBytes, aSeed);
290 seed = &aSeed.get();
291 }
292
293 CSSM_ALGORITHMS algId = context.algorithm();
294
295 /* Curve and prime types - optional */
296 feePrimeType primeType = FPT_Default;
297 uint32 uPrimeType = context.getInt(CSSM_ATTRIBUTE_FEE_PRIME_TYPE);
298 switch(uPrimeType) {
299 case CSSM_FEE_PRIME_TYPE_DEFAULT:
300 break;
301 case CSSM_FEE_PRIME_TYPE_MERSENNE:
302 primeType = FPT_Mersenne;
303 break;
304 case CSSM_FEE_PRIME_TYPE_FEE:
305 primeType = FPT_FEE;
306 break;
307 case CSSM_FEE_PRIME_TYPE_GENERAL:
308 primeType = FPT_General;
309 break;
310 default:
311 /* FIXME - maybe we should be more specific */
312 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
313 }
314 feeCurveType curveType = FCT_Default;
315 switch(algId) {
316 case CSSM_ALGID_ECDSA:
317 /* no options */
318 curveType = FCT_ANSI;
319 break;
320 default:
321 {
322 uint32 uCurveType = context.getInt(CSSM_ATTRIBUTE_FEE_CURVE_TYPE);
323 switch(uCurveType) {
324 case CSSM_FEE_CURVE_TYPE_DEFAULT:
325 break;
326 case CSSM_FEE_CURVE_TYPE_MONTGOMERY:
327 curveType = FCT_Montgomery;
328 break;
329 case CSSM_FEE_CURVE_TYPE_WEIERSTRASS:
330 curveType = FCT_Weierstrass;
331 break;
332 case CSSM_FEE_CURVE_TYPE_ANSI_X9_62:
333 curveType = FCT_ANSI;
334 break;
335 default:
336 /* FIXME - maybe we should be more specific */
337 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS);
338 }
339 break;
340 }
341 }
342 feeReturn frtn = feePubKeyInitFromPrivDataKeyBits(
343 fPrivBinKey.feeKey(),
344 (unsigned char *)seed->data(),
345 (unsigned int)seed->length(),
346 keyBits,
347 primeType,
348 curveType,
349 /*
350 * our random seed: trust it
351 * caller's seed: hash it
352 */
353 haveSeed ? 1 : 0);
354 if(frtn) {
355 throwCryptKit(frtn, "feePubKeyInitFromPrivDataKeyBits");
356 }
357 frtn = feePubKeyInitPubKeyFromPriv(fPrivBinKey.feeKey(),
358 fPubBinKey.feeKey());
359 if(frtn) {
360 throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv");
361 }
362 }
363
364
365 /***
366 *** FEE-style CSPKeyInfoProvider.
367 ***/
368 CryptKit::FEEKeyInfoProvider::FEEKeyInfoProvider(
369 const CssmKey &cssmKey,
370 AppleCSPSession &session) :
371 CSPKeyInfoProvider(cssmKey, session)
372 {
373 }
374 CSPKeyInfoProvider *FEEKeyInfoProvider::provider(
375 const CssmKey &cssmKey,
376 AppleCSPSession &session)
377 {
378 switch(cssmKey.algorithm()) {
379 case CSSM_ALGID_FEE:
380 case CSSM_ALGID_ECDSA:
381 break;
382 default:
383 return NULL;
384 }
385 switch(cssmKey.keyClass()) {
386 case CSSM_KEYCLASS_PUBLIC_KEY:
387 case CSSM_KEYCLASS_PRIVATE_KEY:
388 /* FIXME - verify proper CSSM_KEYBLOB_RAW_FORMAT_xx */
389 break;
390 default:
391 return NULL;
392 }
393 /* OK, we'll handle this one */
394 return new FEEKeyInfoProvider(cssmKey, session);
395 }
396
397 /* Given a raw key, cook up a Binary key */
398 void CryptKit::FEEKeyInfoProvider::CssmKeyToBinary(
399 CssmKey *paramKey, // optional, ignored
400 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT
401 BinaryKey **binKey)
402 {
403 *binKey = NULL;
404 feePubKey feeKey = NULL;
405
406 /* first cook up a feePubKey, then drop that into a BinaryKey */
407 feeKey = rawCssmKeyToFee(mKey);
408 FEEBinaryKey *feeBinKey = new FEEBinaryKey(feeKey);
409 *binKey = feeBinKey;
410 }
411
412 /*
413 * Obtain key size in bits.
414 * Currently only raw public keys are dealt with (they're the ones
415 * which come from certs, the only current use for this function).
416 * Note that if we need to handle ref keys, we'll need a session ref...
417 */
418 void CryptKit::FEEKeyInfoProvider::QueryKeySizeInBits(
419 CSSM_KEY_SIZE &keySize)
420 {
421 feePubKey feeKey = NULL;
422
423 if(mKey.blobType() != CSSM_KEYBLOB_RAW) {
424 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT);
425 }
426 feeKey = rawCssmKeyToFee(mKey);
427 keySize.LogicalKeySizeInBits = feePubKeyBitsize(feeKey);
428 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits;
429 feePubKeyFree(feeKey);
430 }
431
432 /*
433 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
434 * passthrough.
435 */
436 bool CryptKit::FEEKeyInfoProvider::getHashableBlob(
437 Allocator &allocator,
438 CssmData &blob) // blob to hash goes here
439 {
440 /*
441 * The optimized case, a raw key in the "proper" format already.
442 * Currently this is:
443 * FEE public key in default/NONE form (which happens to be DER)
444 */
445 assert(mKey.blobType() == CSSM_KEYBLOB_RAW);
446 if((mKey.algorithm() == CSSM_ALGID_FEE) &&
447 (mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_NONE) &&
448 (mKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY)) {
449 const CssmData &keyBlob = CssmData::overlay(mKey.KeyData);
450 copyCssmData(keyBlob, blob, allocator);
451 return true;
452 }
453
454 /* caller converts to binary and proceeds */
455 return false;
456 }
457
458 #endif /* CRYPTKIT_CSP_ENABLE */