]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2000-2001 Apple Computer, 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 | #include "securestorage.h" | |
20 | #include <security_cdsa_client/genkey.h> | |
21 | //#include <Security/Access.h> //@@@CONV | |
22 | #include <security_utilities/osxcode.h> | |
23 | #include <memory> | |
24 | ||
25 | using namespace CssmClient; | |
26 | //using namespace KeychainCore; | |
27 | ||
28 | // | |
29 | // Manage CSPDL attachments | |
30 | // | |
31 | CSPDLImpl::CSPDLImpl(const Guid &guid) | |
32 | : CSPImpl(Cssm::standard()->autoModule(guid)), | |
33 | DLImpl(CSPImpl::module()) | |
34 | { | |
35 | } | |
36 | ||
37 | CSPDLImpl::CSPDLImpl(const Module &module) | |
38 | : CSPImpl(module), | |
39 | DLImpl(module) | |
40 | { | |
41 | } | |
42 | ||
43 | CSPDLImpl::~CSPDLImpl() | |
427c49bc A |
44 | try |
45 | { | |
46 | } | |
47 | catch (...) | |
b1ab9ed8 A |
48 | { |
49 | } | |
50 | ||
51 | Allocator &CSPDLImpl::allocator() const | |
52 | { | |
53 | DLImpl::allocator(); return CSPImpl::allocator(); | |
54 | } | |
55 | ||
56 | void CSPDLImpl::allocator(Allocator &alloc) | |
57 | { | |
58 | CSPImpl::allocator(alloc); DLImpl::allocator(alloc); | |
59 | } | |
60 | ||
61 | bool CSPDLImpl::operator <(const CSPDLImpl &other) const | |
62 | { | |
63 | return (static_cast<const CSPImpl &>(*this) < static_cast<const CSPImpl &>(other) || | |
64 | (!(static_cast<const CSPImpl &>(other) < static_cast<const CSPImpl &>(*this)) | |
65 | && static_cast<const DLImpl &>(*this) < static_cast<const DLImpl &>(other))); | |
66 | } | |
67 | ||
68 | bool CSPDLImpl::operator ==(const CSPDLImpl &other) const | |
69 | { | |
70 | return (static_cast<const CSPImpl &>(*this) == static_cast<const CSPImpl &>(other) | |
71 | && static_cast<const DLImpl &>(*this) == static_cast<const DLImpl &>(other)); | |
72 | } | |
73 | ||
74 | CSSM_SERVICE_MASK CSPDLImpl::subserviceMask() const | |
75 | { | |
76 | return CSPImpl::subserviceType() | DLImpl::subserviceType(); | |
77 | } | |
78 | ||
79 | void CSPDLImpl::subserviceId(uint32 id) | |
80 | { | |
81 | CSPImpl::subserviceId(id); DLImpl::subserviceId(id); | |
82 | } | |
83 | ||
84 | ||
85 | // | |
86 | // Secure storage | |
87 | // | |
88 | SSCSPDLImpl::SSCSPDLImpl(const Guid &guid) : CSPDLImpl::CSPDLImpl(guid) | |
89 | { | |
90 | } | |
91 | ||
92 | SSCSPDLImpl::SSCSPDLImpl(const Module &module) : CSPDLImpl::CSPDLImpl(module) | |
93 | { | |
94 | } | |
95 | ||
96 | SSCSPDLImpl::~SSCSPDLImpl() | |
97 | { | |
98 | } | |
99 | ||
100 | DbImpl * | |
101 | SSCSPDLImpl::newDb(const char *inDbName, const CSSM_NET_ADDRESS *inDbLocation) | |
102 | { | |
103 | return new SSDbImpl(SSCSPDL(this), inDbName, inDbLocation); | |
104 | } | |
105 | ||
106 | ||
107 | // | |
108 | // SSDbImpl -- Secure Storage Database Implementation | |
109 | // | |
110 | SSDbImpl::SSDbImpl(const SSCSPDL &cspdl, const char *inDbName, | |
111 | const CSSM_NET_ADDRESS *inDbLocation) | |
112 | : DbImpl(cspdl, inDbName, inDbLocation) | |
113 | { | |
114 | } | |
115 | ||
116 | SSDbImpl::~SSDbImpl() | |
117 | { | |
118 | } | |
119 | ||
120 | void | |
121 | SSDbImpl::create() | |
122 | { | |
123 | DbImpl::create(); | |
124 | } | |
125 | ||
126 | void | |
127 | SSDbImpl::open() | |
128 | { | |
129 | DbImpl::open(); | |
130 | } | |
131 | ||
132 | SSDbUniqueRecord | |
133 | SSDbImpl::insert(CSSM_DB_RECORDTYPE recordType, | |
134 | const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes, | |
135 | const CSSM_DATA *data, | |
136 | const CSSM_RESOURCE_CONTROL_CONTEXT *rc) | |
137 | { | |
138 | // Get the handle of the DL underlying this CSPDL. | |
139 | CSSM_DL_DB_HANDLE dldbh; | |
140 | passThrough(CSSM_APPLECSPDL_DB_GET_HANDLE, NULL, | |
141 | reinterpret_cast<void **>(&dldbh)); | |
142 | ||
143 | // Turn off autocommit on the underlying DL and remember the old state. | |
144 | CSSM_BOOL autoCommit = CSSM_TRUE; | |
145 | check(CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, | |
146 | 0, reinterpret_cast<void **>(&autoCommit))); | |
147 | SSGroup group(SSDb(this), rc); | |
148 | const CSSM_ACCESS_CREDENTIALS *cred = rc ? rc->AccessCred : NULL; | |
149 | try | |
150 | { | |
151 | return insert(recordType, attributes, data, group, cred); | |
152 | if (autoCommit) | |
153 | { | |
154 | // autoCommit was on so commit now that we are done and turn | |
155 | // it back on. | |
156 | check(CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_COMMIT, NULL, NULL)); | |
157 | CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, | |
158 | reinterpret_cast<const void *>(autoCommit), NULL); | |
159 | } | |
160 | } | |
161 | catch(...) | |
162 | { | |
163 | try { group->deleteKey(cred); } catch (...) {} | |
164 | if (autoCommit) | |
165 | { | |
166 | // autoCommit was off so rollback since we failed and turn | |
167 | // autoCommit back on. | |
168 | CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_ROLLBACK, NULL, NULL); | |
169 | CSSM_DL_PassThrough(dldbh, CSSM_APPLEFILEDL_TOGGLE_AUTOCOMMIT, | |
170 | reinterpret_cast<const void *>(autoCommit), NULL); | |
171 | } | |
172 | throw; | |
173 | } | |
174 | ||
175 | // keep the compiler happy -- this path is NEVER taken | |
176 | CssmError::throwMe(0); | |
177 | } | |
178 | ||
179 | SSDbUniqueRecord | |
180 | SSDbImpl::insert(CSSM_DB_RECORDTYPE recordType, | |
181 | const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes, | |
182 | const CSSM_DATA *data, const SSGroup &group, | |
183 | const CSSM_ACCESS_CREDENTIALS *cred) | |
184 | { | |
185 | // Create an encoded dataBlob for this item. | |
186 | CssmDataContainer dataBlob(allocator()); | |
187 | group->encodeDataBlob(data, cred, dataBlob); | |
188 | ||
189 | // Insert the record with the new juicy dataBlob. | |
190 | return SSDbUniqueRecord(safe_cast<SSDbUniqueRecordImpl *> | |
191 | (&(*DbImpl::insert(recordType, attributes, &dataBlob)))); | |
192 | } | |
193 | ||
194 | ||
195 | // DbCursorMaker | |
196 | DbCursorImpl * | |
197 | SSDbImpl::newDbCursor(const CSSM_QUERY &query, Allocator &allocator) | |
198 | { | |
199 | return new SSDbCursorImpl(Db(this), query, allocator); | |
200 | } | |
201 | ||
202 | DbCursorImpl * | |
203 | SSDbImpl::newDbCursor(uint32 capacity, Allocator &allocator) | |
204 | { | |
205 | return new SSDbCursorImpl(Db(this), capacity, allocator); | |
206 | } | |
207 | ||
208 | ||
209 | // SSDbUniqueRecordMaker | |
210 | DbUniqueRecordImpl * | |
211 | SSDbImpl::newDbUniqueRecord() | |
212 | { | |
213 | return new SSDbUniqueRecordImpl(Db(this)); | |
214 | } | |
215 | ||
216 | ||
217 | // | |
218 | // SSGroup -- Group key with acl, used to protect a group of items. | |
219 | // | |
220 | // @@@ Get this from a shared spot. | |
221 | CSSM_DB_NAME_ATTR(SSGroupImpl::kLabel, 6, (char*) "Label", 0, NULL, BLOB); | |
222 | ||
223 | // Create a new group. | |
224 | SSGroupImpl::SSGroupImpl(const SSDb &ssDb, | |
225 | const CSSM_RESOURCE_CONTROL_CONTEXT *credAndAclEntry) | |
226 | : KeyImpl(ssDb->csp()), mLabel(ssDb->allocator()) | |
227 | { | |
228 | mLabel.Length = kLabelSize; | |
229 | mLabel.Data = reinterpret_cast<uint8 *> | |
230 | (mLabel.mAllocator.malloc(mLabel.Length)); | |
231 | ||
232 | // Get our csp and set up a random number generation context. | |
233 | CSP csp(this->csp()); | |
234 | Random random(csp, CSSM_ALGID_APPLE_YARROW); | |
235 | ||
236 | // Generate a kLabelSize byte random number that will be the label of | |
237 | // the key which we store in the dataBlob. | |
427c49bc | 238 | random.generate(mLabel, (uint32)mLabel.Length); |
b1ab9ed8 A |
239 | |
240 | // Overwrite the first 4 bytes with the magic cookie for a group. | |
241 | reinterpret_cast<uint32 *>(mLabel.Data)[0] = h2n(uint32(kGroupMagic)); | |
242 | ||
243 | // @@@ Ensure that the label is unique (Chance of collision is 2^80 -- | |
244 | // birthday paradox). | |
245 | ||
246 | // Generate a permanent 3DES key that we will use to encrypt the data. | |
247 | GenerateKey genKey(csp, CSSM_ALGID_3DES_3KEY, 192); | |
248 | genKey.database(ssDb); | |
249 | ||
250 | // Set the acl of the key correctly here | |
251 | genKey.rcc(credAndAclEntry); | |
252 | ||
253 | // Generate the key | |
254 | genKey(*this, KeySpec(CSSM_KEYUSE_ENCRYPT|CSSM_KEYUSE_DECRYPT, | |
255 | CSSM_KEYATTR_PERMANENT|CSSM_KEYATTR_SENSITIVE, | |
256 | mLabel)); | |
257 | ||
258 | // Activate ourself so CSSM_FreeKey will get called when we go out of | |
259 | // scope. | |
260 | activate(); | |
261 | } | |
262 | ||
263 | // Lookup an existing group based on a dataBlob. | |
264 | SSGroupImpl::SSGroupImpl(const SSDb &ssDb, const CSSM_DATA &dataBlob) | |
265 | : KeyImpl(ssDb->csp()), mLabel(ssDb->allocator()) | |
266 | { | |
267 | if (dataBlob.Length < kLabelSize + kIVSize) | |
268 | CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND); // Not a SS record | |
269 | ||
270 | mLabel = CssmData(dataBlob.Data, kLabelSize); | |
271 | if (*reinterpret_cast<const uint32 *>(mLabel.Data) != h2n (uint32(kGroupMagic))) | |
272 | CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND); // Not a SS record | |
273 | ||
274 | // Look up the symmetric key with that label. | |
275 | DbCursor cursor(new DbDbCursorImpl(ssDb, 0, Allocator::standard())); | |
276 | cursor->recordType(CSSM_DL_DB_RECORD_SYMMETRIC_KEY); | |
277 | cursor->add(CSSM_DB_EQUAL, kLabel, mLabel); | |
278 | ||
279 | DbUniqueRecord keyId; | |
280 | CssmDataContainer keyData(ssDb->allocator()); | |
281 | if (!cursor->next(NULL, &keyData, keyId)) | |
282 | CssmError::throwMe(CSSMERR_DL_RECORD_NOT_FOUND); // The key can't be found | |
283 | ||
284 | // Set the key part of ourself. | |
285 | static_cast<CSSM_KEY &>(*this) = | |
286 | *reinterpret_cast<const CSSM_KEY *>(keyData.Data); | |
287 | ||
288 | // Activate ourself so CSSM_FreeKey will get called when we go out of | |
289 | // scope. | |
290 | activate(); | |
291 | } | |
292 | ||
293 | bool | |
294 | SSGroupImpl::isGroup(const CSSM_DATA &dataBlob) | |
295 | { | |
296 | return dataBlob.Length >= kLabelSize + kIVSize | |
297 | && *reinterpret_cast<const uint32 *>(dataBlob.Data) == h2n(uint32(kGroupMagic)); | |
298 | } | |
299 | ||
300 | const CssmData | |
301 | SSGroupImpl::label() const | |
302 | { | |
303 | return mLabel; | |
304 | } | |
305 | ||
306 | void | |
307 | SSGroupImpl::decodeDataBlob(const CSSM_DATA &dataBlob, | |
308 | const CSSM_ACCESS_CREDENTIALS *cred, | |
309 | Allocator &allocator, CSSM_DATA &data) | |
310 | { | |
311 | // First get the IV and the cipherText from the blob. | |
312 | CssmData iv(&dataBlob.Data[kLabelSize], kIVSize); | |
313 | CssmData cipherText(&dataBlob.Data[kLabelSize + kIVSize], | |
314 | dataBlob.Length - (kLabelSize + kIVSize)); | |
315 | ||
316 | CssmDataContainer plainText1(allocator); | |
317 | CssmDataContainer plainText2(allocator); | |
318 | // Decrypt the data | |
319 | // @@@ Don't use staged decrypt once the AppleCSPDL can do combo | |
320 | // encryption. | |
321 | // Setup decryption context | |
322 | Decrypt decrypt(csp(), algorithm()); | |
323 | decrypt.mode(CSSM_ALGMODE_CBCPadIV8); | |
324 | decrypt.padding(CSSM_PADDING_PKCS1); | |
325 | decrypt.initVector(iv); | |
326 | decrypt.key(Key(this)); | |
327 | decrypt.cred(AccessCredentials::overlay(cred)); | |
328 | decrypt.decrypt(&cipherText, 1, &plainText1, 1); | |
329 | decrypt.final(plainText2); | |
330 | ||
331 | // Use DL allocator for allocating memory for data. | |
427c49bc A |
332 | CSSM_SIZE length = plainText1.Length + plainText2.Length; |
333 | data.Data = allocator.alloc<uint8>((UInt32)length); | |
b1ab9ed8 A |
334 | data.Length = length; |
335 | memcpy(data.Data, plainText1.Data, plainText1.Length); | |
336 | memcpy(&data.Data[plainText1.Length], plainText2.Data, plainText2.Length); | |
337 | } | |
338 | ||
339 | void | |
340 | SSGroupImpl::encodeDataBlob(const CSSM_DATA *data, | |
341 | const CSSM_ACCESS_CREDENTIALS *cred, | |
342 | CssmDataContainer &dataBlob) | |
343 | { | |
344 | // Get our csp and set up a random number generation context. | |
345 | CSP csp(this->csp()); | |
346 | Random random(csp, CSSM_ALGID_APPLE_YARROW); | |
347 | ||
348 | // Encrypt data using key and encode it in a dataBlob. | |
349 | ||
350 | // First calculate a random IV. | |
351 | uint8 ivBuf[kIVSize]; | |
352 | CssmData iv(ivBuf, kIVSize); | |
353 | random.generate(iv, kIVSize); | |
354 | ||
355 | // Setup encryption context | |
356 | Encrypt encrypt(csp, algorithm()); | |
357 | encrypt.mode(CSSM_ALGMODE_CBCPadIV8); | |
358 | encrypt.padding(CSSM_PADDING_PKCS1); | |
359 | encrypt.initVector(iv); | |
360 | encrypt.key(Key(this)); | |
361 | encrypt.cred(AccessCredentials::overlay(cred)); | |
362 | ||
363 | // Encrypt the data | |
364 | const CssmData nothing; | |
365 | const CssmData *plainText = data ? CssmData::overlay(data) : ¬hing; | |
366 | // @@@ Don't use staged encrypt once the AppleCSPDL can do combo | |
367 | // encryption. | |
368 | CssmDataContainer cipherText1, cipherText2; | |
369 | encrypt.encrypt(plainText, 1, &cipherText1, 1); | |
370 | encrypt.final(cipherText2); | |
371 | ||
372 | // Create a dataBlob containing the label followed by the IV followed | |
373 | // by the cipherText. | |
427c49bc | 374 | CSSM_SIZE length = (kLabelSize + kIVSize |
b1ab9ed8 | 375 | + cipherText1.Length + cipherText2.Length); |
427c49bc | 376 | dataBlob.Data = dataBlob.mAllocator.alloc<uint8>((UInt32)length); |
b1ab9ed8 A |
377 | dataBlob.Length = length; |
378 | memcpy(dataBlob.Data, mLabel.Data, kLabelSize); | |
379 | memcpy(&dataBlob.Data[kLabelSize], iv.Data, kIVSize); | |
380 | memcpy(&dataBlob.Data[kLabelSize + kIVSize], | |
381 | cipherText1.Data, cipherText1.Length); | |
382 | memcpy(&dataBlob.Data[kLabelSize + kIVSize + cipherText1.Length], | |
383 | cipherText2.Data, cipherText2.Length); | |
384 | } | |
385 | ||
386 | ||
387 | // | |
388 | // SSDbCursorImpl -- Secure Storage Database Cursor Implementation. | |
389 | // | |
390 | SSDbCursorImpl::SSDbCursorImpl(const Db &db, const CSSM_QUERY &query, | |
391 | Allocator &allocator) | |
392 | : DbDbCursorImpl(db, query, allocator) | |
393 | { | |
394 | } | |
395 | ||
396 | SSDbCursorImpl::SSDbCursorImpl(const Db &db, uint32 capacity, | |
397 | Allocator &allocator) | |
398 | : DbDbCursorImpl(db, capacity, allocator) | |
399 | { | |
400 | } | |
401 | ||
402 | bool | |
403 | SSDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, | |
404 | DbUniqueRecord &uniqueId) | |
405 | { | |
406 | return next(attributes, data, uniqueId, NULL); | |
407 | } | |
408 | ||
409 | bool | |
410 | SSDbCursorImpl::next(DbAttributes *attributes, ::CssmDataContainer *data, | |
411 | DbUniqueRecord &uniqueId, | |
412 | const CSSM_ACCESS_CREDENTIALS *cred) | |
413 | { | |
414 | if (!data) | |
415 | return DbDbCursorImpl::next(attributes, data, uniqueId); | |
416 | ||
417 | DbAttributes noAttrs, *attrs; | |
418 | attrs = attributes ? attributes : &noAttrs; | |
419 | ||
420 | // Get the datablob for this record | |
421 | CssmDataContainer dataBlob(allocator()); | |
422 | for (;;) | |
423 | { | |
424 | if (!DbDbCursorImpl::next(attrs, &dataBlob, uniqueId)) | |
425 | return false; | |
426 | ||
427 | // Keep going until we find a non key type record. | |
428 | CSSM_DB_RECORDTYPE rt = attrs->recordType(); | |
429 | if (rt != CSSM_DL_DB_RECORD_SYMMETRIC_KEY | |
430 | && rt != CSSM_DL_DB_RECORD_PRIVATE_KEY | |
431 | && rt != CSSM_DL_DB_RECORD_PUBLIC_KEY) | |
432 | { | |
433 | // @@@ Check the label and if it doesn't start with the magic for a SSKey return the key. | |
434 | break; | |
435 | } | |
436 | else | |
437 | { | |
438 | // Free the key we just retrieved | |
439 | database()->csp()->freeKey(*reinterpret_cast<CssmKey *>(dataBlob.Data)); | |
440 | } | |
441 | } | |
442 | ||
443 | if (!SSGroupImpl::isGroup(dataBlob)) | |
444 | { | |
445 | data->Data = dataBlob.Data; | |
446 | data->Length = dataBlob.Length; | |
447 | dataBlob.Data = NULL; | |
448 | dataBlob.Length = 0; | |
449 | return true; | |
450 | } | |
451 | ||
452 | // Get the group for dataBlob | |
453 | SSGroup group(database(), dataBlob); | |
454 | ||
455 | // Decode the dataBlob, pass in the DL allocator. | |
456 | group->decodeDataBlob(dataBlob, cred, database()->allocator(), *data); | |
457 | return true; | |
458 | } | |
459 | ||
460 | bool | |
461 | SSDbCursorImpl::nextKey(DbAttributes *attributes, Key &key, | |
462 | DbUniqueRecord &uniqueId) | |
463 | { | |
464 | DbAttributes noAttrs, *attrs; | |
465 | attrs = attributes ? attributes : &noAttrs; | |
466 | CssmDataContainer keyData(database()->allocator()); | |
467 | for (;;) | |
468 | { | |
469 | if (!DbDbCursorImpl::next(attrs, &keyData, uniqueId)) | |
470 | return false; | |
471 | // Keep going until we find a key type record. | |
472 | CSSM_DB_RECORDTYPE rt = attrs->recordType(); | |
473 | if (rt == CSSM_DL_DB_RECORD_SYMMETRIC_KEY | |
474 | || rt == CSSM_DL_DB_RECORD_PRIVATE_KEY | |
475 | || rt == CSSM_DL_DB_RECORD_PUBLIC_KEY) | |
476 | break; | |
477 | } | |
478 | ||
479 | key = Key(database()->csp(), *reinterpret_cast<CSSM_KEY *>(keyData.Data)); | |
480 | return true; | |
481 | } | |
482 | ||
483 | void | |
484 | SSDbCursorImpl::activate() | |
485 | { | |
486 | return DbDbCursorImpl::activate(); | |
487 | } | |
488 | ||
489 | void | |
490 | SSDbCursorImpl::deactivate() | |
491 | { | |
492 | return DbDbCursorImpl::deactivate(); | |
493 | } | |
494 | ||
495 | ||
496 | // | |
497 | // SSDbUniqueRecordImpl -- Secure Storage UniqueRecord Implementation. | |
498 | // | |
499 | SSDbUniqueRecordImpl::SSDbUniqueRecordImpl(const Db &db) | |
500 | : DbUniqueRecordImpl(db) | |
501 | { | |
502 | } | |
503 | ||
504 | SSDbUniqueRecordImpl::~SSDbUniqueRecordImpl() | |
505 | { | |
506 | } | |
507 | ||
508 | void | |
509 | SSDbUniqueRecordImpl::deleteRecord() | |
510 | { | |
511 | deleteRecord(NULL); | |
512 | } | |
513 | ||
514 | void | |
515 | SSDbUniqueRecordImpl::deleteRecord(const CSSM_ACCESS_CREDENTIALS *cred) | |
516 | { | |
517 | // Get the datablob for this record | |
518 | // @@@ Fixme so we don't need to call DbUniqueRecordImpl::get | |
519 | CssmDataContainer dataBlob(allocator()); | |
520 | DbAttributes attributes; | |
521 | ||
522 | DbUniqueRecordImpl::get(&attributes, &dataBlob); | |
523 | CSSM_KEY_PTR keyPtr = (CSSM_KEY_PTR) dataBlob.data(); | |
524 | ||
525 | // delete data part first: | |
526 | // (1) don't leave data without keys around | |
527 | // (2) delete orphaned data anyway | |
528 | DbUniqueRecordImpl::deleteRecord(); | |
529 | ||
530 | // @@@ Use transactions? | |
531 | if (SSGroupImpl::isGroup(dataBlob)) | |
532 | try { | |
533 | // Get the group for dataBlob | |
534 | SSGroup group(database(), dataBlob); | |
535 | // Delete the group (key) | |
536 | group->deleteKey(cred); | |
537 | } catch (const CssmError &err) { | |
538 | switch (err.error) { | |
539 | case CSSMERR_DL_RECORD_NOT_FOUND: | |
540 | // Zombie item (no group key). Finally at peace! No error | |
541 | break; | |
542 | default: | |
543 | ||
544 | if (attributes.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY || | |
545 | attributes.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY || | |
546 | attributes.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY) | |
547 | { | |
548 | allocator().free(keyPtr->KeyData.Data); | |
549 | } | |
550 | ||
551 | throw; | |
552 | } | |
553 | } | |
554 | ||
555 | if (attributes.recordType() == CSSM_DL_DB_RECORD_PUBLIC_KEY || | |
556 | attributes.recordType() == CSSM_DL_DB_RECORD_PRIVATE_KEY || | |
557 | attributes.recordType() == CSSM_DL_DB_RECORD_SYMMETRIC_KEY) | |
558 | { | |
559 | allocator().free(keyPtr->KeyData.Data); | |
560 | } | |
561 | } | |
562 | ||
563 | void | |
564 | SSDbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType, | |
565 | const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes, | |
566 | const CSSM_DATA *data, | |
567 | CSSM_DB_MODIFY_MODE modifyMode) | |
568 | { | |
569 | modify(recordType, attributes, data, modifyMode, NULL); | |
570 | } | |
571 | ||
572 | void | |
573 | SSDbUniqueRecordImpl::modify(CSSM_DB_RECORDTYPE recordType, | |
574 | const CSSM_DB_RECORD_ATTRIBUTE_DATA *attributes, | |
575 | const CSSM_DATA *data, | |
576 | CSSM_DB_MODIFY_MODE modifyMode, | |
577 | const CSSM_ACCESS_CREDENTIALS *cred) | |
578 | { | |
579 | if (!data) | |
580 | { | |
581 | DbUniqueRecordImpl::modify(recordType, attributes, NULL, modifyMode); | |
582 | return; | |
583 | } | |
584 | ||
585 | // Get the datablob for this record | |
586 | // @@@ Fixme so we don't need to call DbUniqueRecordImpl::get | |
587 | CssmDataContainer oldDataBlob(allocator()); | |
588 | DbUniqueRecordImpl::get(NULL, &oldDataBlob); | |
589 | ||
590 | if (!SSGroupImpl::isGroup(oldDataBlob)) | |
591 | { | |
592 | DbUniqueRecordImpl::modify(recordType, attributes, data, modifyMode); | |
593 | return; | |
594 | } | |
595 | ||
596 | // Get the group for oldDataBlob | |
597 | SSGroup group(database(), oldDataBlob); | |
598 | ||
599 | // Create a new dataBlob. | |
600 | CssmDataContainer dataBlob(allocator()); | |
601 | group->encodeDataBlob(data, cred, dataBlob); | |
602 | DbUniqueRecordImpl::modify(recordType, attributes, &dataBlob, modifyMode); | |
603 | } | |
604 | ||
605 | void | |
606 | SSDbUniqueRecordImpl::get(DbAttributes *attributes, ::CssmDataContainer *data) | |
607 | { | |
608 | get(attributes, data, NULL); | |
609 | } | |
610 | ||
611 | void | |
612 | SSDbUniqueRecordImpl::get(DbAttributes *attributes, ::CssmDataContainer *data, | |
613 | const CSSM_ACCESS_CREDENTIALS *cred) | |
614 | { | |
615 | if (!data) | |
616 | { | |
617 | DbUniqueRecordImpl::get(attributes, NULL); | |
618 | return; | |
619 | } | |
620 | ||
621 | // Get the datablob for this record | |
622 | // @@@ Fixme so we don't need to call DbUniqueRecordImpl::get | |
623 | CssmDataContainer dataBlob(allocator()); | |
624 | DbUniqueRecordImpl::get(attributes, &dataBlob); | |
625 | ||
626 | if (!SSGroupImpl::isGroup(dataBlob)) | |
627 | { | |
628 | data->Data = dataBlob.Data; | |
629 | data->Length = dataBlob.Length; | |
630 | dataBlob.Data = NULL; | |
631 | dataBlob.Length = 0; | |
632 | return; | |
633 | } | |
634 | ||
635 | // Get the group for dataBlob | |
636 | SSGroup group(database(), dataBlob); | |
637 | ||
638 | // Decode the dataBlob, pass in the DL allocator. | |
639 | group->decodeDataBlob(dataBlob, cred, allocator(), *data); | |
640 | } | |
641 | ||
642 | SSGroup | |
643 | SSDbUniqueRecordImpl::group() | |
644 | { | |
645 | // Get the datablob for this record | |
646 | // @@@ Fixme so we don't need to call DbUniqueRecordImpl::get | |
647 | CssmDataContainer dataBlob(allocator()); | |
648 | DbUniqueRecordImpl::get(NULL, &dataBlob); | |
649 | return SSGroup(database(), dataBlob); | |
650 | } |