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 * FEECSPUtils.h - Misc. utility function for FEE/CryptKit CSP.
24 #ifdef CRYPTKIT_CSP_ENABLE
26 #include <security_utilities/debugging.h>
27 #include <security_utilities/logging.h>
28 #include "FEECSPUtils.h"
30 #include <security_cryptkit/feeFunctions.h>
31 #include <security_cryptkit/feePublicKey.h>
33 #define feeMiscDebug(args...) secinfo("feeMisc", ## args)
35 /* Given a FEE error, throw appropriate CssmError */
36 void CryptKit::throwCryptKit(
38 const char *op
) /* optional */
41 Security::Syslog::error("Apple CSP %s: %s", op
, feeReturnString(frtn
));
47 case FR_BadPubKeyString
:
48 case FR_IncompatibleKey
:
50 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
52 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
);
53 case FR_BadSignatureFormat
: /* signature corrupted */
54 CssmError::throwMe(CSSMERR_CSP_INVALID_SIGNATURE
);
55 case FR_InvalidSignature
: /* signature intact, but not valid */
56 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED
);
57 case FR_IllegalArg
: /* illegal argument */
58 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT
);
59 case FR_BadCipherText
: /* malformed ciphertext */
60 case FR_BadEnc64
: /* bad enc64() format */
61 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA
);
62 case FR_Unimplemented
: /* unimplemented function */
63 CssmError::throwMe(CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
);
64 case FR_Memory
: /* unimplemented function */
65 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
66 case FR_ShortPrivData
:
67 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED
);
68 case FR_IllegalCurve
: /* e.g., ECDSA with Montgomery curve */
69 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY
);
71 /* I don't think we should ever see these no matter what the
72 * caller throws at us */
73 case FR_WrongSignatureType
: /* ElGamal vs. ECDSA */
74 case FR_BadUsageName
: /* bad usageName */
75 case FR_BadCipherFile
:
76 case FR_Internal
: /* internal library error */
77 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR
);
83 * -- obtain CSSM key of specified CSSM_ATTRIBUTE_TYPE
84 * -- validate keyClass
85 * -- validate keyUsage
86 * -- convert to feePubKey, allocating the feePubKey if necessary
88 * Returned key can be of algorithm CSSM_ALGID_ECDSA or CSSM_ALGID_FEE;
89 * caller has to verify proper algorithm for operation.
91 feePubKey
CryptKit::contextToFeeKey(
92 const Context
&context
,
93 AppleCSPSession
&session
,
94 CSSM_ATTRIBUTE_TYPE attrType
, // CSSM_ATTRIBUTE_KEY, CSSM_ATTRIBUTE_PUBLIC_KEY
95 CSSM_KEYCLASS keyClass
, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY
96 CSSM_KEYUSE usage
, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc.
97 bool &mallocdKey
) // RETURNED
100 context
.get
<CssmKey
>(attrType
, CSSMERR_CSP_MISSING_ATTR_KEY
);
101 const CSSM_KEYHEADER
&hdr
= cssmKey
.KeyHeader
;
102 switch(hdr
.AlgorithmId
) {
104 case CSSM_ALGID_ECDSA
:
107 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH
);
109 if(hdr
.KeyClass
!= keyClass
) {
110 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
112 cspValidateIntendedKeyUsage(&hdr
, usage
);
113 cspVerifyKeyTimes(hdr
);
114 return cssmKeyToFee(cssmKey
, session
, mallocdKey
);
118 * Convert a CssmKey to a feePubKey. May result in the creation of a new
119 * feePubKey (when cssmKey is a raw key); allocdKey is true in that case
120 * in which case the caller generally has to free the allocd key).
122 feePubKey
CryptKit::cssmKeyToFee(
123 const CssmKey
&cssmKey
,
124 AppleCSPSession
&session
,
125 bool &allocdKey
) // RETURNED
127 feePubKey feeKey
= NULL
;
130 const CSSM_KEYHEADER
*hdr
= &cssmKey
.KeyHeader
;
131 switch(hdr
->AlgorithmId
) {
133 case CSSM_ALGID_ECDSA
:
136 // someone else's key (should never happen)
137 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
139 switch(hdr
->BlobType
) {
140 case CSSM_KEYBLOB_RAW
:
141 feeKey
= rawCssmKeyToFee(cssmKey
);
144 case CSSM_KEYBLOB_REFERENCE
:
146 BinaryKey
&binKey
= session
.lookupRefKey(cssmKey
);
147 FEEBinaryKey
*feeBinKey
= dynamic_cast<FEEBinaryKey
*>(&binKey
);
148 /* this cast failing means that this is some other
149 * kind of binary key */
150 if(feeBinKey
== NULL
) {
151 feeMiscDebug("CryptKit::cssmKeyToFee: wrong BinaryKey subclass\n");
152 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
154 assert(feeBinKey
->feeKey() != NULL
);
155 feeKey
= feeBinKey
->feeKey();
159 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT
);
165 * Convert a raw CssmKey to a newly alloc'd feePubKey.
167 feePubKey
CryptKit::rawCssmKeyToFee(
168 const CssmKey
&cssmKey
)
170 const CSSM_KEYHEADER
*hdr
= &cssmKey
.KeyHeader
;
171 assert(hdr
->BlobType
== CSSM_KEYBLOB_RAW
);
173 switch(hdr
->AlgorithmId
) {
175 case CSSM_ALGID_ECDSA
:
178 // someone else's key (should never happen)
179 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM
);
182 switch(hdr
->KeyClass
) {
183 case CSSM_KEYCLASS_PUBLIC_KEY
:
184 case CSSM_KEYCLASS_PRIVATE_KEY
:
187 // someone else's key
188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS
);
191 feePubKey feeKey
= feePubKeyAlloc();
193 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR
);
196 feeReturn frtn
= FR_IllegalArg
;
197 bool badFormat
= false;
200 * The actual key init depends on key type and incoming format
202 switch(hdr
->AlgorithmId
) {
204 switch(hdr
->KeyClass
) {
205 case CSSM_KEYCLASS_PUBLIC_KEY
:
206 switch(hdr
->Format
) {
207 case FEE_KEYBLOB_DEFAULT_FORMAT
:
208 /* FEE, public key, default: custom DER */
209 frtn
= feePubKeyInitFromDERPubBlob(feeKey
,
210 cssmKey
.KeyData
.Data
,
211 cssmKey
.KeyData
.Length
);
213 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
214 /* FEE, public key, native byte stream */
215 frtn
= feePubKeyInitFromPubBlob(feeKey
,
216 cssmKey
.KeyData
.Data
,
217 (unsigned int)cssmKey
.KeyData
.Length
);
224 case CSSM_KEYCLASS_PRIVATE_KEY
:
225 switch(hdr
->Format
) {
226 case FEE_KEYBLOB_DEFAULT_FORMAT
:
227 /* FEE, private key, default: custom DER */
228 frtn
= feePubKeyInitFromDERPrivBlob(feeKey
,
229 cssmKey
.KeyData
.Data
,
230 cssmKey
.KeyData
.Length
);
232 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
233 /* FEE, private key, native byte stream */
234 frtn
= feePubKeyInitFromPrivBlob(feeKey
,
235 cssmKey
.KeyData
.Data
,
236 (unsigned int)cssmKey
.KeyData
.Length
);
244 /* not reached, we already checked */
247 /* end of case ALGID_FEE */
250 case CSSM_ALGID_ECDSA
:
251 switch(hdr
->KeyClass
) {
252 case CSSM_KEYCLASS_PUBLIC_KEY
:
253 switch(hdr
->Format
) {
254 case CSSM_KEYBLOB_RAW_FORMAT_NONE
:
255 case CSSM_KEYBLOB_RAW_FORMAT_X509
:
256 /* ECDSA, public key, default: X509 */
257 frtn
= feePubKeyInitFromX509Blob(feeKey
,
258 cssmKey
.KeyData
.Data
,
259 cssmKey
.KeyData
.Length
);
262 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
:
264 * An oddity here: we can parse this incoming key, but
265 * it contains both private and public parts. We throw
266 * out the private component here.
268 frtn
= feePubKeyInitFromOpenSSLBlob(feeKey
,
270 cssmKey
.KeyData
.Data
,
271 cssmKey
.KeyData
.Length
);
274 * NOTE: we cannot *import* a key in raw X9.62 format.
275 * We'd need to know the curve, i.e., the feeDepth.
276 * I suppose we could infer that from the blob length but
277 * a better way would be to have a new context attribute
278 * specifying which curve.
279 * For now, imported raw keys have to be in X509 format.
281 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
287 case CSSM_KEYCLASS_PRIVATE_KEY
:
288 switch(hdr
->Format
) {
289 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8
:
290 /* ECDSA, private key, PKCS8 */
291 frtn
= feePubKeyInitFromPKCS8Blob(feeKey
,
292 cssmKey
.KeyData
.Data
,
293 cssmKey
.KeyData
.Length
);
296 case CSSM_KEYBLOB_RAW_FORMAT_NONE
:
297 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL
:
298 /* ECDSA, private, default: OpenSSL */
299 /* see comment above re: OpenSSL public/private keys */
300 frtn
= feePubKeyInitFromOpenSSLBlob(feeKey
,
302 cssmKey
.KeyData
.Data
,
303 cssmKey
.KeyData
.Length
);
305 /* see comment above about X9.62 format public key blobs */
306 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING
:
313 /* not reached, we already checked */
316 /* end of case CSSM_ALGID_ECDSA */
320 CssmError::throwMe(hdr
->KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
?
321 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT
:
322 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT
);
325 feePubKeyFree(feeKey
);
326 throwCryptKit(frtn
, "feePubKeyInitFromKeyBlob");
332 * Glue function which allows C code to use AppleCSPSession
333 * as an RNG. A ptr to this function gets passed down to
334 * CryptKit C functions as a feeRandFcn.
336 feeReturn
CryptKit::feeRandCallback(
337 void *ref
, // actually an AppleCSPSession *
338 unsigned char *bytes
, // must be alloc'd by caller
341 AppleCSPSession
*session
=
342 reinterpret_cast<AppleCSPSession
*>(ref
);
344 session
->getRandomBytes(numBytes
, bytes
);
352 #endif /* CRYPTKIT_CSP_ENABLE */