]> git.saurik.com Git - apple/security.git/blob - libsecurity_apple_csp/lib/FEECSPUtils.cpp
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_apple_csp / lib / FEECSPUtils.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 * Created 2/20/2001 by dmitch.
23 */
24
25 #ifdef CRYPTKIT_CSP_ENABLE
26
27 #include <security_utilities/debugging.h>
28 #include <security_utilities/logging.h>
29 #include "FEECSPUtils.h"
30 #include "FEEKeys.h"
31 #include <security_cryptkit/feeFunctions.h>
32 #include <security_cryptkit/feePublicKey.h>
33
34 #define feeMiscDebug(args...) secdebug("feeMisc", ## args)
35
36 /* Given a FEE error, throw appropriate CssmError */
37 void CryptKit::throwCryptKit(
38 feeReturn frtn,
39 const char *op) /* optional */
40 {
41 if(op) {
42 Security::Syslog::error("Apple CSP %s: %s", op, feeReturnString(frtn));
43 }
44 switch(frtn) {
45 case FR_Success:
46 return;
47 case FR_BadPubKey:
48 case FR_BadPubKeyString:
49 case FR_IncompatibleKey:
50 case FR_BadKeyBlob:
51 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
52 case FR_IllegalDepth:
53 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE);
54 case FR_BadSignatureFormat: /* signature corrupted */
55 CssmError::throwMe(CSSMERR_CSP_INVALID_SIGNATURE);
56 case FR_InvalidSignature: /* signature intact, but not valid */
57 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED);
58 case FR_IllegalArg: /* illegal argument */
59 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT);
60 case FR_BadCipherText: /* malformed ciphertext */
61 case FR_BadEnc64: /* bad enc64() format */
62 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
63 case FR_Unimplemented: /* unimplemented function */
64 CssmError::throwMe(CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED);
65 case FR_Memory: /* unimplemented function */
66 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
67 case FR_ShortPrivData:
68 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED);
69 case FR_IllegalCurve: /* e.g., ECDSA with Montgomery curve */
70 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY);
71
72 /* I don't think we should ever see these no matter what the
73 * caller throws at us */
74 case FR_WrongSignatureType: /* ElGamal vs. ECDSA */
75 case FR_BadUsageName: /* bad usageName */
76 case FR_BadCipherFile:
77 case FR_Internal: /* internal library error */
78 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
79 }
80 }
81
82 /*
83 * Given a Context:
84 * -- obtain CSSM key of specified CSSM_ATTRIBUTE_TYPE
85 * -- validate keyClass
86 * -- validate keyUsage
87 * -- convert to feePubKey, allocating the feePubKey if necessary
88 *
89 * Returned key can be of algorithm CSSM_ALGID_ECDSA or CSSM_ALGID_FEE;
90 * caller has to verify proper algorithm for operation.
91 */
92 feePubKey CryptKit::contextToFeeKey(
93 const Context &context,
94 AppleCSPSession &session,
95 CSSM_ATTRIBUTE_TYPE attrType, // CSSM_ATTRIBUTE_KEY, CSSM_ATTRIBUTE_PUBLIC_KEY
96 CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY
97 CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc.
98 bool &mallocdKey) // RETURNED
99 {
100 CssmKey &cssmKey =
101 context.get<CssmKey>(attrType, CSSMERR_CSP_MISSING_ATTR_KEY);
102 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader;
103 switch(hdr.AlgorithmId) {
104 case CSSM_ALGID_FEE:
105 case CSSM_ALGID_ECDSA:
106 break;
107 default:
108 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH);
109 }
110 if(hdr.KeyClass != keyClass) {
111 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
112 }
113 cspValidateIntendedKeyUsage(&hdr, usage);
114 cspVerifyKeyTimes(hdr);
115 return cssmKeyToFee(cssmKey, session, mallocdKey);
116 }
117
118 /*
119 * Convert a CssmKey to a feePubKey. May result in the creation of a new
120 * feePubKey (when cssmKey is a raw key); allocdKey is true in that case
121 * in which case the caller generally has to free the allocd key).
122 */
123 feePubKey CryptKit::cssmKeyToFee(
124 const CssmKey &cssmKey,
125 AppleCSPSession &session,
126 bool &allocdKey) // RETURNED
127 {
128 feePubKey feeKey = NULL;
129 allocdKey = false;
130
131 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
132 switch(hdr->AlgorithmId) {
133 case CSSM_ALGID_FEE:
134 case CSSM_ALGID_ECDSA:
135 break;
136 default:
137 // someone else's key (should never happen)
138 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
139 }
140 switch(hdr->BlobType) {
141 case CSSM_KEYBLOB_RAW:
142 feeKey = rawCssmKeyToFee(cssmKey);
143 allocdKey = true;
144 break;
145 case CSSM_KEYBLOB_REFERENCE:
146 {
147 BinaryKey &binKey = session.lookupRefKey(cssmKey);
148 FEEBinaryKey *feeBinKey = dynamic_cast<FEEBinaryKey *>(&binKey);
149 /* this cast failing means that this is some other
150 * kind of binary key */
151 if(feeBinKey == NULL) {
152 feeMiscDebug("CryptKit::cssmKeyToFee: wrong BinaryKey subclass\n");
153 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
154 }
155 assert(feeBinKey->feeKey() != NULL);
156 feeKey = feeBinKey->feeKey();
157 break;
158 }
159 default:
160 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT);
161 }
162 return feeKey;
163 }
164
165 /*
166 * Convert a raw CssmKey to a newly alloc'd feePubKey.
167 */
168 feePubKey CryptKit::rawCssmKeyToFee(
169 const CssmKey &cssmKey)
170 {
171 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader;
172 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
173
174 switch(hdr->AlgorithmId) {
175 case CSSM_ALGID_FEE:
176 case CSSM_ALGID_ECDSA:
177 break;
178 default:
179 // someone else's key (should never happen)
180 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM);
181 }
182
183 switch(hdr->KeyClass) {
184 case CSSM_KEYCLASS_PUBLIC_KEY:
185 case CSSM_KEYCLASS_PRIVATE_KEY:
186 break;
187 default:
188 // someone else's key
189 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS);
190 }
191
192 feePubKey feeKey = feePubKeyAlloc();
193 if(feeKey == NULL) {
194 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR);
195 }
196
197 feeReturn frtn = FR_IllegalArg;
198 bool badFormat = false;
199
200 /*
201 * The actual key init depends on key type and incoming format
202 */
203 switch(hdr->AlgorithmId) {
204 case CSSM_ALGID_FEE:
205 switch(hdr->KeyClass) {
206 case CSSM_KEYCLASS_PUBLIC_KEY:
207 switch(hdr->Format) {
208 case FEE_KEYBLOB_DEFAULT_FORMAT:
209 /* FEE, public key, default: custom DER */
210 frtn = feePubKeyInitFromDERPubBlob(feeKey,
211 cssmKey.KeyData.Data,
212 cssmKey.KeyData.Length);
213 break;
214 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
215 /* FEE, public key, native byte stream */
216 frtn = feePubKeyInitFromPubBlob(feeKey,
217 cssmKey.KeyData.Data,
218 cssmKey.KeyData.Length);
219 break;
220 default:
221 badFormat = true;
222 break;
223 }
224 break;
225 case CSSM_KEYCLASS_PRIVATE_KEY:
226 switch(hdr->Format) {
227 case FEE_KEYBLOB_DEFAULT_FORMAT:
228 /* FEE, private key, default: custom DER */
229 frtn = feePubKeyInitFromDERPrivBlob(feeKey,
230 cssmKey.KeyData.Data,
231 cssmKey.KeyData.Length);
232 break;
233 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
234 /* FEE, private key, native byte stream */
235 frtn = feePubKeyInitFromPrivBlob(feeKey,
236 cssmKey.KeyData.Data,
237 cssmKey.KeyData.Length);
238 break;
239 default:
240 badFormat = true;
241 break;
242 }
243 break;
244 default:
245 /* not reached, we already checked */
246 break;
247 }
248 /* end of case ALGID_FEE */
249 break;
250
251 case CSSM_ALGID_ECDSA:
252 switch(hdr->KeyClass) {
253 case CSSM_KEYCLASS_PUBLIC_KEY:
254 switch(hdr->Format) {
255 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
256 case CSSM_KEYBLOB_RAW_FORMAT_X509:
257 /* ECDSA, public key, default: X509 */
258 frtn = feePubKeyInitFromX509Blob(feeKey,
259 cssmKey.KeyData.Data,
260 cssmKey.KeyData.Length);
261 break;
262
263 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
264 /*
265 * An oddity here: we can parse this incoming key, but
266 * it contains both private and public parts. We throw
267 * out the private component here.
268 */
269 frtn = feePubKeyInitFromOpenSSLBlob(feeKey,
270 1, /* pubOnly */
271 cssmKey.KeyData.Data,
272 cssmKey.KeyData.Length);
273 break;
274 /*
275 * NOTE: we cannot *import* a key in raw X9.62 format.
276 * We'd need to know the curve, i.e., the feeDepth.
277 * I suppose we could infer that from the blob length but
278 * a better way would be to have a new context attribute
279 * specifying which curve.
280 * For now, imported raw keys have to be in X509 format.
281 */
282 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
283 default:
284 badFormat = true;
285 break;
286 }
287 break;
288 case CSSM_KEYCLASS_PRIVATE_KEY:
289 switch(hdr->Format) {
290 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8:
291 /* ECDSA, private key, PKCS8 */
292 frtn = feePubKeyInitFromPKCS8Blob(feeKey,
293 cssmKey.KeyData.Data,
294 cssmKey.KeyData.Length);
295 break;
296
297 case CSSM_KEYBLOB_RAW_FORMAT_NONE:
298 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL:
299 /* ECDSA, private, default: OpenSSL */
300 /* see comment above re: OpenSSL public/private keys */
301 frtn = feePubKeyInitFromOpenSSLBlob(feeKey,
302 0, /* pubOnly */
303 cssmKey.KeyData.Data,
304 cssmKey.KeyData.Length);
305 break;
306 /* see comment above about X9.62 format public key blobs */
307 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING:
308 default:
309 badFormat = true;
310 break;
311 }
312 break;
313 default:
314 /* not reached, we already checked */
315 break;
316 }
317 /* end of case CSSM_ALGID_ECDSA */
318 break;
319 }
320 if(badFormat) {
321 CssmError::throwMe(hdr->KeyClass == CSSM_KEYCLASS_PRIVATE_KEY ?
322 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT :
323 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT);
324 }
325 if(frtn) {
326 feePubKeyFree(feeKey);
327 throwCryptKit(frtn, "feePubKeyInitFromKeyBlob");
328 }
329 return feeKey;
330 }
331
332 /*
333 * Glue function which allows C code to use AppleCSPSession
334 * as an RNG. A ptr to this function gets passed down to
335 * CryptKit C functions as a feeRandFcn.
336 */
337 feeReturn CryptKit::feeRandCallback(
338 void *ref, // actually an AppleCSPSession *
339 unsigned char *bytes, // must be alloc'd by caller
340 unsigned numBytes)
341 {
342 AppleCSPSession *session =
343 reinterpret_cast<AppleCSPSession *>(ref);
344 try {
345 session->getRandomBytes(numBytes, bytes);
346 }
347 catch(...) {
348 return FR_Internal;
349 }
350 return FR_Success;
351 }
352
353 #endif /* CRYPTKIT_CSP_ENABLE */