2 * Copyright (c) 2000-2001,2011-2012,2014 Apple 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 * FEEKeys.cpp - FEE-related asymmetric key pair classes.
24 #ifdef CRYPTKIT_CSP_ENABLE
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>
37 #define feeKeyDebug(args...) secinfo("feeKey", ## args)
40 *** FEE-style BinaryKey
43 /* constructor with optional existing feePubKey */
44 CryptKit::FEEBinaryKey::FEEBinaryKey(feePubKey feeKey
)
48 mFeeKey
= feePubKeyAlloc();
50 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
55 CryptKit::FEEBinaryKey::~FEEBinaryKey()
58 feePubKeyFree(mFeeKey
);
63 void CryptKit::FEEBinaryKey::generateKeyBlob(
66 CSSM_KEYBLOB_FORMAT
&format
,
67 AppleCSPSession
&session
,
68 const CssmKey
*paramKey
, /* optional, unused here */
69 CSSM_KEYATTR_FLAGS
&attrFlags
) /* IN/OUT */
71 unsigned char *keyBlob
= NULL
;
73 feeReturn frtn
= FR_Internal
;
74 bool freeTheKey
= false;
75 feePubKey keyToEncode
= mFeeKey
;
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
);
86 frtn
= feePubKeyInitPubKeyFromPriv(mFeeKey
, keyToEncode
);
88 feePubKeyFree(keyToEncode
);
89 throwCryptKit(frtn
, "feePubKeyInitPubKeyFromPriv");
94 bool badFormat
= false;
95 int isPrivate
= feePubKeyIsPrivate(keyToEncode
);
97 switch(mKeyHeader
.AlgorithmId
) {
100 /* FEE private key */
102 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST
:
103 format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
105 case CSSM_KEYBLOB_RAW_FORMAT_NONE
:
106 frtn
= feePubKeyCreateDERPrivBlob(keyToEncode
, &keyBlob
, &len
);
108 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
109 frtn
= feePubKeyCreatePrivBlob(keyToEncode
, &keyBlob
, &len
);
119 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST
:
120 format
= CSSM_KEYBLOB_RAW_FORMAT_NONE
;
122 case CSSM_KEYBLOB_RAW_FORMAT_NONE
:
123 frtn
= feePubKeyCreateDERPubBlob(keyToEncode
, &keyBlob
, &len
);
125 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
126 frtn
= feePubKeyCreatePubBlob(keyToEncode
, &keyBlob
, &len
);
133 /* end of base ALGID_FEE */
136 case CSSM_ALGID_ECDSA
:
138 /* ECDSA/ECDH private key */
140 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8
:
141 /* ECDSA private key: PKCS8 */
142 frtn
= feePubKeyCreatePKCS8Blob(keyToEncode
, &keyBlob
, &len
);
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
);
151 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST
:
152 format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
154 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
155 /* raw private key bytes */
156 frtn
= feeCreateECDSAPrivBlob(keyToEncode
, &keyBlob
, &len
);
166 * Note there is no OpenSSL case here, that format is only generated for
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
);
177 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST
:
178 format
= CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
;
180 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
182 frtn
= feeCreateECDSAPubBlob(keyToEncode
, &keyBlob
, &len
);
189 /* end of case CSSM_ALGID_ECDSA */
198 CssmError::throwMe(isPrivate
?
199 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT
:
200 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT
);
203 throwCryptKit(frtn
, "feePubKeyCreate*Blob");
205 setUpCssmData(blob
, len
, allocator
);
206 memmove(blob
.data(), keyBlob
, len
);
210 /* free the temp pub key we created here */
211 feePubKeyFree(keyToEncode
);
216 *** FEE-style AppleKeyPairGenContext
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.
224 void CryptKit::FEEKeyPairGenContext::generate(
225 const Context
&context
,
229 FEEBinaryKey
*pubBinKey
= new FEEBinaryKey();
230 FEEBinaryKey
*privBinKey
= new FEEBinaryKey();
233 AppleKeyPairGenContext::generate(context
,
248 void CryptKit::FEEKeyPairGenContext::generate(const Context
&context
, uint32
, CssmData
¶ms
, uint32
&attrCount
, Context::Attr
* &attrs
) {
249 CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED
);
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
,
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.
264 FEEBinaryKey
&fPubBinKey
=
265 dynamic_cast<FEEBinaryKey
&>(pubBinKey
);
266 FEEBinaryKey
&fPrivBinKey
=
267 dynamic_cast<FEEBinaryKey
&>(privBinKey
);
270 * Two parameters from context. Key size in bits is required;
271 * seed is optional. If not present, we cook up random private data.
273 keyBits
= context
.getInt(CSSM_ATTRIBUTE_KEY_LENGTH
,
274 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH
);
275 CssmCryptoData
*cseed
= context
.get
<CssmCryptoData
>(CSSM_ATTRIBUTE_SEED
);
278 CssmAutoData
aSeed(session()); // malloc on demand
280 /* caller specified seed */
282 seed
= &cseed
->param();
285 /* generate random seed */
287 unsigned keyBytes
= ((keyBits
+ 7) / 8) + 1;
288 aSeed
.malloc(keyBytes
);
289 session().getRandomBytes(keyBytes
, aSeed
);
293 CSSM_ALGORITHMS algId
= context
.algorithm();
295 /* Curve and prime types - optional */
296 feePrimeType primeType
= FPT_Default
;
297 uint32 uPrimeType
= context
.getInt(CSSM_ATTRIBUTE_FEE_PRIME_TYPE
);
299 case CSSM_FEE_PRIME_TYPE_DEFAULT
:
301 case CSSM_FEE_PRIME_TYPE_MERSENNE
:
302 primeType
= FPT_Mersenne
;
304 case CSSM_FEE_PRIME_TYPE_FEE
:
307 case CSSM_FEE_PRIME_TYPE_GENERAL
:
308 primeType
= FPT_General
;
311 /* FIXME - maybe we should be more specific */
312 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS
);
314 feeCurveType curveType
= FCT_Default
;
316 case CSSM_ALGID_ECDSA
:
318 curveType
= FCT_ANSI
;
322 uint32 uCurveType
= context
.getInt(CSSM_ATTRIBUTE_FEE_CURVE_TYPE
);
324 case CSSM_FEE_CURVE_TYPE_DEFAULT
:
326 case CSSM_FEE_CURVE_TYPE_MONTGOMERY
:
327 curveType
= FCT_Montgomery
;
329 case CSSM_FEE_CURVE_TYPE_WEIERSTRASS
:
330 curveType
= FCT_Weierstrass
;
332 case CSSM_FEE_CURVE_TYPE_ANSI_X9_62
:
333 curveType
= FCT_ANSI
;
336 /* FIXME - maybe we should be more specific */
337 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS
);
342 feeReturn frtn
= feePubKeyInitFromPrivDataKeyBits(
343 fPrivBinKey
.feeKey(),
344 (unsigned char *)seed
->data(),
345 (unsigned int)seed
->length(),
350 * our random seed: trust it
351 * caller's seed: hash it
355 throwCryptKit(frtn
, "feePubKeyInitFromPrivDataKeyBits");
357 frtn
= feePubKeyInitPubKeyFromPriv(fPrivBinKey
.feeKey(),
358 fPubBinKey
.feeKey());
360 throwCryptKit(frtn
, "feePubKeyInitPubKeyFromPriv");
366 *** FEE-style CSPKeyInfoProvider.
368 CryptKit::FEEKeyInfoProvider::FEEKeyInfoProvider(
369 const CssmKey
&cssmKey
,
370 AppleCSPSession
&session
) :
371 CSPKeyInfoProvider(cssmKey
, session
)
374 CSPKeyInfoProvider
*FEEKeyInfoProvider::provider(
375 const CssmKey
&cssmKey
,
376 AppleCSPSession
&session
)
378 switch(cssmKey
.algorithm()) {
380 case CSSM_ALGID_ECDSA
:
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 */
393 /* OK, we'll handle this one */
394 return new FEEKeyInfoProvider(cssmKey
, session
);
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
404 feePubKey feeKey
= NULL
;
406 /* first cook up a feePubKey, then drop that into a BinaryKey */
407 feeKey
= rawCssmKeyToFee(mKey
);
408 FEEBinaryKey
*feeBinKey
= new FEEBinaryKey(feeKey
);
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...
418 void CryptKit::FEEKeyInfoProvider::QueryKeySizeInBits(
419 CSSM_KEY_SIZE
&keySize
)
421 feePubKey feeKey
= NULL
;
423 if(mKey
.blobType() != CSSM_KEYBLOB_RAW
) {
424 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT
);
426 feeKey
= rawCssmKeyToFee(mKey
);
427 keySize
.LogicalKeySizeInBits
= feePubKeyBitsize(feeKey
);
428 keySize
.EffectiveKeySizeInBits
= keySize
.LogicalKeySizeInBits
;
429 feePubKeyFree(feeKey
);
433 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST
436 bool CryptKit::FEEKeyInfoProvider::getHashableBlob(
437 Allocator
&allocator
,
438 CssmData
&blob
) // blob to hash goes here
441 * The optimized case, a raw key in the "proper" format already.
443 * FEE public key in default/NONE form (which happens to be DER)
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
);
454 /* caller converts to binary and proceeds */
458 #endif /* CRYPTKIT_CSP_ENABLE */