/* * 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. */ // // AppleCSPContext.cpp - CSP-wide contexts // #include "AppleCSPContext.h" #include "AppleCSPSession.h" #include "AppleCSPUtils.h" /* * Empty destructor (just to avoid out-of-line copies) */ AppleCSPContext::~AppleCSPContext() { } /* * get symmetric key bits - context.key can be either ref or raw. * A convenience routine typically used by subclass's init(). */ void AppleCSPContext::symmetricKeyBits( const Context &context, CSSM_ALGORITHMS requiredAlg, // throws if this doesn't match key alg CSSM_KEYUSE intendedUse, // throws if key usage doesn't match this UInt8 *&keyBits, // RETURNED (not mallocd or copied) UInt32 &keyLen) // RETURNED { /* key must be present and it must be a session key matching caller's spec */ CssmKey &key = context.get(CSSM_ATTRIBUTE_KEY, CSSMERR_CSP_MISSING_ATTR_KEY); if(key.keyClass() != CSSM_KEYCLASS_SESSION_KEY) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } if(key.algorithm() != requiredAlg) { CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH); } cspValidateIntendedKeyUsage(&key.KeyHeader, intendedUse); /* extract raw bits one way or the other */ switch(key.blobType()) { case CSSM_KEYBLOB_RAW: /* easy case, the bits are right there in the CssmKey */ if(key.blobFormat() != CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); } keyLen = key.length(); keyBits = key.KeyData.Data; break; case CSSM_KEYBLOB_REFERENCE: { /* do a lookup to get a binary key */ BinaryKey &binKey = mSession.lookupRefKey(key); /* fails if this is not a SymmetricBinaryKey */ SymmetricBinaryKey *symBinKey = dynamic_cast(&binKey); if(symBinKey == NULL) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } keyLen = symBinKey->mKeyData.Length; keyBits = symBinKey->mKeyData.Data; break; } default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); } return; } // Called from subclass after it allocates its BinaryKeys. // Caller frees BinaryKeys if we throw any exception. void AppleKeyPairGenContext::generate( const Context &context, AppleCSPSession &session, CssmKey &pubKey, BinaryKey *pubBinKey, CssmKey &privKey, BinaryKey *privBinKey) { uint32 keySize; cspKeyStorage privStorage; cspKeyStorage pubStorage; CssmKey::Header &pubHdr = pubKey.header(); CssmKey::Header &privHdr = privKey.header(); // validate context and key header args pubStorage = cspParseKeyAttr(CKT_Public, pubHdr.KeyAttr); privStorage = cspParseKeyAttr(CKT_Private, privHdr.KeyAttr); cspValidateKeyUsageBits(CKT_Public, pubHdr.KeyUsage); cspValidateKeyUsageBits(CKT_Private, privHdr.KeyUsage); // have subclass generate the key pairs in the form of // its native BinaryKeys generate(context, *pubBinKey, *privBinKey, keySize); // FIXME - Any other header setup? pubHdr.LogicalKeySizeInBits = privHdr.LogicalKeySizeInBits = keySize; pubHdr.KeyAttr &= ~KEY_ATTR_RETURN_MASK; privHdr.KeyAttr &= ~KEY_ATTR_RETURN_MASK; // Handle key formatting. Delete the BinaryKeys if // we're not creating ref keys. switch(pubStorage) { case CKS_Ref: session.addRefKey(*pubBinKey, pubKey); break; case CKS_Data: pubHdr.Format = requestedKeyFormat(context, pubKey); pubBinKey->mKeyHeader = pubHdr; pubBinKey->generateKeyBlob( session.normAlloc(), // alloc in user space CssmData::overlay(pubKey.KeyData), pubHdr.Format); delete pubBinKey; break; case CKS_None: delete pubBinKey; break; } switch(privStorage) { case CKS_Ref: session.addRefKey(*privBinKey, privKey); break; case CKS_Data: privHdr.Format = requestedKeyFormat(context, privKey); privBinKey->mKeyHeader = privHdr; privBinKey->generateKeyBlob( session.normAlloc(), // alloc in user space CssmData::overlay(privKey.KeyData), privHdr.Format); delete privBinKey; break; case CKS_None: delete privBinKey; break; } } /* * Called from subclass's generate method. Subclass is also a * AppleCSPContext. */ void AppleSymmKeyGenContext::generateSymKey( const Context &context, AppleCSPSession &session, // for ref keys CssmKey &cssmKey) // RETURNED { /* there really is no legal way this should throw... */ uint32 reqKeySize = context.getInt( CSSM_ATTRIBUTE_KEY_LENGTH, CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH); if((reqKeySize < minSizeInBits) || (reqKeySize > maxSizeInBits)) { CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE); } if(mustBeByteSized) { if((reqKeySize & 0x7) != 0) { CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE); } } // validate KeyAtrr and KeyUsage already present in header cspKeyStorage keyStorage; CssmKey::Header &hdr = cssmKey.header(); keyStorage = cspParseKeyAttr(CKT_Session, hdr.KeyAttr); cspValidateKeyUsageBits(CKT_Session, hdr.KeyUsage); hdr.KeyAttr &= ~KEY_ATTR_RETURN_MASK; hdr.LogicalKeySizeInBits = reqKeySize; uint32 keySizeInBytes = (reqKeySize + 7) / 8; SymmetricBinaryKey *binKey = NULL; CssmData *keyData = NULL; switch(keyStorage) { case CKS_None: /* no way */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); case CKS_Ref: /* cook up a symmetric binary key */ binKey = new SymmetricBinaryKey(reqKeySize); keyData = &binKey->mKeyData; break; case CKS_Data: /* key bytes --> caller's cssmKey */ keyData = &(CssmData::overlay(cssmKey.KeyData)); setUpCssmData(*keyData, keySizeInBytes, session.normAlloc()); break; } // in any case, fill key bytes with random data session.getRandomBytes(keySizeInBytes, keyData->Data); if(keyStorage == CKS_Ref) { session.addRefKey(*binKey, cssmKey); } else { /* Raw data */ hdr.BlobType = CSSM_KEYBLOB_RAW; hdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; } // FIXME - any other header fields? } // // Symmetric Binary Key support // SymmetricBinaryKey::SymmetricBinaryKey( unsigned keySizeInBits) : mAllocator(CssmAllocator::standard(CssmAllocator::sensitive)) { setUpCssmData(mKeyData, (keySizeInBits + 7) / 8, mAllocator); } SymmetricBinaryKey::~SymmetricBinaryKey() { freeCssmData(mKeyData, mAllocator); } void SymmetricBinaryKey::generateKeyBlob( CssmAllocator &allocator, CssmData &blob, CSSM_KEYBLOB_FORMAT &format) // CSSM_KEYBLOB_RAW_FORMAT_PKCS1, etc. { switch(format) { case CSSM_KEYBLOB_RAW_FORMAT_NONE: // default case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: // the one we can do break; default: CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SYMMETRIC_KEY_FORMAT); } copyCssmData(mKeyData, blob, allocator); format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; }