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
));
127 mUniqueId
= inSSDatabase
->ssInsert(mRecordType
, &attributes
, &blob
);
130 header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me.
131 makeReferenceKey(mAllocator
, keyReference(), ioKey
);
134 // Constructor for a key retrived from a Db.
135 SSKey::SSKey(SSDLSession
&session
, CssmKey
&ioKey
, SSDatabase
&inSSDatabase
,
136 const SSUniqueRecord
&uniqueId
, CSSM_DB_RECORDTYPE recordType
,
138 : ReferencedKey(session
.mSSCSPDLSession
),
139 mAllocator(session
.allocator()), mKeyHandle(noKey
), mUniqueId(uniqueId
),
140 mRecordType(recordType
),
141 mClientSession(session
.clientSession())
143 CssmKey::Header
&header
= ioKey
.header();
144 memset(&header
, 0, sizeof(header
)); // Clear key header
146 if (!mUniqueId
|| !mUniqueId
->database())
147 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR
);
149 header
.HeaderVersion
= CSSM_KEYHEADER_VERSION
;
152 case CSSM_DL_DB_RECORD_PUBLIC_KEY
:
153 header
.KeyClass
= CSSM_KEYCLASS_PUBLIC_KEY
;
155 case CSSM_DL_DB_RECORD_PRIVATE_KEY
:
156 header
.KeyClass
= CSSM_KEYCLASS_PRIVATE_KEY
;
158 case CSSM_DL_DB_RECORD_SYMMETRIC_KEY
:
159 header
.KeyClass
= CSSM_KEYCLASS_SESSION_KEY
;
162 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
165 DbAttributes
attributes(mUniqueId
->database());
166 attributes
.recordType(mRecordType
);
167 attributes
.add(KeySchema::KeyClass
); // 0
168 attributes
.add(KeySchema::Permanent
); // 1
169 attributes
.add(KeySchema::Private
); // 2
170 attributes
.add(KeySchema::Modifiable
); // 3
171 attributes
.add(KeySchema::KeyCreator
); // 4
172 attributes
.add(KeySchema::KeyType
); // 5
173 attributes
.add(KeySchema::KeySizeInBits
); // 6
174 attributes
.add(KeySchema::StartDate
); // 7
175 attributes
.add(KeySchema::EndDate
); // 8
176 attributes
.add(KeySchema::Sensitive
); // 9
177 attributes
.add(KeySchema::AlwaysSensitive
); // 10
178 attributes
.add(KeySchema::Extractable
); // 11
179 attributes
.add(KeySchema::NeverExtractable
); // 12
180 attributes
.add(KeySchema::Encrypt
); // 13
181 attributes
.add(KeySchema::Decrypt
); // 14
182 attributes
.add(KeySchema::Derive
); // 15
183 attributes
.add(KeySchema::Sign
); // 16
184 attributes
.add(KeySchema::Verify
); // 17
185 attributes
.add(KeySchema::SignRecover
); // 18
186 attributes
.add(KeySchema::VerifyRecover
); // 19
187 attributes
.add(KeySchema::Wrap
); // 20
188 attributes
.add(KeySchema::Unwrap
); // 21
190 mUniqueId
->get(&attributes
, NULL
);
192 // Assert that the mRecordType matches the KeyClass attribute.
193 if (mRecordType
!= uint32(attributes
[0]))
194 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
196 header
.AlgorithmId
= attributes
[5]; // KeyType
197 header
.LogicalKeySizeInBits
= attributes
[6]; // KeySizeInBits
199 if (attributes
[1]) header
.setAttribute(CSSM_KEYATTR_PERMANENT
);
200 if (attributes
[2]) header
.setAttribute(CSSM_KEYATTR_PRIVATE
);
201 if (attributes
[3]) header
.setAttribute(CSSM_KEYATTR_MODIFIABLE
);
202 if (attributes
[9]) header
.setAttribute(CSSM_KEYATTR_SENSITIVE
);
203 if (attributes
[11]) header
.setAttribute(CSSM_KEYATTR_EXTRACTABLE
);
204 if (attributes
[10]) header
.setAttribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
);
205 if (attributes
[12]) header
.setAttribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
);
207 if (attributes
[13]) header
.usage(CSSM_KEYUSE_ENCRYPT
);
208 if (attributes
[14]) header
.usage(CSSM_KEYUSE_DECRYPT
);
209 if (attributes
[15]) header
.usage(CSSM_KEYUSE_DERIVE
);
210 if (attributes
[16]) header
.usage(CSSM_KEYUSE_SIGN
);
211 if (attributes
[17]) header
.usage(CSSM_KEYUSE_VERIFY
);
212 if (attributes
[18]) header
.usage(CSSM_KEYUSE_SIGN_RECOVER
);
213 if (attributes
[19]) header
.usage(CSSM_KEYUSE_VERIFY_RECOVER
);
214 if (attributes
[20]) header
.usage(CSSM_KEYUSE_WRAP
);
215 if (attributes
[21]) header
.usage(CSSM_KEYUSE_UNWRAP
);
217 // If all usages are allowed set usage to CSSM_KEYUSE_ANY
218 if (header
.usage() == (CSSM_KEYUSE_ENCRYPT
| CSSM_KEYUSE_DECRYPT
219 | CSSM_KEYUSE_DERIVE
| CSSM_KEYUSE_SIGN
220 | CSSM_KEYUSE_VERIFY
| CSSM_KEYUSE_SIGN_RECOVER
221 | CSSM_KEYUSE_VERIFY_RECOVER
| CSSM_KEYUSE_WRAP
222 | CSSM_KEYUSE_UNWRAP
))
223 header
.usage(CSSM_KEYUSE_ANY
);
225 if (!attributes
[7].size() || !attributes
[8].size())
226 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
228 header
.StartDate
= attributes
[7].at
<CSSM_DATE
>(0);
229 header
.EndDate
= attributes
[8].at
<CSSM_DATE
>(0);
231 makeReferenceKey(mAllocator
, keyReference(), ioKey
);
232 header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me.
237 if (mKeyHandle
!= noKey
)
238 clientSession().releaseKey(mKeyHandle
);
242 SSKey::free(const AccessCredentials
*accessCred
, CssmKey
&ioKey
,
245 freeReferenceKey(mAllocator
, ioKey
);
248 if (!mUniqueId
|| !mUniqueId
->database())
249 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
251 // @@@ Evaluate accessCred against Db acl.
252 // What should we do with accessCred? Reauthenticate
253 // mUniqueId->database()?
254 mUniqueId
->deleteRecord();
257 if (mKeyHandle
!= noKey
)
259 clientSession().releaseKey(mKeyHandle
);
264 SecurityServer::ClientSession
&
265 SSKey::clientSession()
267 return mClientSession
;
270 KeyHandle
SSKey::optionalKeyHandle() const
278 if (mKeyHandle
== noKey
)
280 // Deal with uninstantiated keys.
281 if (!mUniqueId
|| !mUniqueId
->database())
282 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
284 CssmDataContainer
blob(mAllocator
);
285 mUniqueId
->get(NULL
, &blob
);
286 CssmKey::Header dummyHeader
; // @@@ Unused
288 clientSession().decodeKey(mUniqueId
->database().dbHandle(), blob
,
291 secinfo("SecAccessReference", "decoded a new key into handle %d [reference %ld]", mKeyHandle
, keyReference());
293 // @@@ Check decoded header against returned header
300 // ACL retrieval and change operations
303 SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE
&owner
, Allocator
&allocator
)
305 clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner
),
310 SSKey::changeOwner(const AccessCredentials
&accessCred
,
311 const AclOwnerPrototype
&newOwner
)
313 clientSession().changeKeyOwner(keyHandle(), accessCred
, newOwner
);
318 SSKey::getAcl(const char *selectionTag
, uint32
&numberOfAclInfos
,
319 AclEntryInfo
*&aclInfos
, Allocator
&allocator
)
321 clientSession().getKeyAcl(keyHandle(), selectionTag
, numberOfAclInfos
,
322 aclInfos
, allocator
);
326 SSKey::changeAcl(const AccessCredentials
&accessCred
, const AclEdit
&aclEdit
)
328 clientSession().changeKeyAcl(keyHandle(), accessCred
, aclEdit
);
333 SSKey::didChangeAcl()
335 if (mUniqueId
== true)
337 secinfo("keyacl", "SSKey::didChangeAcl() keyHandle: %lu updating DL entry", (unsigned long)mKeyHandle
);
338 // The key is persistent, make the change on disk.
339 CssmDataContainer
keyBlob(mAllocator
);
340 clientSession().encodeKey(keyHandle(), keyBlob
);
341 mUniqueId
->modify(mRecordType
, NULL
, &keyBlob
, CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
345 secinfo("keyacl", "SSKey::didChangeAcl() keyHandle: %lu transient key no update done", (unsigned long)mKeyHandle
);