]> git.saurik.com Git - apple/security.git/blobdiff - securityd/src/localdatabase.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / securityd / src / localdatabase.cpp
diff --git a/securityd/src/localdatabase.cpp b/securityd/src/localdatabase.cpp
new file mode 100644 (file)
index 0000000..418cc31
--- /dev/null
@@ -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 <security_agent_client/agentclient.h>
+#include <security_cdsa_utilities/acl_any.h>   // for default owner ACLs
+#include <security_cdsa_client/wrapkey.h>
+#include <security_cdsa_client/genkey.h>
+#include <security_cdsa_client/signclient.h>
+#include <security_cdsa_client/cryptoclient.h>
+#include <security_cdsa_client/macclient.h>
+#include <security_utilities/endian.h>
+
+
+//
+// Create a Database object from initial parameters (create operation)
+//
+LocalDatabase::LocalDatabase(Process &proc)
+       : Database(proc)
+{
+}
+
+
+static inline LocalKey &myKey(Key &key)
+{
+       return safer_cast<LocalKey &>(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<Key> &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<Key> &publicKey, RefPointer<Key> &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<Key> &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<Key> &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);
+}