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 */
41void 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 */
98cspKeyStorage 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
197static 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 */
215void 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
317void 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 */
369void 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 */
393void 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
409void setUpData(
410	CSSM_DATA			&data,
411	size_t				length,
412	Allocator		&allocator)
413{
414	setUpCssmData(CssmData::overlay(data), length, allocator);
415}
416
417void 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
428void 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 */
449void 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
458void 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 */
471CSSM_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 */
494void 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 */
507CSSM_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 */
560CSSM_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 */
584void 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 */
600static 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 */
622static 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 */
636void 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
690