]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2000-2001,2004-2006,2008-2009 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 | // key - representation of securityd key objects | |
27 | // | |
28 | #include "kckey.h" | |
29 | #include "server.h" | |
30 | #include "database.h" | |
31 | #include <security_cdsa_utilities/acl_any.h> | |
32 | #include <security_cdsa_utilities/cssmendian.h> | |
33 | ||
34 | ||
35 | // | |
36 | // Create a Key object from a database-encoded blob. | |
37 | // Note that this doesn't decode the blob (yet). | |
38 | // | |
39 | KeychainKey::KeychainKey(Database &db, const KeyBlob *blob) | |
40 | : LocalKey(db, n2h(blob->header.attributes())) | |
41 | { | |
42 | // perform basic validation on the incoming blob | |
43 | assert(blob); | |
44 | blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB); | |
79b9da22 A |
45 | if (blob->startCryptoBlob > blob->totalLength) { |
46 | CssmError::throwMe(CSSMERR_APPLEDL_INVALID_KEY_BLOB); | |
47 | } | |
d8f41ccd A |
48 | switch (blob->version()) { |
49 | #if defined(COMPAT_OSX_10_0) | |
50 | case KeyBlob::version_MacOS_10_0: | |
51 | break; | |
52 | #endif | |
53 | case KeyBlob::version_MacOS_10_1: | |
54 | break; | |
e3d460c9 A |
55 | case KeyBlob::version_partition: |
56 | break; | |
d8f41ccd A |
57 | default: |
58 | CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB); | |
59 | } | |
60 | ||
61 | // set it up | |
62 | mBlob = blob->copy(Allocator::standard()); | |
63 | mValidBlob = true; | |
64 | db.addReference(*this); | |
fa7225c8 | 65 | secinfo("SSkey", "%p (handle %#x) created from blob version %x", |
d8f41ccd A |
66 | this, handle(), blob->version()); |
67 | } | |
68 | ||
69 | ||
70 | // | |
71 | // Create a Key from an explicit CssmKey. | |
72 | // | |
73 | KeychainKey::KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes, | |
74 | const AclEntryPrototype *owner) | |
75 | : LocalKey(db, newKey, moreAttributes) | |
76 | { | |
77 | assert(moreAttributes & CSSM_KEYATTR_PERMANENT); | |
78 | setOwner(owner); | |
79 | mBlob = NULL; | |
80 | mValidBlob = false; | |
81 | db.addReference(*this); | |
82 | } | |
83 | ||
84 | ||
85 | KeychainKey::~KeychainKey() | |
86 | { | |
87 | Allocator::standard().free(mBlob); | |
fa7225c8 | 88 | secinfo("SSkey", "%p destroyed", this); |
d8f41ccd A |
89 | } |
90 | ||
91 | ||
92 | KeychainDatabase &KeychainKey::database() const | |
93 | { | |
94 | return referent<KeychainDatabase>(); | |
95 | } | |
96 | ||
97 | ||
98 | // | |
99 | // Retrieve the actual CssmKey value for the key object. | |
100 | // This will decode its blob if needed (and appropriate). | |
101 | // | |
102 | void KeychainKey::getKey() | |
103 | { | |
104 | decode(); | |
105 | } | |
106 | ||
107 | void KeychainKey::getHeader(CssmKey::Header &hdr) | |
108 | { | |
109 | assert(mValidBlob); | |
110 | hdr = mBlob->header; | |
111 | n2hi(hdr); // correct for endian-ness | |
112 | } | |
113 | ||
114 | ||
115 | // | |
116 | // Ensure that a key is fully decoded. | |
117 | // This makes the mKey key value available for use, as well as its ACL. | |
118 | // Caller must hold the key object lock. | |
119 | // | |
120 | void KeychainKey::decode() | |
121 | { | |
122 | if (!mValidKey) { | |
123 | assert(mValidBlob); // must have a blob to decode | |
124 | ||
125 | // decode the key | |
126 | void *publicAcl, *privateAcl; | |
127 | CssmKey key; | |
128 | database().decodeKey(mBlob, key, publicAcl, privateAcl); | |
129 | mKey = CssmClient::Key(Server::csp(), key); | |
130 | acl().importBlob(publicAcl, privateAcl); | |
131 | // publicAcl points into the blob; privateAcl was allocated for us | |
132 | Allocator::standard().free(privateAcl); | |
133 | ||
134 | // extract managed attribute bits | |
135 | mAttributes = mKey.header().attributes() & managedAttributes; | |
136 | mKey.header().clearAttribute(managedAttributes); | |
137 | mKey.header().setAttribute(forcedAttributes); | |
138 | ||
139 | // key is valid now | |
140 | mValidKey = true; | |
141 | } | |
142 | } | |
143 | ||
144 | ||
145 | // | |
146 | // Encode a key into a blob. | |
147 | // We'll have to ask our Database to do this - we don't have its keys. | |
148 | // Note that this returns memory we own and keep. | |
149 | // | |
150 | KeyBlob *KeychainKey::blob() | |
151 | { | |
152 | if (!mValidBlob) { | |
153 | assert(mValidKey); // must have valid key to encode | |
154 | ||
155 | // export Key ACL to blob form | |
156 | CssmData pubAcl, privAcl; | |
157 | acl().exportBlob(pubAcl, privAcl); | |
158 | ||
159 | // assemble external key form | |
160 | CssmKey externalKey = mKey; | |
161 | externalKey.clearAttribute(forcedAttributes); | |
162 | externalKey.setAttribute(mAttributes); | |
163 | ||
164 | // encode the key and replace blob | |
165 | KeyBlob *newBlob = database().encodeKey(externalKey, pubAcl, privAcl); | |
166 | Allocator::standard().free(mBlob); | |
167 | mBlob = newBlob; | |
168 | mValidBlob = true; | |
169 | ||
170 | // clean up and go | |
171 | acl().allocator.free(pubAcl); | |
172 | acl().allocator.free(privAcl); | |
173 | } | |
174 | return mBlob; | |
175 | } | |
176 | ||
177 | void KeychainKey::invalidateBlob() | |
178 | { | |
179 | mValidBlob = false; | |
180 | } | |
181 | ||
182 | ||
183 | // | |
184 | // Override ACL-related methods and events. | |
185 | // Decode the key before ACL activity; invalidate the stored blob on ACL edits; | |
186 | // and return the key's database as "related". | |
187 | // | |
188 | void KeychainKey::instantiateAcl() | |
189 | { | |
190 | StLock<Mutex> _(*this); | |
191 | decode(); | |
192 | } | |
193 | ||
194 | void KeychainKey::changedAcl() | |
195 | { | |
196 | invalidateBlob(); | |
197 | } | |
198 | ||
199 | ||
200 | // | |
201 | // Intercept Key validation and double-check that the keychain is (still) unlocked | |
202 | // | |
203 | void KeychainKey::validate(AclAuthorization auth, const AccessCredentials *cred, | |
204 | Database *relatedDatabase) | |
205 | { | |
206 | if(!mBlob->isClearText()) { | |
207 | /* unlock not needed for cleartext keys */ | |
208 | if (KeychainDatabase *db = dynamic_cast<KeychainDatabase *>(relatedDatabase)) | |
fa7225c8 | 209 | db->unlockDb(false); |
d8f41ccd A |
210 | } |
211 | SecurityServerAcl::validate(auth, cred, relatedDatabase); | |
79b9da22 A |
212 | |
213 | // Need the common lock some more. unlockDb and validate (in validatePartition) also take it, so must be down here. | |
214 | StMaybeLock<Mutex> lock(relatedDatabase && relatedDatabase->hasCommon() ? &(relatedDatabase->common()) : NULL); | |
d8f41ccd A |
215 | database().activity(); // upon successful validation |
216 | } | |
217 | ||
218 | ||
219 | // | |
220 | // We're a key (duh) | |
221 | // | |
222 | AclKind KeychainKey::aclKind() const | |
223 | { | |
224 | return keyAcl; | |
225 | } | |
226 | ||
227 | ||
228 | Database *KeychainKey::relatedDatabase() | |
229 | { | |
230 | return &database(); | |
231 | } | |
232 | ||
233 | SecurityServerAcl &KeychainKey::acl() | |
234 | { | |
235 | return *this; | |
236 | } |