2 * Copyright (c) 2000-2001,2007,2011 Apple Inc. All Rights Reserved.
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
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.
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>
32 namespace CssmClient
{
34 static inline void check(CSSM_RETURN rc
)
36 ObjectImpl::check(rc
);
41 // AclBearer methods (trivial)
43 AclBearer::~AclBearer()
48 // Variant forms of AclBearer implemented in terms of its canonical virtual methods
50 void AclBearer::addAcl(const AclEntryInput
&input
, const CSSM_ACCESS_CREDENTIALS
*cred
)
52 changeAcl(AclEdit(input
), cred
);
55 void AclBearer::changeAcl(CSSM_ACL_HANDLE handle
, const AclEntryInput
&input
,
56 const CSSM_ACCESS_CREDENTIALS
*cred
)
58 changeAcl(AclEdit(handle
, input
), cred
);
61 void AclBearer::deleteAcl(CSSM_ACL_HANDLE handle
, const CSSM_ACCESS_CREDENTIALS
*cred
)
63 changeAcl(AclEdit(handle
), cred
);
66 void AclBearer::deleteAcl(const char *tag
, const CSSM_ACCESS_CREDENTIALS
*cred
)
68 AutoAclEntryInfoList entries
;
70 for (uint32 n
= 0; n
< entries
.count(); n
++)
71 deleteAcl(entries
[n
].handle(), cred
);
76 // KeyAclBearer implementation
78 void KeyAclBearer::getAcl(AutoAclEntryInfoList
&aclInfos
, const char *selectionTag
) const
80 aclInfos
.allocator(allocator
);
81 check(CSSM_GetKeyAcl(csp
, &key
, reinterpret_cast<const CSSM_STRING
*>(selectionTag
), aclInfos
, aclInfos
));
84 void KeyAclBearer::changeAcl(const CSSM_ACL_EDIT
&aclEdit
, const CSSM_ACCESS_CREDENTIALS
*cred
)
86 check(CSSM_ChangeKeyAcl(csp
, AccessCredentials::needed(cred
), &aclEdit
, &key
));
89 void KeyAclBearer::getOwner(AutoAclOwnerPrototype
&owner
) const
91 owner
.allocator(allocator
);
92 check(CSSM_GetKeyOwner(csp
, &key
, owner
));
95 void KeyAclBearer::changeOwner(const CSSM_ACL_OWNER_PROTOTYPE
&newOwner
,
96 const CSSM_ACCESS_CREDENTIALS
*cred
)
98 check(CSSM_ChangeKeyOwner(csp
, AccessCredentials::needed(cred
), &key
, &newOwner
));
103 // A single global structure containing pseudo-static data
109 AutoCredentials nullCred
;
110 AutoCredentials promptCred
;
111 AutoCredentials unlockCred
;
112 AutoCredentials cancelCred
;
113 AutoCredentials promptedPINCred
;
114 AutoCredentials promptedPINItemCred
;
116 AclOwnerPrototype anyOwner
;
121 ModuleNexus
<Statics
> statics
;
126 // Make pseudo-statics.
127 // Note: This is an eternal object. It is not currently destroyed
128 // if the containing code is unloaded.
131 : alloc(Allocator::standard()),
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))
141 // nullCred: nothing at all
143 // an empty THRESHOLD sample to match threshold subjects with "free" subjects
144 nullCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_THRESHOLD
);
146 // promptCred: a credential permitting user prompt confirmations
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()));
157 unlockCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
,
158 new(alloc
) ListElement(CSSM_SAMPLE_TYPE_KEYCHAIN_PROMPT
));
160 cancelCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_KEYCHAIN_LOCK
,
161 new(alloc
) ListElement(CSSM_WORDID_CANCELED
));
166 promptedPINCred.tag("PIN1");
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.
172 promptedPINCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
,
173 new(alloc
) ListElement(alloc
, CssmData()));
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.
180 promptedPINItemCred
.tag("PIN1");
181 promptedPINItemCred
.sample(0) = TypedList(alloc
, CSSM_SAMPLE_TYPE_PROMPTED_PASSWORD
,
182 new(alloc
) ListElement(alloc
, CssmData()));
187 // Make and break AclFactories
189 AclFactory::AclFactory()
192 AclFactory::~AclFactory()
197 // Return basic pseudo-static values
199 const AccessCredentials
*AclFactory::nullCred() const
200 { return &statics().nullCred
; }
202 const AccessCredentials
*AclFactory::promptCred() const
203 { return &statics().promptCred
; }
205 const AccessCredentials
*AclFactory::unlockCred() const
206 { return &statics().unlockCred
; }
209 const AccessCredentials
*AclFactory::cancelCred() const
210 { return &statics().cancelCred
; }
212 const AccessCredentials
*AclFactory::promptedPINCred() const
213 { return &statics().promptedPINCred
; }
215 const AccessCredentials
*AclFactory::promptedPINItemCred() const
216 { return &statics().promptedPINItemCred
; }
220 // Manage the (pseudo) credentials used to explicitly provide a passphrase to a keychain.
221 // Use the eternal unlockCred() for normal (protected prompt) unlocking.
223 AclFactory::KeychainCredentials::~KeychainCredentials ()
225 DataWalkers::chunkFree(mCredentials
, allocator
);
228 AclFactory::PassphraseUnlockCredentials::PassphraseUnlockCredentials (const CssmData
& password
,
229 Allocator
& allocator
) : KeychainCredentials(allocator
)
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()));
238 // Manage the (pseudo) credentials used to explicitly change a keychain's passphrase
240 AclFactory::PasswordChangeCredentials::PasswordChangeCredentials (const CssmData
& password
,
241 Allocator
& allocator
) : KeychainCredentials(allocator
)
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()));
250 // Manage the (pseudo) credentials used to explicitly provide a master key to a keychain.
252 AclFactory::MasterKeyUnlockCredentials::MasterKeyUnlockCredentials (const CssmClient::Key
& key
,
253 Allocator
& allocator
) : KeychainCredentials(allocator
)
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)
261 // Data format is for consumption by kcdatabase.cpp:unflattenKey()
263 size_t dataLen
= sizeof(CSSM_KEY
) + key
->keyData().length();
264 CssmAutoData
flattenedKey(allocator
);
265 flattenedKey
.malloc(dataLen
);
266 memset(flattenedKey
, 0, dataLen
);
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());
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()));
284 // Wide open ("ANY") CSSM forms for owner and ACL entry
286 const AclOwnerPrototype
&AclFactory::anyOwner() const
287 { return statics().anyOwner
; }
289 const AclEntryInfo
&AclFactory::anyAcl() const
290 { return statics().anyAcl
; }
294 // Create an ANY style AclEntryInput.
295 // This can be used to explicitly request wide-open authorization on a new CSSM object.
297 AclFactory::AnyResourceContext::AnyResourceContext(const CSSM_ACCESS_CREDENTIALS
*cred
)
298 : mAny(CSSM_ACL_SUBJECT_TYPE_ANY
), mTag(CSSM_ACL_AUTHORIZATION_ANY
)
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
;
306 // install the cred (not copied)
314 AclFactory::Subject::Subject(Allocator
&alloc
, CSSM_ACL_SUBJECT_TYPE type
)
315 : TypedList(alloc
, type
)
319 AclFactory::PWSubject::PWSubject(Allocator
&alloc
)
320 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PASSWORD
)
323 AclFactory::PWSubject::PWSubject(Allocator
&alloc
, const CssmData
&secret
)
324 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PASSWORD
)
326 append(new(alloc
) ListElement(alloc
, secret
));
329 AclFactory::PromptPWSubject::PromptPWSubject(Allocator
&alloc
, const CssmData
&prompt
)
330 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD
)
332 append(new(alloc
) ListElement(alloc
, prompt
));
335 AclFactory::PromptPWSubject::PromptPWSubject(Allocator
&alloc
, const CssmData
&prompt
, const CssmData
&secret
)
336 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PROMPTED_PASSWORD
)
338 append(new(alloc
) ListElement(alloc
, prompt
));
339 append(new(alloc
) ListElement(alloc
, secret
));
342 AclFactory::ProtectedPWSubject::ProtectedPWSubject(Allocator
&alloc
)
343 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PROTECTED_PASSWORD
)
346 AclFactory::PinSubject::PinSubject(Allocator
&alloc
, uint32 slot
)
347 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PREAUTH
)
349 append(new(alloc
) ListElement(CSSM_ACL_AUTHORIZATION_PREAUTH(slot
)));
352 AclFactory::PinSourceSubject::PinSourceSubject(Allocator
&alloc
, const TypedList
&form
)
353 : Subject(alloc
, CSSM_ACL_SUBJECT_TYPE_PREAUTH_SOURCE
)
355 append(new(alloc
) ListElement(form
));
359 } // end namespace CssmClient
360 } // end namespace Security