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