]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
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" | |
d8f41ccd A |
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, | |
dd5fb164 | 203 | cred, &keyToBeWrapped.database()); |
d8f41ccd A |
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 | } |