]> git.saurik.com Git - apple/security.git/blob - SecurityServer/key.cpp
Security-179.tar.gz
[apple/security.git] / SecurityServer / key.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 // key - representation of SecurityServer key objects
21 //
22 #include "key.h"
23 #include "server.h"
24 #include "xdatabase.h"
25 #include <Security/acl_any.h>
26
27
28 //
29 // Create a Key object from a database-encoded blob.
30 // Note that this doesn't decode the blob (yet).
31 //
32 Key::Key(Database &db, const KeyBlob *blob)
33 : SecurityServerAcl(keyAcl, CssmAllocator::standard()), mDigest(Server::csp().allocator())
34 {
35 // perform basic validation on the incoming blob
36 assert(blob);
37 blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB);
38 switch (blob->version()) {
39 #if defined(COMPAT_OSX_10_0)
40 case blob->version_MacOS_10_0:
41 break;
42 #endif
43 case blob->version_MacOS_10_1:
44 break;
45 default:
46 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB);
47 }
48
49 // set it up
50 mDatabase = &db;
51 mBlob = blob->copy(CssmAllocator::standard());
52 mAttributes = 0;
53 mValidBlob = true;
54 mValidKey = false;
55 mValidUID = false;
56 secdebug("SSkey", "%p (handle 0x%lx) created from blob version %lx",
57 this, handle(), blob->version());
58 }
59
60
61 //
62 // Create a Key from an explicit CssmKey.
63 //
64 Key::Key(Database *db, const CssmKey &newKey, uint32 moreAttributes,
65 const AclEntryPrototype *owner)
66 : SecurityServerAcl(keyAcl, CssmAllocator::standard()), mDigest(Server::csp().allocator())
67 {
68 if (moreAttributes & CSSM_KEYATTR_PERMANENT) {
69 // better have a database to make it permanent in...
70 if (!db)
71 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);
72 } else {
73 // non-permanent; ignore database
74 db = NULL;
75 }
76
77 mDatabase = db;
78 mValidKey = true;
79 mBlob = NULL;
80 mValidBlob = false;
81 mValidUID = false;
82 setup(newKey, moreAttributes);
83
84 // establish initial ACL; reinterpret empty (null-list) owner as NULL for resilence's sake
85 if (owner && !owner->subject().empty())
86 cssmSetInitial(*owner); // specified
87 else
88 cssmSetInitial(new AnyAclSubject()); // defaulted
89 secdebug("SSkey", "%p (handle 0x%lx) created from key alg=%ld use=0x%lx attr=0x%lx db=%p",
90 this, handle(), mKey.header().algorithm(), mKey.header().usage(), mAttributes, db);
91 }
92
93
94 //
95 // Set up the CssmKey part of this Key according to instructions.
96 //
97 void Key::setup(const CssmKey &newKey, uint32 moreAttributes)
98 {
99 mKey = CssmClient::Key(Server::csp(), newKey, false);
100 CssmKey::Header &header = mKey->header();
101
102 // copy key header
103 header = newKey.header();
104 mAttributes = (header.attributes() & ~forcedAttributes) | moreAttributes;
105
106 // apply initial values of derived attributes (these are all in managedAttributes)
107 if (!(mAttributes & CSSM_KEYATTR_EXTRACTABLE))
108 mAttributes |= CSSM_KEYATTR_NEVER_EXTRACTABLE;
109 if (mAttributes & CSSM_KEYATTR_SENSITIVE)
110 mAttributes |= CSSM_KEYATTR_ALWAYS_SENSITIVE;
111
112 // verify internal/external attribute separation
113 assert((header.attributes() & managedAttributes) == forcedAttributes);
114 }
115
116
117 Key::~Key()
118 {
119 CssmAllocator::standard().free(mBlob);
120 secdebug("SSkey", "%p destroyed", this);
121 }
122
123
124 //
125 // Form a KeySpec with checking and masking
126 //
127 Key::KeySpec::KeySpec(uint32 usage, uint32 attrs)
128 : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes)
129 {
130 if (attrs & generatedAttributes)
131 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
132 }
133
134 Key::KeySpec::KeySpec(uint32 usage, uint32 attrs, const CssmData &label)
135 : CssmClient::KeySpec(usage, (attrs & ~managedAttributes) | forcedAttributes, label)
136 {
137 if (attrs & generatedAttributes)
138 CssmError::throwMe(CSSMERR_CSP_INVALID_KEYATTR_MASK);
139 }
140
141
142 //
143 // Retrieve the actual CssmKey value for the key object.
144 // This will decode its blob if needed (and appropriate).
145 //
146 CssmClient::Key Key::keyValue()
147 {
148 decode();
149 return mKey;
150 }
151
152
153 //
154 // Ensure that a key is fully decoded.
155 // This makes the mKey key value available for use, as well as its ACL.
156 //
157 void Key::decode()
158 {
159 if (!mValidKey) {
160 assert(mDatabase); // have to have a database (to decode the blob)
161 assert(mValidBlob); // must have a blob to decode
162
163 // decode the key
164 void *publicAcl, *privateAcl;
165 CssmKey key;
166 database()->decodeKey(mBlob, key, publicAcl, privateAcl);
167 mKey = CssmClient::Key(Server::csp(), key);
168 importBlob(publicAcl, privateAcl);
169 // publicAcl points into the blob; privateAcl was allocated for us
170 CssmAllocator::standard().free(privateAcl);
171
172 // extract managed attribute bits
173 mAttributes = mKey.header().attributes() & managedAttributes;
174 mKey.header().clearAttribute(managedAttributes);
175 mKey.header().setAttribute(forcedAttributes);
176
177 // key is valid now
178 mValidKey = true;
179 }
180 }
181
182
183 //
184 // Return a key's handle and header in external form
185 //
186 void Key::returnKey(Handle &h, CssmKey::Header &hdr)
187 {
188 // return handle
189 h = handle();
190
191 // obtain the key header, from the valid key or the blob if no valid key
192 if (mValidKey) {
193 hdr = mKey.header();
194 } else {
195 assert(mValidBlob);
196 hdr = mBlob->header;
197 n2hi(hdr); // correct for endian-ness
198 }
199
200 // adjust for external attributes
201 hdr.clearAttribute(forcedAttributes);
202 hdr.setAttribute(mAttributes);
203 }
204
205
206 //
207 // Generate the canonical key digest.
208 // This is defined by a CSP feature that we invoke here.
209 //
210 const CssmData &Key::canonicalDigest()
211 {
212 if (!mDigest) {
213 CssmClient::PassThrough ctx(Server::csp());
214 ctx.key(keyValue());
215 CssmData *digest = NULL;
216 ctx(CSSM_APPLECSP_KEYDIGEST, (const void *)NULL, &digest);
217 assert(digest);
218 mDigest.set(*digest); // takes ownership of digest data
219 Server::csp().allocator().free(digest); // the CssmData itself
220 }
221 return mDigest.get();
222 }
223
224
225 //
226 // Encode a key into a blob.
227 // We'll have to ask our Database to do this - we don't have its keys.
228 // Note that this returns memory we own and keep.
229 //
230 KeyBlob *Key::blob()
231 {
232 if (mDatabase == NULL) // can't encode independent keys
233 CssmError::throwMe(CSSMERR_DL_INVALID_DB_HANDLE);
234 if (!mValidBlob) {
235 assert(mValidKey); // must have valid key to encode
236 //@@@ release mBlob memory here
237
238 // export Key ACL to blob form
239 CssmData pubAcl, privAcl;
240 exportBlob(pubAcl, privAcl);
241
242 // assemble external key form
243 CssmKey externalKey = mKey;
244 externalKey.clearAttribute(forcedAttributes);
245 externalKey.setAttribute(mAttributes);
246
247 // encode the key and replace blob
248 KeyBlob *newBlob = database()->encodeKey(externalKey, pubAcl, privAcl);
249 CssmAllocator::standard().free(mBlob);
250 mBlob = newBlob;
251 mValidBlob = true;
252
253 // clean up and go
254 database()->allocator.free(pubAcl);
255 database()->allocator.free(privAcl);
256 }
257 return mBlob;
258 }
259
260
261 //
262 // Return the UID of a key (the hash of its bits)
263 //
264 KeyUID &Key::uid()
265 {
266 if (!mValidUID) {
267 //@@@ calculate UID here
268 memset(&mUID, 0, sizeof(mUID));
269 mValidUID = true;
270 }
271 return mUID;
272 }
273
274
275 //
276 // Intercept ACL change requests and reset blob validity
277 //
278 void Key::instantiateAcl()
279 {
280 decode();
281 }
282
283 void Key::changedAcl()
284 {
285 mValidBlob = false;
286 }
287
288 const Database *Key::relatedDatabase() const
289 { return database(); }