2 * Copyright (c) 2004 Apple Computer, Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 // localdatabase - locally implemented database using internal CSP cryptography
30 #include "localdatabase.h"
31 #include "agentquery.h"
35 #include <security_agent_client/agentclient.h>
36 #include <security_cdsa_utilities/acl_any.h> // for default owner ACLs
37 #include <security_cdsa_client/wrapkey.h>
38 #include <security_cdsa_client/genkey.h>
39 #include <security_cdsa_client/signclient.h>
40 #include <security_cdsa_client/cryptoclient.h>
41 #include <security_cdsa_client/macclient.h>
42 #include <security_utilities/endian.h>
46 // Create a Database object from initial parameters (create operation)
48 LocalDatabase::LocalDatabase(Process
&proc
)
54 static inline LocalKey
&myKey(Key
&key
)
56 return safer_cast
<LocalKey
&>(key
);
63 CSSM_KEY_SIZE
LocalDatabase::queryKeySize(Key
&key
)
65 CssmClient::Key
theKey(Server::csp(), myKey(key
));
66 return theKey
.sizeInBits();
71 // Signatures and MACs
73 void LocalDatabase::generateSignature(const Context
&context
, Key
&key
,
74 CSSM_ALGORITHMS signOnlyAlgorithm
, const CssmData
&data
, CssmData
&signature
)
76 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
77 key
.validate(CSSM_ACL_AUTHORIZATION_SIGN
, context
);
78 CssmClient::Sign
signer(Server::csp(), context
.algorithm(), signOnlyAlgorithm
);
79 signer
.override(context
);
80 signer
.sign(data
, signature
);
83 void LocalDatabase::verifySignature(const Context
&context
, Key
&key
,
84 CSSM_ALGORITHMS verifyOnlyAlgorithm
, const CssmData
&data
, const CssmData
&signature
)
86 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
87 CssmClient::Verify
verifier(Server::csp(), context
.algorithm(), verifyOnlyAlgorithm
);
88 verifier
.override(context
);
89 verifier
.verify(data
, signature
);
92 void LocalDatabase::generateMac(const Context
&context
, Key
&key
,
93 const CssmData
&data
, CssmData
&mac
)
95 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
96 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
97 CssmClient::GenerateMac
signer(Server::csp(), context
.algorithm());
98 signer
.override(context
);
99 signer
.sign(data
, mac
);
102 void LocalDatabase::verifyMac(const Context
&context
, Key
&key
,
103 const CssmData
&data
, const CssmData
&mac
)
105 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
106 key
.validate(CSSM_ACL_AUTHORIZATION_MAC
, context
);
107 CssmClient::VerifyMac
verifier(Server::csp(), context
.algorithm());
108 verifier
.override(context
);
109 verifier
.verify(data
, mac
);
114 // Encryption/decryption
116 void LocalDatabase::encrypt(const Context
&context
, Key
&key
,
117 const CssmData
&clear
, CssmData
&cipher
)
119 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
120 key
.validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
);
121 CssmClient::Encrypt
cryptor(Server::csp(), context
.algorithm());
122 cryptor
.override(context
);
124 size_t totalLength
= cryptor
.encrypt(clear
, cipher
, remData
);
125 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
127 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
128 cipher
.length(totalLength
);
131 void LocalDatabase::decrypt(const Context
&context
, Key
&key
,
132 const CssmData
&cipher
, CssmData
&clear
)
134 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
135 key
.validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
);
136 CssmClient::Decrypt
cryptor(Server::csp(), context
.algorithm());
137 cryptor
.override(context
);
139 size_t totalLength
= cryptor
.decrypt(cipher
, clear
, remData
);
140 // shouldn't need remData - if an algorithm REQUIRES this, we'd have to ship it
142 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
143 clear
.length(totalLength
);
148 // Key generation and derivation.
149 // Currently, we consider symmetric key generation to be fast, but
150 // asymmetric key generation to be (potentially) slow.
152 void LocalDatabase::generateKey(const Context
&context
,
153 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
154 uint32 usage
, uint32 attrs
, RefPointer
<Key
> &newKey
)
157 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
158 generate
.override(context
);
161 // @@@ turn "none" return into reference if permanent (only)
163 generate(key
, Key::KeySpec(usage
, attrs
));
165 // register and return the generated key
166 newKey
= makeKey(key
, attrs
& Key::managedAttributes
, owner
);
169 void LocalDatabase::generateKey(const Context
&context
,
170 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
171 uint32 pubUsage
, uint32 pubAttrs
, uint32 privUsage
, uint32 privAttrs
,
172 RefPointer
<Key
> &publicKey
, RefPointer
<Key
> &privateKey
)
175 CssmClient::GenerateKey
generate(Server::csp(), context
.algorithm());
176 generate
.override(context
);
178 // this may take a while; let our server object know
179 Server::active().longTermActivity();
182 // @@@ turn "none" return into reference if permanent (only)
183 CssmKey pubKey
, privKey
;
184 generate(pubKey
, Key::KeySpec(pubUsage
, pubAttrs
),
185 privKey
, Key::KeySpec(privUsage
, privAttrs
));
187 // register and return the generated keys
188 publicKey
= makeKey(pubKey
, pubAttrs
& Key::managedAttributes
, owner
);
189 privateKey
= makeKey(privKey
, privAttrs
& Key::managedAttributes
, owner
);
192 RefPointer
<Key
> LocalDatabase::deriveKey(const Context
&context
, Key
*baseKey
,
193 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
194 CssmData
*param
, uint32 usage
, uint32 attrs
)
196 // prepare a key-derivation context
198 baseKey
->validate(CSSM_ACL_AUTHORIZATION_DERIVE
, cred
);
199 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(*baseKey
).cssmKey());
201 CssmClient::DeriveKey
derive(Server::csp(), context
.algorithm(), CSSM_ALGID_NONE
);
202 derive
.override(context
);
205 // @@@ turn "none" return into reference if permanent (only)
207 derive(param
, Key::KeySpec(usage
, attrs
), key
);
209 // register and return the generated key
210 return makeKey(key
, attrs
& Key::managedAttributes
, owner
);
215 // Key wrapping and unwrapping.
216 // Note that the key argument (the key in the context) is optional because of the special
217 // case of "cleartext" (null algorithm) wrapping for import/export.
220 void LocalDatabase::wrapKey(const Context
&context
, Key
*key
,
221 Key
&keyToBeWrapped
, const AccessCredentials
*cred
,
222 const CssmData
&descriptiveData
, CssmKey
&wrappedKey
)
224 keyToBeWrapped
.validate(context
.algorithm() == CSSM_ALGID_NONE
?
225 CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR
: CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED
,
227 if(!(keyToBeWrapped
.attributes() & CSSM_KEYATTR_EXTRACTABLE
)) {
228 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK
);
231 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(*key
).cssmKey());
232 key
->validate(CSSM_ACL_AUTHORIZATION_ENCRYPT
, context
);
234 CssmClient::WrapKey
wrap(Server::csp(), context
.algorithm());
235 wrap
.override(context
);
236 wrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
237 wrap(myKey(keyToBeWrapped
), wrappedKey
, &descriptiveData
);
240 RefPointer
<Key
> LocalDatabase::unwrapKey(const Context
&context
, Key
*key
,
241 const AccessCredentials
*cred
, const AclEntryPrototype
*owner
,
242 uint32 usage
, uint32 attrs
, const CssmKey wrappedKey
,
243 Key
*publicKey
, CssmData
*descriptiveData
)
246 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(*key
).cssmKey());
247 key
->validate(CSSM_ACL_AUTHORIZATION_DECRYPT
, context
);
249 CssmClient::UnwrapKey
unwrap(Server::csp(), context
.algorithm());
250 unwrap
.override(context
);
251 CssmKey unwrappedKey
;
252 unwrap
.cred(const_cast<AccessCredentials
*>(cred
)); //@@@ const madness - fix in client/pod
254 AclEntryInput
ownerInput(*owner
); //@@@ const trouble - fix in client/pod
255 unwrap
.aclEntry(ownerInput
);
258 // @@@ Invoking conversion operator to CssmKey & on *publicKey and take the address of the result.
259 unwrap(wrappedKey
, Key::KeySpec(usage
, attrs
), unwrappedKey
,
260 descriptiveData
, publicKey
? &static_cast<const CssmKey
&>(myKey(*publicKey
)) : NULL
);
262 return makeKey(unwrappedKey
, attrs
& Key::managedAttributes
, owner
);
267 // Miscellaneous CSSM functions
269 uint32
LocalDatabase::getOutputSize(const Context
&context
, Key
&key
, uint32 inputSize
, bool encrypt
)
271 // We're fudging here somewhat, since the context can be any type.
272 // ctx.override will fix the type, and no-one's the wiser.
273 context
.replace(CSSM_ATTRIBUTE_KEY
, myKey(key
).cssmKey());
274 CssmClient::Digest
ctx(Server::csp(), context
.algorithm());
275 ctx
.override(context
);
276 return ctx
.getOutputSize(inputSize
, encrypt
);
281 // (Re-)Authenticate the database. This changes the stored credentials.
283 void LocalDatabase::authenticate(const AccessCredentials
*cred
)
285 StLock
<Mutex
> _(common());
286 AccessCredentials
*newCred
= DataWalkers::copy(cred
, Allocator::standard());
287 Allocator::standard().free(mCred
);