/ OSX / libsecurity_cdsa_client / lib / aclclient.cpp
aclclient.cpp
  1  /*
  2   * Copyright (c) 2000-2001,2007,2011 Apple Inc. All Rights Reserved.
  3   * 
  4   * The contents of this file constitute Original Code as defined in and are
  5   * subject to the Apple Public Source License Version 1.2 (the 'License').
  6   * You may not use this file except in compliance with the License. Please obtain
  7   * a copy of the License at http://www.apple.com/publicsource and read it before
  8   * using this file.
  9   * 
 10   * This Original Code and all software distributed under the License are
 11   * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
 12   * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
 13   * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 14   * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
 15   * specific language governing rights and limitations under the License.
 16   */
 17  
 18  
 19  //
 20  // aclclient
 21  //
 22  #include <security_cdsa_client/cssmclient.h>
 23  #include <security_cdsa_client/aclclient.h>
 24  #include <security_cdsa_client/keyclient.h>
 25  #include <security_cdsa_client/keychainacl.h>
 26  #include <security_cdsa_utilities/cssmwalkers.h>
 27  #include <security_cdsa_utilities/cssmdata.h>
 28  #include <security_cdsa_utilities/cssmendian.h>
 29  #include <securityd_client/handletypes.h>
 30  
 31  namespace Security {
 32  namespace CssmClient {
 33  
 34  static inline void check(CSSM_RETURN rc)
 35  {
 36  	ObjectImpl::check(rc);
 37  }
 38  
 39  
 40  //
 41  // AclBearer methods (trivial)
 42  //
 43  AclBearer::~AclBearer()
 44  { }
 45  
 46  
 47  //
 48  // Variant forms of AclBearer implemented in terms of its canonical virtual methods
 49  //
 50  void AclBearer::addAcl(const AclEntryInput &input, const CSSM_ACCESS_CREDENTIALS *cred)
 51  {
 52  	changeAcl(AclEdit(input), cred);
 53  }
 54  
 55  void AclBearer::changeAcl(CSSM_ACL_HANDLE handle, const AclEntryInput &input,
 56  	const CSSM_ACCESS_CREDENTIALS *cred)
 57  {
 58  	changeAcl(AclEdit(handle, input), cred);
 59  }
 60  
 61  void AclBearer::deleteAcl(CSSM_ACL_HANDLE handle, const CSSM_ACCESS_CREDENTIALS *cred)
 62  {
 63  	changeAcl(AclEdit(handle), cred);
 64  }
 65  
 66  void AclBearer::deleteAcl(const char *tag, const CSSM_ACCESS_CREDENTIALS *cred)
 67  {
 68  	AutoAclEntryInfoList entries;
 69  	getAcl(entries, tag);
 70  	for (uint32 n = 0; n < entries.count(); n++)
 71  		deleteAcl(entries[n].handle(), cred);
 72  }
 73  
 74  
 75  //
 76  // KeyAclBearer implementation
 77  //
 78  void KeyAclBearer::getAcl(AutoAclEntryInfoList &aclInfos, const char *selectionTag) const
 79  {
 80  	aclInfos.allocator(allocator);
 81  	check(CSSM_GetKeyAcl(csp, &key, reinterpret_cast<const CSSM_STRING *>(selectionTag), aclInfos, aclInfos));
 82  }
 83  
 84  void KeyAclBearer::changeAcl(const CSSM_ACL_EDIT &aclEdit, const CSSM_ACCESS_CREDENTIALS *cred)
 85  {
 86  	check(CSSM_ChangeKeyAcl(csp, AccessCredentials::needed(cred), &aclEdit, &key));
 87  }
 88  
 89  void KeyAclBearer::getOwner(AutoAclOwnerPrototype &owner) const
 90  {
 91  	owner.allocator(allocator);
 92  	check(CSSM_GetKeyOwner(csp, &key, owner));
 93  }
 94  
 95  void KeyAclBearer::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE &newOwner,
 96  	const CSSM_ACCESS_CREDENTIALS *cred)
 97  {
 98  	check(CSSM_ChangeKeyOwner(csp, AccessCredentials::needed(cred), &key, &newOwner));
 99  }
100  
101  
102  //
103  // A single global structure containing pseudo-static data
104  //
105  struct Statics {
106  	Statics();
107  	Allocator &alloc;
108  
109  	AutoCredentials nullCred;
110  	AutoCredentials promptCred;
111  	AutoCredentials unlockCred;
112  	AutoCredentials cancelCred;
113  	AutoCredentials promptedPINCred;
114  	AutoCredentials promptedPINItemCred;
115  	
116  	AclOwnerPrototype anyOwner;
117  	AclEntryInfo anyAcl;
118  };
119  
120  namespace {
121  	ModuleNexus<Statics> statics;
122  }
123  
124  
125  //
126  // Make pseudo-statics.
127  // Note: This is an eternal object. It is not currently destroyed
128  // if the containing code is unloaded.
129  //
130  Statics::Statics()
131  	: alloc(Allocator::standard()),
132  	  nullCred(alloc, 1),
133  	  promptCred(alloc, 3),
134  	  unlockCred(alloc, 1),
135  	  cancelCred(alloc, 1),
136  	  promptedPINCred(alloc, 1),
137  	  promptedPINItemCred(alloc, 1),
138  	  anyOwner(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY)),
139  	  anyAcl(AclEntryPrototype(TypedList(alloc, CSSM_ACL_SUBJECT_TYPE_ANY), 1))
140  {
141  	// nullCred: nothing at all
142  	// contains:
143  	//  an empty THRESHOLD sample to match threshold subjects with "free" subjects
144  	nullCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD);
145  
146  	// promptCred: a credential permitting user prompt confirmations
147  	// contains:
148  	//  a KEYCHAIN_PROMPT sample, both by itself and in a THRESHOLD
149  	//  a PROMPTED_PASSWORD sample
150  	promptCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT);
151  	promptCred.sample(1) = TypedList(alloc, CSSM_SAMPLE_TYPE_THRESHOLD,
152  		new(alloc) ListElement(TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT)));
153  	promptCred.sample(2) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
154  		new(alloc) ListElement(alloc, CssmData()));
155  
156  	// unlockCred: ???
157  	unlockCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
158  		new(alloc) ListElement(CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT));
159  	
160  	cancelCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
161  									 new(alloc) ListElement(CSSM_WORDID_CANCELED));
162  	
163  	/*
164  		We don't set this:
165  	 
166  			promptedPINCred.tag("PIN1");
167  
168  		here to avoid triggering code in TokenDatabase::getAcl in securityd that
169  		would always show a PIN unlock dialog. This credential is used for an
170  		unlock of the database, i.e. a dbauthenticate call to unlock the card.
171  	*/
172  	promptedPINCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
173  										  new(alloc) ListElement(alloc, CssmData()));
174  
175  	/*
176  		This credential is used for items like non-repudiation keys that always
177  		require an explicit entry of the PIN. We set this so that Token::authenticate
178  		will recognize the number of the PIN we need to unlock.
179  	*/
180  	promptedPINItemCred.tag("PIN1");
181  	promptedPINItemCred.sample(0) = TypedList(alloc, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD,
182  										  new(alloc) ListElement(alloc, CssmData()));
183  }
184  
185  
186  //
187  // Make and break AclFactories
188  //
189  AclFactory::AclFactory()
190  { }
191  
192  AclFactory::~AclFactory()
193  { }
194  
195  
196  //
197  // Return basic pseudo-static values
198  //
199  const AccessCredentials *AclFactory::nullCred() const
200  { return &statics().nullCred; }
201  
202  const AccessCredentials *AclFactory::promptCred() const
203  { return &statics().promptCred; }
204  
205  const AccessCredentials *AclFactory::unlockCred() const
206  { return &statics().unlockCred; }
207  
208  
209  const AccessCredentials *AclFactory::cancelCred() const
210  { return &statics().cancelCred; }
211  
212  const AccessCredentials *AclFactory::promptedPINCred() const
213  { return &statics().promptedPINCred; }
214  
215  const AccessCredentials *AclFactory::promptedPINItemCred() const
216  { return &statics().promptedPINItemCred; }
217  
218  
219  //
220  // Manage the (pseudo) credentials used to explicitly provide a passphrase to a keychain.
221  // Use the eternal unlockCred() for normal (protected prompt) unlocking.
222  //
223  AclFactory::KeychainCredentials::~KeychainCredentials ()
224  {
225      DataWalkers::chunkFree(mCredentials, allocator);
226  }
227  
228  AclFactory::PassphraseUnlockCredentials::PassphraseUnlockCredentials (const CssmData& password,
229  	Allocator& allocator) : KeychainCredentials(allocator)
230  {
231      mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
232  		new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD),
233  		new (allocator) ListElement (CssmAutoData(allocator, password).release()));
234  }
235  
236  
237  //
238  // Manage the (pseudo) credentials used to explicitly change a keychain's passphrase
239  //
240  AclFactory::PasswordChangeCredentials::PasswordChangeCredentials (const CssmData& password,
241  	Allocator& allocator) : KeychainCredentials(allocator)
242  {
243      mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_CHANGE_LOCK,
244  		new (allocator) ListElement (CSSM_SAMPLE_TYPE_PASSWORD),
245  		new (allocator) ListElement (CssmAutoData(allocator, password).release()));
246  }
247  
248  
249  //
250  // Manage the (pseudo) credentials used to explicitly provide a master key to a keychain.
251  //
252  AclFactory::MasterKeyUnlockCredentials::MasterKeyUnlockCredentials (const CssmClient::Key& key,
253          Allocator& allocator) : KeychainCredentials(allocator)
254  {
255      // Flatten out this key into:
256      //    { h2ni(CSSM_KEY) : raw data for CSSM_KEY }
257      //  which is also (on x86_64):
258      //    { h2ni(CSSM_KEYHEADER) : 4 byte align : CSSM_DATA{0:0} : raw data for CSSM_KEY }
259      //                 (placement of alignment bytes uncertain)
260      //
261      // Data format is for consumption by kcdatabase.cpp:unflattenKey()
262  
263      size_t dataLen = sizeof(CSSM_KEY) + key->keyData().length();
264      CssmAutoData flattenedKey(allocator);
265      flattenedKey.malloc(dataLen);
266      memset(flattenedKey, 0, dataLen);
267  
268      // The key header must be in network-byte order for some reason
269      CSSM_KEYHEADER header = key->header();
270      Security::h2ni(header);
271      memcpy(flattenedKey, &header, sizeof(CSSM_KEYHEADER));
272      memcpy(((uint8_t*) flattenedKey.data()) + sizeof(CSSM_KEY), key->keyData().data(), key->keyData().length());
273  
274      mCredentials->sample(0) = TypedList(allocator, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK,
275                                           new (allocator) ListElement(CSSM_SAMPLE_TYPE_SYMMETRIC_KEY),
276                                           new (allocator) ListElement(CssmAutoData(allocator, CssmData::wrap((SecurityServer::KeyHandle) 0)).release()),
277                                           new (allocator) ListElement(CssmAutoData(allocator, CssmData::wrap(*((const CssmKey*) key))).release()),
278                                           new (allocator) ListElement(flattenedKey.release()));
279  }
280  
281  
282  
283  //
284  // Wide open ("ANY") CSSM forms for owner and ACL entry
285  //
286  const AclOwnerPrototype &AclFactory::anyOwner() const
287  { return statics().anyOwner; }
288  
289  const AclEntryInfo &AclFactory::anyAcl() const
290  { return statics().anyAcl; }
291  
292  
293  //
294  // Create an ANY style AclEntryInput.
295  // This can be used to explicitly request wide-open authorization on a new CSSM object.
296  //
297  AclFactory::AnyResourceContext::AnyResourceContext(const CSSM_ACCESS_CREDENTIALS *cred)
298  	: mAny(CSSM_ACL_SUBJECT_TYPE_ANY), mTag(CSSM_ACL_AUTHORIZATION_ANY)
299  {
300  	// set up an ANY/EVERYTHING AclEntryInput
301  	input().proto().subject() += &mAny;
302  	AuthorizationGroup &authGroup = input().proto().authorization();
303  	authGroup.NumberOfAuthTags = 1;
304  	authGroup.AuthTags = &mTag;
305  	
306  	// install the cred (not copied)
307  	credentials(cred);
308  }
309  
310  
311  //
312  // CSSM ACL makers
313  //
314  AclFactory::Subject::Subject(Allocator &alloc, CSSM_ACL_SUBJECT_TYPE type)
315  	: TypedList(alloc, type)
316  { }
317  
318  
319  AclFactory::PWSubject::PWSubject(Allocator &alloc)
320  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD)
321  { }
322  
323  AclFactory::PWSubject::PWSubject(Allocator &alloc, const CssmData &secret)
324  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PASSWORD)
325  {
326  	append(new(alloc) ListElement(alloc, secret));
327  }
328  
329  AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt)
330  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD)
331  {
332  	append(new(alloc) ListElement(alloc, prompt));
333  }
334  
335  AclFactory::PromptPWSubject::PromptPWSubject(Allocator &alloc, const CssmData &prompt, const CssmData &secret)
336  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD)
337  {
338  	append(new(alloc) ListElement(alloc, prompt));
339  	append(new(alloc) ListElement(alloc, secret));
340  }
341  
342  AclFactory::ProtectedPWSubject::ProtectedPWSubject(Allocator &alloc)
343  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD)
344  { }
345  
346  AclFactory::PinSubject::PinSubject(Allocator &alloc, uint32 slot)
347  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH)
348  {
349  	append(new(alloc) ListElement(CSSM_ACL_AUTHORIZATION_PREAUTH(slot)));
350  }
351  
352  AclFactory::PinSourceSubject::PinSourceSubject(Allocator &alloc, const TypedList &form)
353  	: Subject(alloc, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE)
354  {
355  	append(new(alloc) ListElement(form));
356  }
357  
358  
359  } // end namespace CssmClient
360  } // end namespace Security