localdatabase.cpp
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_cdsa_utilities/acl_any.h> // for default owner ACLs 34 #include <security_cdsa_client/wrapkey.h> 35 #include <security_cdsa_client/genkey.h> 36 #include <security_cdsa_client/signclient.h> 37 #include <security_cdsa_client/cryptoclient.h> 38 #include <security_cdsa_client/macclient.h> 39 #include <security_utilities/endian.h> 40 41 42 // 43 // Create a Database object from initial parameters (create operation) 44 // 45 LocalDatabase::LocalDatabase(Process &proc) 46 : Database(proc) 47 { 48 } 49 50 51 static inline LocalKey &myKey(Key &key) 52 { 53 return safer_cast<LocalKey &>(key); 54 } 55 56 57 // 58 // Key inquiries 59 // 60 void LocalDatabase::queryKeySizeInBits(Key &key, CssmKeySize &result) 61 { 62 CssmClient::Key theKey(Server::csp(), myKey(key)); 63 result = theKey.sizeInBits(); 64 } 65 66 67 // 68 // Signatures and MACs 69 // 70 void LocalDatabase::generateSignature(const Context &context, Key &key, 71 CSSM_ALGORITHMS signOnlyAlgorithm, const CssmData &data, CssmData &signature) 72 { 73 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 74 key.validate(CSSM_ACL_AUTHORIZATION_SIGN, context); 75 CssmClient::Sign signer(Server::csp(), context.algorithm(), signOnlyAlgorithm); 76 signer.override(context); 77 signer.sign(data, signature); 78 } 79 80 void LocalDatabase::verifySignature(const Context &context, Key &key, 81 CSSM_ALGORITHMS verifyOnlyAlgorithm, const CssmData &data, const CssmData &signature) 82 { 83 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 84 CssmClient::Verify verifier(Server::csp(), context.algorithm(), verifyOnlyAlgorithm); 85 verifier.override(context); 86 verifier.verify(data, signature); 87 } 88 89 void LocalDatabase::generateMac(const Context &context, Key &key, 90 const CssmData &data, CssmData &mac) 91 { 92 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 93 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); 94 CssmClient::GenerateMac signer(Server::csp(), context.algorithm()); 95 signer.override(context); 96 signer.sign(data, mac); 97 } 98 99 void LocalDatabase::verifyMac(const Context &context, Key &key, 100 const CssmData &data, const CssmData &mac) 101 { 102 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 103 key.validate(CSSM_ACL_AUTHORIZATION_MAC, context); 104 CssmClient::VerifyMac verifier(Server::csp(), context.algorithm()); 105 verifier.override(context); 106 verifier.verify(data, mac); 107 } 108 109 110 // 111 // Encryption/decryption 112 // 113 void LocalDatabase::encrypt(const Context &context, Key &key, 114 const CssmData &clear, CssmData &cipher) 115 { 116 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 117 key.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); 118 CssmClient::Encrypt cryptor(Server::csp(), context.algorithm()); 119 cryptor.override(context); 120 CssmData remData; 121 size_t totalLength = cryptor.encrypt(clear, cipher, remData); 122 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it 123 if (remData) 124 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 125 cipher.length(totalLength); 126 } 127 128 void LocalDatabase::decrypt(const Context &context, Key &key, 129 const CssmData &cipher, CssmData &clear) 130 { 131 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 132 key.validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); 133 CssmClient::Decrypt cryptor(Server::csp(), context.algorithm()); 134 cryptor.override(context); 135 CssmData remData; 136 size_t totalLength = cryptor.decrypt(cipher, clear, remData); 137 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it 138 if (remData) 139 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 140 clear.length(totalLength); 141 } 142 143 144 // 145 // Key generation and derivation. 146 // Currently, we consider symmetric key generation to be fast, but 147 // asymmetric key generation to be (potentially) slow. 148 // 149 void LocalDatabase::generateKey(const Context &context, 150 const AccessCredentials *cred, const AclEntryPrototype *owner, 151 uint32 usage, uint32 attrs, RefPointer<Key> &newKey) 152 { 153 // prepare a context 154 CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); 155 generate.override(context); 156 157 // generate key 158 // @@@ turn "none" return into reference if permanent (only) 159 CssmKey key; 160 generate(key, LocalKey::KeySpec(usage, attrs)); 161 162 // register and return the generated key 163 newKey = makeKey(key, attrs & LocalKey::managedAttributes, owner); 164 } 165 166 void LocalDatabase::generateKey(const Context &context, 167 const AccessCredentials *cred, const AclEntryPrototype *owner, 168 uint32 pubUsage, uint32 pubAttrs, uint32 privUsage, uint32 privAttrs, 169 RefPointer<Key> &publicKey, RefPointer<Key> &privateKey) 170 { 171 // prepare a context 172 CssmClient::GenerateKey generate(Server::csp(), context.algorithm()); 173 generate.override(context); 174 175 // this may take a while; let our server object know 176 Server::active().longTermActivity(); 177 178 // generate keys 179 // @@@ turn "none" return into reference if permanent (only) 180 CssmKey pubKey, privKey; 181 generate(pubKey, LocalKey::KeySpec(pubUsage, pubAttrs), 182 privKey, LocalKey::KeySpec(privUsage, privAttrs)); 183 184 // register and return the generated keys 185 publicKey = makeKey(pubKey, pubAttrs & LocalKey::managedAttributes, 186 (pubAttrs & CSSM_KEYATTR_PUBLIC_KEY_ENCRYPT) ? owner : NULL); 187 privateKey = makeKey(privKey, privAttrs & LocalKey::managedAttributes, owner); 188 } 189 190 191 // 192 // Key wrapping and unwrapping. 193 // Note that the key argument (the key in the context) is optional because of the special 194 // case of "cleartext" (null algorithm) wrapping for import/export. 195 // 196 197 void LocalDatabase::wrapKey(const Context &context, const AccessCredentials *cred, 198 Key *wrappingKey, Key &keyToBeWrapped, 199 const CssmData &descriptiveData, CssmKey &wrappedKey) 200 { 201 keyToBeWrapped.validate(context.algorithm() == CSSM_ALGID_NONE ? 202 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR : CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED, 203 cred, &keyToBeWrapped.database()); 204 if (wrappingKey) { 205 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); 206 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT, context); 207 } 208 CssmClient::WrapKey wrap(Server::csp(), context.algorithm()); 209 wrap.override(context); 210 wrap.cred(cred); 211 wrap(myKey(keyToBeWrapped), wrappedKey, &descriptiveData); 212 } 213 214 void LocalDatabase::unwrapKey(const Context &context, 215 const AccessCredentials *cred, const AclEntryPrototype *owner, 216 Key *wrappingKey, Key *publicKey, CSSM_KEYUSE usage, CSSM_KEYATTR_FLAGS attrs, 217 const CssmKey wrappedKey, RefPointer<Key> &unwrappedKey, CssmData &descriptiveData) 218 { 219 if (wrappingKey) { 220 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*wrappingKey).cssmKey()); 221 wrappingKey->validate(CSSM_ACL_AUTHORIZATION_DECRYPT, context); 222 } 223 // we are not checking access on the public key, if any 224 225 CssmClient::UnwrapKey unwrap(Server::csp(), context.algorithm()); 226 unwrap.override(context); 227 unwrap.cred(cred); 228 229 // the AclEntryInput will have to live until unwrap is done 230 AclEntryInput ownerInput; 231 if (owner) { 232 ownerInput.proto() = *owner; 233 unwrap.owner(ownerInput); 234 } 235 236 CssmKey result; 237 unwrap(wrappedKey, LocalKey::KeySpec(usage, attrs), result, &descriptiveData, 238 publicKey ? &myKey(*publicKey).cssmKey() : NULL); 239 unwrappedKey = makeKey(result, attrs & LocalKey::managedAttributes, owner); 240 } 241 242 243 // 244 // Key derivation 245 // 246 void LocalDatabase::deriveKey(const Context &context, Key *key, 247 const AccessCredentials *cred, const AclEntryPrototype *owner, 248 CssmData *param, uint32 usage, uint32 attrs, RefPointer<Key> &derivedKey) 249 { 250 if (key) { 251 key->validate(CSSM_ACL_AUTHORIZATION_DERIVE, context); 252 context.replace(CSSM_ATTRIBUTE_KEY, myKey(*key).cssmKey()); 253 } 254 CssmClient::DeriveKey derive(Server::csp(), context.algorithm(), CSSM_ALGID_NONE); 255 derive.override(context); 256 257 // derive key 258 // @@@ turn "none" return into reference if permanent (only) 259 CssmKey dKey; 260 derive(param, LocalKey::KeySpec(usage, attrs), dKey); 261 262 // register and return the generated key 263 derivedKey = makeKey(dKey, attrs & LocalKey::managedAttributes, owner); 264 } 265 266 267 // 268 // Miscellaneous CSSM functions 269 // 270 void LocalDatabase::getOutputSize(const Context &context, Key &key, uint32 inputSize, 271 bool encrypt, uint32 &result) 272 { 273 // We're fudging here somewhat, since the context can be any type. 274 // ctx.override will fix the type, and no-one's the wiser. 275 context.replace(CSSM_ATTRIBUTE_KEY, myKey(key).cssmKey()); 276 CssmClient::Digest ctx(Server::csp(), context.algorithm()); 277 ctx.override(context); 278 result = ctx.getOutputSize(inputSize, encrypt); 279 }