-/*
- * Copyright (c) 2000-2001,2008 Apple 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.
- */
-
-
-//
-// SSKey - reference keys for the security server
-//
-#include "SSKey.h"
-
-#include "SSCSPSession.h"
-#include "SSCSPDLSession.h"
-#include "SSDatabase.h"
-#include "SSDLSession.h"
-#include <security_cdsa_utilities/KeySchema.h>
-#include <security_cdsa_plugin/cssmplugin.h>
-
-using namespace CssmClient;
-using namespace SecurityServer;
-
-// Constructor for a Security Server generated key.
-SSKey::SSKey(SSCSPSession &session, KeyHandle keyHandle, CssmKey &ioKey,
- SSDatabase &inSSDatabase, uint32 inKeyAttr,
- const CssmData *inKeyLabel)
-: ReferencedKey(session.mSSCSPDLSession),
-mAllocator(session), mKeyHandle(keyHandle),
-mClientSession(session.clientSession())
-{
- CssmKey::Header &header = ioKey.header();
- if (inKeyAttr & CSSM_KEYATTR_PERMANENT)
- {
- if (!inSSDatabase)
- 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(inSSDatabase);
- 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 = inSSDatabase->insert(mRecordType, &attributes, &blob,
- true);
- }
-
- header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
- makeReferenceKey(mAllocator, keyReference(), ioKey);
-}
-
-// Constructor for a key retrived from a Db.
-SSKey::SSKey(SSDLSession &session, CssmKey &ioKey, SSDatabase &inSSDatabase,
- const SSUniqueRecord &uniqueId, CSSM_DB_RECORDTYPE recordType,
- CssmData &keyBlob)
-: ReferencedKey(session.mSSCSPDLSession),
-mAllocator(session.allocator()), mKeyHandle(noKey), mUniqueId(uniqueId),
-mRecordType(recordType),
-mClientSession(session.clientSession())
-{
- CssmKey::Header &header = ioKey.header();
- 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);
-
- makeReferenceKey(mAllocator, keyReference(), ioKey);
- header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
-}
-
-SSKey::~SSKey()
-{
- if (mKeyHandle != noKey)
- clientSession().releaseKey(mKeyHandle);
-}
-
-void
-SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey,
- CSSM_BOOL deleteKey)
-{
- freeReferenceKey(mAllocator, ioKey);
- if (deleteKey)
- {
- if (!mUniqueId || !mUniqueId->database())
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
-
- // @@@ Evaluate accessCred against Db acl.
- // What should we do with accessCred? Reauthenticate
- // mUniqueId->database()?
- mUniqueId->deleteRecord();
- }
-
- if (mKeyHandle != noKey)
- {
- clientSession().releaseKey(mKeyHandle);
- mKeyHandle = noKey;
- }
-}
-
-SecurityServer::ClientSession &
-SSKey::clientSession()
-{
- return mClientSession;
-}
-
-KeyHandle SSKey::optionalKeyHandle() const
-{
- return mKeyHandle;
-}
-
-KeyHandle
-SSKey::keyHandle()
-{
- if (mKeyHandle == noKey)
- {
- // Deal with uninstantiated keys.
- if (!mUniqueId || !mUniqueId->database())
- CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
-
- CssmDataContainer blob(mAllocator);
- mUniqueId->get(NULL, &blob);
- CssmKey::Header dummyHeader; // @@@ Unused
- mKeyHandle =
- clientSession().decodeKey(mUniqueId->database().dbHandle(), blob,
- dummyHeader);
-
- // @@@ Check decoded header against returned header
- }
-
- return mKeyHandle;
-}
-
-//
-// ACL retrieval and change operations
-//
-void
-SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE &owner, Allocator &allocator)
-{
- clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner),
- allocator);
-}
-
-void
-SSKey::changeOwner(const AccessCredentials &accessCred,
- const AclOwnerPrototype &newOwner)
-{
- clientSession().changeKeyOwner(keyHandle(), accessCred, newOwner);
- didChangeAcl();
-}
-
-void
-SSKey::getAcl(const char *selectionTag, uint32 &numberOfAclInfos,
- AclEntryInfo *&aclInfos, Allocator &allocator)
-{
- clientSession().getKeyAcl(keyHandle(), selectionTag, numberOfAclInfos,
- aclInfos, allocator);
-}
-
-void
-SSKey::changeAcl(const AccessCredentials &accessCred, const AclEdit &aclEdit)
-{
- clientSession().changeKeyAcl(keyHandle(), accessCred, aclEdit);
- didChangeAcl();
-}
-
-void
-SSKey::didChangeAcl()
-{
- if (mUniqueId == true)
- {
- secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle);
- // The key is persistent, make the change on disk.
- CssmDataContainer keyBlob(mAllocator);
- clientSession().encodeKey(keyHandle(), keyBlob);
- mUniqueId->modify(mRecordType, NULL, &keyBlob, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
- }
- else
- {
- secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle);
- }
-}