+++ /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);
- }
-}
-