--- /dev/null
+/*
+ * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
+ *
+ * The contents of this file constitute Original Code as defined in and are
+ * subject to the Apple Public Source License Version 1.2 (the 'License').
+ * You may not use this file except in compliance with the License. Please obtain
+ * a copy of the License at http://www.apple.com/publicsource and read it before
+ * using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+ * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+ * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
+ * specific language governing rights and limitations under the License.
+ */
+
+
+//
+// AppleCSPUtils.cpp - CSP-wide utility functions
+//
+
+#include "AppleCSPUtils.h"
+#include <Security/cssmerr.h>
+#include <security_utilities/alloc.h>
+#include <security_cdsa_utilities/cssmdates.h>
+#include <string.h>
+#include <FEECSPUtils.h>
+#include <SHA1_MD5_Object.h>
+#include "RSA_DSA_keys.h"
+#include <syslog.h>
+
+/*
+ * Validate key attribute bits per specified key type.
+ *
+ * Used to check requested key attributes for new keys and for validating
+ * incoming existing keys. For checking key attributes for new keys,
+ * assumes that KEYATTR_RETURN_xxx bits have been checked elsewhere
+ * and stripped off before coming here.
+ */
+void cspValidateKeyAttr(
+ cspKeyType keyType,
+ uint32 keyAttr)
+{
+ uint32 sensitiveBit = (keyAttr & CSSM_KEYATTR_SENSITIVE) ? 1 : 0;
+ uint32 extractBit = (keyAttr & CSSM_KEYATTR_EXTRACTABLE) ? 1 : 0;
+
+ /* first general CSP-wide checks */
+ if(keyAttr & KEY_ATTR_RETURN_MASK) {
+ //errorLog0(" KEY_ATTR_RETURN bits set\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ if(keyAttr & CSSM_KEYATTR_PERMANENT) {
+ //errorLog0(" PERMANENT bit not supported\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
+ }
+ if(keyAttr & CSSM_KEYATTR_PRIVATE) {
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYATTR_MASK);
+ }
+ /* Anything else? */
+
+ /* now check per keyType */
+ switch(keyType) {
+ case CKT_Session:
+ break;
+
+ case CKT_Public:
+ if(sensitiveBit || !extractBit) {
+ //errorLog0("Public keys must be extractable in the clear\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ break;
+
+ case CKT_Private:
+ //if(!sensitiveBit) {
+ // errorLog0("Private keys must have KEYATTR_SENSITIVE\n");
+ // CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ //}
+
+ /*
+ * One more restriction - EXTRACTABLE - caller must check since
+ * that involves KEYUSE bits.
+ */
+ break;
+ default:
+ CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
+ }
+ return;
+}
+
+/*
+ * Perform sanity check of incoming key attribute bits for a given
+ * key type, and return a cspKeyStorage value.
+ *
+ * Called from any routine which generates a new key. This specifically
+ * excludes WrapKey().
+ */
+cspKeyStorage cspParseKeyAttr(
+ cspKeyType keyType,
+ uint32 keyAttr)
+{
+ uint32 sensitiveBit = (keyAttr & CSSM_KEYATTR_SENSITIVE) ? 1 : 0;
+ uint32 rtnDataBit = (keyAttr & CSSM_KEYATTR_RETURN_DATA) ? 1 : 0;
+ uint32 rtnRefBit = (keyAttr & CSSM_KEYATTR_RETURN_REF) ? 1 : 0;
+ uint32 extractBit = (keyAttr & CSSM_KEYATTR_EXTRACTABLE) ? 1 : 0;
+
+ cspKeyStorage rtn;
+
+ /* first general CDSA-wide checks */
+ if(keyAttr & (CSSM_KEYATTR_ALWAYS_SENSITIVE |
+ CSSM_KEYATTR_NEVER_EXTRACTABLE)) {
+ //errorLog0("ALWAYS_SENSITIVE, NEVER_EXTRACTABLE illegal at SPI\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ switch(keyAttr & KEY_ATTR_RETURN_MASK) {
+ /* ensure only one bit is set */
+ case CSSM_KEYATTR_RETURN_DATA:
+ rtn = CKS_Data;
+ break;
+ case CSSM_KEYATTR_RETURN_REF:
+ rtn = CKS_Ref;
+ break;
+ case CSSM_KEYATTR_RETURN_NONE:
+ rtn = CKS_None;
+ break;
+ case CSSM_KEYATTR_RETURN_DEFAULT:
+ /* CSP default */
+ rtnRefBit = 1;
+ rtn = CKS_Ref;
+ break;
+ default:
+ //errorLog0("Multiple KEYATTR_RETURN bits set\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+
+ /* now CSP-wide checks for all key types */
+ if(keyType != CKT_Session) {
+ /* session keys modifiable, no others are */
+ if(keyAttr & CSSM_KEYATTR_MODIFIABLE) {
+ //errorLog0("CSSM_KEYATTR_MODIFIABLE not supported\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ }
+ if(rtnDataBit) {
+ if(!extractBit) {
+ //errorLog0("RETURN_DATA and !EXTRACTABLE not supported\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ if(sensitiveBit) {
+ //errorLog0("RETURN_DATA and SENSITIVE not supported\n");
+ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
+ }
+ }
+
+ /* now check per keyType. We're ust checking for things specific
+ * to KEYATTR_RETURN_xxx; cspValidateKeyAttr will check other fields. */
+ #if 0
+ // nothing for now
+ switch(keyType) {
+ case CKT_Session:
+ break;
+
+ case MKT_Public:
+ break;
+
+ case MKT_Private:
+ if(rtnDataBit) {
+ errorLog0("Private keys must be generated by ref\n");
+ goto errorOut;
+ }
+ /*
+ * One more restriction - EXTRACTABLE - caller must check since
+ * that involves KEYUSE bits.
+ */
+ break;
+ default:
+ CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
+ }
+ #endif // 0
+
+ /* validate other common static attributes */
+ cspValidateKeyAttr(keyType, (keyAttr & ~KEY_ATTR_RETURN_MASK));
+ return rtn;
+}
+
+
+/* used in cspValidateKeyUsageBits() */
+/*
+ * This is a vestige from OS9/ASA. In the real world there are in fact certs with
+ * keyUsage extensions which specify, e.g., verify and wrap. I think we'll just
+ * have to ignore the old exclusivity rules.
+ */
+#define IGNORE_KEYUSE_EXCLUSIVITY 1
+#if IGNORE_KEYUSE_EXCLUSIVITY
+#define checkExclusiveUsage(ku, cb, ob, em)
+#else
+static void checkExclusiveUsage(
+ uint32 keyUsage, // requested usage word
+ uint32 checkBits, // if any of these are set
+ uint32 otherBits, // these are the only other bits which can be set
+ const char *errMsg)
+{
+ if(keyUsage & checkBits) {
+ if(keyUsage & ~otherBits) {
+ errorLog0((char *)errMsg);
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ }
+}
+#endif /* IGNORE_KEYUSE_EXCLUSIVITY */
+
+/*
+ * Validate key usage bits for specified key type.
+ */
+void cspValidateKeyUsageBits (
+ cspKeyType keyType,
+ uint32 keyUsage)
+{
+ /* general restrictions */
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_ANY,
+ CSSM_KEYUSE_ANY,
+ "CSSM_KEYUSE_ANY overload");
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_DERIVE,
+ CSSM_KEYUSE_DERIVE,
+ "CSSM_KEYUSE_DERIVE overload\n");
+
+ /* brute force per key type. */
+ switch(keyType) {
+ case CKT_Session:
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+ CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT,
+ "session key usage: encrypt/decrypt overload\n");
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY |
+ CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER,
+ CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY |
+ CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER,
+ "session key usage: sign/verify overload\n");
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
+ CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP,
+ "session key usage: wrap/unwrap overload\n");
+ break;
+
+ case CKT_Public:
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_ENCRYPT,
+ CSSM_KEYUSE_ENCRYPT,
+ "public key usage: encrypt overload\n");
+ if(keyUsage & CSSM_KEYUSE_DECRYPT) {
+ errorLog0("public key usage: DECRYPT illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ if(keyUsage & (CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER)) {
+ errorLog0("public key usage: SIGN illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER,
+ CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER,
+ "public key usage: verify overload\n");
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_WRAP,
+ CSSM_KEYUSE_WRAP,
+ "public key usage: wrap overload\n");
+ if(keyUsage & CSSM_KEYUSE_UNWRAP) {
+ errorLog0("public key usage: UNWRAP illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ break;
+
+ case CKT_Private:
+ if(keyUsage & CSSM_KEYUSE_ENCRYPT) {
+ errorLog0("private key usage: ENCRYPT illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_DECRYPT,
+ CSSM_KEYUSE_DECRYPT,
+ "private key usage: decrypt overload\n");
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER,
+ CSSM_KEYUSE_SIGN | CSSM_KEYUSE_SIGN_RECOVER,
+ "private key usage: sign overload\n");
+ if(keyUsage & (CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_VERIFY_RECOVER)) {
+ errorLog0("private key usage: VERIFY illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ if(keyUsage & CSSM_KEYUSE_WRAP) {
+ errorLog0("private key usage: WRAP illegal\n");
+ CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEYUSAGE_MASK);
+ }
+ checkExclusiveUsage(keyUsage,
+ CSSM_KEYUSE_UNWRAP,
+ CSSM_KEYUSE_UNWRAP,
+ "private key usage: unwrap overload\n");
+ break;
+ default:
+ CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
+ }
+}
+
+/*
+ * Validate existing key's usage bits against intended use.
+ */
+
+/*
+ * For now, a key marked for KEYUSE_{WRAP|UNWRAP} can also be used for
+ * KEYUSE_{ENCRYPT|DECRYPT}. This is a temporary workaround for
+ * Radar 2716153.
+ */
+#define RELAXED_WRAP_USAGE 1
+
+void cspValidateIntendedKeyUsage(
+ const CSSM_KEYHEADER *hdr,
+ CSSM_KEYUSE intendedUsage)
+{
+ uint32 keyUsage = hdr->KeyUsage;
+ cspKeyType keyType;
+
+ /* first, the obvious */
+ if(keyUsage & CSSM_KEYUSE_ANY) {
+ /* OK for now */
+ return;
+ }
+ if(!(keyUsage & intendedUsage)) {
+ #if RELAXED_WRAP_USAGE
+ if(! ( ( (keyUsage & CSSM_KEYUSE_WRAP) &&
+ (intendedUsage == CSSM_KEYUSE_ENCRYPT)
+ ) ||
+ ( (keyUsage & CSSM_KEYUSE_UNWRAP) &&
+ (intendedUsage == CSSM_KEYUSE_DECRYPT)
+ )
+ ) )
+ #endif
+ CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
+ }
+
+ /* now validate all of the key's usage bits - this is mainly to
+ * prevent and detect tampering */
+ switch(hdr->KeyClass) {
+ case CSSM_KEYCLASS_SESSION_KEY:
+ keyType = CKT_Session;
+ break;
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ keyType = CKT_Public;
+ break;
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ keyType = CKT_Private;
+ break;
+ default:
+ CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR);
+ }
+ try {
+ cspValidateKeyUsageBits(keyType, keyUsage);
+ }
+ catch (...) {
+ /* override error.... */
+ CssmError::throwMe(CSSMERR_CSP_KEY_USAGE_INCORRECT);
+ }
+}
+
+/*
+ * Set up a key header.
+ */
+void setKeyHeader(
+ CSSM_KEYHEADER &hdr,
+ const Guid &myGuid,
+ CSSM_ALGORITHMS alg,
+ CSSM_KEYCLASS keyClass,
+ CSSM_KEYATTR_FLAGS attrs,
+ CSSM_KEYUSE use)
+{
+ memset(&hdr, 0, sizeof(CSSM_KEYHEADER));
+ hdr.HeaderVersion = CSSM_KEYHEADER_VERSION;
+ hdr.CspId = myGuid;
+ hdr.AlgorithmId = alg;
+ hdr.KeyClass = keyClass;
+ hdr.KeyUsage = use;
+ hdr.KeyAttr = attrs;
+
+ // defaults (change as needed)
+ hdr.WrapAlgorithmId = CSSM_ALGID_NONE;
+}
+
+/*
+ * Ensure that indicated CssmData can handle 'length' bytes
+ * of data. Malloc the Data ptr if necessary.
+ */
+void setUpCssmData(
+ CssmData &data,
+ size_t length,
+ Allocator &allocator)
+{
+ /* FIXME - I'm sure Perry has more elegant ways of doing this,
+ * but I can't figure them out. */
+ if(data.Length == 0) {
+ data.Data = (uint8 *)allocator.malloc(length);
+ }
+ else if(data.Length < length) {
+ CssmError::throwMe(CSSMERR_CSP_INVALID_DATA);
+ }
+ data.Length = length;
+}
+
+void setUpData(
+ CSSM_DATA &data,
+ size_t length,
+ Allocator &allocator)
+{
+ setUpCssmData(CssmData::overlay(data), length, allocator);
+}
+
+void freeCssmData(
+ CssmData &data,
+ Allocator &allocator)
+{
+ if(data.Data) {
+ allocator.free(data.Data);
+ data.Data = NULL;
+ }
+ data.Length = 0;
+}
+
+void freeData(
+ CSSM_DATA *data,
+ Allocator &allocator,
+ bool freeStruct) // free the CSSM_DATA itself
+{
+ if(data == NULL) {
+ return;
+ }
+ if(data->Data) {
+ allocator.free(data->Data);
+ data->Data = NULL;
+ }
+ data->Length = 0;
+ if(freeStruct) {
+ allocator.free(data);
+ }
+}
+
+/*
+ * Copy source to destination, mallocing destination if necessary.
+ */
+void copyCssmData(
+ const CssmData &src,
+ CssmData &dst,
+ Allocator &allocator)
+{
+ setUpCssmData(dst, src.Length, allocator);
+ memmove(dst.Data, src.Data, src.Length);
+}
+
+void copyData(
+ const CSSM_DATA &src,
+ CSSM_DATA &dst,
+ Allocator &allocator)
+{
+ copyCssmData(CssmData::overlay(src),
+ CssmData::overlay(dst),
+ allocator);
+}
+
+/*
+ * Compare two CSSM_DATAs, return CSSM_TRUE if identical.
+ */
+CSSM_BOOL cspCompareCssmData(
+ const CSSM_DATA *data1,
+ const CSSM_DATA *data2)
+{
+ if((data1 == NULL) || (data1->Data == NULL) ||
+ (data2 == NULL) || (data2->Data == NULL) ||
+ (data1->Length != data2->Length)) {
+ return CSSM_FALSE;
+ }
+ if(data1->Length != data2->Length) {
+ return CSSM_FALSE;
+ }
+ if(memcmp(data1->Data, data2->Data, data1->Length) == 0) {
+ return CSSM_TRUE;
+ }
+ else {
+ return CSSM_FALSE;
+ }
+}
+
+/*
+ * This takes care of mallocing the KeyLabel field.
+ */
+void copyCssmHeader(
+ const CssmKey::Header &src,
+ CssmKey::Header &dst,
+ Allocator &allocator)
+{
+ dst = src;
+}
+
+/*
+ * Given a wrapped key, infer its raw format for custom Apple unwrapping.
+ * This is a real kludge; it only works as long as each the key's
+ * default format is used to generate the blob to be wrapped.
+ */
+CSSM_KEYBLOB_FORMAT inferFormat(
+ const CssmKey &wrappedKey)
+{
+ switch(wrappedKey.keyClass()) {
+ case CSSM_KEYCLASS_SESSION_KEY:
+ return CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ switch(wrappedKey.algorithm()) {
+ case CSSM_ALGID_RSA:
+ return RSA_PUB_KEY_FORMAT;
+ case CSSM_ALGID_DSA:
+ return DSA_PUB_KEY_FORMAT;
+ #ifdef CRYPTKIT_CSP_ENABLE
+ case CSSM_ALGID_FEE:
+ return FEE_KEYBLOB_DEFAULT_FORMAT;
+ case CSSM_ALGID_ECDSA:
+ return CSSM_KEYBLOB_RAW_FORMAT_X509;
+ #endif
+ case CSSM_ALGID_DH:
+ return CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
+ default:
+ /* punt */
+ return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+ }
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ switch(wrappedKey.algorithm()) {
+ case CSSM_ALGID_RSA:
+ return RSA_PRIV_KEY_FORMAT;
+ case CSSM_ALGID_DSA:
+ return DSA_PRIV_KEY_FORMAT;
+ #ifdef CRYPTKIT_CSP_ENABLE
+ case CSSM_ALGID_FEE:
+ return FEE_KEYBLOB_DEFAULT_FORMAT;
+ case CSSM_ALGID_ECDSA:
+ return CSSM_KEYBLOB_RAW_FORMAT_OPENSSL;
+ #endif
+ case CSSM_ALGID_DH:
+ return CSSM_KEYBLOB_RAW_FORMAT_PKCS3;
+ default:
+ /* punt */
+ return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+ }
+ default:
+ /* punt */
+ return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+ }
+}
+
+/*
+ * Given a key and a Context, obtain the optional associated
+ * CSSM_ATTRIBUTE_{PUBLIC,PRIVATE,SYMMETRIC}_KEY_FORMAT attribute as a
+ * CSSM_KEYBLOB_FORMAT.
+ */
+CSSM_KEYBLOB_FORMAT requestedKeyFormat(
+ const Context &context,
+ const CssmKey &key)
+{
+ CSSM_ATTRIBUTE_TYPE attrType;
+
+ switch(key.keyClass()) {
+ case CSSM_KEYCLASS_SESSION_KEY:
+ attrType = CSSM_ATTRIBUTE_SYMMETRIC_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_PUBLIC_KEY:
+ attrType = CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT;
+ break;
+ case CSSM_KEYCLASS_PRIVATE_KEY:
+ attrType = CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT;
+ break;
+ default:
+ return CSSM_KEYBLOB_RAW_FORMAT_NONE;
+ }
+ /* not present ==> 0 ==> CSSM_KEYBLOB_RAW_FORMAT_NONE */
+ return context.getInt(attrType);
+}
+
+/* one-shot SHA1 digest */
+void cspGenSha1Hash(
+ const void *inData,
+ size_t inDataLen,
+ void *out) // caller mallocs, digest goes here
+{
+ SHA1Object sha1;
+
+ sha1.digestInit();
+ sha1.digestUpdate(inData, inDataLen);
+ sha1.digestFinal(out);
+}
+
+/*
+ * Convert a CSSM_DATE to a CssmUniformDate, or NULL if the CSSM_DATE
+ * is empty.
+ */
+static CssmUniformDate *cspGetUniformDate(
+ const CSSM_DATE &cdate)
+{
+ bool isZero = true;
+ unsigned char *cp = (unsigned char *)&cdate;
+ for(unsigned i=0; i<sizeof(cdate); i++) {
+ if(*cp++ != 0) {
+ isZero = false;
+ break;
+ }
+ }
+ if(isZero) {
+ return NULL;
+ }
+ else {
+ return new CssmUniformDate(CssmDate::overlay(cdate));
+ }
+}
+
+/*
+ * Get "now" as a CssmUniformDate.
+ */
+static CssmUniformDate *cspNow()
+{
+ CFAbsoluteTime cfTime = CFAbsoluteTimeGetCurrent();
+ return new CssmUniformDate(cfTime);
+}
+
+#define keyDateDebug(args...) secdebug("keyDate", ## args)
+
+/*
+ * Verify temporal validity of specified key.
+ * An empty (all zero) time field means "ignore this".
+ * Throws CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE or
+ * CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE as appropriate.
+ */
+void cspVerifyKeyTimes(
+ const CSSM_KEYHEADER &hdr)
+{
+ CSSM_RETURN err = CSSM_OK;
+ CssmUniformDate *now = NULL; // evaluate lazily
+ CssmUniformDate *end = NULL; // ditto
+ CssmUniformDate *start = cspGetUniformDate(hdr.StartDate);
+
+ if(start) {
+ now = cspNow();
+ if(*now < *start) {
+ keyDateDebug("Invalid start date");
+ err = CSSMERR_CSP_APPLE_INVALID_KEY_START_DATE;
+ }
+ else {
+ keyDateDebug("Valid start date");
+ }
+ }
+ else {
+ keyDateDebug("Empty start date");
+ }
+
+ if(!err) {
+ end = cspGetUniformDate(hdr.EndDate);
+ if(end) {
+ if(now == NULL) {
+ now = cspNow();
+ }
+ if(*now > *end) {
+ keyDateDebug("Invalid end date");
+ err = CSSMERR_CSP_APPLE_INVALID_KEY_END_DATE;
+ }
+ else {
+ keyDateDebug("Valid end date");
+ }
+ }
+ else {
+ keyDateDebug("Empty end date");
+ }
+ }
+ if(now) {
+ delete now;
+ }
+ if(end) {
+ delete end;
+ }
+ if(start) {
+ delete start;
+ }
+ if(err) {
+ CssmError::throwMe(err);
+ }
+}
+