/ securityd / src / localdatabase.cpp
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  }