]> git.saurik.com Git - apple/security.git/blob - securityd/src/localdatabase.cpp
Security-57031.40.6.tar.gz
[apple/security.git] / securityd / src / 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_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 //
46 LocalDatabase::LocalDatabase(Process &proc)
47 : Database(proc)
48 {
49 }
50
51
52 static inline LocalKey &myKey(Key &key)
53 {
54 return safer_cast<LocalKey &>(key);
55 }
56
57
58 //
59 // Key inquiries
60 //
61 void 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 //
71 void 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
81 void 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
90 void 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
100 void 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 //
114 void 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
129 void 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 //
150 void 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
167 void 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
198 void 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
215 void 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 //
247 void 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 //
271 void 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 }