2 * Copyright (c) 2000-2001,2008,2011-2012 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.
20 // SSKey - reference keys for the security server
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>
31 using namespace CssmClient
;
32 using namespace SecurityServer
;
34 // Constructor for a Security Server generated key.
35 SSKey::SSKey(SSCSPSession
&session
, KeyHandle keyHandle
, CssmKey
&ioKey
,
36 SSDatabase
&inSSDatabase
, uint32 inKeyAttr
,
37 const CssmData
*inKeyLabel
)
38 : ReferencedKey(session
.mSSCSPDLSession
),
39 mAllocator(session
), mKeyHandle(keyHandle
),
40 mClientSession(session
.clientSession())
42 CssmKey::Header
&header
= ioKey
.header();
43 if (inKeyAttr
& CSSM_KEYATTR_PERMANENT
)
46 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE
);
48 // EncodeKey and store it in the db.
49 CssmDataContainer
blob(mAllocator
);
50 clientSession().encodeKey(keyHandle
, blob
);
52 assert(header
.HeaderVersion
== CSSM_KEYHEADER_VERSION
);
53 switch (header
.KeyClass
)
55 case CSSM_KEYCLASS_PUBLIC_KEY
:
56 mRecordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
58 case CSSM_KEYCLASS_PRIVATE_KEY
:
59 mRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
61 case CSSM_KEYCLASS_SESSION_KEY
:
62 mRecordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
65 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
73 // We store the keys real CSP guid on disk
74 CssmGuidData
creatorGuid(header
.CspId
);
75 CssmDateData
startDate(header
.StartDate
);
76 CssmDateData
endDate(header
.EndDate
);
78 DbAttributes
attributes(inSSDatabase
);
79 attributes
.recordType(mRecordType
);
80 attributes
.add(KeySchema::KeyClass
, mRecordType
);
81 attributes
.add(KeySchema::PrintName
, label
);
82 attributes
.add(KeySchema::Alias
, none
);
83 attributes
.add(KeySchema::Permanent
,
84 header
.attribute(CSSM_KEYATTR_PERMANENT
));
85 attributes
.add(KeySchema::Private
,
86 header
.attribute(CSSM_KEYATTR_PRIVATE
));
87 attributes
.add(KeySchema::Modifiable
,
88 header
.attribute(CSSM_KEYATTR_MODIFIABLE
));
89 attributes
.add(KeySchema::Label
, label
);
90 attributes
.add(KeySchema::ApplicationTag
, none
);
91 attributes
.add(KeySchema::KeyCreator
, creatorGuid
);
92 attributes
.add(KeySchema::KeyType
, header
.AlgorithmId
);
93 attributes
.add(KeySchema::KeySizeInBits
, header
.LogicalKeySizeInBits
);
94 // @@@ Get the real effective key size.
95 attributes
.add(KeySchema::EffectiveKeySize
, header
.LogicalKeySizeInBits
);
96 attributes
.add(KeySchema::StartDate
, startDate
);
97 attributes
.add(KeySchema::EndDate
, endDate
);
98 attributes
.add(KeySchema::Sensitive
,
99 header
.attribute(CSSM_KEYATTR_SENSITIVE
));
100 attributes
.add(KeySchema::AlwaysSensitive
,
101 header
.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
));
102 attributes
.add(KeySchema::Extractable
,
103 header
.attribute(CSSM_KEYATTR_EXTRACTABLE
));
104 attributes
.add(KeySchema::NeverExtractable
,
105 header
.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
));
106 attributes
.add(KeySchema::Encrypt
,
107 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_ENCRYPT
));
108 attributes
.add(KeySchema::Decrypt
,
109 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_DECRYPT
));
110 attributes
.add(KeySchema::Derive
,
111 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_DERIVE
));
112 attributes
.add(KeySchema::Sign
,
113 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_SIGN
));
114 attributes
.add(KeySchema::Verify
,
115 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_VERIFY
));
116 attributes
.add(KeySchema::SignRecover
,
117 header
.useFor(CSSM_KEYUSE_ANY
118 | CSSM_KEYUSE_SIGN_RECOVER
));
119 attributes
.add(KeySchema::VerifyRecover
,
120 header
.useFor(CSSM_KEYUSE_ANY
121 | CSSM_KEYUSE_VERIFY_RECOVER
));
122 attributes
.add(KeySchema::Wrap
,
123 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_WRAP
));
124 attributes
.add(KeySchema::Unwrap
,
125 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_UNWRAP
));
128 mUniqueId
= inSSDatabase
->insert(mRecordType
, &attributes
, &blob
,
132 header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me.
133 makeReferenceKey(mAllocator
, keyReference(), ioKey
);
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
,
140 : ReferencedKey(session
.mSSCSPDLSession
),
141 mAllocator(session
.allocator()), mKeyHandle(noKey
), mUniqueId(uniqueId
),
142 mRecordType(recordType
),
143 mClientSession(session
.clientSession())
145 CssmKey::Header
&header
= ioKey
.header();
146 memset(&header
, 0, sizeof(header
)); // Clear key header
148 if (!mUniqueId
|| !mUniqueId
->database())
149 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
151 header
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
154 case CSSM_DL_DB_RECORD_PUBLIC_KEY
:
155 header
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
157 case CSSM_DL_DB_RECORD_PRIVATE_KEY
:
158 header
.KeyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
160 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
:
161 header
.KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
164 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
167 DbAttributes
attributes(mUniqueId
->database());
168 attributes
.recordType(mRecordType
);
169 attributes
.add(KeySchema::KeyClass
); // 0
170 attributes
.add(KeySchema::Permanent
); // 1
171 attributes
.add(KeySchema::Private
); // 2
172 attributes
.add(KeySchema::Modifiable
); // 3
173 attributes
.add(KeySchema::KeyCreator
); // 4
174 attributes
.add(KeySchema::KeyType
); // 5
175 attributes
.add(KeySchema::KeySizeInBits
); // 6
176 attributes
.add(KeySchema::StartDate
); // 7
177 attributes
.add(KeySchema::EndDate
); // 8
178 attributes
.add(KeySchema::Sensitive
); // 9
179 attributes
.add(KeySchema::AlwaysSensitive
); // 10
180 attributes
.add(KeySchema::Extractable
); // 11
181 attributes
.add(KeySchema::NeverExtractable
); // 12
182 attributes
.add(KeySchema::Encrypt
); // 13
183 attributes
.add(KeySchema::Decrypt
); // 14
184 attributes
.add(KeySchema::Derive
); // 15
185 attributes
.add(KeySchema::Sign
); // 16
186 attributes
.add(KeySchema::Verify
); // 17
187 attributes
.add(KeySchema::SignRecover
); // 18
188 attributes
.add(KeySchema::VerifyRecover
); // 19
189 attributes
.add(KeySchema::Wrap
); // 20
190 attributes
.add(KeySchema::Unwrap
); // 21
192 mUniqueId
->get(&attributes
, NULL
);
194 // Assert that the mRecordType matches the KeyClass attribute.
195 if (mRecordType
!= uint32(attributes
[0]))
196 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
198 header
.AlgorithmId
= attributes
[5]; // KeyType
199 header
.LogicalKeySizeInBits
= attributes
[6]; // KeySizeInBits
201 if (attributes
[1]) header
.setAttribute(CSSM_KEYATTR_PERMANENT
);
202 if (attributes
[2]) header
.setAttribute(CSSM_KEYATTR_PRIVATE
);
203 if (attributes
[3]) header
.setAttribute(CSSM_KEYATTR_MODIFIABLE
);
204 if (attributes
[9]) header
.setAttribute(CSSM_KEYATTR_SENSITIVE
);
205 if (attributes
[11]) header
.setAttribute(CSSM_KEYATTR_EXTRACTABLE
);
206 if (attributes
[10]) header
.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
);
207 if (attributes
[12]) header
.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
);
209 if (attributes
[13]) header
.usage(CSSM_KEYUSE_ENCRYPT
);
210 if (attributes
[14]) header
.usage(CSSM_KEYUSE_DECRYPT
);
211 if (attributes
[15]) header
.usage(CSSM_KEYUSE_DERIVE
);
212 if (attributes
[16]) header
.usage(CSSM_KEYUSE_SIGN
);
213 if (attributes
[17]) header
.usage(CSSM_KEYUSE_VERIFY
);
214 if (attributes
[18]) header
.usage(CSSM_KEYUSE_SIGN_RECOVER
);
215 if (attributes
[19]) header
.usage(CSSM_KEYUSE_VERIFY_RECOVER
);
216 if (attributes
[20]) header
.usage(CSSM_KEYUSE_WRAP
);
217 if (attributes
[21]) header
.usage(CSSM_KEYUSE_UNWRAP
);
219 // If all usages are allowed set usage to CSSM_KEYUSE_ANY
220 if (header
.usage() == (CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
221 | CSSM_KEYUSE_DERIVE
| CSSM_KEYUSE_SIGN
222 | CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_SIGN_RECOVER
223 | CSSM_KEYUSE_VERIFY_RECOVER
| CSSM_KEYUSE_WRAP
224 | CSSM_KEYUSE_UNWRAP
))
225 header
.usage(CSSM_KEYUSE_ANY
);
227 if (!attributes
[7].size() || !attributes
[8].size())
228 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
230 header
.StartDate
= attributes
[7].at
<CSSM_DATE
>(0);
231 header
.EndDate
= attributes
[8].at
<CSSM_DATE
>(0);
233 makeReferenceKey(mAllocator
, keyReference(), ioKey
);
234 header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me.
239 if (mKeyHandle
!= noKey
)
240 clientSession().releaseKey(mKeyHandle
);
244 SSKey::free(const AccessCredentials
*accessCred
, CssmKey
&ioKey
,
247 freeReferenceKey(mAllocator
, ioKey
);
250 if (!mUniqueId
|| !mUniqueId
->database())
251 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
253 // @@@ Evaluate accessCred against Db acl.
254 // What should we do with accessCred? Reauthenticate
255 // mUniqueId->database()?
256 mUniqueId
->deleteRecord();
259 if (mKeyHandle
!= noKey
)
261 clientSession().releaseKey(mKeyHandle
);
266 SecurityServer::ClientSession
&
267 SSKey::clientSession()
269 return mClientSession
;
272 KeyHandle
SSKey::optionalKeyHandle() const
280 if (mKeyHandle
== noKey
)
282 // Deal with uninstantiated keys.
283 if (!mUniqueId
|| !mUniqueId
->database())
284 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
286 CssmDataContainer
blob(mAllocator
);
287 mUniqueId
->get(NULL
, &blob
);
288 CssmKey::Header dummyHeader
; // @@@ Unused
290 clientSession().decodeKey(mUniqueId
->database().dbHandle(), blob
,
293 secdebugfunc("SecAccessReference", "decoded a new key into handle %d [reference %d]", mKeyHandle
, keyReference());
295 // @@@ Check decoded header against returned header
302 // ACL retrieval and change operations
305 SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE
&owner
, Allocator
&allocator
)
307 clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner
),
312 SSKey::changeOwner(const AccessCredentials
&accessCred
,
313 const AclOwnerPrototype
&newOwner
)
315 clientSession().changeKeyOwner(keyHandle(), accessCred
, newOwner
);
320 SSKey::getAcl(const char *selectionTag
, uint32
&numberOfAclInfos
,
321 AclEntryInfo
*&aclInfos
, Allocator
&allocator
)
323 clientSession().getKeyAcl(keyHandle(), selectionTag
, numberOfAclInfos
,
324 aclInfos
, allocator
);
328 SSKey::changeAcl(const AccessCredentials
&accessCred
, const AclEdit
&aclEdit
)
330 clientSession().changeKeyAcl(keyHandle(), accessCred
, aclEdit
);
335 SSKey::didChangeAcl()
337 if (mUniqueId
== true)
339 secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle
);
340 // The key is persistent, make the change on disk.
341 CssmDataContainer
keyBlob(mAllocator
);
342 clientSession().encodeKey(keyHandle(), keyBlob
);
343 mUniqueId
->modify(mRecordType
, NULL
, &keyBlob
, CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
347 secdebug("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle
);