]> git.saurik.com Git - apple/securityd.git/blob - src/kckey.cpp
securityd-27896.tar.gz
[apple/securityd.git] / src / kckey.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25 //
26 // key - representation of securityd key objects
27 //
28 #include "kckey.h"
29 #include "server.h"
30 #include "database.h"
31 #include <security_cdsa_utilities/acl_any.h>
32
33
34 //
35 // Create a Key object from a database-encoded blob.
36 // Note that this doesn't decode the blob (yet).
37 //
38 KeychainKey::KeychainKey(Database &db, const KeyBlob *blob)
39 : LocalKey(db, n2h(blob->header.attributes()))
40 {
41 // perform basic validation on the incoming blob
42 assert(blob);
43 blob->validate(CSSMERR_APPLEDL_INVALID_KEY_BLOB);
44 switch (blob->version()) {
45 #if defined(COMPAT_OSX_10_0)
46 case KeyBlob::version_MacOS_10_0:
47 break;
48 #endif
49 case KeyBlob::version_MacOS_10_1:
50 break;
51 default:
52 CssmError::throwMe(CSSMERR_APPLEDL_INCOMPATIBLE_KEY_BLOB);
53 }
54
55 // set it up
56 mBlob = blob->copy(Allocator::standard());
57 mValidBlob = true;
58 db.addReference(*this);
59 secdebug("SSkey", "%p (handle 0x%lx) created from blob version %lx",
60 this, handle(), blob->version());
61 }
62
63
64 //
65 // Create a Key from an explicit CssmKey.
66 //
67 KeychainKey::KeychainKey(Database &db, const CssmKey &newKey, uint32 moreAttributes,
68 const AclEntryPrototype *owner)
69 : LocalKey(db, newKey, moreAttributes)
70 {
71 assert(moreAttributes & CSSM_KEYATTR_PERMANENT);
72 setOwner(owner);
73 mBlob = NULL;
74 mValidBlob = false;
75 db.addReference(*this);
76 }
77
78
79 KeychainKey::~KeychainKey()
80 {
81 Allocator::standard().free(mBlob);
82 secdebug("SSkey", "%p destroyed", this);
83 }
84
85
86 KeychainDatabase &KeychainKey::database() const
87 {
88 return referent<KeychainDatabase>();
89 }
90
91
92 //
93 // Retrieve the actual CssmKey value for the key object.
94 // This will decode its blob if needed (and appropriate).
95 //
96 void KeychainKey::getKey()
97 {
98 decode();
99 }
100
101 void KeychainKey::getHeader(CssmKey::Header &hdr)
102 {
103 assert(mValidBlob);
104 hdr = mBlob->header;
105 n2hi(hdr); // correct for endian-ness
106 }
107
108
109 //
110 // Ensure that a key is fully decoded.
111 // This makes the mKey key value available for use, as well as its ACL.
112 //
113 void KeychainKey::decode()
114 {
115 if (!mValidKey) {
116 assert(mValidBlob); // must have a blob to decode
117
118 // decode the key
119 void *publicAcl, *privateAcl;
120 CssmKey key;
121 database().decodeKey(mBlob, key, publicAcl, privateAcl);
122 mKey = CssmClient::Key(Server::csp(), key);
123 acl().importBlob(publicAcl, privateAcl);
124 // publicAcl points into the blob; privateAcl was allocated for us
125 Allocator::standard().free(privateAcl);
126
127 // extract managed attribute bits
128 mAttributes = mKey.header().attributes() & managedAttributes;
129 mKey.header().clearAttribute(managedAttributes);
130 mKey.header().setAttribute(forcedAttributes);
131
132 // key is valid now
133 mValidKey = true;
134 }
135 }
136
137
138 //
139 // Encode a key into a blob.
140 // We'll have to ask our Database to do this - we don't have its keys.
141 // Note that this returns memory we own and keep.
142 //
143 KeyBlob *KeychainKey::blob()
144 {
145 if (!mValidBlob) {
146 assert(mValidKey); // must have valid key to encode
147
148 // export Key ACL to blob form
149 CssmData pubAcl, privAcl;
150 acl().exportBlob(pubAcl, privAcl);
151
152 // assemble external key form
153 CssmKey externalKey = mKey;
154 externalKey.clearAttribute(forcedAttributes);
155 externalKey.setAttribute(mAttributes);
156
157 // encode the key and replace blob
158 KeyBlob *newBlob = database().encodeKey(externalKey, pubAcl, privAcl);
159 Allocator::standard().free(mBlob);
160 mBlob = newBlob;
161 mValidBlob = true;
162
163 // clean up and go
164 acl().allocator.free(pubAcl);
165 acl().allocator.free(privAcl);
166 }
167 return mBlob;
168 }
169
170 void KeychainKey::invalidateBlob()
171 {
172 mValidBlob = false;
173 }
174
175
176 //
177 // Override ACL-related methods and events.
178 // Decode the key before ACL activity; invalidate the stored blob on ACL edits;
179 // and return the key's database as "related".
180 //
181 void KeychainKey::instantiateAcl()
182 {
183 decode();
184 }
185
186 void KeychainKey::changedAcl()
187 {
188 invalidateBlob();
189 }
190
191
192 //
193 // Intercept Key validation and double-check that the keychain is (still) unlocked
194 //
195 void KeychainKey::validate(AclAuthorization auth, const AccessCredentials *cred,
196 Database *relatedDatabase)
197 {
198 if (KeychainDatabase *db = dynamic_cast<KeychainDatabase *>(relatedDatabase))
199 db->unlockDb();
200 SecurityServerAcl::validate(auth, cred, relatedDatabase);
201 }
202
203
204 //
205 // We're a key (duh)
206 //
207 AclKind KeychainKey::aclKind() const
208 {
209 return keyAcl;
210 }
211
212
213 Database *KeychainKey::relatedDatabase()
214 {
215 return &database();
216 }
217
218 SecurityServerAcl &KeychainKey::acl()
219 {
220 return *this;
221 }