]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_csp/lib/AppleCSPUtils.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_csp / lib / AppleCSPUtils.cpp
1 /*
2 * Copyright (c) 2000-2001,2011,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 // 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...) secinfo("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