X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/securityd/src/localdatabase.cpp diff --git a/securityd/src/localdatabase.cpp b/securityd/src/localdatabase.cpp new file mode 100644 index 00000000..418cc311 --- /dev/null +++ b/securityd/src/localdatabase.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2004,2006,2008 Apple Inc. All Rights Reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The 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. + * + * @APPLE_LICENSE_HEADER_END@ + */ + + +// +// localdatabase - locally implemented database using internal CSP cryptography +// +#include "localdatabase.h" +#include "agentquery.h" +#include "localkey.h" +#include "server.h" +#include "session.h" +#include +#include // for default owner ACLs +#include +#include +#include +#include +#include +#include + + +// +// Create a Database object from initial parameters (create operation) +// +LocalDatabase::LocalDatabase(Process &proc) + : Database(proc) +{ +} + + +static inline LocalKey &myKey(Key &key) +{ + return safer_cast(key); +} + + +// +// Key inquiries +// +void LocalDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result) +{ + CssmClient::Key theKey(Server::csp(), myKey(key)); + result = theKey.sizeInBits(); +} + + +// +// Signatures and MACs +// +void LocalDatabase::generateSignature(const Context &context, Key &key, + CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + key.validate(CSSM_ACL_AUTHORIZATION_SIGN, context); + CssmClient::Sign signer(Server::csp(), context.algorithm(), signOnlyAlgorithm); + signer.override(context); + signer.sign(data, signature); +} + +void LocalDatabase::verifySignature(const Context &context, Key &key, + CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + CssmClient::Verify verifier(Server::csp(), context.algorithm(), verifyOnlyAlgorithm); + verifier.override(context); + verifier.verify(data, signature); +} + +void LocalDatabase::generateMac(const Context &context, Key &key, + const CssmData &data, CssmData &mac) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); + CssmClient::GenerateMac signer(Server::csp(), context.algorithm()); + signer.override(context); + signer.sign(data, mac); +} + +void LocalDatabase::verifyMac(const Context &context, Key &key, + const CssmData &data, const CssmData &mac) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); + CssmClient::VerifyMac verifier(Server::csp(), context.algorithm()); + verifier.override(context); + verifier.verify(data, mac); +} + + +// +// Encryption/decryption +// +void LocalDatabase::encrypt(const Context &context, Key &key, + const CssmData &clear, CssmData &cipher) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + key.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); + CssmClient::Encrypt cryptor(Server::csp(), context.algorithm()); + cryptor.override(context); + CssmData remData; + size_t totalLength = cryptor.encrypt(clear, cipher, remData); + // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it + if (remData) + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + cipher.length(totalLength); +} + +void LocalDatabase::decrypt(const Context &context, Key &key, + const CssmData &cipher, CssmData &clear) +{ + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + key.validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); + CssmClient::Decrypt cryptor(Server::csp(), context.algorithm()); + cryptor.override(context); + CssmData remData; + size_t totalLength = cryptor.decrypt(cipher, clear, remData); + // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it + if (remData) + CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); + clear.length(totalLength); +} + + +// +// Key generation and derivation. +// Currently, we consider symmetric key generation to be fast, but +// asymmetric key generation to be (potentially) slow. +// +void LocalDatabase::generateKey(const Context &context, + const AccessCredentials *cred, const AclEntryPrototype *owner, + uint32 usage, uint32 attrs, RefPointer &newKey) +{ + // prepare a context + CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); + generate.override(context); + + // generate key + // @@@ turn "none" return into reference if permanent (only) + CssmKey key; + generate(key, LocalKey::KeySpec(usage, attrs)); + + // register and return the generated key + newKey = makeKey(key, attrs & LocalKey::managedAttributes, owner); +} + +void LocalDatabase::generateKey(const Context &context, + const AccessCredentials *cred, const AclEntryPrototype *owner, + uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, + RefPointer &publicKey, RefPointer &privateKey) +{ + // prepare a context + CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); + generate.override(context); + + // this may take a while; let our server object know + Server::active().longTermActivity(); + + // generate keys + // @@@ turn "none" return into reference if permanent (only) + CssmKey pubKey, privKey; + generate(pubKey, LocalKey::KeySpec(pubUsage, pubAttrs), + privKey, LocalKey::KeySpec(privUsage, privAttrs)); + + // register and return the generated keys + publicKey = makeKey(pubKey, pubAttrs & LocalKey::managedAttributes, + (pubAttrs & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) ? owner : NULL); + privateKey = makeKey(privKey, privAttrs & LocalKey::managedAttributes, owner); +} + + +// +// Key wrapping and unwrapping. +// Note that the key argument (the key in the context) is optional because of the special +// case of "cleartext" (null algorithm) wrapping for import/export. +// + +void LocalDatabase::wrapKey(const Context &context, const AccessCredentials *cred, + Key *wrappingKey, Key &keyToBeWrapped, + const CssmData &descriptiveData, CssmKey &wrappedKey) +{ + keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ? + CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, + cred); + if (wrappingKey) { + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); + } + CssmClient::WrapKey wrap(Server::csp(), context.algorithm()); + wrap.override(context); + wrap.cred(cred); + wrap(myKey(keyToBeWrapped), wrappedKey, &descriptiveData); +} + +void LocalDatabase::unwrapKey(const Context &context, + const AccessCredentials *cred, const AclEntryPrototype *owner, + Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, + const CssmKey wrappedKey, RefPointer &unwrappedKey, CssmData &descriptiveData) +{ + if (wrappingKey) { + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); + wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); + } + // we are not checking access on the public key, if any + + CssmClient::UnwrapKey unwrap(Server::csp(), context.algorithm()); + unwrap.override(context); + unwrap.cred(cred); + + // the AclEntryInput will have to live until unwrap is done + AclEntryInput ownerInput; + if (owner) { + ownerInput.proto() = *owner; + unwrap.owner(ownerInput); + } + + CssmKey result; + unwrap(wrappedKey, LocalKey::KeySpec(usage, attrs), result, &descriptiveData, + publicKey ? &myKey(*publicKey).cssmKey() : NULL); + unwrappedKey = makeKey(result, attrs & LocalKey::managedAttributes, owner); +} + + +// +// Key derivation +// +void LocalDatabase::deriveKey(const Context &context, Key *key, + const AccessCredentials *cred, const AclEntryPrototype *owner, + CssmData *param, uint32 usage, uint32 attrs, RefPointer &derivedKey) +{ + if (key) { + key->validate(CSSM_ACL_AUTHORIZATION_DERIVE, context); + context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); + } + CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE); + derive.override(context); + + // derive key + // @@@ turn "none" return into reference if permanent (only) + CssmKey dKey; + derive(param, LocalKey::KeySpec(usage, attrs), dKey); + + // register and return the generated key + derivedKey = makeKey(dKey, attrs & LocalKey::managedAttributes, owner); +} + + +// +// Miscellaneous CSSM functions +// +void LocalDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, + bool encrypt, uint32 &result) +{ + // We're fudging here somewhat, since the context can be any type. + // ctx.override will fix the type, and no-one's the wiser. + context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); + CssmClient::Digest ctx(Server::csp(), context.algorithm()); + ctx.override(context); + result = ctx.getOutputSize(inputSize, encrypt); +}