1/* 2 * Copyright (c) 2004,2006,2008 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25// 26// localdatabase - locally implemented database using internal CSP cryptography 27// 28#include "localdatabase.h" 29#include "agentquery.h" 30#include "localkey.h" 31#include "server.h" 32#include "session.h" 33#include <security_agent_client/agentclient.h> 34#include <security_cdsa_utilities/acl_any.h> // for default owner ACLs 35#include <security_cdsa_client/wrapkey.h> 36#include <security_cdsa_client/genkey.h> 37#include <security_cdsa_client/signclient.h> 38#include <security_cdsa_client/cryptoclient.h> 39#include <security_cdsa_client/macclient.h> 40#include <security_utilities/endian.h> 41 42 43// 44// Create a Database object from initial parameters (create operation) 45// 46LocalDatabase::LocalDatabase(Process &proc) 47 : Database(proc) 48{ 49} 50 51 52static inline LocalKey &myKey(Key &key) 53{ 54 return safer_cast<LocalKey &>(key); 55} 56 57 58// 59// Key inquiries 60// 61void LocalDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result) 62{ 63 CssmClient::Key theKey(Server::csp(), myKey(key)); 64 result = theKey.sizeInBits(); 65} 66 67 68// 69// Signatures and MACs 70// 71void LocalDatabase::generateSignature(const Context &context, Key &key, 72 CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature) 73{ 74 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 75 key.validate(CSSM_ACL_AUTHORIZATION_SIGN, context); 76 CssmClient::Sign signer(Server::csp(), context.algorithm(), signOnlyAlgorithm); 77 signer.override(context); 78 signer.sign(data, signature); 79} 80 81void LocalDatabase::verifySignature(const Context &context, Key &key, 82 CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature) 83{ 84 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 85 CssmClient::Verify verifier(Server::csp(), context.algorithm(), verifyOnlyAlgorithm); 86 verifier.override(context); 87 verifier.verify(data, signature); 88} 89 90void LocalDatabase::generateMac(const Context &context, Key &key, 91 const CssmData &data, CssmData &mac) 92{ 93 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 94 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); 95 CssmClient::GenerateMac signer(Server::csp(), context.algorithm()); 96 signer.override(context); 97 signer.sign(data, mac); 98} 99 100void LocalDatabase::verifyMac(const Context &context, Key &key, 101 const CssmData &data, const CssmData &mac) 102{ 103 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 104 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); 105 CssmClient::VerifyMac verifier(Server::csp(), context.algorithm()); 106 verifier.override(context); 107 verifier.verify(data, mac); 108} 109 110 111// 112// Encryption/decryption 113// 114void LocalDatabase::encrypt(const Context &context, Key &key, 115 const CssmData &clear, CssmData &cipher) 116{ 117 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 118 key.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); 119 CssmClient::Encrypt cryptor(Server::csp(), context.algorithm()); 120 cryptor.override(context); 121 CssmData remData; 122 size_t totalLength = cryptor.encrypt(clear, cipher, remData); 123 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it 124 if (remData) 125 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 126 cipher.length(totalLength); 127} 128 129void LocalDatabase::decrypt(const Context &context, Key &key, 130 const CssmData &cipher, CssmData &clear) 131{ 132 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 133 key.validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); 134 CssmClient::Decrypt cryptor(Server::csp(), context.algorithm()); 135 cryptor.override(context); 136 CssmData remData; 137 size_t totalLength = cryptor.decrypt(cipher, clear, remData); 138 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it 139 if (remData) 140 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 141 clear.length(totalLength); 142} 143 144 145// 146// Key generation and derivation. 147// Currently, we consider symmetric key generation to be fast, but 148// asymmetric key generation to be (potentially) slow. 149// 150void LocalDatabase::generateKey(const Context &context, 151 const AccessCredentials *cred, const AclEntryPrototype *owner, 152 uint32 usage, uint32 attrs, RefPointer<Key> &newKey) 153{ 154 // prepare a context 155 CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); 156 generate.override(context); 157 158 // generate key 159 // @@@ turn "none" return into reference if permanent (only) 160 CssmKey key; 161 generate(key, LocalKey::KeySpec(usage, attrs)); 162 163 // register and return the generated key 164 newKey = makeKey(key, attrs & LocalKey::managedAttributes, owner); 165} 166 167void LocalDatabase::generateKey(const Context &context, 168 const AccessCredentials *cred, const AclEntryPrototype *owner, 169 uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, 170 RefPointer<Key> &publicKey, RefPointer<Key> &privateKey) 171{ 172 // prepare a context 173 CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); 174 generate.override(context); 175 176 // this may take a while; let our server object know 177 Server::active().longTermActivity(); 178 179 // generate keys 180 // @@@ turn "none" return into reference if permanent (only) 181 CssmKey pubKey, privKey; 182 generate(pubKey, LocalKey::KeySpec(pubUsage, pubAttrs), 183 privKey, LocalKey::KeySpec(privUsage, privAttrs)); 184 185 // register and return the generated keys 186 publicKey = makeKey(pubKey, pubAttrs & LocalKey::managedAttributes, 187 (pubAttrs & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) ? owner : NULL); 188 privateKey = makeKey(privKey, privAttrs & LocalKey::managedAttributes, owner); 189} 190 191 192// 193// Key wrapping and unwrapping. 194// Note that the key argument (the key in the context) is optional because of the special 195// case of "cleartext" (null algorithm) wrapping for import/export. 196// 197 198void LocalDatabase::wrapKey(const Context &context, const AccessCredentials *cred, 199 Key *wrappingKey, Key &keyToBeWrapped, 200 const CssmData &descriptiveData, CssmKey &wrappedKey) 201{ 202 keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ? 203 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, 204 cred); 205 if (wrappingKey) { 206 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); 207 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); 208 } 209 CssmClient::WrapKey wrap(Server::csp(), context.algorithm()); 210 wrap.override(context); 211 wrap.cred(cred); 212 wrap(myKey(keyToBeWrapped), wrappedKey, &descriptiveData); 213} 214 215void LocalDatabase::unwrapKey(const Context &context, 216 const AccessCredentials *cred, const AclEntryPrototype *owner, 217 Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, 218 const CssmKey wrappedKey, RefPointer<Key> &unwrappedKey, CssmData &descriptiveData) 219{ 220 if (wrappingKey) { 221 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); 222 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); 223 } 224 // we are not checking access on the public key, if any 225 226 CssmClient::UnwrapKey unwrap(Server::csp(), context.algorithm()); 227 unwrap.override(context); 228 unwrap.cred(cred); 229 230 // the AclEntryInput will have to live until unwrap is done 231 AclEntryInput ownerInput; 232 if (owner) { 233 ownerInput.proto() = *owner; 234 unwrap.owner(ownerInput); 235 } 236 237 CssmKey result; 238 unwrap(wrappedKey, LocalKey::KeySpec(usage, attrs), result, &descriptiveData, 239 publicKey ? &myKey(*publicKey).cssmKey() : NULL); 240 unwrappedKey = makeKey(result, attrs & LocalKey::managedAttributes, owner); 241} 242 243 244// 245// Key derivation 246// 247void LocalDatabase::deriveKey(const Context &context, Key *key, 248 const AccessCredentials *cred, const AclEntryPrototype *owner, 249 CssmData *param, uint32 usage, uint32 attrs, RefPointer<Key> &derivedKey) 250{ 251 if (key) { 252 key->validate(CSSM_ACL_AUTHORIZATION_DERIVE, context); 253 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); 254 } 255 CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE); 256 derive.override(context); 257 258 // derive key 259 // @@@ turn "none" return into reference if permanent (only) 260 CssmKey dKey; 261 derive(param, LocalKey::KeySpec(usage, attrs), dKey); 262 263 // register and return the generated key 264 derivedKey = makeKey(dKey, attrs & LocalKey::managedAttributes, owner); 265} 266 267 268// 269// Miscellaneous CSSM functions 270// 271void LocalDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, 272 bool encrypt, uint32 &result) 273{ 274 // We're fudging here somewhat, since the context can be any type. 275 // ctx.override will fix the type, and no-one's the wiser. 276 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 277 CssmClient::Digest ctx(Server::csp(), context.algorithm()); 278 ctx.override(context); 279 result = ctx.getOutputSize(inputSize, encrypt); 280} 281