]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
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 | // AppleCSPUtils.cpp - CSP-wide utility functions | |
21 | // | |
22 | ||
23 | #include "AppleCSPUtils.h" | |
24 | #include <Security/cssmerr.h> | |
25 | #include <security_utilities/alloc.h> | |
26 | #include <security_cdsa_utilities/cssmdates.h> | |
27 | #include <string.h> | |
28 | #include <FEECSPUtils.h> | |
29 | #include <SHA1_MD5_Object.h> | |
30 | #include "RSA_DSA_keys.h" | |
31 | #include <syslog.h> | |
32 | ||
33 | /* | |
34 | * Validate key attribute bits per specified key type. | |
35 | * | |
36 | * Used to check requested key attributes for new keys and for validating | |
37 | * incoming existing keys. For checking key attributes for new keys, | |
38 | * assumes that KEYATTR_RETURN_xxx bits have been checked elsewhere | |
39 | * and stripped off before coming here. | |
40 | */ | |
41 | void cspValidateKeyAttr( | |
42 | cspKeyType keyType, | |
43 | uint32 keyAttr) | |
44 | { | |
45 | uint32 sensitiveBit = (keyAttr & CSSM_KEYATTR_SENSITIVE) ? 1 : 0; | |
46 | uint32 extractBit = (keyAttr & CSSM_KEYATTR_EXTRACTABLE) ? 1 : 0; | |
47 | ||
48 | /* first general CSP-wide checks */ | |
49 | if(keyAttr & KEY_ATTR_RETURN_MASK) { | |
50 | //errorLog0(" KEY_ATTR_RETURN bits set\n"); | |
51 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
52 | } | |
53 | if(keyAttr & CSSM_KEYATTR_PERMANENT) { | |
54 | //errorLog0(" PERMANENT bit not supported\n"); | |
55 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK); | |
56 | } | |
57 | if(keyAttr & CSSM_KEYATTR_PRIVATE) { | |
58 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK); | |
59 | } | |
60 | /* Anything else? */ | |
61 | ||
62 | /* now check per keyType */ | |
63 | switch(keyType) { | |
64 | case CKT_Session: | |
65 | break; | |
66 | ||
67 | case CKT_Public: | |
68 | if(sensitiveBit || !extractBit) { | |
69 | //errorLog0("Public keys must be extractable in the clear\n"); | |
70 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
71 | } | |
72 | break; | |
73 | ||
74 | case CKT_Private: | |
75 | //if(!sensitiveBit) { | |
76 | // errorLog0("Private keys must have KEYATTR_SENSITIVE\n"); | |
77 | // CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
78 | //} | |
79 | ||
80 | /* | |
81 | * One more restriction - EXTRACTABLE - caller must check since | |
82 | * that involves KEYUSE bits. | |
83 | */ | |
84 | break; | |
85 | default: | |
86 | CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); | |
87 | } | |
88 | return; | |
89 | } | |
90 | ||
91 | /* | |
92 | * Perform sanity check of incoming key attribute bits for a given | |
93 | * key type, and return a cspKeyStorage value. | |
94 | * | |
95 | * Called from any routine which generates a new key. This specifically | |
96 | * excludes WrapKey(). | |
97 | */ | |
98 | cspKeyStorage cspParseKeyAttr( | |
99 | cspKeyType keyType, | |
100 | uint32 keyAttr) | |
101 | { | |
102 | uint32 sensitiveBit = (keyAttr & CSSM_KEYATTR_SENSITIVE) ? 1 : 0; | |
103 | uint32 rtnDataBit = (keyAttr & CSSM_KEYATTR_RETURN_DATA) ? 1 : 0; | |
104 | uint32 rtnRefBit = (keyAttr & CSSM_KEYATTR_RETURN_REF) ? 1 : 0; | |
105 | uint32 extractBit = (keyAttr & CSSM_KEYATTR_EXTRACTABLE) ? 1 : 0; | |
106 | ||
107 | cspKeyStorage rtn; | |
108 | ||
109 | /* first general CDSA-wide checks */ | |
110 | if(keyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE | | |
111 | CSSM_KEYATTR_NEVER_EXTRACTABLE)) { | |
112 | //errorLog0("ALWAYS_SENSITIVE, NEVER_EXTRACTABLE illegal at SPI\n"); | |
113 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
114 | } | |
115 | switch(keyAttr & KEY_ATTR_RETURN_MASK) { | |
116 | /* ensure only one bit is set */ | |
117 | case CSSM_KEYATTR_RETURN_DATA: | |
118 | rtn = CKS_Data; | |
119 | break; | |
120 | case CSSM_KEYATTR_RETURN_REF: | |
121 | rtn = CKS_Ref; | |
122 | break; | |
123 | case CSSM_KEYATTR_RETURN_NONE: | |
124 | rtn = CKS_None; | |
125 | break; | |
126 | case CSSM_KEYATTR_RETURN_DEFAULT: | |
127 | /* CSP default */ | |
128 | rtnRefBit = 1; | |
129 | rtn = CKS_Ref; | |
130 | break; | |
131 | default: | |
132 | //errorLog0("Multiple KEYATTR_RETURN bits set\n"); | |
133 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
134 | } | |
135 | ||
136 | /* now CSP-wide checks for all key types */ | |
137 | if(keyType != CKT_Session) { | |
138 | /* session keys modifiable, no others are */ | |
139 | if(keyAttr & CSSM_KEYATTR_MODIFIABLE) { | |
140 | //errorLog0("CSSM_KEYATTR_MODIFIABLE not supported\n"); | |
141 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
142 | } | |
143 | } | |
144 | if(rtnDataBit) { | |
145 | if(!extractBit) { | |
146 | //errorLog0("RETURN_DATA and !EXTRACTABLE not supported\n"); | |
147 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
148 | } | |
149 | if(sensitiveBit) { | |
150 | //errorLog0("RETURN_DATA and SENSITIVE not supported\n"); | |
151 | CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); | |
152 | } | |
153 | } | |
154 | ||
155 | /* now check per keyType. We're ust checking for things specific | |
156 | * to KEYATTR_RETURN_xxx; cspValidateKeyAttr will check other fields. */ | |
157 | #if 0 | |
158 | // nothing for now | |
159 | switch(keyType) { | |
160 | case CKT_Session: | |
161 | break; | |
162 | ||
163 | case MKT_Public: | |
164 | break; | |
165 | ||
166 | case MKT_Private: | |
167 | if(rtnDataBit) { | |
168 | errorLog0("Private keys must be generated by ref\n"); | |
169 | goto errorOut; | |
170 | } | |
171 | /* | |
172 | * One more restriction - EXTRACTABLE - caller must check since | |
173 | * that involves KEYUSE bits. | |
174 | */ | |
175 | break; | |
176 | default: | |
177 | CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); | |
178 | } | |
179 | #endif // 0 | |
180 | ||
181 | /* validate other common static attributes */ | |
182 | cspValidateKeyAttr(keyType, (keyAttr & ~KEY_ATTR_RETURN_MASK)); | |
183 | return rtn; | |
184 | } | |
185 | ||
186 | ||
187 | /* used in cspValidateKeyUsageBits() */ | |
188 | /* | |
189 | * This is a vestige from OS9/ASA. In the real world there are in fact certs with | |
190 | * keyUsage extensions which specify, e.g., verify and wrap. I think we'll just | |
191 | * have to ignore the old exclusivity rules. | |
192 | */ | |
193 | #define IGNORE_KEYUSE_EXCLUSIVITY 1 | |
194 | #if IGNORE_KEYUSE_EXCLUSIVITY | |
195 | #define checkExclusiveUsage(ku, cb, ob, em) | |
196 | #else | |
197 | static void checkExclusiveUsage( | |
198 | uint32 keyUsage, // requested usage word | |
199 | uint32 checkBits, // if any of these are set | |
200 | uint32 otherBits, // these are the only other bits which can be set | |
201 | const char *errMsg) | |
202 | { | |
203 | if(keyUsage & checkBits) { | |
204 | if(keyUsage & ~otherBits) { | |
205 | errorLog0((char *)errMsg); | |
206 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
207 | } | |
208 | } | |
209 | } | |
210 | #endif /* IGNORE_KEYUSE_EXCLUSIVITY */ | |
211 | ||
212 | /* | |
213 | * Validate key usage bits for specified key type. | |
214 | */ | |
215 | void cspValidateKeyUsageBits ( | |
216 | cspKeyType keyType, | |
217 | uint32 keyUsage) | |
218 | { | |
219 | /* general restrictions */ | |
220 | checkExclusiveUsage(keyUsage, | |
221 | CSSM_KEYUSE_ANY, | |
222 | CSSM_KEYUSE_ANY, | |
223 | "CSSM_KEYUSE_ANY overload"); | |
224 | checkExclusiveUsage(keyUsage, | |
225 | CSSM_KEYUSE_DERIVE, | |
226 | CSSM_KEYUSE_DERIVE, | |
227 | "CSSM_KEYUSE_DERIVE overload\n"); | |
228 | ||
229 | /* brute force per key type. */ | |
230 | switch(keyType) { | |
231 | case CKT_Session: | |
232 | checkExclusiveUsage(keyUsage, | |
233 | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, | |
234 | CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT, | |
235 | "session key usage: encrypt/decrypt overload\n"); | |
236 | checkExclusiveUsage(keyUsage, | |
237 | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY | | |
238 | CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER, | |
239 | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY | | |
240 | CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER, | |
241 | "session key usage: sign/verify overload\n"); | |
242 | checkExclusiveUsage(keyUsage, | |
243 | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP, | |
244 | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP, | |
245 | "session key usage: wrap/unwrap overload\n"); | |
246 | break; | |
247 | ||
248 | case CKT_Public: | |
249 | checkExclusiveUsage(keyUsage, | |
250 | CSSM_KEYUSE_ENCRYPT, | |
251 | CSSM_KEYUSE_ENCRYPT, | |
252 | "public key usage: encrypt overload\n"); | |
253 | if(keyUsage & CSSM_KEYUSE_DECRYPT) { | |
254 | errorLog0("public key usage: DECRYPT illegal\n"); | |
255 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
256 | } | |
257 | if(keyUsage & (CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER)) { | |
258 | errorLog0("public key usage: SIGN illegal\n"); | |
259 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
260 | } | |
261 | checkExclusiveUsage(keyUsage, | |
262 | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER, | |
263 | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER, | |
264 | "public key usage: verify overload\n"); | |
265 | checkExclusiveUsage(keyUsage, | |
266 | CSSM_KEYUSE_WRAP, | |
267 | CSSM_KEYUSE_WRAP, | |
268 | "public key usage: wrap overload\n"); | |
269 | if(keyUsage & CSSM_KEYUSE_UNWRAP) { | |
270 | errorLog0("public key usage: UNWRAP illegal\n"); | |
271 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
272 | } | |
273 | break; | |
274 | ||
275 | case CKT_Private: | |
276 | if(keyUsage & CSSM_KEYUSE_ENCRYPT) { | |
277 | errorLog0("private key usage: ENCRYPT illegal\n"); | |
278 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
279 | } | |
280 | checkExclusiveUsage(keyUsage, | |
281 | CSSM_KEYUSE_DECRYPT, | |
282 | CSSM_KEYUSE_DECRYPT, | |
283 | "private key usage: decrypt overload\n"); | |
284 | checkExclusiveUsage(keyUsage, | |
285 | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER, | |
286 | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER, | |
287 | "private key usage: sign overload\n"); | |
288 | if(keyUsage & (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER)) { | |
289 | errorLog0("private key usage: VERIFY illegal\n"); | |
290 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
291 | } | |
292 | if(keyUsage & CSSM_KEYUSE_WRAP) { | |
293 | errorLog0("private key usage: WRAP illegal\n"); | |
294 | CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK); | |
295 | } | |
296 | checkExclusiveUsage(keyUsage, | |
297 | CSSM_KEYUSE_UNWRAP, | |
298 | CSSM_KEYUSE_UNWRAP, | |
299 | "private key usage: unwrap overload\n"); | |
300 | break; | |
301 | default: | |
302 | CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); | |
303 | } | |
304 | } | |
305 | ||
306 | /* | |
307 | * Validate existing key's usage bits against intended use. | |
308 | */ | |
309 | ||
310 | /* | |
311 | * For now, a key marked for KEYUSE_{WRAP|UNWRAP} can also be used for | |
312 | * KEYUSE_{ENCRYPT|DECRYPT}. This is a temporary workaround for | |
313 | * Radar 2716153. | |
314 | */ | |
315 | #define RELAXED_WRAP_USAGE 1 | |
316 | ||
317 | void cspValidateIntendedKeyUsage( | |
318 | const CSSM_KEYHEADER *hdr, | |
319 | CSSM_KEYUSE intendedUsage) | |
320 | { | |
321 | uint32 keyUsage = hdr->KeyUsage; | |
322 | cspKeyType keyType; | |
323 | ||
324 | /* first, the obvious */ | |
325 | if(keyUsage & CSSM_KEYUSE_ANY) { | |
326 | /* OK for now */ | |
327 | return; | |
328 | } | |
329 | if(!(keyUsage & intendedUsage)) { | |
330 | #if RELAXED_WRAP_USAGE | |
331 | if(! ( ( (keyUsage & CSSM_KEYUSE_WRAP) && | |
332 | (intendedUsage == CSSM_KEYUSE_ENCRYPT) | |
333 | ) || | |
334 | ( (keyUsage & CSSM_KEYUSE_UNWRAP) && | |
335 | (intendedUsage == CSSM_KEYUSE_DECRYPT) | |
336 | ) | |
337 | ) ) | |
338 | #endif | |
339 | CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT); | |
340 | } | |
341 | ||
342 | /* now validate all of the key's usage bits - this is mainly to | |
343 | * prevent and detect tampering */ | |
344 | switch(hdr->KeyClass) { | |
345 | case CSSM_KEYCLASS_SESSION_KEY: | |
346 | keyType = CKT_Session; | |
347 | break; | |
348 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
349 | keyType = CKT_Public; | |
350 | break; | |
351 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
352 | keyType = CKT_Private; | |
353 | break; | |
354 | default: | |
355 | CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); | |
356 | } | |
357 | try { | |
358 | cspValidateKeyUsageBits(keyType, keyUsage); | |
359 | } | |
360 | catch (...) { | |
361 | /* override error.... */ | |
362 | CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT); | |
363 | } | |
364 | } | |
365 | ||
366 | /* | |
367 | * Set up a key header. | |
368 | */ | |
369 | void setKeyHeader( | |
370 | CSSM_KEYHEADER &hdr, | |
371 | const Guid &myGuid, | |
372 | CSSM_ALGORITHMS alg, | |
373 | CSSM_KEYCLASS keyClass, | |
374 | CSSM_KEYATTR_FLAGS attrs, | |
375 | CSSM_KEYUSE use) | |
376 | { | |
377 | memset(&hdr, 0, sizeof(CSSM_KEYHEADER)); | |
378 | hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; | |
379 | hdr.CspId = myGuid; | |
380 | hdr.AlgorithmId = alg; | |
381 | hdr.KeyClass = keyClass; | |
382 | hdr.KeyUsage = use; | |
383 | hdr.KeyAttr = attrs; | |
384 | ||
385 | // defaults (change as needed) | |
386 | hdr.WrapAlgorithmId = CSSM_ALGID_NONE; | |
387 | } | |
388 | ||
389 | /* | |
390 | * Ensure that indicated CssmData can handle 'length' bytes | |
391 | * of data. Malloc the Data ptr if necessary. | |
392 | */ | |
393 | void setUpCssmData( | |
394 | CssmData &data, | |
395 | size_t length, | |
396 | Allocator &allocator) | |
397 | { | |
398 | /* FIXME - I'm sure Perry has more elegant ways of doing this, | |
399 | * but I can't figure them out. */ | |
400 | if(data.Length == 0) { | |
401 | data.Data = (uint8 *)allocator.malloc(length); | |
402 | } | |
403 | else if(data.Length < length) { | |
404 | CssmError::throwMe(CSSMERR_CSP_INVALID_DATA); | |
405 | } | |
406 | data.Length = length; | |
407 | } | |
408 | ||
409 | void setUpData( | |
410 | CSSM_DATA &data, | |
411 | size_t length, | |
412 | Allocator &allocator) | |
413 | { | |
414 | setUpCssmData(CssmData::overlay(data), length, allocator); | |
415 | } | |
416 | ||
417 | void freeCssmData( | |
418 | CssmData &data, | |
419 | Allocator &allocator) | |
420 | { | |
421 | if(data.Data) { | |
422 | allocator.free(data.Data); | |
423 | data.Data = NULL; | |
424 | } | |
425 | data.Length = 0; | |
426 | } | |
427 | ||
428 | void freeData( | |
429 | CSSM_DATA *data, | |
430 | Allocator &allocator, | |
431 | bool freeStruct) // free the CSSM_DATA itself | |
432 | { | |
433 | if(data == NULL) { | |
434 | return; | |
435 | } | |
436 | if(data->Data) { | |
437 | allocator.free(data->Data); | |
438 | data->Data = NULL; | |
439 | } | |
440 | data->Length = 0; | |
441 | if(freeStruct) { | |
442 | allocator.free(data); | |
443 | } | |
444 | } | |
445 | ||
446 | /* | |
447 | * Copy source to destination, mallocing destination if necessary. | |
448 | */ | |
449 | void copyCssmData( | |
450 | const CssmData &src, | |
451 | CssmData &dst, | |
452 | Allocator &allocator) | |
453 | { | |
454 | setUpCssmData(dst, src.Length, allocator); | |
455 | memmove(dst.Data, src.Data, src.Length); | |
456 | } | |
457 | ||
458 | void copyData( | |
459 | const CSSM_DATA &src, | |
460 | CSSM_DATA &dst, | |
461 | Allocator &allocator) | |
462 | { | |
463 | copyCssmData(CssmData::overlay(src), | |
464 | CssmData::overlay(dst), | |
465 | allocator); | |
466 | } | |
467 | ||
468 | /* | |
469 | * Compare two CSSM_DATAs, return CSSM_TRUE if identical. | |
470 | */ | |
471 | CSSM_BOOL cspCompareCssmData( | |
472 | const CSSM_DATA *data1, | |
473 | const CSSM_DATA *data2) | |
474 | { | |
475 | if((data1 == NULL) || (data1->Data == NULL) || | |
476 | (data2 == NULL) || (data2->Data == NULL) || | |
477 | (data1->Length != data2->Length)) { | |
478 | return CSSM_FALSE; | |
479 | } | |
480 | if(data1->Length != data2->Length) { | |
481 | return CSSM_FALSE; | |
482 | } | |
483 | if(memcmp(data1->Data, data2->Data, data1->Length) == 0) { | |
484 | return CSSM_TRUE; | |
485 | } | |
486 | else { | |
487 | return CSSM_FALSE; | |
488 | } | |
489 | } | |
490 | ||
491 | /* | |
492 | * This takes care of mallocing the KeyLabel field. | |
493 | */ | |
494 | void copyCssmHeader( | |
495 | const CssmKey::Header &src, | |
496 | CssmKey::Header &dst, | |
497 | Allocator &allocator) | |
498 | { | |
499 | dst = src; | |
500 | } | |
501 | ||
502 | /* | |
503 | * Given a wrapped key, infer its raw format for custom Apple unwrapping. | |
504 | * This is a real kludge; it only works as long as each the key's | |
505 | * default format is used to generate the blob to be wrapped. | |
506 | */ | |
507 | CSSM_KEYBLOB_FORMAT inferFormat( | |
508 | const CssmKey &wrappedKey) | |
509 | { | |
510 | switch(wrappedKey.keyClass()) { | |
511 | case CSSM_KEYCLASS_SESSION_KEY: | |
512 | return CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; | |
513 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
514 | switch(wrappedKey.algorithm()) { | |
515 | case CSSM_ALGID_RSA: | |
516 | return RSA_PUB_KEY_FORMAT; | |
517 | case CSSM_ALGID_DSA: | |
518 | return DSA_PUB_KEY_FORMAT; | |
519 | #ifdef CRYPTKIT_CSP_ENABLE | |
520 | case CSSM_ALGID_FEE: | |
521 | return FEE_KEYBLOB_DEFAULT_FORMAT; | |
522 | case CSSM_ALGID_ECDSA: | |
523 | return CSSM_KEYBLOB_RAW_FORMAT_X509; | |
524 | #endif | |
525 | case CSSM_ALGID_DH: | |
526 | return CSSM_KEYBLOB_RAW_FORMAT_PKCS3; | |
527 | default: | |
528 | /* punt */ | |
529 | return CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
530 | } | |
531 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
532 | switch(wrappedKey.algorithm()) { | |
533 | case CSSM_ALGID_RSA: | |
534 | return RSA_PRIV_KEY_FORMAT; | |
535 | case CSSM_ALGID_DSA: | |
536 | return DSA_PRIV_KEY_FORMAT; | |
537 | #ifdef CRYPTKIT_CSP_ENABLE | |
538 | case CSSM_ALGID_FEE: | |
539 | return FEE_KEYBLOB_DEFAULT_FORMAT; | |
540 | case CSSM_ALGID_ECDSA: | |
541 | return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; | |
542 | #endif | |
543 | case CSSM_ALGID_DH: | |
544 | return CSSM_KEYBLOB_RAW_FORMAT_PKCS3; | |
545 | default: | |
546 | /* punt */ | |
547 | return CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
548 | } | |
549 | default: | |
550 | /* punt */ | |
551 | return CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
552 | } | |
553 | } | |
554 | ||
555 | /* | |
556 | * Given a key and a Context, obtain the optional associated | |
557 | * CSSM_ATTRIBUTE_{PUBLIC,PRIVATE,SYMMETRIC}_KEY_FORMAT attribute as a | |
558 | * CSSM_KEYBLOB_FORMAT. | |
559 | */ | |
560 | CSSM_KEYBLOB_FORMAT requestedKeyFormat( | |
561 | const Context &context, | |
562 | const CssmKey &key) | |
563 | { | |
564 | CSSM_ATTRIBUTE_TYPE attrType; | |
565 | ||
566 | switch(key.keyClass()) { | |
567 | case CSSM_KEYCLASS_SESSION_KEY: | |
568 | attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT; | |
569 | break; | |
570 | case CSSM_KEYCLASS_PUBLIC_KEY: | |
571 | attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT; | |
572 | break; | |
573 | case CSSM_KEYCLASS_PRIVATE_KEY: | |
574 | attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT; | |
575 | break; | |
576 | default: | |
577 | return CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
578 | } | |
579 | /* not present ==> 0 ==> CSSM_KEYBLOB_RAW_FORMAT_NONE */ | |
580 | return context.getInt(attrType); | |
581 | } | |
582 | ||
583 | /* one-shot SHA1 digest */ | |
584 | void cspGenSha1Hash( | |
585 | const void *inData, | |
586 | size_t inDataLen, | |
587 | void *out) // caller mallocs, digest goes here | |
588 | { | |
589 | SHA1Object sha1; | |
590 | ||
591 | sha1.digestInit(); | |
592 | sha1.digestUpdate(inData, inDataLen); | |
593 | sha1.digestFinal(out); | |
594 | } | |
595 | ||
596 | /* | |
597 | * Convert a CSSM_DATE to a CssmUniformDate, or NULL if the CSSM_DATE | |
598 | * is empty. | |
599 | */ | |
600 | static CssmUniformDate *cspGetUniformDate( | |
601 | const CSSM_DATE &cdate) | |
602 | { | |
603 | bool isZero = true; | |
604 | unsigned char *cp = (unsigned char *)&cdate; | |
605 | for(unsigned i=0; i<sizeof(cdate); i++) { | |
606 | if(*cp++ != 0) { | |
607 | isZero = false; | |
608 | break; | |
609 | } | |
610 | } | |
611 | if(isZero) { | |
612 | return NULL; | |
613 | } | |
614 | else { | |
615 | return new CssmUniformDate(CssmDate::overlay(cdate)); | |
616 | } | |
617 | } | |
618 | ||
619 | /* | |
620 | * Get "now" as a CssmUniformDate. | |
621 | */ | |
622 | static CssmUniformDate *cspNow() | |
623 | { | |
624 | CFAbsoluteTime cfTime = CFAbsoluteTimeGetCurrent(); | |
625 | return new CssmUniformDate(cfTime); | |
626 | } | |
627 | ||
628 | #define keyDateDebug(args...) secdebug("keyDate", ## args) | |
629 | ||
630 | /* | |
631 | * Verify temporal validity of specified key. | |
632 | * An empty (all zero) time field means "ignore this". | |
633 | * Throws CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE or | |
634 | * CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE as appropriate. | |
635 | */ | |
636 | void cspVerifyKeyTimes( | |
637 | const CSSM_KEYHEADER &hdr) | |
638 | { | |
639 | CSSM_RETURN err = CSSM_OK; | |
640 | CssmUniformDate *now = NULL; // evaluate lazily | |
641 | CssmUniformDate *end = NULL; // ditto | |
642 | CssmUniformDate *start = cspGetUniformDate(hdr.StartDate); | |
643 | ||
644 | if(start) { | |
645 | now = cspNow(); | |
646 | if(*now < *start) { | |
647 | keyDateDebug("Invalid start date"); | |
648 | err = CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE; | |
649 | } | |
650 | else { | |
651 | keyDateDebug("Valid start date"); | |
652 | } | |
653 | } | |
654 | else { | |
655 | keyDateDebug("Empty start date"); | |
656 | } | |
657 | ||
658 | if(!err) { | |
659 | end = cspGetUniformDate(hdr.EndDate); | |
660 | if(end) { | |
661 | if(now == NULL) { | |
662 | now = cspNow(); | |
663 | } | |
664 | if(*now > *end) { | |
665 | keyDateDebug("Invalid end date"); | |
666 | err = CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE; | |
667 | } | |
668 | else { | |
669 | keyDateDebug("Valid end date"); | |
670 | } | |
671 | } | |
672 | else { | |
673 | keyDateDebug("Empty end date"); | |
674 | } | |
675 | } | |
676 | if(now) { | |
677 | delete now; | |
678 | } | |
679 | if(end) { | |
680 | delete end; | |
681 | } | |
682 | if(start) { | |
683 | delete start; | |
684 | } | |
685 | if(err) { | |
686 | CssmError::throwMe(err); | |
687 | } | |
688 | } | |
689 |