2 * Copyright (c) 2000-2001 Apple Computer, 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 "KeySchema.h"
29 #include <Security/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
)
41 CssmKey::Header
&header
= ioKey
.header();
42 if (inKeyAttr
& CSSM_KEYATTR_PERMANENT
)
45 CssmError::throwMe(CSSMERR_CSP_MISSING_ATTR_DL_DB_HANDLE
);
47 // EncodeKey and store it in the db.
48 CssmDataContainer
blob(clientSession().returnAllocator
);
49 clientSession().encodeKey(keyHandle
, blob
);
51 assert(header
.HeaderVersion
== CSSM_KEYHEADER_VERSION
);
52 switch (header
.KeyClass
)
54 case CSSM_KEYCLASS_PUBLIC_KEY
:
55 mRecordType
= CSSM_DL_DB_RECORD_PUBLIC_KEY
;
57 case CSSM_KEYCLASS_PRIVATE_KEY
:
58 mRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
60 case CSSM_KEYCLASS_SESSION_KEY
:
61 mRecordType
= CSSM_DL_DB_RECORD_SYMMETRIC_KEY
;
64 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
72 // We store the keys real CSP guid on disk
73 CssmGuidData
creatorGuid(header
.CspId
);
74 CssmDateData
startDate(header
.StartDate
);
75 CssmDateData
endDate(header
.EndDate
);
77 DbAttributes
attributes(inSSDatabase
);
78 attributes
.recordType(mRecordType
);
79 attributes
.add(KeySchema::KeyClass
, mRecordType
);
80 attributes
.add(KeySchema::PrintName
, label
);
81 attributes
.add(KeySchema::Alias
, none
);
82 attributes
.add(KeySchema::Permanent
,
83 header
.attribute(CSSM_KEYATTR_PERMANENT
));
84 attributes
.add(KeySchema::Private
,
85 header
.attribute(CSSM_KEYATTR_PRIVATE
));
86 attributes
.add(KeySchema::Modifiable
,
87 header
.attribute(CSSM_KEYATTR_MODIFIABLE
));
88 attributes
.add(KeySchema::Label
, label
);
89 attributes
.add(KeySchema::ApplicationTag
, none
);
90 attributes
.add(KeySchema::KeyCreator
, creatorGuid
);
91 attributes
.add(KeySchema::KeyType
, header
.AlgorithmId
);
92 attributes
.add(KeySchema::KeySizeInBits
, header
.LogicalKeySizeInBits
);
93 // @@@ Get the real effective key size.
94 attributes
.add(KeySchema::EffectiveKeySize
, header
.LogicalKeySizeInBits
);
95 attributes
.add(KeySchema::StartDate
, startDate
);
96 attributes
.add(KeySchema::EndDate
, endDate
);
97 attributes
.add(KeySchema::Sensitive
,
98 header
.attribute(CSSM_KEYATTR_SENSITIVE
));
99 attributes
.add(KeySchema::AlwaysSensitive
,
100 header
.attribute(CSSM_KEYATTR_ALWAYS_SENSITIVE
));
101 attributes
.add(KeySchema::Extractable
,
102 header
.attribute(CSSM_KEYATTR_EXTRACTABLE
));
103 attributes
.add(KeySchema::NeverExtractable
,
104 header
.attribute(CSSM_KEYATTR_NEVER_EXTRACTABLE
));
105 attributes
.add(KeySchema::Encrypt
,
106 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_ENCRYPT
));
107 attributes
.add(KeySchema::Decrypt
,
108 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_DECRYPT
));
109 attributes
.add(KeySchema::Derive
,
110 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_DERIVE
));
111 attributes
.add(KeySchema::Sign
,
112 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_SIGN
));
113 attributes
.add(KeySchema::Verify
,
114 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_VERIFY
));
115 attributes
.add(KeySchema::SignRecover
,
116 header
.useFor(CSSM_KEYUSE_ANY
117 | CSSM_KEYUSE_SIGN_RECOVER
));
118 attributes
.add(KeySchema::VerifyRecover
,
119 header
.useFor(CSSM_KEYUSE_ANY
120 | CSSM_KEYUSE_VERIFY_RECOVER
));
121 attributes
.add(KeySchema::Wrap
,
122 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_WRAP
));
123 attributes
.add(KeySchema::Unwrap
,
124 header
.useFor(CSSM_KEYUSE_ANY
| CSSM_KEYUSE_UNWRAP
));
127 mUniqueId
= inSSDatabase
->insert(mRecordType
, &attributes
, &blob
,
131 header
.cspGuid(session
.plugin
.myGuid()); // Set the csp guid to me.
132 makeReferenceKey(mAllocator
, keyReference(), ioKey
);
135 // Constructor for a key retrived from a Db.
136 SSKey::SSKey(SSDLSession
&session
, CssmKey
&ioKey
, SSDatabase
&inSSDatabase
,
137 const SSUniqueRecord
&uniqueId
, CSSM_DB_RECORDTYPE recordType
,
139 : ReferencedKey(session
.mSSCSPDLSession
),
140 mAllocator(session
.allocator()), mKeyHandle(noKey
), mUniqueId(uniqueId
),
141 mRecordType(recordType
)
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 keyPool
<SSCSPDLSession
>().clientSession();
273 if (mKeyHandle
== noKey
)
275 // Deal with uninstantiated keys.
276 if (!mUniqueId
|| !mUniqueId
->database())
277 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY
);
279 CssmDataContainer blob
;
280 mUniqueId
->get(NULL
, &blob
);
281 CssmKey::Header dummyHeader
; // @@@ Unused
283 clientSession().decodeKey(mUniqueId
->database().dbHandle(), blob
,
286 // @@@ Check decoded header against returned header
293 // ACL retrieval and change operations
296 SSKey::getOwner(CSSM_ACL_OWNER_PROTOTYPE
&owner
, CssmAllocator
&allocator
)
298 clientSession().getKeyOwner(keyHandle(), AclOwnerPrototype::overlay(owner
),
303 SSKey::changeOwner(const AccessCredentials
&accessCred
,
304 const AclOwnerPrototype
&newOwner
)
306 clientSession().changeKeyOwner(keyHandle(), accessCred
, newOwner
);
307 if (mUniqueId
== true)
309 // The key is persistant, make the change on disk.
310 CssmDataContainer
keyBlob(clientSession().returnAllocator
);
311 clientSession().encodeKey(keyHandle(), keyBlob
);
312 mUniqueId
->modify(mRecordType
, NULL
, &keyBlob
,
313 CSSM_DB_MODIFY_ATTRIBUTE_NONE
);
318 SSKey::getAcl(const char *selectionTag
, uint32
&numberOfAclInfos
,
319 AclEntryInfo
*&aclInfos
, CssmAllocator
&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
);
329 if (mUniqueId
== true)
331 // The key is persistant, make the change on disk.
332 CssmDataContainer
keyBlob(clientSession().returnAllocator
);
333 clientSession().encodeKey(keyHandle(), keyBlob
);
334 mUniqueId
->modify(mRecordType
, NULL
, &keyBlob
,
335 CSSM_DB_MODIFY_ATTRIBUTE_NONE
);