]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_cspdl/lib/SSKey.cpp
Security-58286.1.32.tar.gz
[apple/security.git] / OSX / libsecurity_apple_cspdl / lib / SSKey.cpp
1 /*
2 * Copyright (c) 2000-2001,2008,2011-2012 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 // SSKey - reference keys for the security server
21 //
22 #include "SSKey.h"
23
24 #include "SSCSPSession.h"
25 #include "SSCSPDLSession.h"
26 #include "SSDatabase.h"
27 #include "SSDLSession.h"
28 #include <security_cdsa_utilities/KeySchema.h>
29 #include <security_cdsa_plugin/cssmplugin.h>
30 #include <security_utilities/threading.h>
31
32 using namespace CssmClient;
33 using namespace SecurityServer;
34
35 // Constructor for a Security Server generated key.
36 SSKey::SSKey(SSCSPSession &session, KeyHandle keyHandle, CssmKey &ioKey,
37 SSDatabase &inSSDatabase, uint32 inKeyAttr,
38 const CssmData *inKeyLabel)
39 : ReferencedKey(session.mSSCSPDLSession),
40 mAllocator(session), mKeyHandle(keyHandle),
41 mClientSession(session.clientSession())
42 {
43 StLock<Mutex> _ (mMutex); // In the constructor??? Yes. Our handlers aren't thread safe in the slightest...
44 CssmKey::Header &header = ioKey.header();
45 if (inKeyAttr & CSSM_KEYATTR_PERMANENT)
46 {
47 if (!inSSDatabase)
48 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE);
49
50 // EncodeKey and store it in the db.
51 CssmDataContainer blob(mAllocator);
52 clientSession().encodeKey(keyHandle, blob);
53
54 assert(header.HeaderVersion == CSSM_KEYHEADER_VERSION);
55 switch (header.KeyClass)
56 {
57 case CSSM_KEYCLASS_PUBLIC_KEY:
58 mRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY;
59 break;
60 case CSSM_KEYCLASS_PRIVATE_KEY:
61 mRecordType = CSSM_DL_DB_RECORD_PRIVATE_KEY;
62 break;
63 case CSSM_KEYCLASS_SESSION_KEY:
64 mRecordType = CSSM_DL_DB_RECORD_SYMMETRIC_KEY;
65 break;
66 default:
67 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
68 }
69
70 CssmData label;
71 if (inKeyLabel)
72 label = *inKeyLabel;
73
74 CssmData none;
75 // We store the keys real CSP guid on disk
76 CssmGuidData creatorGuid(header.CspId);
77 CssmDateData startDate(header.StartDate);
78 CssmDateData endDate(header.EndDate);
79
80 DbAttributes attributes(inSSDatabase);
81 attributes.recordType(mRecordType);
82 attributes.add(KeySchema::KeyClass, mRecordType);
83 attributes.add(KeySchema::PrintName, label);
84 attributes.add(KeySchema::Alias, none);
85 attributes.add(KeySchema::Permanent,
86 header.attribute(CSSM_KEYATTR_PERMANENT));
87 attributes.add(KeySchema::Private,
88 header.attribute(CSSM_KEYATTR_PRIVATE));
89 attributes.add(KeySchema::Modifiable,
90 header.attribute(CSSM_KEYATTR_MODIFIABLE));
91 attributes.add(KeySchema::Label, label);
92 attributes.add(KeySchema::ApplicationTag, none);
93 attributes.add(KeySchema::KeyCreator, creatorGuid);
94 attributes.add(KeySchema::KeyType, header.AlgorithmId);
95 attributes.add(KeySchema::KeySizeInBits, header.LogicalKeySizeInBits);
96 // @@@ Get the real effective key size.
97 attributes.add(KeySchema::EffectiveKeySize, header.LogicalKeySizeInBits);
98 attributes.add(KeySchema::StartDate, startDate);
99 attributes.add(KeySchema::EndDate, endDate);
100 attributes.add(KeySchema::Sensitive,
101 header.attribute(CSSM_KEYATTR_SENSITIVE));
102 attributes.add(KeySchema::AlwaysSensitive,
103 header.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE));
104 attributes.add(KeySchema::Extractable,
105 header.attribute(CSSM_KEYATTR_EXTRACTABLE));
106 attributes.add(KeySchema::NeverExtractable,
107 header.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE));
108 attributes.add(KeySchema::Encrypt,
109 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_ENCRYPT));
110 attributes.add(KeySchema::Decrypt,
111 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DECRYPT));
112 attributes.add(KeySchema::Derive,
113 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_DERIVE));
114 attributes.add(KeySchema::Sign,
115 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_SIGN));
116 attributes.add(KeySchema::Verify,
117 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_VERIFY));
118 attributes.add(KeySchema::SignRecover,
119 header.useFor(CSSM_KEYUSE_ANY
120 | CSSM_KEYUSE_SIGN_RECOVER));
121 attributes.add(KeySchema::VerifyRecover,
122 header.useFor(CSSM_KEYUSE_ANY
123 | CSSM_KEYUSE_VERIFY_RECOVER));
124 attributes.add(KeySchema::Wrap,
125 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_WRAP));
126 attributes.add(KeySchema::Unwrap,
127 header.useFor(CSSM_KEYUSE_ANY | CSSM_KEYUSE_UNWRAP));
128
129 mUniqueId = inSSDatabase->ssInsert(mRecordType, &attributes, &blob);
130 }
131
132 header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
133 makeReferenceKey(mAllocator, keyReference(), ioKey);
134 }
135
136 // Constructor for a key retrived from a Db.
137 SSKey::SSKey(SSDLSession &session, CssmKey &ioKey, SSDatabase &inSSDatabase,
138 const SSUniqueRecord &uniqueId, CSSM_DB_RECORDTYPE recordType,
139 CssmData &keyBlob)
140 : ReferencedKey(session.mSSCSPDLSession),
141 mAllocator(session.allocator()), mKeyHandle(noKey), mUniqueId(uniqueId),
142 mRecordType(recordType),
143 mClientSession(session.clientSession())
144 {
145 StLock<Mutex> _ (mMutex);
146 CssmKey::Header &header = ioKey.header();
147 memset(&header, 0, sizeof(header)); // Clear key header
148
149 if (!mUniqueId || !mUniqueId->database())
150 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR);
151
152 header.HeaderVersion = CSSM_KEYHEADER_VERSION;
153 switch (mRecordType)
154 {
155 case CSSM_DL_DB_RECORD_PUBLIC_KEY:
156 header.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
157 break;
158 case CSSM_DL_DB_RECORD_PRIVATE_KEY:
159 header.KeyClass = CSSM_KEYCLASS_PRIVATE_KEY;
160 break;
161 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY:
162 header.KeyClass = CSSM_KEYCLASS_SESSION_KEY;
163 break;
164 default:
165 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
166 }
167
168 DbAttributes attributes(mUniqueId->database());
169 attributes.recordType(mRecordType);
170 attributes.add(KeySchema::KeyClass); // 0
171 attributes.add(KeySchema::Permanent); // 1
172 attributes.add(KeySchema::Private); // 2
173 attributes.add(KeySchema::Modifiable); // 3
174 attributes.add(KeySchema::KeyCreator); // 4
175 attributes.add(KeySchema::KeyType); // 5
176 attributes.add(KeySchema::KeySizeInBits); // 6
177 attributes.add(KeySchema::StartDate); // 7
178 attributes.add(KeySchema::EndDate); // 8
179 attributes.add(KeySchema::Sensitive); // 9
180 attributes.add(KeySchema::AlwaysSensitive); // 10
181 attributes.add(KeySchema::Extractable); // 11
182 attributes.add(KeySchema::NeverExtractable); // 12
183 attributes.add(KeySchema::Encrypt); // 13
184 attributes.add(KeySchema::Decrypt); // 14
185 attributes.add(KeySchema::Derive); // 15
186 attributes.add(KeySchema::Sign); // 16
187 attributes.add(KeySchema::Verify); // 17
188 attributes.add(KeySchema::SignRecover); // 18
189 attributes.add(KeySchema::VerifyRecover); // 19
190 attributes.add(KeySchema::Wrap); // 20
191 attributes.add(KeySchema::Unwrap); // 21
192
193 mUniqueId->get(&attributes, NULL);
194
195 // Assert that the mRecordType matches the KeyClass attribute.
196 if (mRecordType != uint32(attributes[0]))
197 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
198
199 header.AlgorithmId = attributes[5]; // KeyType
200 header.LogicalKeySizeInBits = attributes[6]; // KeySizeInBits
201
202 if (attributes[1]) header.setAttribute(CSSM_KEYATTR_PERMANENT);
203 if (attributes[2]) header.setAttribute(CSSM_KEYATTR_PRIVATE);
204 if (attributes[3]) header.setAttribute(CSSM_KEYATTR_MODIFIABLE);
205 if (attributes[9]) header.setAttribute(CSSM_KEYATTR_SENSITIVE);
206 if (attributes[11]) header.setAttribute(CSSM_KEYATTR_EXTRACTABLE);
207 if (attributes[10]) header.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE);
208 if (attributes[12]) header.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE);
209
210 if (attributes[13]) header.usage(CSSM_KEYUSE_ENCRYPT);
211 if (attributes[14]) header.usage(CSSM_KEYUSE_DECRYPT);
212 if (attributes[15]) header.usage(CSSM_KEYUSE_DERIVE);
213 if (attributes[16]) header.usage(CSSM_KEYUSE_SIGN);
214 if (attributes[17]) header.usage(CSSM_KEYUSE_VERIFY);
215 if (attributes[18]) header.usage(CSSM_KEYUSE_SIGN_RECOVER);
216 if (attributes[19]) header.usage(CSSM_KEYUSE_VERIFY_RECOVER);
217 if (attributes[20]) header.usage(CSSM_KEYUSE_WRAP);
218 if (attributes[21]) header.usage(CSSM_KEYUSE_UNWRAP);
219
220 // If all usages are allowed set usage to CSSM_KEYUSE_ANY
221 if (header.usage() == (CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT
222 | CSSM_KEYUSE_DERIVE | CSSM_KEYUSE_SIGN
223 | CSSM_KEYUSE_VERIFY | CSSM_KEYUSE_SIGN_RECOVER
224 | CSSM_KEYUSE_VERIFY_RECOVER | CSSM_KEYUSE_WRAP
225 | CSSM_KEYUSE_UNWRAP))
226 header.usage(CSSM_KEYUSE_ANY);
227
228 if (!attributes[7].size() || !attributes[8].size())
229 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
230
231 header.StartDate = attributes[7].at<CSSM_DATE>(0);
232 header.EndDate = attributes[8].at<CSSM_DATE>(0);
233
234 makeReferenceKey(mAllocator, keyReference(), ioKey);
235 header.cspGuid(session.plugin.myGuid()); // Set the csp guid to me.
236 }
237
238 SSKey::~SSKey()
239 try {
240 StLock<Mutex> _(mMutex); // In the destructor too??? Yes. See SSCSPSession.cpp:354 for an explanation of this code's policy on threads.
241 if (mKeyHandle != noKey)
242 clientSession().releaseKey(mKeyHandle);
243 } catch (...) {
244 /*
245 * If the key handle have been invalidated, releaseKey will throw an exception
246 */
247 return;
248 }
249
250
251 void
252 SSKey::free(const AccessCredentials *accessCred, CssmKey &ioKey,
253 CSSM_BOOL deleteKey)
254 {
255 StLock<Mutex> _(mMutex);
256 freeReferenceKey(mAllocator, ioKey);
257 if (deleteKey)
258 {
259 if (!mUniqueId || !mUniqueId->database())
260 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
261
262 // @@@ Evaluate accessCred against Db acl.
263 // What should we do with accessCred? Reauthenticate
264 // mUniqueId->database()?
265 mUniqueId->deleteRecord();
266 }
267
268 if (mKeyHandle != noKey)
269 {
270 clientSession().releaseKey(mKeyHandle);
271 mKeyHandle = noKey;
272 }
273 }
274
275 SecurityServer::ClientSession &
276 SSKey::clientSession()
277 {
278 StLock<Mutex> _(mMutex);
279 return mClientSession;
280 }
281
282 KeyHandle SSKey::optionalKeyHandle() const
283 {
284 StLock<Mutex> _(mMutex);
285 return mKeyHandle;
286 }
287
288 KeyHandle
289 SSKey::keyHandle()
290 {
291 StLock<Mutex> _(mMutex);
292 if (mKeyHandle == noKey)
293 {
294 // Deal with uninstantiated keys.
295 if (!mUniqueId || !mUniqueId->database())
296 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY);
297
298 CssmDataContainer blob(mAllocator);
299 mUniqueId->get(NULL, &blob);
300 CssmKey::Header dummyHeader; // @@@ Unused
301 mKeyHandle =
302 clientSession().decodeKey(mUniqueId->database().dbHandle(), blob,
303 dummyHeader);
304
305 secinfo("SecAccessReference", "decoded a new key into handle %d [reference %ld]", mKeyHandle, keyReference());
306
307 // @@@ Check decoded header against returned header
308 }
309
310 return mKeyHandle;
311 }
312
313 //
314 // ACL retrieval and change operations
315 //
316 void
317 SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE &owner, Allocator &allocator)
318 {
319 StLock<Mutex> _ (mMutex);
320 clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner),
321 allocator);
322 }
323
324 void
325 SSKey::changeOwner(const AccessCredentials &accessCred,
326 const AclOwnerPrototype &newOwner)
327 {
328 StLock<Mutex> _ (mMutex);
329 clientSession().changeKeyOwner(keyHandle(), accessCred, newOwner);
330 didChangeAcl();
331 }
332
333 void
334 SSKey::getAcl(const char *selectionTag, uint32 &numberOfAclInfos,
335 AclEntryInfo *&aclInfos, Allocator &allocator)
336 {
337 StLock<Mutex> _ (mMutex);
338 clientSession().getKeyAcl(keyHandle(), selectionTag, numberOfAclInfos,
339 aclInfos, allocator);
340 }
341
342 void
343 SSKey::changeAcl(const AccessCredentials &accessCred, const AclEdit &aclEdit)
344 {
345 StLock<Mutex> _ (mMutex);
346 clientSession().changeKeyAcl(keyHandle(), accessCred, aclEdit);
347 didChangeAcl();
348 }
349
350 void
351 SSKey::didChangeAcl()
352 {
353 if (mUniqueId == true)
354 {
355 secinfo("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle);
356 // The key is persistent, make the change on disk.
357 CssmDataContainer keyBlob(mAllocator);
358 clientSession().encodeKey(keyHandle(), keyBlob);
359 mUniqueId->modify(mRecordType, NULL, &keyBlob, CSSM_DB_MODIFY_ATTRIBUTE_NONE);
360 }
361 else
362 {
363 secinfo("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle);
364 }
365 }