]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/FEECSPUtils.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / FEECSPUtils.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 * FEECSPUtils.h - Misc. utility function for FEE/CryptKit CSP.
21 *
22 */
23
24 #ifdef CRYPTKIT_CSP_ENABLE
25
26 #include <security_utilities/debugging.h>
27 #include <security_utilities/logging.h>
28 #include "FEECSPUtils.h"
29 #include "FEEKeys.h"
30 #include <security_cryptkit/feeFunctions.h>
31 #include <security_cryptkit/feePublicKey.h>
32
33 #define feeMiscDebug(args...) secinfo("feeMisc", ## args)
34
35 /* Given a FEE error, throw appropriate CssmError */
36 void CryptKit::throwCryptKit(
37 feeReturn frtn,
38 const char *op) /* optional */
39 {
40 if(op) {
41 Security::Syslog::error("Apple CSP %s: %s", op, feeReturnString(frtn));
42 }
43 switch(frtn) {
44 case FR_Success:
45 return;
46 case FR_BadPubKey:
47 case FR_BadPubKeyString:
48 case FR_IncompatibleKey:
49 case FR_BadKeyBlob:
50 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
51 case FR_IllegalDepth:
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);
70
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);
78 }
79 }
80
81 /*
82 * Given a Context:
83 * -- obtain CSSM key of specified CSSM_ATTRIBUTE_TYPE
84 * -- validate keyClass
85 * -- validate keyUsage
86 * -- convert to feePubKey, allocating the feePubKey if necessary
87 *
88 * Returned key can be of algorithm CSSM_ALGID_ECDSA or CSSM_ALGID_FEE;
89 * caller has to verify proper algorithm for operation.
90 */
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
98 {
99 CssmKey &cssmKey =
100 context.get<CssmKey>(attrType, CSSMERR_CSP_MISSING_ATTR_KEY);
101 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
102 switch(hdr.AlgorithmId) {
103 case CSSM_ALGID_FEE:
104 case CSSM_ALGID_ECDSA:
105 break;
106 default:
107 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
108 }
109 if(hdr.KeyClass != keyClass) {
110 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
111 }
112 cspValidateIntendedKeyUsage(&hdr, usage);
113 cspVerifyKeyTimes(hdr);
114 return cssmKeyToFee(cssmKey, session, mallocdKey);
115 }
116
117 /*
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).
121 */
122 feePubKey CryptKit::cssmKeyToFee(
123 const CssmKey &cssmKey,
124 AppleCSPSession &session,
125 bool &allocdKey) // RETURNED
126 {
127 feePubKey feeKey = NULL;
128 allocdKey = false;
129
130 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
131 switch(hdr->AlgorithmId) {
132 case CSSM_ALGID_FEE:
133 case CSSM_ALGID_ECDSA:
134 break;
135 default:
136 // someone else's key (should never happen)
137 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
138 }
139 switch(hdr->BlobType) {
140 case CSSM_KEYBLOB_RAW:
141 feeKey = rawCssmKeyToFee(cssmKey);
142 allocdKey = true;
143 break;
144 case CSSM_KEYBLOB_REFERENCE:
145 {
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);
153 }
154 assert(feeBinKey->feeKey() != NULL);
155 feeKey = feeBinKey->feeKey();
156 break;
157 }
158 default:
159 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
160 }
161 return feeKey;
162 }
163
164 /*
165 * Convert a raw CssmKey to a newly alloc'd feePubKey.
166 */
167 feePubKey CryptKit::rawCssmKeyToFee(
168 const CssmKey &cssmKey)
169 {
170 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
171 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
172
173 switch(hdr->AlgorithmId) {
174 case CSSM_ALGID_FEE:
175 case CSSM_ALGID_ECDSA:
176 break;
177 default:
178 // someone else's key (should never happen)
179 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
180 }
181
182 switch(hdr->KeyClass) {
183 case CSSM_KEYCLASS_PUBLIC_KEY:
184 case CSSM_KEYCLASS_PRIVATE_KEY:
185 break;
186 default:
187 // someone else's key
188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
189 }
190
191 feePubKey feeKey = feePubKeyAlloc();
192 if(feeKey == NULL) {
193 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
194 }
195
196 feeReturn frtn = FR_IllegalArg;
197 bool badFormat = false;
198
199 /*
200 * The actual key init depends on key type and incoming format
201 */
202 switch(hdr->AlgorithmId) {
203 case CSSM_ALGID_FEE:
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);
212 break;
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);
218 break;
219 default:
220 badFormat = true;
221 break;
222 }
223 break;
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);
231 break;
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);
237 break;
238 default:
239 badFormat = true;
240 break;
241 }
242 break;
243 default:
244 /* not reached, we already checked */
245 break;
246 }
247 /* end of case ALGID_FEE */
248 break;
249
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);
260 break;
261
262 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
263 /*
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.
267 */
268 frtn = feePubKeyInitFromOpenSSLBlob(feeKey,
269 1, /* pubOnly */
270 cssmKey.KeyData.Data,
271 cssmKey.KeyData.Length);
272 break;
273 /*
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.
280 */
281 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
282 default:
283 badFormat = true;
284 break;
285 }
286 break;
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);
294 break;
295
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,
301 0, /* pubOnly */
302 cssmKey.KeyData.Data,
303 cssmKey.KeyData.Length);
304 break;
305 /* see comment above about X9.62 format public key blobs */
306 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
307 default:
308 badFormat = true;
309 break;
310 }
311 break;
312 default:
313 /* not reached, we already checked */
314 break;
315 }
316 /* end of case CSSM_ALGID_ECDSA */
317 break;
318 }
319 if(badFormat) {
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);
323 }
324 if(frtn) {
325 feePubKeyFree(feeKey);
326 throwCryptKit(frtn, "feePubKeyInitFromKeyBlob");
327 }
328 return feeKey;
329 }
330
331 /*
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.
335 */
336 feeReturn CryptKit::feeRandCallback(
337 void *ref, // actually an AppleCSPSession *
338 unsigned char *bytes, // must be alloc'd by caller
339 unsigned numBytes)
340 {
341 AppleCSPSession *session =
342 reinterpret_cast<AppleCSPSession *>(ref);
343 try {
344 session->getRandomBytes(numBytes, bytes);
345 }
346 catch(...) {
347 return FR_Internal;
348 }
349 return FR_Success;
350 }
351
352 #endif /* CRYPTKIT_CSP_ENABLE */