void SDCSPSession::GenerateKey(CSSM_CC_HANDLE ccHandle, const Context &context, uint32 keyUsage, uint32 keyAttr, const CssmData *keyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, CssmKey &key, CSSM_PRIVILEGE privilege) { CSSM_DB_HANDLE database = getDatabase(context); validateKeyAttr(keyAttr); const AccessCredentials *cred = NULL; const AclEntryInput *owner = NULL; if (credAndAclEntry) { cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); } KeyHandle keyHandle; clientSession().generateKey(ClientSession::toIPCHandle(database), context, keyUsage, keyAttr, cred, owner, keyHandle, key.header()); makeReferenceKey(keyHandle, key, database, keyAttr, keyLabel); }
void SDCSPSession::GenerateKeyPair(CSSM_CC_HANDLE ccHandle, const Context &context, uint32 publicKeyUsage, uint32 publicKeyAttr, const CssmData *publicKeyLabel, CssmKey &publicKey, uint32 privateKeyUsage, uint32 privateKeyAttr, const CssmData *privateKeyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, CssmKey &privateKey, CSSM_PRIVILEGE privilege) { CSSM_DB_HANDLE database = getDatabase(context); validateKeyAttr(publicKeyAttr); validateKeyAttr(privateKeyAttr); const AccessCredentials *cred = NULL; const AclEntryInput *owner = NULL; if (credAndAclEntry) { cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); } /* * Public keys must be extractable in the clear - that's the Apple * policy. The raw CSP is unable to enforce the extractable * bit since it always sees that as true (it's managed and forced * true by the SecurityServer). So... */ if(!(publicKeyAttr & CSSM_KEYATTR_EXTRACTABLE)) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } KeyHandle pubKeyHandle, privKeyHandle; clientSession().generateKey(ClientSession::toIPCHandle(database), context, publicKeyUsage, publicKeyAttr, privateKeyUsage, privateKeyAttr, cred, owner, pubKeyHandle, publicKey.header(), privKeyHandle, privateKey.header()); makeReferenceKey(privKeyHandle, privateKey, database, privateKeyAttr, privateKeyLabel); // @@@ What if this throws, we need to free privateKey. makeReferenceKey(pubKeyHandle, publicKey, database, publicKeyAttr, publicKeyLabel); }
void SDCSPSession::DeriveKey(CSSM_CC_HANDLE ccHandle, const Context &context, CssmData ¶m, uint32 keyUsage, uint32 keyAttr, const CssmData *keyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry, CssmKey &derivedKey) { CSSM_DB_HANDLE database = getDatabase(context); validateKeyAttr(keyAttr); const AccessCredentials *cred = NULL; const AclEntryInput *owner = NULL; if (credAndAclEntry) { cred = AccessCredentials::overlay(credAndAclEntry->AccessCred); owner = &AclEntryInput::overlay(credAndAclEntry->InitialAclEntry); } /* optional BaseKey */ const CssmKey *keyInContext = context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY); KeyHandle contextKeyHandle = keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; KeyHandle keyHandle; switch(context.algorithm()) { case CSSM_ALGID_KEYCHAIN_KEY: { // special interpretation: take DLDBHandle -> DbHandle from params clientSession().extractMasterKey(ClientSession::toIPCHandle(database), context, (DbHandle)getDatabase(param.interpretedAs<CSSM_DL_DB_HANDLE>(CSSMERR_CSP_INVALID_ATTR_DL_DB_HANDLE)), keyUsage, keyAttr, cred, owner, keyHandle, derivedKey.header()); } break; default: clientSession().deriveKey(ClientSession::toIPCHandle(database), context, contextKeyHandle, keyUsage, keyAttr, param, cred, owner, keyHandle, derivedKey.header()); break; } makeReferenceKey(keyHandle, derivedKey, database, keyAttr, keyLabel); }
// // Turn raw keybits into a symmetric key in the CSP // CssmClient::Key DatabaseCryptoCore::makeRawKey(void *data, size_t length, CSSM_ALGORITHMS algid, CSSM_KEYUSE usage) { // build a fake key CssmKey key; key.header().BlobType = CSSM_KEYBLOB_RAW; key.header().Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; key.header().AlgorithmId = algid; key.header().KeyClass = CSSM_KEYCLASS_SESSION_KEY; key.header().KeyUsage = usage; key.header().KeyAttr = 0; key.KeyData = CssmData(data, length); // unwrap it into the CSP (but keep it raw) UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); CssmKey unwrappedKey; CssmData descriptiveData; unwrap(key, KeySpec(CSSM_KEYUSE_ANY, CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE), unwrappedKey, &descriptiveData, NULL); return CssmClient::Key(Server::csp(), unwrappedKey); }
void SDCSPSession::UnwrapKey(CSSM_CC_HANDLE CCHandle, const Context &context, const CssmKey *PublicKey, const CssmWrappedKey &WrappedKey, uint32 KeyUsage, uint32 KeyAttr, const CssmData *KeyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry, CssmKey &UnwrappedKey, CssmData &DescriptiveData, CSSM_PRIVILEGE Privilege) { CSSM_DB_HANDLE database = getDatabase(context); validateKeyAttr(KeyAttr); const AccessCredentials *cred = NULL; const AclEntryInput *owner = NULL; if (CredAndAclEntry) { cred = AccessCredentials::overlay(CredAndAclEntry->AccessCred); owner = &AclEntryInput::overlay(CredAndAclEntry->InitialAclEntry); } KeyHandle publicKey = noKey; if (PublicKey) { if (PublicKey->blobType() == CSSM_KEYBLOB_RAW) { // @@@ We need to unwrap the publicKey into the SecurityServer // before continuing CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } else publicKey = lookupKey(*PublicKey).keyHandle(); } // @@@ Deal with permanent keys const CssmKey *keyInContext = context.get<const CssmKey>(CSSM_ATTRIBUTE_KEY); KeyHandle contextKeyHandle = keyInContext ? lookupKey(*keyInContext).keyHandle() : noKey; KeyHandle unwrappedKeyHandle; clientSession().unwrapKey(ClientSession::toIPCHandle(database), context, contextKeyHandle, publicKey, WrappedKey, KeyUsage, KeyAttr, cred, owner, DescriptiveData, unwrappedKeyHandle, UnwrappedKey.header(), *this); makeReferenceKey(unwrappedKeyHandle, UnwrappedKey, database, KeyAttr, KeyLabel); }
// Constructor for a Security Server generated key. SDKey::SDKey(SDCSPSession &session, KeyHandle hKey, CssmKey &ioKey, CSSM_DB_HANDLE inDBHandle, uint32 inKeyAttr, const CssmData *inKeyLabel) : ReferencedKey(session.mSDCSPDLSession), mAllocator(session), mKeyHandle(hKey), mClientSession(session.clientSession()) { CssmKey::Header &header = ioKey.header(); #if 0 if (inKeyAttr & CSSM_KEYATTR_PERMANENT) { if (!inDBHandle) CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE); // EncodeKey and store it in the db. CssmDataContainer blob(mAllocator); clientSession().encodeKey(keyHandle, blob); assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION); switch (header.KeyClass) { case CSSM_KEYCLASS_PUBLIC_KEY: mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; break; case CSSM_KEYCLASS_PRIVATE_KEY: mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY; break; case CSSM_KEYCLASS_SESSION_KEY: mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY; break; default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } CssmData label; if (inKeyLabel) label = *inKeyLabel; CssmData none; // We store the keys real CSP guid on disk CssmGuidData creatorGuid(header.CspId); CssmDateData startDate(header.StartDate); CssmDateData endDate(header.EndDate); DbAttributes attributes(inDBHandle); attributes.recordType(mRecordType); attributes.add(KeySchema::KeyClass, mRecordType); attributes.add(KeySchema::PrintName, label); attributes.add(KeySchema::Alias, none); attributes.add(KeySchema::Permanent, header.attribute(CSSM_KEYATTR_PERMANENT)); attributes.add(KeySchema::Private, header.attribute(CSSM_KEYATTR_PRIVATE)); attributes.add(KeySchema::Modifiable, header.attribute(CSSM_KEYATTR_MODIFIABLE)); attributes.add(KeySchema::Label, label); attributes.add(KeySchema::ApplicationTag, none); attributes.add(KeySchema::KeyCreator, creatorGuid); attributes.add(KeySchema::KeyType, header.AlgorithmId); attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits); // @@@ Get the real effective key size. attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits); attributes.add(KeySchema::StartDate, startDate); attributes.add(KeySchema::EndDate, endDate); attributes.add(KeySchema::Sensitive, header.attribute(CSSM_KEYATTR_SENSITIVE)); attributes.add(KeySchema::AlwaysSensitive, header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE)); attributes.add(KeySchema::Extractable, header.attribute(CSSM_KEYATTR_EXTRACTABLE)); attributes.add(KeySchema::NeverExtractable, header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE)); attributes.add(KeySchema::Encrypt, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT)); attributes.add(KeySchema::Decrypt, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT)); attributes.add(KeySchema::Derive, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE)); attributes.add(KeySchema::Sign, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN)); attributes.add(KeySchema::Verify, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY)); attributes.add(KeySchema::SignRecover, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN_RECOVER)); attributes.add(KeySchema::VerifyRecover, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY_RECOVER)); attributes.add(KeySchema::Wrap, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP)); attributes.add(KeySchema::Unwrap, header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP)); // @@@ Fixme mUniqueId = inDBHandle->insert(mRecordType, &attributes, &blob, true); } #endif header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me. makeReferenceKey(mAllocator, keyReference(), ioKey); }
// Constructor for a key retrived from a Db. SDKey::SDKey(SDDLSession &session, CssmKey &ioKey, KeyHandle hKey, CSSM_DB_HANDLE inDBHandle, RecordHandle record, CSSM_DB_RECORDTYPE recordType, CssmData &keyBlob) : ReferencedKey(session.mSDCSPDLSession), mAllocator(session.allocator()), mKeyHandle(hKey), mRecord(record), mRecordType(recordType), mClientSession(session.clientSession()) { CssmKey::Header &header = ioKey.header(); #if 0 memset(&header, 0, sizeof(header)); // Clear key header if (!mUniqueId || !mUniqueId->database()) CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); header.HeaderVersion = CSSM_KEYHEADER_VERSION; switch (mRecordType) { case CSSM_DL_DB_RECORD_PUBLIC_KEY: header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; break; case CSSM_DL_DB_RECORD_PRIVATE_KEY: header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY; break; case CSSM_DL_DB_RECORD_SYMMETRIC_KEY: header.KeyClass = CSSM_KEYCLASS_SESSION_KEY; break; default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } DbAttributes attributes(mUniqueId->database()); attributes.recordType(mRecordType); attributes.add(KeySchema::KeyClass); // 0 attributes.add(KeySchema::Permanent); // 1 attributes.add(KeySchema::Private); // 2 attributes.add(KeySchema::Modifiable); // 3 attributes.add(KeySchema::KeyCreator); // 4 attributes.add(KeySchema::KeyType); // 5 attributes.add(KeySchema::KeySizeInBits); // 6 attributes.add(KeySchema::StartDate); // 7 attributes.add(KeySchema::EndDate); // 8 attributes.add(KeySchema::Sensitive); // 9 attributes.add(KeySchema::AlwaysSensitive); // 10 attributes.add(KeySchema::Extractable); // 11 attributes.add(KeySchema::NeverExtractable); // 12 attributes.add(KeySchema::Encrypt); // 13 attributes.add(KeySchema::Decrypt); // 14 attributes.add(KeySchema::Derive); // 15 attributes.add(KeySchema::Sign); // 16 attributes.add(KeySchema::Verify); // 17 attributes.add(KeySchema::SignRecover); // 18 attributes.add(KeySchema::VerifyRecover); // 19 attributes.add(KeySchema::Wrap); // 20 attributes.add(KeySchema::Unwrap); // 21 mUniqueId->get(&attributes, NULL); // Assert that the mRecordType matches the KeyClass attribute. if (mRecordType != uint32(attributes[0])) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); header.AlgorithmId = attributes[5]; // KeyType header.LogicalKeySizeInBits = attributes[6]; // KeySizeInBits if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT); if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE); if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE); if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE); if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE); if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE); if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE); if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT); if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT); if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE); if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN); if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY); if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER); if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER); if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP); if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP); // If all usages are allowed set usage to CSSM_KEYUSE_ANY if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP)) header.usage(CSSM_KEYUSE_ANY); if (!attributes[7].size() || !attributes[8].size()) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); header.StartDate = attributes[7].at<CSSM_DATE>(0); header.EndDate = attributes[8].at<CSSM_DATE>(0); #endif makeReferenceKey(mAllocator, keyReference(), ioKey); header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me. }
void AppleCSPSession::WrapKey( CSSM_CC_HANDLE CCHandle, const Context &Context, const AccessCredentials &AccessCred, const CssmKey &UnwrappedKey, const CssmData *DescriptiveData, CssmKey &WrappedKey, CSSM_PRIVILEGE Privilege) { CssmKey::Header &wrappedHdr = WrappedKey.header(); bool isNullWrap = false; CssmKey *wrappingKey = NULL; CSSM_KEYBLOB_FORMAT wrapFormat; switch(UnwrappedKey.keyClass()) { case CSSM_KEYCLASS_PUBLIC_KEY: case CSSM_KEYCLASS_PRIVATE_KEY: case CSSM_KEYCLASS_SESSION_KEY: break; default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } /* wrapping key only required for non-NULL wrap */ wrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY); if(wrappingKey == NULL) { if((Context.algorithm() == CSSM_ALGID_NONE) && (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) { // NULL wrap, OK isNullWrap = true; } else { errorLog0("WrapKey: missing wrapping key\n"); CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY); } } /* * Validate misc. params as best we can */ if(isNullWrap) { wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_NONE; } else { /* * Can only wrap session and private keys. */ #if !ALLOW_PUB_KEY_WRAP if(UnwrappedKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } #endif /* ALLOW_PUB_KEY_WRAP */ cspValidateIntendedKeyUsage(&wrappingKey->KeyHeader, CSSM_KEYUSE_WRAP); cspVerifyKeyTimes(wrappingKey->KeyHeader); /* * make sure wrapping key type matches context */ CSSM_CONTEXT_TYPE wrapType; switch(wrappingKey->KeyHeader.KeyClass) { case CSSM_KEYCLASS_PUBLIC_KEY: case CSSM_KEYCLASS_PRIVATE_KEY: wrapType = CSSM_ALGCLASS_ASYMMETRIC; break; case CSSM_KEYCLASS_SESSION_KEY: wrapType = CSSM_ALGCLASS_SYMMETRIC; break; default: errorLog0("WrapKey: bad class of wrappingKey\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); } if(wrapType != Context.type()) { errorLog0("WrapKey: mismatch wrappingKey/contextType\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); } if(Context.algorithm() == CSSM_ALGID_NONE) { errorLog0("WrapKey: null wrap alg, non-null key\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } /* * Get optional wrap format, set default per incoming keys * Note: no such atrribute ==> 0 ==> FORMAT_NONE, which we * take to mean "use the default". */ wrapFormat = Context.getInt(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT); if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_NONE) { /* figure out a default based on unwrapped key */ switch(UnwrappedKey.keyClass()) { case CSSM_KEYCLASS_SESSION_KEY: wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7; break; case CSSM_KEYCLASS_PUBLIC_KEY: wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; break; case CSSM_KEYCLASS_PRIVATE_KEY: switch(UnwrappedKey.algorithm()) { case CSSM_ALGID_FEE: wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM; break; default: wrapFormat = CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8; break; } break; default: /* NOT REACHED - checked above */ break; } } /* no format present or FORMAT_NONE */ } /* make sure we have a valid format here */ switch(wrapFormat) { case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7: if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) { /* this wrapping style only for symmetric keys */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } break; case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8: case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL: if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) { /* these wrapping styles only for private keys */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } break; case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM: /* no restrictions (well AES can't be the wrap alg but that will * be caught later */ break; case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: /* RSA private key, reference format, only */ if(UnwrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } if(UnwrappedKey.algorithm() != CSSM_ALGID_RSA) { CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } if(UnwrappedKey.blobType() != CSSM_KEYBLOB_REFERENCE) { CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); } break; case CSSM_KEYBLOB_WRAPPED_FORMAT_NONE: if(isNullWrap) { /* only time this is OK */ break; } /* else fall thru */ default: dprintf1("KeyWrap: invalid wrapFormat (%d)\n", (int)wrapFormat); CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT); } /* get the blob to be wrappped */ CssmData rawBlob; bool allocdRawBlob = false; CSSM_KEYBLOB_FORMAT rawFormat; /* * Outgoing same as incoming unless a partial key is completed during * generateKeyBlob() */ const CssmKey::Header &unwrappedHdr = UnwrappedKey.header(); CSSM_KEYATTR_FLAGS unwrappedKeyAttrFlags = unwrappedHdr.KeyAttr; switch(UnwrappedKey.blobType()) { case CSSM_KEYBLOB_RAW: /* * Trivial case - we already have the blob. * This op - wrapping a raw key - is not supported for the * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1 format since that doesn't * operate on a key blob. */ rawBlob = CssmData::overlay(UnwrappedKey.KeyData); rawFormat = UnwrappedKey.blobFormat(); break; case CSSM_KEYBLOB_REFERENCE: /* get binary key, then get blob from it */ { BinaryKey &binKey = lookupRefKey(UnwrappedKey); /* * Subsequent tests for extractability: don't trust the * caller's header; use the one in the BinaryKey. */ CSSM_KEYATTR_FLAGS keyAttr = binKey.mKeyHeader.KeyAttr; if(!(keyAttr & CSSM_KEYATTR_EXTRACTABLE)) { /* this key not extractable in any form */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } /* * CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: we're ready to roll; * all we need is the reference key. */ if(wrapFormat == CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1) { break; } /* * Null wrap - prevent caller from obtaining * clear bits if CSSM_KEYATTR_SENSITIVE */ if(isNullWrap && (keyAttr & CSSM_KEYATTR_SENSITIVE)) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } /* * Special case for PKCS8 and openssl: need to get blob of a specific * algorithm-dependent format. Caller can override our * preference with a * CSSM_ATTRIBUTE_{PRIVATE,PUBLIC,SESSION}_KEY_FORMAT * context attribute. */ rawFormat = requestedKeyFormat(Context, UnwrappedKey); if(rawFormat == CSSM_KEYBLOB_RAW_FORMAT_NONE) { CSSM_ALGORITHMS keyAlg = binKey.mKeyHeader.AlgorithmId; switch(wrapFormat) { case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8: rawFormat = pkcs8RawKeyFormat(keyAlg); break; case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL: rawFormat = opensslRawKeyFormat(keyAlg); break; default: /* punt and take default for key type */ break; } } /* * DescriptiveData for encoding, currently only used for * SSH1 keys. */ if((DescriptiveData != NULL) && (DescriptiveData->Length != 0)) { binKey.descData(*DescriptiveData); } /* optional parameter-bearing key */ CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY); binKey.generateKeyBlob(privAllocator, rawBlob, rawFormat, *this, paramKey, unwrappedKeyAttrFlags); } allocdRawBlob = true; // remember - we need to free break; default: errorLog0("WrapKey: bad unwrappedKey BlobType\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } /* * Prepare outgoing header. */ setKeyHeader(wrappedHdr, plugin.myGuid(), unwrappedHdr.algorithm(), // same as incoming unwrappedHdr.keyClass(), // same as incoming unwrappedKeyAttrFlags, unwrappedHdr.KeyUsage); wrappedHdr.LogicalKeySizeInBits = unwrappedHdr.LogicalKeySizeInBits; wrappedHdr.WrapAlgorithmId = Context.algorithm(); // true for null // and non-Null wrappedHdr.StartDate = unwrappedHdr.StartDate; wrappedHdr.EndDate = unwrappedHdr.EndDate; wrappedHdr.Format = wrapFormat; if(isNullWrap) { wrappedHdr.BlobType = CSSM_KEYBLOB_RAW; } else { wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED; } /* * special cases - break out here for Apple Custom and OpenSSHv1 */ if(!isNullWrap) { switch(wrapFormat) { case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM: try { WrapKeyCms(CCHandle, Context, AccessCred, UnwrappedKey, rawBlob, allocdRawBlob, DescriptiveData, WrappedKey, Privilege); } catch(...) { if(allocdRawBlob) { freeCssmData(rawBlob, privAllocator); } throw; } if(allocdRawBlob) { freeCssmData(rawBlob, privAllocator); } return; case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: { /* * 1. We don't have to worry about allocdRawBlob since this * operation only works on reference keys and we did not * obtain the raw blob from the BinaryKey. * 2. This is a redundant lookupRefKey, I know, but since * that returns a reference, it would just be too messy to have * the previous call be in the same scope as this. */ BinaryKey &binKey = lookupRefKey(UnwrappedKey); WrapKeyOpenSSH1(CCHandle, Context, AccessCred, binKey, rawBlob, allocdRawBlob, DescriptiveData, WrappedKey, Privilege); return; } default: /* proceed to encrypt blob */ break; } } /* !isNullWrap */ /* * Generate wrapped blob. Careful, we need to conditionally free * rawBlob on error. */ CssmData encryptedBlob; CssmData remData; WrappedKey.KeyData.Data = NULL; // ignore possible incoming KeyData WrappedKey.KeyData.Length = 0; try { if(isNullWrap) { /* copy raw blob to caller's wrappedKey */ copyCssmData(rawBlob, CssmData::overlay(WrappedKey.KeyData), normAllocator); wrappedHdr.Format = rawFormat; } else { /* encrypt rawBlob using caller's context, then encode to * WrappedKey.KeyData */ CSSM_SIZE bytesEncrypted; EncryptData(CCHandle, Context, &rawBlob, // ClearBufs[] 1, // ClearBufCount &encryptedBlob, // CipherBufs[], 1, // CipherBufCount, bytesEncrypted, remData, Privilege); // I'm not 100% sure about this.... assert(remData.Length == 0); encryptedBlob.Length = bytesEncrypted; WrappedKey.KeyData = encryptedBlob; wrappedHdr.BlobType = CSSM_KEYBLOB_WRAPPED; // OK to be zero or not present wrappedHdr.WrapMode = Context.getInt( CSSM_ATTRIBUTE_MODE); } } catch (...) { errorLog0("WrapKey: EncryptData() threw exception\n"); if(allocdRawBlob) { freeCssmData(rawBlob, privAllocator); } freeCssmData(remData,normAllocator); throw; } if(allocdRawBlob) { freeCssmData(rawBlob, privAllocator); } freeCssmData(remData, normAllocator); }
/* * Unwrap key function. Used for: * * -- Given key of BlobType CSSM_KEYBLOB_WRAPPED, decode and decrypt * it, yielding a key in either raw or reference format. Unwrapping * key may be either raw or reference. The context must match * the unwrapping key (ALGCLASS_SYMMETRIC or ALGCLASS_ASYMMETRIC). * * Private keys are assumed to be PKCS8 encoded; session keys * are assumed to be PKCS7 encoded. * * -- Convert a Raw key to a reference key (with no decrypting). * This is called a NULL unwrap; no unwrapping key need be present in * the context, but the context must be of class * ALGCLASS_SYMMETRIC and algorithm ALGID_NONE. */ void AppleCSPSession::UnwrapKey( CSSM_CC_HANDLE CCHandle, const Context &Context, const CssmKey *PublicKey, const CssmKey &WrappedKey, uint32 KeyUsage, uint32 KeyAttr, const CssmData *KeyLabel, const CSSM_RESOURCE_CONTROL_CONTEXT *CredAndAclEntry, CssmKey &UnwrappedKey, CssmData &DescriptiveData, CSSM_PRIVILEGE Privilege) { bool isNullUnwrap = false; CssmKey *unwrappingKey = NULL; cspKeyType keyType; // CKT_Public, etc. CSSM_KEYBLOB_FORMAT wrapFormat = WrappedKey.blobFormat(); /* obtain unwrapping key if present */ unwrappingKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_KEY); if(unwrappingKey == NULL) { if((Context.algorithm() == CSSM_ALGID_NONE) && (Context.type() == CSSM_ALGCLASS_SYMMETRIC)) { // NULL unwrap, OK isNullUnwrap = true; } else { errorLog0("UnwrapKey: missing wrapping key\n"); CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_KEY); } } /* * validate unwrappingKey */ if(!isNullUnwrap) { /* make sure unwrapping key type matches context */ CSSM_CONTEXT_TYPE unwrapType; switch(unwrappingKey->KeyHeader.KeyClass) { case CSSM_KEYCLASS_PUBLIC_KEY: case CSSM_KEYCLASS_PRIVATE_KEY: unwrapType = CSSM_ALGCLASS_ASYMMETRIC; break; case CSSM_KEYCLASS_SESSION_KEY: unwrapType = CSSM_ALGCLASS_SYMMETRIC; break; default: errorLog0("UnwrapKey: bad class of wrappingKey\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); } if(unwrapType != Context.type()) { errorLog0("UnwrapKey: mismatch unwrappingKey/contextType\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); } if(Context.algorithm() == CSSM_ALGID_NONE) { errorLog0("UnwrapKey: null wrap alg, non-null key\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } cspValidateIntendedKeyUsage(&unwrappingKey->KeyHeader, CSSM_KEYUSE_UNWRAP); cspVerifyKeyTimes(unwrappingKey->KeyHeader); } /* validate WrappedKey */ switch(WrappedKey.keyClass()) { case CSSM_KEYCLASS_PUBLIC_KEY: #if !ALLOW_PUB_KEY_WRAP if(!isNullUnwrap) { errorLog0("UnwrapKey: unwrap of public key illegal\n"); CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } #endif /* ALLOW_PUB_KEY_WRAP */ keyType = CKT_Public; break; case CSSM_KEYCLASS_PRIVATE_KEY: keyType = CKT_Private; break; case CSSM_KEYCLASS_SESSION_KEY: keyType = CKT_Session; break; default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } if(isNullUnwrap) { if(WrappedKey.blobType() != CSSM_KEYBLOB_RAW) { errorLog0("UnwrapKey: expected raw blobType\n"); CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); } } else { if(WrappedKey.blobType() != CSSM_KEYBLOB_WRAPPED) { errorLog0("UnwrapKey: expected wrapped blobType\n"); CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); } } /* validate requested storage and usage */ cspKeyStorage keyStorage = cspParseKeyAttr(keyType, KeyAttr); switch(keyStorage) { case CKS_Ref: case CKS_Data: break; // OK default: CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK); } cspValidateKeyUsageBits(keyType, KeyUsage); /* prepare outgoing header */ CssmKey::Header &unwrappedHdr = UnwrappedKey.header(); const CssmKey::Header &wrappedHdr = WrappedKey.header(); setKeyHeader(unwrappedHdr, plugin.myGuid(), wrappedHdr.algorithm(), // same as incoming wrappedHdr.keyClass(), // same as incoming KeyAttr & ~KEY_ATTR_RETURN_MASK, KeyUsage); unwrappedHdr.LogicalKeySizeInBits = wrappedHdr.LogicalKeySizeInBits; unwrappedHdr.StartDate = wrappedHdr.StartDate; unwrappedHdr.EndDate = wrappedHdr.EndDate; UnwrappedKey.KeyData.Data = NULL; // ignore possible incoming KeyData UnwrappedKey.KeyData.Length = 0; /* validate wrappedKey format */ if(!isNullUnwrap) { switch(wrapFormat) { case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7: if(WrappedKey.keyClass() != CSSM_KEYCLASS_SESSION_KEY) { /* this unwrapping style only for symmetric keys */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } break; case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8: case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL: if(WrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) { /* these unwrapping styles only for private keys */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } break; case CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM: UnwrapKeyCms(CCHandle, Context, WrappedKey, CredAndAclEntry, UnwrappedKey, DescriptiveData, Privilege, keyStorage); return; case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSH1: /* RSA private key, unwrap to ref key only */ if(WrappedKey.keyClass() != CSSM_KEYCLASS_PRIVATE_KEY) { CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); } if(WrappedKey.algorithm() != CSSM_ALGID_RSA) { CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); } if(keyStorage != CKS_Ref) { errorLog0("UNwrapKey: OPENSSH1 only wraps to reference key\n"); CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); } UnwrapKeyOpenSSH1(CCHandle, Context, WrappedKey, CredAndAclEntry, UnwrappedKey, DescriptiveData, Privilege, keyStorage); return; default: CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_WRAPPED_KEY_FORMAT); } } /* Get key blob, decoding and decrypting if necessary */ CssmData decodedBlob; CssmData remData; try { if(isNullUnwrap) { /* simple copy of raw blob */ copyData(WrappedKey.KeyData, UnwrappedKey.KeyData, normAllocator); unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW; unwrappedHdr.Format = wrapFormat; } else { decodedBlob = CssmData::overlay(WrappedKey.KeyData); CSSM_SIZE bytesDecrypted; CssmData *unwrapData = CssmData::overlay(&UnwrappedKey.KeyData); DecryptData(CCHandle, Context, &decodedBlob, // CipherBufs[], 1, // CipherBufCount, unwrapData, // ClearBufs[] 1, // ClearBufCount bytesDecrypted, remData, Privilege); // I'm not 100% sure about this.... assert(remData.Length == 0); UnwrappedKey.KeyData.Length = bytesDecrypted; unwrappedHdr.BlobType = CSSM_KEYBLOB_RAW; /* * Figure out various header fields from resulting blob */ switch(wrapFormat) { case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS7: unwrappedHdr.Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; if(unwrappedHdr.LogicalKeySizeInBits == 0) { unwrappedHdr.LogicalKeySizeInBits = (unsigned)(bytesDecrypted * 8); } /* app has to infer/know algorithm */ break; case CSSM_KEYBLOB_WRAPPED_FORMAT_PKCS8: pkcs8InferKeyHeader(UnwrappedKey); break; case CSSM_KEYBLOB_WRAPPED_FORMAT_OPENSSL: /* * App told us key algorithm (in WrappedKey). * Infer format and key size. */ opensslInferKeyHeader(UnwrappedKey); break; } } } catch (...) { errorLog0("UnwrapKey: DecryptData() threw exception\n"); freeCssmData(remData, normAllocator); throw; } freeCssmData(remData, normAllocator); /* * One more thing: cook up a BinaryKey if caller wants a * reference key. */ if(keyStorage == CKS_Ref) { /* * We have a key in raw format; convert to BinaryKey. */ BinaryKey *binKey = NULL; CSPKeyInfoProvider *provider = infoProvider(UnwrappedKey); /* optional parameter-bearing key */ CssmKey *paramKey = Context.get<CssmKey>(CSSM_ATTRIBUTE_PARAM_KEY); provider->CssmKeyToBinary(paramKey, UnwrappedKey.KeyHeader.KeyAttr, &binKey); addRefKey(*binKey, UnwrappedKey); delete provider; } }
// // Decode a key blob // void DatabaseCryptoCore::decodeKeyCore(KeyBlob *blob, CssmKey &key, void * &pubAcl, void * &privAcl) const { // Assemble the encrypted blob as a CSSM "wrapped key" CssmKey wrappedKey; wrappedKey.KeyHeader = blob->header; h2ni(wrappedKey.KeyHeader); wrappedKey.blobType(blob->wrappedHeader.blobType); wrappedKey.blobFormat(blob->wrappedHeader.blobFormat); wrappedKey.wrapAlgorithm(blob->wrappedHeader.wrapAlgorithm); wrappedKey.wrapMode(blob->wrappedHeader.wrapMode); wrappedKey.KeyData = CssmData(blob->cryptoBlob(), blob->cryptoBlobLength()); bool inTheClear = blob->isClearText(); if(!inTheClear) { // verify signature (check against corruption) assert(isValid()); // need our database secrets CssmData signChunk[] = { CssmData::wrap(blob, fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CSSM_ALGORITHMS verifyAlgorithm = CSSM_ALGID_SHA1HMAC; #if defined(COMPAT_OSX_10_0) if (blob->version() == blob->version_MacOS_10_0) verifyAlgorithm = CSSM_ALGID_SHA1HMAC_LEGACY; // BSafe bug compatibility #endif VerifyMac verifier(Server::csp(), verifyAlgorithm); verifier.key(mSigningKey); CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); verifier.verify(signChunk, 2, signature); } /* else signature indicates cleartext */ // extract and hold some header bits the CSP does not want to see uint32 heldAttributes = n2h(blob->header.attributes()) & managedAttributes; CssmData privAclData; if(inTheClear) { /* NULL unwrap */ UnwrapKey unwrap(Server::csp(), CSSM_ALGID_NONE); wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?) unwrap(wrappedKey, KeySpec(n2h(blob->header.usage()), (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes), key, &privAclData); } else { // decrypt the key using an unwrapping operation UnwrapKey unwrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); unwrap.key(mEncryptionKey); unwrap.mode(CSSM_ALGMODE_CBCPadIV8); unwrap.padding(CSSM_PADDING_PKCS1); CssmData ivd(blob->iv, sizeof(blob->iv)); unwrap.initVector(ivd); unwrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)); wrappedKey.clearAttribute(managedAttributes); //@@@ shouldn't be needed(?) unwrap(wrappedKey, KeySpec(n2h(blob->header.usage()), (n2h(blob->header.attributes()) & ~managedAttributes) | forcedAttributes), key, &privAclData); } // compare retrieved key headers with blob headers (sanity check) // @@@ this should probably be checked over carefully CssmKey::Header &real = key.header(); CssmKey::Header &incoming = blob->header; n2hi(incoming); if (real.HeaderVersion != incoming.HeaderVersion || real.cspGuid() != incoming.cspGuid()) CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); if (real.algorithm() != incoming.algorithm()) CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); // re-insert held bits key.header().KeyAttr |= heldAttributes; if(inTheClear && (real.keyClass() != CSSM_KEYCLASS_PUBLIC_KEY)) { /* Spoof - cleartext KeyBlob passed off as private key */ CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); } // got a valid key: return the pieces pubAcl = blob->publicAclBlob(); // points into blob (shared) privAcl = privAclData; // was allocated by CSP decrypt, else NULL for // cleatext keys // key was set by unwrap operation }
// // Encode a key blob // KeyBlob *DatabaseCryptoCore::encodeKeyCore(const CssmKey &inKey, const CssmData &publicAcl, const CssmData &privateAcl, bool inTheClear) const { CssmKey key = inKey; uint8 iv[8]; CssmKey wrappedKey; if(inTheClear && (privateAcl.Length != 0)) { /* can't store private ACL component in the clear */ CssmError::throwMe(CSSMERR_DL_INVALID_ACCESS_CREDENTIALS); } // extract and hold some header bits the CSP does not want to see uint32 heldAttributes = key.attributes() & managedAttributes; key.clearAttribute(managedAttributes); key.setAttribute(forcedAttributes); if(inTheClear) { /* NULL wrap of public key */ WrapKey wrap(Server::csp(), CSSM_ALGID_NONE); wrap(key, wrappedKey, NULL); } else { assert(isValid()); // need our database secrets // create new IV Server::active().random(iv); // use a CMS wrap to encrypt the key WrapKey wrap(Server::csp(), CSSM_ALGID_3DES_3KEY_EDE); wrap.key(mEncryptionKey); wrap.mode(CSSM_ALGMODE_CBCPadIV8); wrap.padding(CSSM_PADDING_PKCS1); CssmData ivd(iv, sizeof(iv)); wrap.initVector(ivd); wrap.add(CSSM_ATTRIBUTE_WRAPPED_KEY_FORMAT, uint32(CSSM_KEYBLOB_WRAPPED_FORMAT_APPLE_CUSTOM)); wrap(key, wrappedKey, &privateAcl); } // stick the held attribute bits back in key.clearAttribute(forcedAttributes); key.setAttribute(heldAttributes); // allocate the final KeyBlob, uh, blob size_t length = sizeof(KeyBlob) + publicAcl.length() + wrappedKey.length(); KeyBlob *blob = Allocator::standard().malloc<KeyBlob>(length); // assemble the KeyBlob memset(blob, 0, sizeof(KeyBlob)); // fill alignment gaps blob->initialize(); if(!inTheClear) { memcpy(blob->iv, iv, sizeof(iv)); } blob->header = key.header(); h2ni(blob->header); // endian-correct the header blob->wrappedHeader.blobType = wrappedKey.blobType(); blob->wrappedHeader.blobFormat = wrappedKey.blobFormat(); blob->wrappedHeader.wrapAlgorithm = wrappedKey.wrapAlgorithm(); blob->wrappedHeader.wrapMode = wrappedKey.wrapMode(); memcpy(blob->publicAclBlob(), publicAcl, publicAcl.length()); blob->startCryptoBlob = sizeof(KeyBlob) + publicAcl.length(); memcpy(blob->cryptoBlob(), wrappedKey.data(), wrappedKey.length()); blob->totalLength = blob->startCryptoBlob + wrappedKey.length(); if(inTheClear) { /* indicate that this is cleartext for decoding */ blob->setClearTextSignature(); } else { // sign the blob CssmData signChunk[] = { CssmData(blob->data(), fieldOffsetOf(&KeyBlob::blobSignature)), CssmData(blob->publicAclBlob(), blob->publicAclBlobLength() + blob->cryptoBlobLength()) }; CssmData signature(blob->blobSignature, sizeof(blob->blobSignature)); GenerateMac signer(Server::csp(), CSSM_ALGID_SHA1HMAC_LEGACY); //@@@!!! CRUD signer.key(mSigningKey); signer.sign(signChunk, 2, signature); assert(signature.length() == sizeof(blob->blobSignature)); } // all done. Clean up Server::csp()->allocator().free(wrappedKey); return blob; }
void KeyDataAttributeCoder::decode(TokenContext *tokenContext, const MetaAttribute &metaAttribute, Record &record) { const MetaRecord &mr = metaAttribute.metaRecord(); CssmKey key; key.header().cspGuid(Guid::overlay(gGuidAppleSdCSPDL)); key.blobType(CSSM_KEYBLOB_REFERENCE); key.blobFormat(CSSM_KEYBLOB_REF_FORMAT_INTEGER); key.algorithm(mr.metaAttribute(kSecKeyKeyType) .attribute(tokenContext, record).uint32Value()); key.keyClass(mr.metaAttribute(kSecKeyKeyClass) .attribute(tokenContext, record).uint32Value()); key.header().LogicalKeySizeInBits = mr.metaAttribute(kSecKeyKeySizeInBits).attribute(tokenContext, record) .uint32Value(); key.header().KeyAttr = (mr.metaAttribute(kSecKeyPermanent).attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_PERMANENT : 0) | (mr.metaAttribute(kSecKeyPrivate).attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_PRIVATE : 0) | (mr.metaAttribute(kSecKeyModifiable).attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_MODIFIABLE : 0) | (mr.metaAttribute(kSecKeySensitive).attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_SENSITIVE : 0) | (mr.metaAttribute(kSecKeyAlwaysSensitive) .attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_ALWAYS_SENSITIVE : 0) | (mr.metaAttribute(kSecKeyExtractable).attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_EXTRACTABLE : 0) | (mr.metaAttribute(kSecKeyNeverExtractable) .attribute(tokenContext, record) .boolValue() ? CSSM_KEYATTR_NEVER_EXTRACTABLE : 0); CSSM_KEYUSE usage = (mr.metaAttribute(kSecKeyEncrypt).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_ENCRYPT : 0) | (mr.metaAttribute(kSecKeyDecrypt).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_DECRYPT : 0) | (mr.metaAttribute(kSecKeySign).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_SIGN : 0) | (mr.metaAttribute(kSecKeyVerify).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_VERIFY : 0) | (mr.metaAttribute(kSecKeySignRecover).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_SIGN_RECOVER : 0) | (mr.metaAttribute(kSecKeyVerifyRecover) .attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_VERIFY_RECOVER : 0) | (mr.metaAttribute(kSecKeyWrap).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_WRAP : 0) | (mr.metaAttribute(kSecKeyUnwrap).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_UNWRAP : 0) | (mr.metaAttribute(kSecKeyDerive).attribute(tokenContext, record) .boolValue() ? CSSM_KEYUSE_DERIVE : 0); if (usage == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP | CSSM_KEYUSE_UNWRAP | CSSM_KEYUSE_DERIVE)) usage = CSSM_KEYUSE_ANY; key.header().KeyUsage = usage; // Dates mr.metaAttribute(kSecKeyStartDate).attribute(tokenContext, record) .getDateValue(key.header().StartDate); mr.metaAttribute(kSecKeyEndDate).attribute(tokenContext, record) .getDateValue(key.header().EndDate); record.attributeAtIndex(metaAttribute.attributeIndex(), new Attribute(&key, sizeof(key))); }
// 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, after safe completion of // generateKeyBlob (which may throw, in which case the binary keys // get deleted by our caller). CSSM_KEYATTR_FLAGS attrFlags = 0; 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, session, NULL, // no paramKey here! attrFlags); break; case CKS_None: 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, session, NULL, attrFlags); break; case CKS_None: break; } if(pubStorage != CKS_Ref) { delete pubBinKey; } if(privStorage != CKS_Ref) { delete privBinKey; } }
/* * 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? }