1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 /*
5 * The following code handles the storage of PKCS 11 modules used by the
6 * NSS. For the rest of NSS, only one kind of database handle exists:
7 *
8 * SFTKDBHandle
9 *
10 * There is one SFTKDBHandle for the each key database and one for each cert
11 * database. These databases are opened as associated pairs, one pair per
12 * slot. SFTKDBHandles are reference counted objects.
13 *
14 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
15 * represents the underlying physical database. These objects are not
16 * reference counted, an are 'owned' by their respective SFTKDBHandles.
17 *
18 *
19 */
20 #include "sftkdb.h"
21 #include "sftkdbti.h"
22 #include "pkcs11t.h"
23 #include "pkcs11i.h"
24 #include "sdb.h"
25 #include "prprf.h"
26 #include "pratom.h"
27 #include "lgglue.h"
28 #include "utilpars.h"
29 #include "secerr.h"
30 #include "softoken.h"
31 #if defined(_WIN32)
32 #include <windows.h>
33 #endif
34
35 /*
36 * We want all databases to have the same binary representation independent of
37 * endianness or length of the host architecture. In general PKCS #11 attributes
38 * are endian/length independent except those attributes that pass CK_ULONG.
39 *
40 * The following functions fixes up the CK_ULONG type attributes so that the data
41 * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
42 * byte order values (big endian).
43 */
44 #define BBP 8
45
46 PRBool
sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)47 sftkdb_isULONGAttribute(CK_ATTRIBUTE_TYPE type)
48 {
49 switch (type) {
50 case CKA_CERTIFICATE_CATEGORY:
51 case CKA_CERTIFICATE_TYPE:
52 case CKA_CLASS:
53 case CKA_JAVA_MIDP_SECURITY_DOMAIN:
54 case CKA_KEY_GEN_MECHANISM:
55 case CKA_KEY_TYPE:
56 case CKA_MECHANISM_TYPE:
57 case CKA_MODULUS_BITS:
58 case CKA_PRIME_BITS:
59 case CKA_SUBPRIME_BITS:
60 case CKA_VALUE_BITS:
61 case CKA_VALUE_LEN:
62
63 case CKA_TRUST_DIGITAL_SIGNATURE:
64 case CKA_TRUST_NON_REPUDIATION:
65 case CKA_TRUST_KEY_ENCIPHERMENT:
66 case CKA_TRUST_DATA_ENCIPHERMENT:
67 case CKA_TRUST_KEY_AGREEMENT:
68 case CKA_TRUST_KEY_CERT_SIGN:
69 case CKA_TRUST_CRL_SIGN:
70
71 case CKA_TRUST_SERVER_AUTH:
72 case CKA_TRUST_CLIENT_AUTH:
73 case CKA_TRUST_CODE_SIGNING:
74 case CKA_TRUST_EMAIL_PROTECTION:
75 case CKA_TRUST_IPSEC_END_SYSTEM:
76 case CKA_TRUST_IPSEC_TUNNEL:
77 case CKA_TRUST_IPSEC_USER:
78 case CKA_TRUST_TIME_STAMPING:
79 case CKA_TRUST_STEP_UP_APPROVED:
80 return PR_TRUE;
81 default:
82 break;
83 }
84 return PR_FALSE;
85 }
86
87 /* are the attributes private? */
88 static PRBool
sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)89 sftkdb_isPrivateAttribute(CK_ATTRIBUTE_TYPE type)
90 {
91 switch (type) {
92 case CKA_VALUE:
93 case CKA_PRIVATE_EXPONENT:
94 case CKA_PRIME_1:
95 case CKA_PRIME_2:
96 case CKA_EXPONENT_1:
97 case CKA_EXPONENT_2:
98 case CKA_COEFFICIENT:
99 return PR_TRUE;
100 default:
101 break;
102 }
103 return PR_FALSE;
104 }
105
106 /* These attributes must be authenticated with an hmac. */
107 static PRBool
sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)108 sftkdb_isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type)
109 {
110 switch (type) {
111 case CKA_MODULUS:
112 case CKA_PUBLIC_EXPONENT:
113 case CKA_CERT_SHA1_HASH:
114 case CKA_CERT_MD5_HASH:
115 case CKA_TRUST_SERVER_AUTH:
116 case CKA_TRUST_CLIENT_AUTH:
117 case CKA_TRUST_EMAIL_PROTECTION:
118 case CKA_TRUST_CODE_SIGNING:
119 case CKA_TRUST_STEP_UP_APPROVED:
120 case CKA_NSS_OVERRIDE_EXTENSIONS:
121 return PR_TRUE;
122 default:
123 break;
124 }
125 return PR_FALSE;
126 }
127
128 /*
129 * convert a native ULONG to a database ulong. Database ulong's
130 * are all 4 byte big endian values.
131 */
132 void
sftk_ULong2SDBULong(unsigned char * data,CK_ULONG value)133 sftk_ULong2SDBULong(unsigned char *data, CK_ULONG value)
134 {
135 int i;
136
137 for (i = 0; i < SDB_ULONG_SIZE; i++) {
138 data[i] = (value >> (SDB_ULONG_SIZE - 1 - i) * BBP) & 0xff;
139 }
140 }
141
142 /*
143 * convert a database ulong back to a native ULONG. (reverse of the above
144 * function.
145 */
146 static CK_ULONG
sftk_SDBULong2ULong(unsigned char * data)147 sftk_SDBULong2ULong(unsigned char *data)
148 {
149 int i;
150 CK_ULONG value = 0;
151
152 for (i = 0; i < SDB_ULONG_SIZE; i++) {
153 value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE - 1 - i) * BBP);
154 }
155 return value;
156 }
157
158 /*
159 * fix up the input templates. Our fixed up ints are stored in data and must
160 * be freed by the caller. The new template must also be freed. If there are no
161 * CK_ULONG attributes, the orignal template is passed in as is.
162 */
163 static CK_ATTRIBUTE *
sftkdb_fixupTemplateIn(const CK_ATTRIBUTE * template,int count,unsigned char ** dataOut,int * dataOutSize)164 sftkdb_fixupTemplateIn(const CK_ATTRIBUTE *template, int count,
165 unsigned char **dataOut, int *dataOutSize)
166 {
167 int i;
168 int ulongCount = 0;
169 unsigned char *data;
170 CK_ATTRIBUTE *ntemplate;
171
172 *dataOut = NULL;
173 *dataOutSize = 0;
174
175 /* first count the number of CK_ULONG attributes */
176 for (i = 0; i < count; i++) {
177 /* Don't 'fixup' NULL values */
178 if (!template[i].pValue) {
179 continue;
180 }
181 if (template[i].ulValueLen == sizeof(CK_ULONG)) {
182 if (sftkdb_isULONGAttribute(template[i].type)) {
183 ulongCount++;
184 }
185 }
186 }
187 /* no attributes to fixup, just call on through */
188 if (ulongCount == 0) {
189 return (CK_ATTRIBUTE *)template;
190 }
191
192 /* allocate space for new ULONGS */
193 data = (unsigned char *)PORT_Alloc(SDB_ULONG_SIZE * ulongCount);
194 if (!data) {
195 return NULL;
196 }
197
198 /* allocate new template */
199 ntemplate = PORT_NewArray(CK_ATTRIBUTE, count);
200 if (!ntemplate) {
201 PORT_Free(data);
202 return NULL;
203 }
204 *dataOut = data;
205 *dataOutSize = SDB_ULONG_SIZE * ulongCount;
206 /* copy the old template, fixup the actual ulongs */
207 for (i = 0; i < count; i++) {
208 ntemplate[i] = template[i];
209 /* Don't 'fixup' NULL values */
210 if (!template[i].pValue) {
211 continue;
212 }
213 if (template[i].ulValueLen == sizeof(CK_ULONG)) {
214 if (sftkdb_isULONGAttribute(template[i].type)) {
215 CK_ULONG value = *(CK_ULONG *)template[i].pValue;
216 sftk_ULong2SDBULong(data, value);
217 ntemplate[i].pValue = data;
218 ntemplate[i].ulValueLen = SDB_ULONG_SIZE;
219 data += SDB_ULONG_SIZE;
220 }
221 }
222 }
223 return ntemplate;
224 }
225
226 static const char SFTKDB_META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x";
227
228 /*
229 * return a string describing the database type (key or cert)
230 */
231 const char *
sftkdb_TypeString(SFTKDBHandle * handle)232 sftkdb_TypeString(SFTKDBHandle *handle)
233 {
234 return (handle->type == SFTK_KEYDB_TYPE) ? "key" : "cert";
235 }
236
237 /*
238 * Some attributes are signed with an Hmac and a pbe key generated from
239 * the password. This signature is stored indexed by object handle and
240 * attribute type in the meta data table in the key database.
241 *
242 * Signature entries are indexed by the string
243 * sig_[cert/key]_{ObjectID}_{Attribute}
244 *
245 * This function fetches that pkcs5 signature. Caller supplies a SECItem
246 * pre-allocated to the appropriate size if the SECItem is too small the
247 * function will fail with CKR_BUFFER_TOO_SMALL.
248 */
249 static CK_RV
sftkdb_getRawAttributeSignature(SFTKDBHandle * handle,SDB * db,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE_TYPE type,SECItem * signText)250 sftkdb_getRawAttributeSignature(SFTKDBHandle *handle, SDB *db,
251 CK_OBJECT_HANDLE objectID,
252 CK_ATTRIBUTE_TYPE type,
253 SECItem *signText)
254 {
255 char id[30];
256 CK_RV crv;
257
258 sprintf(id, SFTKDB_META_SIG_TEMPLATE,
259 sftkdb_TypeString(handle),
260 (unsigned int)objectID, (unsigned int)type);
261
262 crv = (*db->sdb_GetMetaData)(db, id, signText, NULL);
263 return crv;
264 }
265
266 CK_RV
sftkdb_GetAttributeSignature(SFTKDBHandle * handle,SFTKDBHandle * keyHandle,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE_TYPE type,SECItem * signText)267 sftkdb_GetAttributeSignature(SFTKDBHandle *handle, SFTKDBHandle *keyHandle,
268 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
269 SECItem *signText)
270 {
271 SDB *db = SFTK_GET_SDB(keyHandle);
272 return sftkdb_getRawAttributeSignature(handle, db, objectID, type, signText);
273 }
274
275 CK_RV
sftkdb_DestroyAttributeSignature(SFTKDBHandle * handle,SDB * db,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE_TYPE type)276 sftkdb_DestroyAttributeSignature(SFTKDBHandle *handle, SDB *db,
277 CK_OBJECT_HANDLE objectID,
278 CK_ATTRIBUTE_TYPE type)
279 {
280 char id[30];
281 CK_RV crv;
282
283 sprintf(id, SFTKDB_META_SIG_TEMPLATE,
284 sftkdb_TypeString(handle),
285 (unsigned int)objectID, (unsigned int)type);
286
287 crv = (*db->sdb_DestroyMetaData)(db, id);
288 return crv;
289 }
290
291 /*
292 * Some attributes are signed with an Hmac and a pbe key generated from
293 * the password. This signature is stored indexed by object handle and
294 * attribute type in the meta data table in the key database.
295 *
296 * Signature entries are indexed by the string
297 * sig_[cert/key]_{ObjectID}_{Attribute}
298 *
299 * This function stores that pkcs5 signature.
300 */
301 CK_RV
sftkdb_PutAttributeSignature(SFTKDBHandle * handle,SDB * keyTarget,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE_TYPE type,SECItem * signText)302 sftkdb_PutAttributeSignature(SFTKDBHandle *handle, SDB *keyTarget,
303 CK_OBJECT_HANDLE objectID, CK_ATTRIBUTE_TYPE type,
304 SECItem *signText)
305 {
306 char id[30];
307 CK_RV crv;
308
309 sprintf(id, SFTKDB_META_SIG_TEMPLATE,
310 sftkdb_TypeString(handle),
311 (unsigned int)objectID, (unsigned int)type);
312
313 crv = (*keyTarget->sdb_PutMetaData)(keyTarget, id, signText, NULL);
314 return crv;
315 }
316
317 /*
318 * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
319 * separate data sections for the database ULONG values.
320 */
321 static CK_RV
sftkdb_fixupTemplateOut(CK_ATTRIBUTE * template,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE * ntemplate,int count,SFTKDBHandle * handle)322 sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_OBJECT_HANDLE objectID,
323 CK_ATTRIBUTE *ntemplate, int count, SFTKDBHandle *handle)
324 {
325 int i;
326 CK_RV crv = CKR_OK;
327 SFTKDBHandle *keyHandle;
328 PRBool checkSig = PR_TRUE;
329 PRBool checkEnc = PR_TRUE;
330
331 PORT_Assert(handle);
332
333 /* find the key handle */
334 keyHandle = handle;
335 if (handle->type != SFTK_KEYDB_TYPE) {
336 checkEnc = PR_FALSE;
337 keyHandle = handle->peerDB;
338 }
339
340 if ((keyHandle == NULL) ||
341 ((SFTK_GET_SDB(keyHandle)->sdb_flags & SDB_HAS_META) == 0) ||
342 (keyHandle->passwordKey.data == NULL)) {
343 checkSig = PR_FALSE;
344 }
345
346 for (i = 0; i < count; i++) {
347 CK_ULONG length = template[i].ulValueLen;
348 template[i].ulValueLen = ntemplate[i].ulValueLen;
349 /* fixup ulongs */
350 if (ntemplate[i].ulValueLen == SDB_ULONG_SIZE) {
351 if (sftkdb_isULONGAttribute(template[i].type)) {
352 if (template[i].pValue) {
353 CK_ULONG value;
354
355 value = sftk_SDBULong2ULong(ntemplate[i].pValue);
356 if (length < sizeof(CK_ULONG)) {
357 template[i].ulValueLen = -1;
358 crv = CKR_BUFFER_TOO_SMALL;
359 continue;
360 }
361 PORT_Memcpy(template[i].pValue, &value, sizeof(CK_ULONG));
362 }
363 template[i].ulValueLen = sizeof(CK_ULONG);
364 }
365 }
366
367 /* if no data was retrieved, no need to process encrypted or signed
368 * attributes */
369 if ((template[i].pValue == NULL) || (template[i].ulValueLen == -1)) {
370 continue;
371 }
372
373 /* fixup private attributes */
374 if (checkEnc && sftkdb_isPrivateAttribute(ntemplate[i].type)) {
375 /* we have a private attribute */
376 /* This code depends on the fact that the cipherText is bigger
377 * than the plain text */
378 SECItem cipherText;
379 SECItem *plainText;
380 SECStatus rv;
381
382 cipherText.data = ntemplate[i].pValue;
383 cipherText.len = ntemplate[i].ulValueLen;
384 PZ_Lock(handle->passwordLock);
385 if (handle->passwordKey.data == NULL) {
386 PZ_Unlock(handle->passwordLock);
387 template[i].ulValueLen = -1;
388 crv = CKR_USER_NOT_LOGGED_IN;
389 continue;
390 }
391 rv = sftkdb_DecryptAttribute(handle,
392 &handle->passwordKey,
393 objectID,
394 ntemplate[i].type,
395 &cipherText, &plainText);
396 PZ_Unlock(handle->passwordLock);
397 if (rv != SECSuccess) {
398 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
399 template[i].ulValueLen = -1;
400 crv = CKR_GENERAL_ERROR;
401 continue;
402 }
403 PORT_Assert(template[i].ulValueLen >= plainText->len);
404 if (template[i].ulValueLen < plainText->len) {
405 SECITEM_ZfreeItem(plainText, PR_TRUE);
406 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
407 template[i].ulValueLen = -1;
408 crv = CKR_GENERAL_ERROR;
409 continue;
410 }
411
412 /* copy the plain text back into the template */
413 PORT_Memcpy(template[i].pValue, plainText->data, plainText->len);
414 template[i].ulValueLen = plainText->len;
415 SECITEM_ZfreeItem(plainText, PR_TRUE);
416 }
417 /* make sure signed attributes are valid */
418 if (checkSig && sftkdb_isAuthenticatedAttribute(ntemplate[i].type)) {
419 SECStatus rv;
420 CK_RV local_crv;
421 SECItem signText;
422 SECItem plainText;
423 unsigned char signData[SDB_MAX_META_DATA_LEN];
424
425 signText.data = signData;
426 signText.len = sizeof(signData);
427
428 /* Use a local variable so that we don't clobber any already
429 * set error. This function returns either CKR_OK or the last
430 * found error in the template */
431 local_crv = sftkdb_GetAttributeSignature(handle, keyHandle,
432 objectID,
433 ntemplate[i].type,
434 &signText);
435 if (local_crv != CKR_OK) {
436 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
437 template[i].ulValueLen = -1;
438 crv = local_crv;
439 continue;
440 }
441
442 plainText.data = ntemplate[i].pValue;
443 plainText.len = ntemplate[i].ulValueLen;
444
445 /*
446 * we do a second check holding the lock just in case the user
447 * loggout while we were trying to get the signature.
448 */
449 PZ_Lock(keyHandle->passwordLock);
450 if (keyHandle->passwordKey.data == NULL) {
451 /* if we are no longer logged in, no use checking the other
452 * Signatures either. */
453 checkSig = PR_FALSE;
454 PZ_Unlock(keyHandle->passwordLock);
455 continue;
456 }
457
458 rv = sftkdb_VerifyAttribute(keyHandle,
459 &keyHandle->passwordKey,
460 objectID, ntemplate[i].type,
461 &plainText, &signText);
462 PZ_Unlock(keyHandle->passwordLock);
463 if (rv != SECSuccess) {
464 PORT_Memset(template[i].pValue, 0, template[i].ulValueLen);
465 template[i].ulValueLen = -1;
466 crv = CKR_SIGNATURE_INVALID; /* better error code? */
467 }
468 /* This Attribute is fine */
469 }
470 }
471 return crv;
472 }
473
474 /*
475 * Some attributes are signed with an HMAC and a pbe key generated from
476 * the password. This signature is stored indexed by object handle and
477 *
478 * Those attributes are:
479 * 1) Trust object hashes and trust values.
480 * 2) public key values.
481 *
482 * Certs themselves are considered properly authenticated by virtue of their
483 * signature, or their matching hash with the trust object.
484 *
485 * These signature is only checked for objects coming from shared databases.
486 * Older dbm style databases have such no signature checks. HMACs are also
487 * only checked when the token is logged in, as it requires a pbe generated
488 * from the password.
489 *
490 * Tokens which have no key database (and therefore no master password) do not
491 * have any stored signature values. Signature values are stored in the key
492 * database, since the signature data is tightly coupled to the key database
493 * password.
494 *
495 * This function takes a template of attributes that were either created or
496 * modified. These attributes are checked to see if the need to be signed.
497 * If they do, then this function signs the attributes and writes them
498 * to the meta data store.
499 *
500 * This function can fail if there are attributes that must be signed, but
501 * the token is not logged in.
502 *
503 * The caller is expected to abort any transaction he was in in the
504 * event of a failure of this function.
505 */
506 static CK_RV
sftk_signTemplate(PLArenaPool * arena,SFTKDBHandle * handle,PRBool mayBeUpdateDB,CK_OBJECT_HANDLE objectID,const CK_ATTRIBUTE * template,CK_ULONG count)507 sftk_signTemplate(PLArenaPool *arena, SFTKDBHandle *handle,
508 PRBool mayBeUpdateDB,
509 CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
510 CK_ULONG count)
511 {
512 unsigned int i;
513 CK_RV crv;
514 SFTKDBHandle *keyHandle = handle;
515 SDB *keyTarget = NULL;
516 PRBool usingPeerDB = PR_FALSE;
517 PRBool inPeerDBTransaction = PR_FALSE;
518
519 PORT_Assert(handle);
520
521 if (handle->type != SFTK_KEYDB_TYPE) {
522 keyHandle = handle->peerDB;
523 usingPeerDB = PR_TRUE;
524 }
525
526 /* no key DB defined? then no need to sign anything */
527 if (keyHandle == NULL) {
528 crv = CKR_OK;
529 goto loser;
530 }
531
532 /* When we are in a middle of an update, we have an update database set,
533 * but we want to write to the real database. The bool mayBeUpdateDB is
534 * set to TRUE if it's possible that we want to write an update database
535 * rather than a primary */
536 keyTarget = (mayBeUpdateDB && keyHandle->update) ? keyHandle->update : keyHandle->db;
537
538 /* skip the the database does not support meta data */
539 if ((keyTarget->sdb_flags & SDB_HAS_META) == 0) {
540 crv = CKR_OK;
541 goto loser;
542 }
543
544 /* If we had to switch databases, we need to initialize a transaction. */
545 if (usingPeerDB) {
546 crv = (*keyTarget->sdb_Begin)(keyTarget);
547 if (crv != CKR_OK) {
548 goto loser;
549 }
550 inPeerDBTransaction = PR_TRUE;
551 }
552
553 for (i = 0; i < count; i++) {
554 if (sftkdb_isAuthenticatedAttribute(template[i].type)) {
555 SECStatus rv;
556 SECItem *signText;
557 SECItem plainText;
558
559 plainText.data = template[i].pValue;
560 plainText.len = template[i].ulValueLen;
561 PZ_Lock(keyHandle->passwordLock);
562 if (keyHandle->passwordKey.data == NULL) {
563 PZ_Unlock(keyHandle->passwordLock);
564 crv = CKR_USER_NOT_LOGGED_IN;
565 goto loser;
566 }
567 rv = sftkdb_SignAttribute(arena, keyHandle, keyTarget,
568 &keyHandle->passwordKey,
569 keyHandle->defaultIterationCount,
570 objectID, template[i].type,
571 &plainText, &signText);
572 PZ_Unlock(keyHandle->passwordLock);
573 if (rv != SECSuccess) {
574 crv = CKR_GENERAL_ERROR; /* better error code here? */
575 goto loser;
576 }
577 crv = sftkdb_PutAttributeSignature(handle, keyTarget, objectID,
578 template[i].type, signText);
579 if (crv != CKR_OK) {
580 goto loser;
581 }
582 }
583 }
584 crv = CKR_OK;
585
586 /* If necessary, commit the transaction */
587 if (inPeerDBTransaction) {
588 crv = (*keyTarget->sdb_Commit)(keyTarget);
589 if (crv != CKR_OK) {
590 goto loser;
591 }
592 inPeerDBTransaction = PR_FALSE;
593 }
594
595 loser:
596 if (inPeerDBTransaction) {
597 /* The transaction must have failed. Abort. */
598 (*keyTarget->sdb_Abort)(keyTarget);
599 PORT_Assert(crv != CKR_OK);
600 if (crv == CKR_OK)
601 crv = CKR_GENERAL_ERROR;
602 }
603 return crv;
604 }
605
606 static CK_RV
sftkdb_CreateObject(PLArenaPool * arena,SFTKDBHandle * handle,SDB * db,CK_OBJECT_HANDLE * objectID,CK_ATTRIBUTE * template,CK_ULONG count)607 sftkdb_CreateObject(PLArenaPool *arena, SFTKDBHandle *handle,
608 SDB *db, CK_OBJECT_HANDLE *objectID,
609 CK_ATTRIBUTE *template, CK_ULONG count)
610 {
611 CK_RV crv;
612
613 crv = (*db->sdb_CreateObject)(db, objectID, template, count);
614 if (crv != CKR_OK) {
615 goto loser;
616 }
617 crv = sftk_signTemplate(arena, handle, (db == handle->update),
618 *objectID, template, count);
619 loser:
620
621 return crv;
622 }
623
624 static CK_RV
sftkdb_fixupSignatures(SFTKDBHandle * handle,SDB * db,CK_OBJECT_HANDLE oldID,CK_OBJECT_HANDLE newID,CK_ATTRIBUTE * ptemplate,CK_ULONG max_attributes)625 sftkdb_fixupSignatures(SFTKDBHandle *handle,
626 SDB *db, CK_OBJECT_HANDLE oldID, CK_OBJECT_HANDLE newID,
627 CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes)
628 {
629 unsigned int i;
630 CK_RV crv = CKR_OK;
631
632 /* if we don't have a meta table, we didn't write any signature objects */
633 if ((db->sdb_flags & SDB_HAS_META) == 0) {
634 return CKR_OK;
635 }
636 for (i = 0; i < max_attributes; i++) {
637 CK_ATTRIBUTE *att = &ptemplate[i];
638 CK_ATTRIBUTE_TYPE type = att->type;
639 if (sftkdb_isPrivateAttribute(type)) {
640 /* move the signature from one object handle to another and delete
641 * the old entry */
642 SECItem signature;
643 unsigned char signData[SDB_MAX_META_DATA_LEN];
644
645 signature.data = signData;
646 signature.len = sizeof(signData);
647 crv = sftkdb_getRawAttributeSignature(handle, db, oldID, type,
648 &signature);
649 if (crv != CKR_OK) {
650 /* NOTE: if we ever change our default write from AES_CBC
651 * to AES_KW, We'll need to change this to a continue as
652 * we won't need the integrity record for AES_KW */
653 break;
654 }
655 crv = sftkdb_PutAttributeSignature(handle, db, newID, type,
656 &signature);
657 if (crv != CKR_OK) {
658 break;
659 }
660 /* now get rid of the old one */
661 crv = sftkdb_DestroyAttributeSignature(handle, db, oldID, type);
662 if (crv != CKR_OK) {
663 break;
664 }
665 }
666 }
667 return crv;
668 }
669
670 CK_ATTRIBUTE *
sftk_ExtractTemplate(PLArenaPool * arena,SFTKObject * object,SFTKDBHandle * handle,CK_OBJECT_HANDLE objectID,SDB * db,CK_ULONG * pcount,CK_RV * crv)671 sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object,
672 SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
673 SDB *db, CK_ULONG *pcount, CK_RV *crv)
674 {
675 unsigned int count;
676 CK_ATTRIBUTE *template;
677 unsigned int i, templateIndex;
678 SFTKSessionObject *sessObject = sftk_narrowToSessionObject(object);
679 PRBool doEnc = PR_TRUE;
680
681 *crv = CKR_OK;
682
683 if (sessObject == NULL) {
684 *crv = CKR_GENERAL_ERROR; /* internal programming error */
685 return NULL;
686 }
687
688 PORT_Assert(handle);
689 /* find the key handle */
690 if (handle->type != SFTK_KEYDB_TYPE) {
691 doEnc = PR_FALSE;
692 }
693
694 PZ_Lock(sessObject->attributeLock);
695 count = 0;
696 for (i = 0; i < sessObject->hashSize; i++) {
697 SFTKAttribute *attr;
698 for (attr = sessObject->head[i]; attr; attr = attr->next) {
699 count++;
700 }
701 }
702 template = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, count);
703 if (template == NULL) {
704 PZ_Unlock(sessObject->attributeLock);
705 *crv = CKR_HOST_MEMORY;
706 return NULL;
707 }
708 templateIndex = 0;
709 for (i = 0; i < sessObject->hashSize; i++) {
710 SFTKAttribute *attr;
711 for (attr = sessObject->head[i]; attr; attr = attr->next) {
712 CK_ATTRIBUTE *tp = &template[templateIndex++];
713 /* copy the attribute */
714 *tp = attr->attrib;
715
716 /* fixup ULONG s */
717 if ((tp->ulValueLen == sizeof(CK_ULONG)) &&
718 (sftkdb_isULONGAttribute(tp->type))) {
719 CK_ULONG value = *(CK_ULONG *)tp->pValue;
720 unsigned char *data;
721
722 tp->pValue = PORT_ArenaAlloc(arena, SDB_ULONG_SIZE);
723 data = (unsigned char *)tp->pValue;
724 if (data == NULL) {
725 *crv = CKR_HOST_MEMORY;
726 break;
727 }
728 sftk_ULong2SDBULong(data, value);
729 tp->ulValueLen = SDB_ULONG_SIZE;
730 }
731
732 /* encrypt private attributes */
733 if (doEnc && sftkdb_isPrivateAttribute(tp->type)) {
734 /* we have a private attribute */
735 SECItem *cipherText;
736 SECItem plainText;
737 SECStatus rv;
738
739 plainText.data = tp->pValue;
740 plainText.len = tp->ulValueLen;
741 PZ_Lock(handle->passwordLock);
742 if (handle->passwordKey.data == NULL) {
743 PZ_Unlock(handle->passwordLock);
744 *crv = CKR_USER_NOT_LOGGED_IN;
745 break;
746 }
747 rv = sftkdb_EncryptAttribute(arena, handle, db,
748 &handle->passwordKey,
749 handle->defaultIterationCount,
750 objectID,
751 tp->type,
752 &plainText, &cipherText);
753 PZ_Unlock(handle->passwordLock);
754 if (rv == SECSuccess) {
755 tp->pValue = cipherText->data;
756 tp->ulValueLen = cipherText->len;
757 } else {
758 *crv = CKR_GENERAL_ERROR; /* better error code here? */
759 break;
760 }
761 PORT_Memset(plainText.data, 0, plainText.len);
762 }
763 }
764 }
765 PORT_Assert(templateIndex <= count);
766 PZ_Unlock(sessObject->attributeLock);
767
768 if (*crv != CKR_OK) {
769 return NULL;
770 }
771 if (pcount) {
772 *pcount = count;
773 }
774 return template;
775 }
776
777 /*
778 * return a pointer to the attribute in the give template.
779 * The return value is not const, as the caller may modify
780 * the given attribute value, but such modifications will
781 * modify the actual value in the template.
782 */
783 static CK_ATTRIBUTE *
sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute,CK_ATTRIBUTE * ptemplate,CK_ULONG len)784 sftkdb_getAttributeFromTemplate(CK_ATTRIBUTE_TYPE attribute,
785 CK_ATTRIBUTE *ptemplate, CK_ULONG len)
786 {
787 CK_ULONG i;
788
789 for (i = 0; i < len; i++) {
790 if (attribute == ptemplate[i].type) {
791 return &ptemplate[i];
792 }
793 }
794 return NULL;
795 }
796
797 static const CK_ATTRIBUTE *
sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute,const CK_ATTRIBUTE * ptemplate,CK_ULONG len)798 sftkdb_getAttributeFromConstTemplate(CK_ATTRIBUTE_TYPE attribute,
799 const CK_ATTRIBUTE *ptemplate, CK_ULONG len)
800 {
801 CK_ULONG i;
802
803 for (i = 0; i < len; i++) {
804 if (attribute == ptemplate[i].type) {
805 return &ptemplate[i];
806 }
807 }
808 return NULL;
809 }
810
811 /*
812 * fetch a template which identifies 'unique' entries based on object type
813 */
814 static CK_RV
sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType,unsigned char * objTypeData,CK_ATTRIBUTE * findTemplate,CK_ULONG * findCount,CK_ATTRIBUTE * ptemplate,int len)815 sftkdb_getFindTemplate(CK_OBJECT_CLASS objectType, unsigned char *objTypeData,
816 CK_ATTRIBUTE *findTemplate, CK_ULONG *findCount,
817 CK_ATTRIBUTE *ptemplate, int len)
818 {
819 CK_ATTRIBUTE *attr;
820 CK_ULONG count = 1;
821
822 sftk_ULong2SDBULong(objTypeData, objectType);
823 findTemplate[0].type = CKA_CLASS;
824 findTemplate[0].pValue = objTypeData;
825 findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
826
827 switch (objectType) {
828 case CKO_CERTIFICATE:
829 case CKO_NSS_TRUST:
830 attr = sftkdb_getAttributeFromTemplate(CKA_ISSUER, ptemplate, len);
831 if (attr == NULL) {
832 return CKR_TEMPLATE_INCOMPLETE;
833 }
834 findTemplate[1] = *attr;
835 attr = sftkdb_getAttributeFromTemplate(CKA_SERIAL_NUMBER,
836 ptemplate, len);
837 if (attr == NULL) {
838 return CKR_TEMPLATE_INCOMPLETE;
839 }
840 findTemplate[2] = *attr;
841 count = 3;
842 break;
843
844 case CKO_PRIVATE_KEY:
845 case CKO_PUBLIC_KEY:
846 case CKO_SECRET_KEY:
847 attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, len);
848 if (attr == NULL) {
849 return CKR_TEMPLATE_INCOMPLETE;
850 }
851 if (attr->ulValueLen == 0) {
852 /* key is too generic to determine that it's unique, usually
853 * happens in the key gen case */
854 return CKR_OBJECT_HANDLE_INVALID;
855 }
856
857 findTemplate[1] = *attr;
858 count = 2;
859 break;
860
861 case CKO_NSS_CRL:
862 attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
863 if (attr == NULL) {
864 return CKR_TEMPLATE_INCOMPLETE;
865 }
866 findTemplate[1] = *attr;
867 count = 2;
868 break;
869
870 case CKO_NSS_SMIME:
871 attr = sftkdb_getAttributeFromTemplate(CKA_SUBJECT, ptemplate, len);
872 if (attr == NULL) {
873 return CKR_TEMPLATE_INCOMPLETE;
874 }
875 findTemplate[1] = *attr;
876 attr = sftkdb_getAttributeFromTemplate(CKA_NSS_EMAIL, ptemplate, len);
877 if (attr == NULL) {
878 return CKR_TEMPLATE_INCOMPLETE;
879 }
880 findTemplate[2] = *attr;
881 count = 3;
882 break;
883 default:
884 attr = sftkdb_getAttributeFromTemplate(CKA_VALUE, ptemplate, len);
885 if (attr == NULL) {
886 return CKR_TEMPLATE_INCOMPLETE;
887 }
888 findTemplate[1] = *attr;
889 count = 2;
890 break;
891 }
892 *findCount = count;
893
894 return CKR_OK;
895 }
896
897 /*
898 * look to see if this object already exists and return its object ID if
899 * it does.
900 */
901 static CK_RV
sftkdb_lookupObject(SDB * db,CK_OBJECT_CLASS objectType,CK_OBJECT_HANDLE * id,CK_ATTRIBUTE * ptemplate,CK_ULONG len)902 sftkdb_lookupObject(SDB *db, CK_OBJECT_CLASS objectType,
903 CK_OBJECT_HANDLE *id, CK_ATTRIBUTE *ptemplate, CK_ULONG len)
904 {
905 CK_ATTRIBUTE findTemplate[3];
906 CK_ULONG count = 1;
907 CK_ULONG objCount = 0;
908 SDBFind *find = NULL;
909 unsigned char objTypeData[SDB_ULONG_SIZE];
910 CK_RV crv;
911
912 *id = CK_INVALID_HANDLE;
913 if (objectType == CKO_NSS_CRL) {
914 return CKR_OK;
915 }
916 crv = sftkdb_getFindTemplate(objectType, objTypeData,
917 findTemplate, &count, ptemplate, len);
918
919 if (crv == CKR_OBJECT_HANDLE_INVALID) {
920 /* key is too generic to determine that it's unique, usually
921 * happens in the key gen case, tell the caller to go ahead
922 * and just create it */
923 return CKR_OK;
924 }
925 if (crv != CKR_OK) {
926 return crv;
927 }
928
929 /* use the raw find, so we get the correct database */
930 crv = (*db->sdb_FindObjectsInit)(db, findTemplate, count, &find);
931 if (crv != CKR_OK) {
932 return crv;
933 }
934 (*db->sdb_FindObjects)(db, find, id, 1, &objCount);
935 (*db->sdb_FindObjectsFinal)(db, find);
936
937 if (objCount == 0) {
938 *id = CK_INVALID_HANDLE;
939 }
940 return CKR_OK;
941 }
942
943 /*
944 * check to see if this template conflicts with others in our current database.
945 */
946 static CK_RV
sftkdb_checkConflicts(SDB * db,CK_OBJECT_CLASS objectType,const CK_ATTRIBUTE * ptemplate,CK_ULONG len,CK_OBJECT_HANDLE sourceID)947 sftkdb_checkConflicts(SDB *db, CK_OBJECT_CLASS objectType,
948 const CK_ATTRIBUTE *ptemplate, CK_ULONG len,
949 CK_OBJECT_HANDLE sourceID)
950 {
951 CK_ATTRIBUTE findTemplate[2];
952 unsigned char objTypeData[SDB_ULONG_SIZE];
953 /* we may need to allocate some temporaries. Keep track of what was
954 * allocated so we can free it in the end */
955 unsigned char *temp1 = NULL;
956 unsigned char *temp2 = NULL;
957 CK_ULONG objCount = 0;
958 SDBFind *find = NULL;
959 CK_OBJECT_HANDLE id;
960 const CK_ATTRIBUTE *attr, *attr2;
961 CK_RV crv;
962 CK_ATTRIBUTE subject;
963
964 /* Currently the only conflict is with nicknames pointing to the same
965 * subject when creating or modifying a certificate. */
966 /* If the object is not a cert, no problem. */
967 if (objectType != CKO_CERTIFICATE) {
968 return CKR_OK;
969 }
970 /* if not setting a nickname then there's still no problem */
971 attr = sftkdb_getAttributeFromConstTemplate(CKA_LABEL, ptemplate, len);
972 if ((attr == NULL) || (attr->ulValueLen == 0)) {
973 return CKR_OK;
974 }
975 /* fetch the subject of the source. For creation and merge, this should
976 * be found in the template */
977 attr2 = sftkdb_getAttributeFromConstTemplate(CKA_SUBJECT, ptemplate, len);
978 if (sourceID == CK_INVALID_HANDLE) {
979 if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen < 0)) {
980 crv = CKR_TEMPLATE_INCOMPLETE;
981 goto done;
982 }
983 } else if ((attr2 == NULL) || ((CK_LONG)attr2->ulValueLen <= 0)) {
984 /* sourceID is set if we are trying to modify an existing entry instead
985 * of creating a new one. In this case the subject may not be (probably
986 * isn't) in the template, we have to read it from the database */
987 subject.type = CKA_SUBJECT;
988 subject.pValue = NULL;
989 subject.ulValueLen = 0;
990 crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
991 if (crv != CKR_OK) {
992 goto done;
993 }
994 if ((CK_LONG)subject.ulValueLen < 0) {
995 crv = CKR_DEVICE_ERROR; /* closest pkcs11 error to corrupted DB */
996 goto done;
997 }
998 temp1 = subject.pValue = PORT_Alloc(++subject.ulValueLen);
999 if (temp1 == NULL) {
1000 crv = CKR_HOST_MEMORY;
1001 goto done;
1002 }
1003 crv = (*db->sdb_GetAttributeValue)(db, sourceID, &subject, 1);
1004 if (crv != CKR_OK) {
1005 goto done;
1006 }
1007 attr2 = &subject;
1008 }
1009
1010 /* check for another cert in the database with the same nickname */
1011 sftk_ULong2SDBULong(objTypeData, objectType);
1012 findTemplate[0].type = CKA_CLASS;
1013 findTemplate[0].pValue = objTypeData;
1014 findTemplate[0].ulValueLen = SDB_ULONG_SIZE;
1015 findTemplate[1] = *attr;
1016
1017 crv = (*db->sdb_FindObjectsInit)(db, findTemplate, 2, &find);
1018 if (crv != CKR_OK) {
1019 goto done;
1020 }
1021 (*db->sdb_FindObjects)(db, find, &id, 1, &objCount);
1022 (*db->sdb_FindObjectsFinal)(db, find);
1023
1024 /* object count == 0 means no conflicting certs found,
1025 * go on with the operation */
1026 if (objCount == 0) {
1027 crv = CKR_OK;
1028 goto done;
1029 }
1030
1031 /* There is a least one cert that shares the nickname, make sure it also
1032 * matches the subject. */
1033 findTemplate[0] = *attr2;
1034 /* we know how big the source subject was. Use that length to create the
1035 * space for the target. If it's not enough space, then it means the
1036 * source subject is too big, and therefore not a match. GetAttributeValue
1037 * will return CKR_BUFFER_TOO_SMALL. Otherwise it should be exactly enough
1038 * space (or enough space to be able to compare the result. */
1039 temp2 = findTemplate[0].pValue = PORT_Alloc(++findTemplate[0].ulValueLen);
1040 if (temp2 == NULL) {
1041 crv = CKR_HOST_MEMORY;
1042 goto done;
1043 }
1044 crv = (*db->sdb_GetAttributeValue)(db, id, findTemplate, 1);
1045 if (crv != CKR_OK) {
1046 if (crv == CKR_BUFFER_TOO_SMALL) {
1047 /* if our buffer is too small, then the Subjects clearly do
1048 * not match */
1049 crv = CKR_ATTRIBUTE_VALUE_INVALID;
1050 goto loser;
1051 }
1052 /* otherwise we couldn't get the value, just fail */
1053 goto done;
1054 }
1055
1056 /* Ok, we have both subjects, make sure they are the same.
1057 * Compare the subjects */
1058 if ((findTemplate[0].ulValueLen != attr2->ulValueLen) ||
1059 (attr2->ulValueLen > 0 &&
1060 PORT_Memcmp(findTemplate[0].pValue, attr2->pValue, attr2->ulValueLen) != 0)) {
1061 crv = CKR_ATTRIBUTE_VALUE_INVALID;
1062 goto loser;
1063 }
1064 crv = CKR_OK;
1065
1066 done:
1067 /* If we've failed for some other reason than a conflict, make sure we
1068 * return an error code other than CKR_ATTRIBUTE_VALUE_INVALID.
1069 * (NOTE: neither sdb_FindObjectsInit nor sdb_GetAttributeValue should
1070 * return CKR_ATTRIBUTE_VALUE_INVALID, so the following is paranoia).
1071 */
1072 if (crv == CKR_ATTRIBUTE_VALUE_INVALID) {
1073 crv = CKR_GENERAL_ERROR; /* clearly a programming error */
1074 }
1075
1076 /* exit point if we found a conflict */
1077 loser:
1078 PORT_Free(temp1);
1079 PORT_Free(temp2);
1080 return crv;
1081 }
1082
1083 /*
1084 * try to update the template to fix any errors. This is only done
1085 * during update.
1086 *
1087 * NOTE: we must update the template or return an error, or the update caller
1088 * will loop forever!
1089 *
1090 * Two copies of the source code for this algorithm exist in NSS.
1091 * Changes must be made in both copies.
1092 * The other copy is in pk11_IncrementNickname() in pk11wrap/pk11merge.c.
1093 *
1094 */
1095 static CK_RV
sftkdb_resolveConflicts(PLArenaPool * arena,CK_OBJECT_CLASS objectType,CK_ATTRIBUTE * ptemplate,CK_ULONG * plen)1096 sftkdb_resolveConflicts(PLArenaPool *arena, CK_OBJECT_CLASS objectType,
1097 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
1098 {
1099 CK_ATTRIBUTE *attr;
1100 char *nickname, *newNickname;
1101 unsigned int end, digit;
1102
1103 /* sanity checks. We should never get here with these errors */
1104 if (objectType != CKO_CERTIFICATE) {
1105 return CKR_GENERAL_ERROR; /* shouldn't happen */
1106 }
1107 attr = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
1108 if ((attr == NULL) || (attr->ulValueLen == 0)) {
1109 return CKR_GENERAL_ERROR; /* shouldn't happen */
1110 }
1111
1112 /* update the nickname */
1113 /* is there a number at the end of the nickname already?
1114 * if so just increment that number */
1115 nickname = (char *)attr->pValue;
1116
1117 /* does nickname end with " #n*" ? */
1118 for (end = attr->ulValueLen - 1;
1119 end >= 2 && (digit = nickname[end]) <= '9' && digit >= '0';
1120 end--) /* just scan */
1121 ;
1122 if (attr->ulValueLen >= 3 &&
1123 end < (attr->ulValueLen - 1) /* at least one digit */ &&
1124 nickname[end] == '#' &&
1125 nickname[end - 1] == ' ') {
1126 /* Already has a suitable suffix string */
1127 } else {
1128 /* ... append " #2" to the name */
1129 static const char num2[] = " #2";
1130 newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + sizeof(num2));
1131 if (!newNickname) {
1132 return CKR_HOST_MEMORY;
1133 }
1134 PORT_Memcpy(newNickname, nickname, attr->ulValueLen);
1135 PORT_Memcpy(&newNickname[attr->ulValueLen], num2, sizeof(num2));
1136 attr->pValue = newNickname; /* modifies ptemplate */
1137 attr->ulValueLen += 3; /* 3 is strlen(num2) */
1138 return CKR_OK;
1139 }
1140
1141 for (end = attr->ulValueLen; end-- > 0;) {
1142 digit = nickname[end];
1143 if (digit > '9' || digit < '0') {
1144 break;
1145 }
1146 if (digit < '9') {
1147 nickname[end]++;
1148 return CKR_OK;
1149 }
1150 nickname[end] = '0';
1151 }
1152
1153 /* we overflowed, insert a new '1' for a carry in front of the number */
1154 newNickname = PORT_ArenaAlloc(arena, attr->ulValueLen + 1);
1155 if (!newNickname) {
1156 return CKR_HOST_MEMORY;
1157 }
1158 /* PORT_Memcpy should handle len of '0' */
1159 PORT_Memcpy(newNickname, nickname, ++end);
1160 newNickname[end] = '1';
1161 PORT_Memset(&newNickname[end + 1], '0', attr->ulValueLen - end);
1162 attr->pValue = newNickname;
1163 attr->ulValueLen++;
1164 return CKR_OK;
1165 }
1166
1167 /*
1168 * set an attribute and sign it if necessary
1169 */
1170 static CK_RV
sftkdb_setAttributeValue(PLArenaPool * arena,SFTKDBHandle * handle,SDB * db,CK_OBJECT_HANDLE objectID,const CK_ATTRIBUTE * template,CK_ULONG count)1171 sftkdb_setAttributeValue(PLArenaPool *arena, SFTKDBHandle *handle,
1172 SDB *db, CK_OBJECT_HANDLE objectID, const CK_ATTRIBUTE *template,
1173 CK_ULONG count)
1174 {
1175 CK_RV crv;
1176 crv = (*db->sdb_SetAttributeValue)(db, objectID, template, count);
1177 if (crv != CKR_OK) {
1178 return crv;
1179 }
1180 crv = sftk_signTemplate(arena, handle, db == handle->update,
1181 objectID, template, count);
1182 return crv;
1183 }
1184
1185 /*
1186 * write a softoken object out to the database.
1187 */
1188 CK_RV
sftkdb_write(SFTKDBHandle * handle,SFTKObject * object,CK_OBJECT_HANDLE * objectID)1189 sftkdb_write(SFTKDBHandle *handle, SFTKObject *object,
1190 CK_OBJECT_HANDLE *objectID)
1191 {
1192 CK_ATTRIBUTE *template;
1193 PLArenaPool *arena;
1194 CK_ULONG count;
1195 CK_RV crv;
1196 SDB *db;
1197 PRBool inTransaction = PR_FALSE;
1198 CK_OBJECT_HANDLE id, candidateID;
1199
1200 *objectID = CK_INVALID_HANDLE;
1201
1202 if (handle == NULL) {
1203 return CKR_TOKEN_WRITE_PROTECTED;
1204 }
1205 db = SFTK_GET_SDB(handle);
1206
1207 /*
1208 * we have opened a new database, but we have not yet updated it. We are
1209 * still running pointing to the old database (so the application can
1210 * still read). We don't want to write to the old database at this point,
1211 * however, since it leads to user confusion. So at this point we simply
1212 * require a user login. Let NSS know this so it can prompt the user.
1213 */
1214 if (db == handle->update) {
1215 return CKR_USER_NOT_LOGGED_IN;
1216 }
1217
1218 arena = PORT_NewArena(256);
1219 if (arena == NULL) {
1220 return CKR_HOST_MEMORY;
1221 }
1222
1223 crv = (*db->sdb_Begin)(db);
1224 if (crv != CKR_OK) {
1225 goto loser;
1226 }
1227 inTransaction = PR_TRUE;
1228
1229 crv = (*db->sdb_GetNewObjectID)(db, &candidateID);
1230 if (crv != CKR_OK) {
1231 goto loser;
1232 }
1233
1234 template = sftk_ExtractTemplate(arena, object, handle, candidateID, db, &count, &crv);
1235 if (!template) {
1236 goto loser;
1237 }
1238
1239 /*
1240 * We want to make the base database as free from object specific knowledge
1241 * as possible. To maintain compatibility, keep some of the desirable
1242 * object specific semantics of the old database.
1243 *
1244 * These were 2 fold:
1245 * 1) there were certain conflicts (like trying to set the same nickname
1246 * on two different subjects) that would return an error.
1247 * 2) Importing the 'same' object would silently update that object.
1248 *
1249 * The following 2 functions mimic the desirable effects of these two
1250 * semantics without pushing any object knowledge to the underlying database
1251 * code.
1252 */
1253
1254 /* make sure we don't have attributes that conflict with the existing DB */
1255 crv = sftkdb_checkConflicts(db, object->objclass, template, count,
1256 CK_INVALID_HANDLE);
1257 if (crv != CKR_OK) {
1258 goto loser;
1259 }
1260 /* Find any copies that match this particular object */
1261 crv = sftkdb_lookupObject(db, object->objclass, &id, template, count);
1262 if (crv != CKR_OK) {
1263 goto loser;
1264 }
1265 if (id == CK_INVALID_HANDLE) {
1266 *objectID = candidateID;
1267 crv = sftkdb_CreateObject(arena, handle, db, objectID, template, count);
1268 } else {
1269 /* object already exists, modify it's attributes */
1270 *objectID = id;
1271 /* The object ID changed from our candidate, we need to move any
1272 * signature attribute signatures to the new object ID. */
1273 crv = sftkdb_fixupSignatures(handle, db, candidateID, id,
1274 template, count);
1275 if (crv != CKR_OK) {
1276 goto loser;
1277 }
1278 crv = sftkdb_setAttributeValue(arena, handle, db, id, template, count);
1279 }
1280 if (crv != CKR_OK) {
1281 goto loser;
1282 }
1283 crv = (*db->sdb_Commit)(db);
1284 inTransaction = PR_FALSE;
1285
1286 loser:
1287 if (inTransaction) {
1288 (*db->sdb_Abort)(db);
1289 /* It is trivial to show the following code cannot
1290 * happen unless something is horribly wrong with our compilier or
1291 * hardware */
1292 PORT_Assert(crv != CKR_OK);
1293 if (crv == CKR_OK)
1294 crv = CKR_GENERAL_ERROR;
1295 }
1296
1297 if (arena) {
1298 PORT_FreeArena(arena, PR_TRUE);
1299 }
1300 if (crv == CKR_OK) {
1301 *objectID |= (handle->type | SFTK_TOKEN_TYPE);
1302 }
1303 return crv;
1304 }
1305
1306 CK_RV
sftkdb_FindObjectsInit(SFTKDBHandle * handle,const CK_ATTRIBUTE * template,CK_ULONG count,SDBFind ** find)1307 sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template,
1308 CK_ULONG count, SDBFind **find)
1309 {
1310 unsigned char *data = NULL;
1311 CK_ATTRIBUTE *ntemplate = NULL;
1312 CK_RV crv;
1313 int dataSize;
1314 SDB *db;
1315
1316 if (handle == NULL) {
1317 return CKR_OK;
1318 }
1319 db = SFTK_GET_SDB(handle);
1320
1321 if (count != 0) {
1322 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1323 if (ntemplate == NULL) {
1324 return CKR_HOST_MEMORY;
1325 }
1326 }
1327
1328 crv = (*db->sdb_FindObjectsInit)(db, ntemplate,
1329 count, find);
1330 if (data) {
1331 PORT_Free(ntemplate);
1332 PORT_ZFree(data, dataSize);
1333 }
1334 return crv;
1335 }
1336
1337 CK_RV
sftkdb_FindObjects(SFTKDBHandle * handle,SDBFind * find,CK_OBJECT_HANDLE * ids,int arraySize,CK_ULONG * count)1338 sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find,
1339 CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count)
1340 {
1341 CK_RV crv;
1342 SDB *db;
1343
1344 if (handle == NULL) {
1345 *count = 0;
1346 return CKR_OK;
1347 }
1348 db = SFTK_GET_SDB(handle);
1349
1350 crv = (*db->sdb_FindObjects)(db, find, ids,
1351 arraySize, count);
1352 if (crv == CKR_OK) {
1353 unsigned int i;
1354 for (i = 0; i < *count; i++) {
1355 ids[i] |= (handle->type | SFTK_TOKEN_TYPE);
1356 }
1357 }
1358 return crv;
1359 }
1360
1361 CK_RV
sftkdb_FindObjectsFinal(SFTKDBHandle * handle,SDBFind * find)1362 sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find)
1363 {
1364 SDB *db;
1365 if (handle == NULL) {
1366 return CKR_OK;
1367 }
1368 db = SFTK_GET_SDB(handle);
1369 return (*db->sdb_FindObjectsFinal)(db, find);
1370 }
1371
1372 CK_RV
sftkdb_GetAttributeValue(SFTKDBHandle * handle,CK_OBJECT_HANDLE objectID,CK_ATTRIBUTE * template,CK_ULONG count)1373 sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
1374 CK_ATTRIBUTE *template, CK_ULONG count)
1375 {
1376 CK_RV crv, crv2;
1377 CK_ATTRIBUTE *ntemplate;
1378 unsigned char *data = NULL;
1379 int dataSize = 0;
1380 SDB *db;
1381
1382 if (handle == NULL) {
1383 return CKR_GENERAL_ERROR;
1384 }
1385
1386 /* short circuit common attributes */
1387 if (count == 1 &&
1388 (template[0].type == CKA_TOKEN ||
1389 template[0].type == CKA_PRIVATE ||
1390 template[0].type == CKA_SENSITIVE)) {
1391 CK_BBOOL boolVal = CK_TRUE;
1392
1393 if (template[0].pValue == NULL) {
1394 template[0].ulValueLen = sizeof(CK_BBOOL);
1395 return CKR_OK;
1396 }
1397 if (template[0].ulValueLen < sizeof(CK_BBOOL)) {
1398 template[0].ulValueLen = -1;
1399 return CKR_BUFFER_TOO_SMALL;
1400 }
1401
1402 if ((template[0].type == CKA_PRIVATE) &&
1403 (handle->type != SFTK_KEYDB_TYPE)) {
1404 boolVal = CK_FALSE;
1405 }
1406 if ((template[0].type == CKA_SENSITIVE) &&
1407 (handle->type != SFTK_KEYDB_TYPE)) {
1408 boolVal = CK_FALSE;
1409 }
1410 *(CK_BBOOL *)template[0].pValue = boolVal;
1411 template[0].ulValueLen = sizeof(CK_BBOOL);
1412 return CKR_OK;
1413 }
1414
1415 db = SFTK_GET_SDB(handle);
1416 /* nothing to do */
1417 if (count == 0) {
1418 return CKR_OK;
1419 }
1420 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1421 if (ntemplate == NULL) {
1422 return CKR_HOST_MEMORY;
1423 }
1424 objectID &= SFTK_OBJ_ID_MASK;
1425 crv = (*db->sdb_GetAttributeValue)(db, objectID,
1426 ntemplate, count);
1427 crv2 = sftkdb_fixupTemplateOut(template, objectID, ntemplate,
1428 count, handle);
1429 if (crv == CKR_OK)
1430 crv = crv2;
1431 if (data) {
1432 PORT_Free(ntemplate);
1433 PORT_ZFree(data, dataSize);
1434 }
1435 return crv;
1436 }
1437
1438 CK_RV
sftkdb_SetAttributeValue(SFTKDBHandle * handle,SFTKObject * object,const CK_ATTRIBUTE * template,CK_ULONG count)1439 sftkdb_SetAttributeValue(SFTKDBHandle *handle, SFTKObject *object,
1440 const CK_ATTRIBUTE *template, CK_ULONG count)
1441 {
1442 CK_ATTRIBUTE *ntemplate;
1443 unsigned char *data = NULL;
1444 PLArenaPool *arena = NULL;
1445 SDB *db;
1446 CK_RV crv = CKR_OK;
1447 CK_OBJECT_HANDLE objectID = (object->handle & SFTK_OBJ_ID_MASK);
1448 PRBool inTransaction = PR_FALSE;
1449 int dataSize;
1450
1451 if (handle == NULL) {
1452 return CKR_TOKEN_WRITE_PROTECTED;
1453 }
1454
1455 db = SFTK_GET_SDB(handle);
1456 /* nothing to do */
1457 if (count == 0) {
1458 return CKR_OK;
1459 }
1460 /*
1461 * we have opened a new database, but we have not yet updated it. We are
1462 * still running pointing to the old database (so the application can
1463 * still read). We don't want to write to the old database at this point,
1464 * however, since it leads to user confusion. So at this point we simply
1465 * require a user login. Let NSS know this so it can prompt the user.
1466 */
1467 if (db == handle->update) {
1468 return CKR_USER_NOT_LOGGED_IN;
1469 }
1470
1471 ntemplate = sftkdb_fixupTemplateIn(template, count, &data, &dataSize);
1472 if (ntemplate == NULL) {
1473 return CKR_HOST_MEMORY;
1474 }
1475
1476 /* make sure we don't have attributes that conflict with the existing DB */
1477 crv = sftkdb_checkConflicts(db, object->objclass, ntemplate, count,
1478 objectID);
1479 if (crv != CKR_OK) {
1480 goto loser;
1481 }
1482
1483 arena = PORT_NewArena(256);
1484 if (arena == NULL) {
1485 crv = CKR_HOST_MEMORY;
1486 goto loser;
1487 }
1488
1489 crv = (*db->sdb_Begin)(db);
1490 if (crv != CKR_OK) {
1491 goto loser;
1492 }
1493 inTransaction = PR_TRUE;
1494 crv = sftkdb_setAttributeValue(arena, handle, db, objectID, ntemplate,
1495 count);
1496 if (crv != CKR_OK) {
1497 goto loser;
1498 }
1499 crv = (*db->sdb_Commit)(db);
1500 loser:
1501 if (crv != CKR_OK && inTransaction) {
1502 (*db->sdb_Abort)(db);
1503 }
1504 if (data) {
1505 PORT_Free(ntemplate);
1506 PORT_ZFree(data, dataSize);
1507 }
1508 if (arena) {
1509 PORT_FreeArena(arena, PR_FALSE);
1510 }
1511 return crv;
1512 }
1513
1514 CK_RV
sftkdb_DestroyObject(SFTKDBHandle * handle,CK_OBJECT_HANDLE objectID,CK_OBJECT_CLASS objclass)1515 sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE objectID,
1516 CK_OBJECT_CLASS objclass)
1517 {
1518 CK_RV crv = CKR_OK;
1519 SDB *db;
1520
1521 if (handle == NULL) {
1522 return CKR_TOKEN_WRITE_PROTECTED;
1523 }
1524 db = SFTK_GET_SDB(handle);
1525 objectID &= SFTK_OBJ_ID_MASK;
1526
1527 crv = (*db->sdb_Begin)(db);
1528 if (crv != CKR_OK) {
1529 return crv;
1530 }
1531 crv = (*db->sdb_DestroyObject)(db, objectID);
1532 if (crv != CKR_OK) {
1533 goto loser;
1534 }
1535 /* if the database supports meta data, delete any old signatures
1536 * that we may have added */
1537 if ((db->sdb_flags & SDB_HAS_META) == SDB_HAS_META) {
1538 SDB *keydb = db;
1539 if (handle->type == SFTK_KEYDB_TYPE) {
1540 /* delete any private attribute signatures that might exist */
1541 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1542 CKA_VALUE);
1543 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1544 CKA_PRIVATE_EXPONENT);
1545 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1546 CKA_PRIME_1);
1547 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1548 CKA_PRIME_2);
1549 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1550 CKA_EXPONENT_1);
1551 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1552 CKA_EXPONENT_2);
1553 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1554 CKA_COEFFICIENT);
1555 } else {
1556 keydb = SFTK_GET_SDB(handle->peerDB);
1557 }
1558 /* now destroy any authenticated attributes that may exist */
1559 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1560 CKA_MODULUS);
1561 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1562 CKA_PUBLIC_EXPONENT);
1563 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1564 CKA_CERT_SHA1_HASH);
1565 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1566 CKA_CERT_MD5_HASH);
1567 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1568 CKA_TRUST_SERVER_AUTH);
1569 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1570 CKA_TRUST_CLIENT_AUTH);
1571 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1572 CKA_TRUST_EMAIL_PROTECTION);
1573 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1574 CKA_TRUST_CODE_SIGNING);
1575 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1576 CKA_TRUST_STEP_UP_APPROVED);
1577 (void)sftkdb_DestroyAttributeSignature(handle, keydb, objectID,
1578 CKA_NSS_OVERRIDE_EXTENSIONS);
1579 }
1580 crv = (*db->sdb_Commit)(db);
1581 loser:
1582 if (crv != CKR_OK) {
1583 (*db->sdb_Abort)(db);
1584 }
1585 return crv;
1586 }
1587
1588 CK_RV
sftkdb_CloseDB(SFTKDBHandle * handle)1589 sftkdb_CloseDB(SFTKDBHandle *handle)
1590 {
1591 #ifdef NO_FORK_CHECK
1592 PRBool parentForkedAfterC_Initialize = PR_FALSE;
1593 #endif
1594 if (handle == NULL) {
1595 return CKR_OK;
1596 }
1597 if (handle->update) {
1598 if (handle->db->sdb_SetForkState) {
1599 (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1600 }
1601 (*handle->update->sdb_Close)(handle->update);
1602 }
1603 if (handle->db) {
1604 if (handle->db->sdb_SetForkState) {
1605 (*handle->db->sdb_SetForkState)(parentForkedAfterC_Initialize);
1606 }
1607 (*handle->db->sdb_Close)(handle->db);
1608 }
1609 if (handle->passwordKey.data) {
1610 SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE);
1611 }
1612 if (handle->passwordLock) {
1613 SKIP_AFTER_FORK(PZ_DestroyLock(handle->passwordLock));
1614 }
1615 if (handle->updatePasswordKey) {
1616 SECITEM_ZfreeItem(handle->updatePasswordKey, PR_TRUE);
1617 }
1618 if (handle->updateID) {
1619 PORT_Free(handle->updateID);
1620 }
1621 PORT_Free(handle);
1622 return CKR_OK;
1623 }
1624
1625 /*
1626 * reset a database to it's uninitialized state.
1627 */
1628 static CK_RV
sftkdb_ResetDB(SFTKDBHandle * handle)1629 sftkdb_ResetDB(SFTKDBHandle *handle)
1630 {
1631 CK_RV crv = CKR_OK;
1632 SDB *db;
1633 if (handle == NULL) {
1634 return CKR_TOKEN_WRITE_PROTECTED;
1635 }
1636 db = SFTK_GET_SDB(handle);
1637 crv = (*db->sdb_Begin)(db);
1638 if (crv != CKR_OK) {
1639 goto loser;
1640 }
1641 crv = (*db->sdb_Reset)(db);
1642 if (crv != CKR_OK) {
1643 goto loser;
1644 }
1645 crv = (*db->sdb_Commit)(db);
1646 loser:
1647 if (crv != CKR_OK) {
1648 (*db->sdb_Abort)(db);
1649 }
1650 return crv;
1651 }
1652
1653 CK_RV
sftkdb_Begin(SFTKDBHandle * handle)1654 sftkdb_Begin(SFTKDBHandle *handle)
1655 {
1656 CK_RV crv = CKR_OK;
1657 SDB *db;
1658
1659 if (handle == NULL) {
1660 return CKR_OK;
1661 }
1662 db = SFTK_GET_SDB(handle);
1663 if (db) {
1664 crv = (*db->sdb_Begin)(db);
1665 }
1666 return crv;
1667 }
1668
1669 CK_RV
sftkdb_Commit(SFTKDBHandle * handle)1670 sftkdb_Commit(SFTKDBHandle *handle)
1671 {
1672 CK_RV crv = CKR_OK;
1673 SDB *db;
1674
1675 if (handle == NULL) {
1676 return CKR_OK;
1677 }
1678 db = SFTK_GET_SDB(handle);
1679 if (db) {
1680 (*db->sdb_Commit)(db);
1681 }
1682 return crv;
1683 }
1684
1685 CK_RV
sftkdb_Abort(SFTKDBHandle * handle)1686 sftkdb_Abort(SFTKDBHandle *handle)
1687 {
1688 CK_RV crv = CKR_OK;
1689 SDB *db;
1690
1691 if (handle == NULL) {
1692 return CKR_OK;
1693 }
1694 db = SFTK_GET_SDB(handle);
1695 if (db) {
1696 crv = (db->sdb_Abort)(db);
1697 }
1698 return crv;
1699 }
1700
1701 /*
1702 * functions to update the database from an old database
1703 */
1704
1705 /*
1706 * known attributes
1707 */
1708 static const CK_ATTRIBUTE_TYPE known_attributes[] = {
1709 CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION,
1710 CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER,
1711 CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED,
1712 CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL,
1713 CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY,
1714 CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE,
1715 CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER,
1716 CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE,
1717 CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT,
1718 CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT,
1719 CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS,
1720 CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE,
1721 CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE,
1722 CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS,
1723 CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS,
1724 CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE,
1725 CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT,
1726 CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS,
1727 CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS,
1728 CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE,
1729 CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES,
1730 CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NSS_URL, CKA_NSS_EMAIL,
1731 CKA_NSS_SMIME_INFO, CKA_NSS_SMIME_TIMESTAMP,
1732 CKA_NSS_PKCS8_SALT, CKA_NSS_PASSWORD_CHECK, CKA_NSS_EXPIRES,
1733 CKA_NSS_KRL, CKA_NSS_PQG_COUNTER, CKA_NSS_PQG_SEED,
1734 CKA_NSS_PQG_H, CKA_NSS_PQG_SEED_BITS, CKA_NSS_MODULE_SPEC,
1735 CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION,
1736 CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT,
1737 CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN,
1738 CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING,
1739 CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM,
1740 CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING,
1741 CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH,
1742 CKA_NSS_DB, CKA_NSS_TRUST, CKA_NSS_OVERRIDE_EXTENSIONS,
1743 CKA_PUBLIC_KEY_INFO
1744 };
1745
1746 static unsigned int known_attributes_size = sizeof(known_attributes) /
1747 sizeof(known_attributes[0]);
1748
1749 static CK_RV
sftkdb_GetObjectTemplate(SDB * source,CK_OBJECT_HANDLE id,CK_ATTRIBUTE * ptemplate,CK_ULONG * max)1750 sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id,
1751 CK_ATTRIBUTE *ptemplate, CK_ULONG *max)
1752 {
1753 unsigned int i, j;
1754 CK_RV crv;
1755
1756 if (*max < known_attributes_size) {
1757 *max = known_attributes_size;
1758 return CKR_BUFFER_TOO_SMALL;
1759 }
1760 for (i = 0; i < known_attributes_size; i++) {
1761 ptemplate[i].type = known_attributes[i];
1762 ptemplate[i].pValue = NULL;
1763 ptemplate[i].ulValueLen = 0;
1764 }
1765
1766 crv = (*source->sdb_GetAttributeValue)(source, id,
1767 ptemplate, known_attributes_size);
1768
1769 if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
1770 return crv;
1771 }
1772
1773 for (i = 0, j = 0; i < known_attributes_size; i++, j++) {
1774 while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) {
1775 i++;
1776 }
1777 if (i >= known_attributes_size) {
1778 break;
1779 }
1780 /* cheap optimization */
1781 if (i == j) {
1782 continue;
1783 }
1784 ptemplate[j] = ptemplate[i];
1785 }
1786 *max = j;
1787 return CKR_OK;
1788 }
1789
1790 static const char SFTKDB_META_UPDATE_TEMPLATE[] = "upd_%s_%s";
1791
1792 /*
1793 * check to see if we have already updated this database.
1794 * a NULL updateID means we are trying to do an in place
1795 * single database update. In that case we have already
1796 * determined that an update was necessary.
1797 */
1798 static PRBool
sftkdb_hasUpdate(const char * typeString,SDB * db,const char * updateID)1799 sftkdb_hasUpdate(const char *typeString, SDB *db, const char *updateID)
1800 {
1801 char *id;
1802 CK_RV crv;
1803 SECItem dummy = { 0, NULL, 0 };
1804 unsigned char dummyData[SDB_MAX_META_DATA_LEN];
1805
1806 if (!updateID) {
1807 return PR_FALSE;
1808 }
1809 id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1810 if (id == NULL) {
1811 return PR_FALSE;
1812 }
1813 dummy.data = dummyData;
1814 dummy.len = sizeof(dummyData);
1815
1816 crv = (*db->sdb_GetMetaData)(db, id, &dummy, NULL);
1817 PR_smprintf_free(id);
1818 return crv == CKR_OK ? PR_TRUE : PR_FALSE;
1819 }
1820
1821 /*
1822 * we just completed an update, store the update id
1823 * so we don't need to do it again. If non was given,
1824 * there is nothing to do.
1825 */
1826 static CK_RV
sftkdb_putUpdate(const char * typeString,SDB * db,const char * updateID)1827 sftkdb_putUpdate(const char *typeString, SDB *db, const char *updateID)
1828 {
1829 char *id;
1830 CK_RV crv;
1831 SECItem dummy = { 0, NULL, 0 };
1832
1833 /* if no id was given, nothing to do */
1834 if (updateID == NULL) {
1835 return CKR_OK;
1836 }
1837
1838 dummy.data = (unsigned char *)updateID;
1839 dummy.len = PORT_Strlen(updateID);
1840
1841 id = PR_smprintf(SFTKDB_META_UPDATE_TEMPLATE, typeString, updateID);
1842 if (id == NULL) {
1843 return PR_FALSE;
1844 }
1845
1846 crv = (*db->sdb_PutMetaData)(db, id, &dummy, NULL);
1847 PR_smprintf_free(id);
1848 return crv;
1849 }
1850
1851 /*
1852 * get a ULong attribute from a template:
1853 * NOTE: this is a raw templated stored in database order!
1854 */
1855 static CK_ULONG
sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE * ptemplate,CK_ULONG len)1856 sftkdb_getULongFromTemplate(CK_ATTRIBUTE_TYPE type,
1857 CK_ATTRIBUTE *ptemplate, CK_ULONG len)
1858 {
1859 CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(type,
1860 ptemplate, len);
1861
1862 if (attr && attr->pValue && attr->ulValueLen == SDB_ULONG_SIZE) {
1863 return sftk_SDBULong2ULong(attr->pValue);
1864 }
1865 return (CK_ULONG)-1;
1866 }
1867
1868 /*
1869 * we need to find a unique CKA_ID.
1870 * The basic idea is to just increment the lowest byte.
1871 * This code also handles the following corner cases:
1872 * 1) the single byte overflows. On overflow we increment the next byte up
1873 * and so forth until we have overflowed the entire CKA_ID.
1874 * 2) If we overflow the entire CKA_ID we expand it by one byte.
1875 * 3) the CKA_ID is non-existant, we create a new one with one byte.
1876 * This means no matter what CKA_ID is passed, the result of this function
1877 * is always a new CKA_ID, and this function will never return the same
1878 * CKA_ID the it has returned in the passed.
1879 */
1880 static CK_RV
sftkdb_incrementCKAID(PLArenaPool * arena,CK_ATTRIBUTE * ptemplate)1881 sftkdb_incrementCKAID(PLArenaPool *arena, CK_ATTRIBUTE *ptemplate)
1882 {
1883 unsigned char *buf = ptemplate->pValue;
1884 CK_ULONG len = ptemplate->ulValueLen;
1885
1886 if (buf == NULL || len == (CK_ULONG)-1) {
1887 /* we have no valid CKAID, we'll create a basic one byte CKA_ID below */
1888 len = 0;
1889 } else {
1890 CK_ULONG i;
1891
1892 /* walk from the back to front, incrementing
1893 * the CKA_ID until we no longer have a carry,
1894 * or have hit the front of the id. */
1895 for (i = len; i != 0; i--) {
1896 buf[i - 1]++;
1897 if (buf[i - 1] != 0) {
1898 /* no more carries, the increment is complete */
1899 return CKR_OK;
1900 }
1901 }
1902 /* we've now overflowed, fall through and expand the CKA_ID by
1903 * one byte */
1904 }
1905 buf = PORT_ArenaAlloc(arena, len + 1);
1906 if (!buf) {
1907 return CKR_HOST_MEMORY;
1908 }
1909 if (len > 0) {
1910 PORT_Memcpy(buf, ptemplate->pValue, len);
1911 }
1912 buf[len] = 0;
1913 ptemplate->pValue = buf;
1914 ptemplate->ulValueLen = len + 1;
1915 return CKR_OK;
1916 }
1917
1918 /*
1919 * drop an attribute from a template.
1920 */
1921 void
sftkdb_dropAttribute(CK_ATTRIBUTE * attr,CK_ATTRIBUTE * ptemplate,CK_ULONG * plen)1922 sftkdb_dropAttribute(CK_ATTRIBUTE *attr, CK_ATTRIBUTE *ptemplate,
1923 CK_ULONG *plen)
1924 {
1925 CK_ULONG count = *plen;
1926 CK_ULONG i;
1927
1928 for (i = 0; i < count; i++) {
1929 if (attr->type == ptemplate[i].type) {
1930 break;
1931 }
1932 }
1933
1934 if (i == count) {
1935 /* attribute not found */
1936 return;
1937 }
1938
1939 /* copy the remaining attributes up */
1940 for (i++; i < count; i++) {
1941 ptemplate[i - 1] = ptemplate[i];
1942 }
1943
1944 /* decrement the template size */
1945 *plen = count - 1;
1946 }
1947
1948 /*
1949 * create some defines for the following functions to document the meaning
1950 * of true/false. (make's it easier to remember what means what.
1951 */
1952 typedef enum {
1953 SFTKDB_DO_NOTHING = 0,
1954 SFTKDB_ADD_OBJECT,
1955 SFTKDB_MODIFY_OBJECT,
1956 SFTKDB_DROP_ATTRIBUTE
1957 } sftkdbUpdateStatus;
1958
1959 /*
1960 * helper function to reconcile a single trust entry.
1961 * Identify which trust entry we want to keep.
1962 * If we don't need to do anything (the records are already equal).
1963 * return SFTKDB_DO_NOTHING.
1964 * If we want to use the source version,
1965 * return SFTKDB_MODIFY_OBJECT
1966 * If we want to use the target version,
1967 * return SFTKDB_DROP_ATTRIBUTE
1968 *
1969 * In the end the caller will remove any attributes in the source
1970 * template when SFTKDB_DROP_ATTRIBUTE is specified, then use do a
1971 * set attributes with that template on the target if we received
1972 * any SFTKDB_MODIFY_OBJECT returns.
1973 */
1974 sftkdbUpdateStatus
sftkdb_reconcileTrustEntry(PLArenaPool * arena,CK_ATTRIBUTE * target,CK_ATTRIBUTE * source)1975 sftkdb_reconcileTrustEntry(PLArenaPool *arena, CK_ATTRIBUTE *target,
1976 CK_ATTRIBUTE *source)
1977 {
1978 CK_ULONG targetTrust = sftkdb_getULongFromTemplate(target->type,
1979 target, 1);
1980 CK_ULONG sourceTrust = sftkdb_getULongFromTemplate(target->type,
1981 source, 1);
1982
1983 /*
1984 * try to pick the best solution between the source and the
1985 * target. Update the source template if we want the target value
1986 * to win out. Prefer cases where we don't actually update the
1987 * trust entry.
1988 */
1989
1990 /* they are the same, everything is already kosher */
1991 if (targetTrust == sourceTrust) {
1992 return SFTKDB_DO_NOTHING;
1993 }
1994
1995 /* handle the case where the source Trust attribute may be a bit
1996 * flakey */
1997 if (sourceTrust == (CK_ULONG)-1) {
1998 /*
1999 * The source Trust is invalid. We know that the target Trust
2000 * must be valid here, otherwise the above
2001 * targetTrust == sourceTrust check would have succeeded.
2002 */
2003 return SFTKDB_DROP_ATTRIBUTE;
2004 }
2005
2006 /* target is invalid, use the source's idea of the trust value */
2007 if (targetTrust == (CK_ULONG)-1) {
2008 /* overwriting the target in this case is OK */
2009 return SFTKDB_MODIFY_OBJECT;
2010 }
2011
2012 /* at this point we know that both attributes exist and have the
2013 * appropriate length (SDB_ULONG_SIZE). We no longer need to check
2014 * ulValueLen for either attribute.
2015 */
2016 if (sourceTrust == CKT_NSS_TRUST_UNKNOWN) {
2017 return SFTKDB_DROP_ATTRIBUTE;
2018 }
2019
2020 /* target has no idea, use the source's idea of the trust value */
2021 if (targetTrust == CKT_NSS_TRUST_UNKNOWN) {
2022 /* overwriting the target in this case is OK */
2023 return SFTKDB_MODIFY_OBJECT;
2024 }
2025
2026 /* so both the target and the source have some idea of what this
2027 * trust attribute should be, and neither agree exactly.
2028 * At this point, we prefer 'hard' attributes over 'soft' ones.
2029 * 'hard' ones are CKT_NSS_TRUSTED, CKT_NSS_TRUSTED_DELEGATOR, and
2030 * CKT_NSS_NOT_TRUTED. Soft ones are ones which don't change the
2031 * actual trust of the cert (CKT_MUST_VERIFY_TRUST,
2032 * CKT_NSS_VALID_DELEGATOR).
2033 */
2034 if ((sourceTrust == CKT_NSS_MUST_VERIFY_TRUST) || (sourceTrust == CKT_NSS_VALID_DELEGATOR)) {
2035 return SFTKDB_DROP_ATTRIBUTE;
2036 }
2037 if ((targetTrust == CKT_NSS_MUST_VERIFY_TRUST) || (targetTrust == CKT_NSS_VALID_DELEGATOR)) {
2038 /* again, overwriting the target in this case is OK */
2039 return SFTKDB_MODIFY_OBJECT;
2040 }
2041
2042 /* both have hard attributes, we have a conflict, let the target win. */
2043 return SFTKDB_DROP_ATTRIBUTE;
2044 }
2045
2046 const CK_ATTRIBUTE_TYPE sftkdb_trustList[] =
2047 { CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH,
2048 CKA_TRUST_CODE_SIGNING, CKA_TRUST_EMAIL_PROTECTION,
2049 CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER,
2050 CKA_TRUST_TIME_STAMPING };
2051
2052 #define SFTK_TRUST_TEMPLATE_COUNT \
2053 (sizeof(sftkdb_trustList) / sizeof(sftkdb_trustList[0]))
2054 /*
2055 * Run through the list of known trust types, and reconcile each trust
2056 * entry one by one. Keep track of we really need to write out the source
2057 * trust object (overwriting the existing one).
2058 */
2059 static sftkdbUpdateStatus
sftkdb_reconcileTrust(PLArenaPool * arena,SDB * db,CK_OBJECT_HANDLE id,CK_ATTRIBUTE * ptemplate,CK_ULONG * plen)2060 sftkdb_reconcileTrust(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
2061 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
2062 {
2063 CK_ATTRIBUTE trustTemplate[SFTK_TRUST_TEMPLATE_COUNT];
2064 unsigned char trustData[SFTK_TRUST_TEMPLATE_COUNT * SDB_ULONG_SIZE];
2065 sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
2066 CK_ULONG i;
2067 CK_RV crv;
2068
2069 for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
2070 trustTemplate[i].type = sftkdb_trustList[i];
2071 trustTemplate[i].pValue = &trustData[i * SDB_ULONG_SIZE];
2072 trustTemplate[i].ulValueLen = SDB_ULONG_SIZE;
2073 }
2074 crv = (*db->sdb_GetAttributeValue)(db, id,
2075 trustTemplate, SFTK_TRUST_TEMPLATE_COUNT);
2076 if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) {
2077 /* target trust has some problems, update it */
2078 update = SFTKDB_MODIFY_OBJECT;
2079 goto done;
2080 }
2081
2082 for (i = 0; i < SFTK_TRUST_TEMPLATE_COUNT; i++) {
2083 CK_ATTRIBUTE *attr = sftkdb_getAttributeFromTemplate(
2084 trustTemplate[i].type, ptemplate, *plen);
2085 sftkdbUpdateStatus status;
2086
2087 /* if target trust value doesn't exist, nothing to merge */
2088 if (trustTemplate[i].ulValueLen == (CK_ULONG)-1) {
2089 /* if the source exists, then we want the source entry,
2090 * go ahead and update */
2091 if (attr && attr->ulValueLen != (CK_ULONG)-1) {
2092 update = SFTKDB_MODIFY_OBJECT;
2093 }
2094 continue;
2095 }
2096
2097 /*
2098 * the source doesn't have the attribute, go to the next attribute
2099 */
2100 if (attr == NULL) {
2101 continue;
2102 }
2103 status = sftkdb_reconcileTrustEntry(arena, &trustTemplate[i], attr);
2104 if (status == SFTKDB_MODIFY_OBJECT) {
2105 update = SFTKDB_MODIFY_OBJECT;
2106 } else if (status == SFTKDB_DROP_ATTRIBUTE) {
2107 /* drop the source copy of the attribute, we are going with
2108 * the target's version */
2109 sftkdb_dropAttribute(attr, ptemplate, plen);
2110 }
2111 }
2112
2113 /* finally manage stepup */
2114 if (update == SFTKDB_MODIFY_OBJECT) {
2115 CK_BBOOL stepUpBool = CK_FALSE;
2116 /* if we are going to write from the source, make sure we don't
2117 * overwrite the stepup bit if it's on*/
2118 trustTemplate[0].type = CKA_TRUST_STEP_UP_APPROVED;
2119 trustTemplate[0].pValue = &stepUpBool;
2120 trustTemplate[0].ulValueLen = sizeof(stepUpBool);
2121 crv = (*db->sdb_GetAttributeValue)(db, id, trustTemplate, 1);
2122 if ((crv == CKR_OK) && (stepUpBool == CK_TRUE)) {
2123 sftkdb_dropAttribute(trustTemplate, ptemplate, plen);
2124 }
2125 } else {
2126 /* we currently aren't going to update. If the source stepup bit is
2127 * on however, do an update so the target gets it as well */
2128 CK_ATTRIBUTE *attr;
2129
2130 attr = sftkdb_getAttributeFromTemplate(CKA_TRUST_STEP_UP_APPROVED,
2131 ptemplate, *plen);
2132 if (attr && (attr->ulValueLen == sizeof(CK_BBOOL)) &&
2133 (*(CK_BBOOL *)(attr->pValue) == CK_TRUE)) {
2134 update = SFTKDB_MODIFY_OBJECT;
2135 }
2136 }
2137
2138 done:
2139 return update;
2140 }
2141
2142 static sftkdbUpdateStatus
sftkdb_handleIDAndName(PLArenaPool * arena,SDB * db,CK_OBJECT_HANDLE id,CK_ATTRIBUTE * ptemplate,CK_ULONG * plen)2143 sftkdb_handleIDAndName(PLArenaPool *arena, SDB *db, CK_OBJECT_HANDLE id,
2144 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen)
2145 {
2146 sftkdbUpdateStatus update = SFTKDB_DO_NOTHING;
2147 CK_ATTRIBUTE *attr1, *attr2;
2148 CK_ATTRIBUTE ttemplate[2] = {
2149 { CKA_ID, NULL, 0 },
2150 { CKA_LABEL, NULL, 0 }
2151 };
2152
2153 attr1 = sftkdb_getAttributeFromTemplate(CKA_LABEL, ptemplate, *plen);
2154 attr2 = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
2155
2156 /* if the source has neither an id nor label, don't bother updating */
2157 if ((!attr1 || attr1->ulValueLen == 0) &&
2158 (!attr2 || attr2->ulValueLen == 0)) {
2159 return SFTKDB_DO_NOTHING;
2160 }
2161
2162 /* the source has either an id or a label, see what the target has */
2163 (void)(*db->sdb_GetAttributeValue)(db, id, ttemplate, 2);
2164
2165 /* if the target has neither, update from the source */
2166 if (((ttemplate[0].ulValueLen == 0) ||
2167 (ttemplate[0].ulValueLen == (CK_ULONG)-1)) &&
2168 ((ttemplate[1].ulValueLen == 0) ||
2169 (ttemplate[1].ulValueLen == (CK_ULONG)-1))) {
2170 return SFTKDB_MODIFY_OBJECT;
2171 }
2172
2173 /* check the CKA_ID */
2174 if ((ttemplate[0].ulValueLen != 0) &&
2175 (ttemplate[0].ulValueLen != (CK_ULONG)-1)) {
2176 /* we have a CKA_ID in the target, don't overwrite
2177 * the target with an empty CKA_ID from the source*/
2178 if (attr1 && attr1->ulValueLen == 0) {
2179 sftkdb_dropAttribute(attr1, ptemplate, plen);
2180 }
2181 } else if (attr1 && attr1->ulValueLen != 0) {
2182 /* source has a CKA_ID, but the target doesn't, update the target */
2183 update = SFTKDB_MODIFY_OBJECT;
2184 }
2185
2186 /* check the nickname */
2187 if ((ttemplate[1].ulValueLen != 0) &&
2188 (ttemplate[1].ulValueLen != (CK_ULONG)-1)) {
2189
2190 /* we have a nickname in the target, and we don't have to update
2191 * the CKA_ID. We are done. NOTE: if we add addition attributes
2192 * in this check, this shortcut can only go on the last of them. */
2193 if (update == SFTKDB_DO_NOTHING) {
2194 return update;
2195 }
2196 /* we have a nickname in the target, don't overwrite
2197 * the target with an empty nickname from the source */
2198 if (attr2 && attr2->ulValueLen == 0) {
2199 sftkdb_dropAttribute(attr2, ptemplate, plen);
2200 }
2201 } else if (attr2 && attr2->ulValueLen != 0) {
2202 /* source has a nickname, but the target doesn't, update the target */
2203 update = SFTKDB_MODIFY_OBJECT;
2204 }
2205
2206 return update;
2207 }
2208
2209 /*
2210 * This function updates the template before we write the object out.
2211 *
2212 * If we are going to skip updating this object, return PR_FALSE.
2213 * If it should be updated we return PR_TRUE.
2214 * To help readability, these have been defined
2215 * as SFTK_DONT_UPDATE and SFTK_UPDATE respectively.
2216 */
2217 static PRBool
sftkdb_updateObjectTemplate(PLArenaPool * arena,SDB * db,CK_OBJECT_CLASS objectType,CK_ATTRIBUTE * ptemplate,CK_ULONG * plen,CK_OBJECT_HANDLE * targetID)2218 sftkdb_updateObjectTemplate(PLArenaPool *arena, SDB *db,
2219 CK_OBJECT_CLASS objectType,
2220 CK_ATTRIBUTE *ptemplate, CK_ULONG *plen,
2221 CK_OBJECT_HANDLE *targetID)
2222 {
2223 PRBool done; /* should we repeat the loop? */
2224 CK_OBJECT_HANDLE id;
2225 CK_RV crv = CKR_OK;
2226
2227 do {
2228 crv = sftkdb_checkConflicts(db, objectType, ptemplate,
2229 *plen, CK_INVALID_HANDLE);
2230 if (crv != CKR_ATTRIBUTE_VALUE_INVALID) {
2231 break;
2232 }
2233 crv = sftkdb_resolveConflicts(arena, objectType, ptemplate, plen);
2234 } while (crv == CKR_OK);
2235
2236 if (crv != CKR_OK) {
2237 return SFTKDB_DO_NOTHING;
2238 }
2239
2240 do {
2241 done = PR_TRUE;
2242 crv = sftkdb_lookupObject(db, objectType, &id, ptemplate, *plen);
2243 if (crv != CKR_OK) {
2244 return SFTKDB_DO_NOTHING;
2245 }
2246
2247 /* This object already exists, merge it, don't update */
2248 if (id != CK_INVALID_HANDLE) {
2249 CK_ATTRIBUTE *attr = NULL;
2250 /* special post processing for attributes */
2251 switch (objectType) {
2252 case CKO_CERTIFICATE:
2253 case CKO_PUBLIC_KEY:
2254 case CKO_PRIVATE_KEY:
2255 /* update target's CKA_ID and labels if they don't already
2256 * exist */
2257 *targetID = id;
2258 return sftkdb_handleIDAndName(arena, db, id, ptemplate, plen);
2259 case CKO_NSS_TRUST:
2260 /* if we have conflicting trust object types,
2261 * we need to reconcile them */
2262 *targetID = id;
2263 return sftkdb_reconcileTrust(arena, db, id, ptemplate, plen);
2264 case CKO_SECRET_KEY:
2265 /* secret keys in the old database are all sdr keys,
2266 * unfortunately they all appear to have the same CKA_ID,
2267 * even though they are truly different keys, so we always
2268 * want to update these keys, but we need to
2269 * give them a new CKA_ID */
2270 /* NOTE: this changes ptemplate */
2271 attr = sftkdb_getAttributeFromTemplate(CKA_ID, ptemplate, *plen);
2272 crv = attr ? sftkdb_incrementCKAID(arena, attr)
2273 : CKR_HOST_MEMORY;
2274 /* in the extremely rare event that we needed memory and
2275 * couldn't get it, just drop the key */
2276 if (crv != CKR_OK) {
2277 return SFTKDB_DO_NOTHING;
2278 }
2279 done = PR_FALSE; /* repeat this find loop */
2280 break;
2281 default:
2282 /* for all other objects, if we found the equivalent object,
2283 * don't update it */
2284 return SFTKDB_DO_NOTHING;
2285 }
2286 }
2287 } while (!done);
2288
2289 /* this object doesn't exist, update it */
2290 return SFTKDB_ADD_OBJECT;
2291 }
2292
2293 static CK_RV
sftkdb_updateIntegrity(PLArenaPool * arena,SFTKDBHandle * handle,SDB * source,CK_OBJECT_HANDLE sourceID,SDB * target,CK_OBJECT_HANDLE targetID,CK_ATTRIBUTE * ptemplate,CK_ULONG max_attributes)2294 sftkdb_updateIntegrity(PLArenaPool *arena, SFTKDBHandle *handle,
2295 SDB *source, CK_OBJECT_HANDLE sourceID,
2296 SDB *target, CK_OBJECT_HANDLE targetID,
2297 CK_ATTRIBUTE *ptemplate, CK_ULONG max_attributes)
2298 {
2299 unsigned int i;
2300 CK_RV global_crv = CKR_OK;
2301
2302 /* if the target doesn't have META data, don't need to do anything */
2303 if ((target->sdb_flags & SDB_HAS_META) == 0) {
2304 return CKR_OK;
2305 }
2306 /* if the source doesn't have meta data, then the record won't require
2307 * integrity */
2308 if ((source->sdb_flags & SDB_HAS_META) == 0) {
2309 return CKR_OK;
2310 }
2311 for (i = 0; i < max_attributes; i++) {
2312 CK_ATTRIBUTE *att = &ptemplate[i];
2313 CK_ATTRIBUTE_TYPE type = att->type;
2314 if (sftkdb_isPrivateAttribute(type)) {
2315 /* copy integrity signatures associated with this record (if any) */
2316 SECItem signature;
2317 unsigned char signData[SDB_MAX_META_DATA_LEN];
2318 CK_RV crv;
2319
2320 signature.data = signData;
2321 signature.len = sizeof(signData);
2322 crv = sftkdb_getRawAttributeSignature(handle, source, sourceID, type,
2323 &signature);
2324 if (crv != CKR_OK) {
2325 /* old databases don't have signature IDs because they are
2326 * 3DES encrypted. Since we know not to look for integrity
2327 * for 3DES records it's OK not to find one here. A new record
2328 * will be created when we reencrypt using AES CBC */
2329 continue;
2330 }
2331 crv = sftkdb_PutAttributeSignature(handle, target, targetID, type,
2332 &signature);
2333 if (crv != CKR_OK) {
2334 /* we had a signature in the source db, but we couldn't store
2335 * it in the target, remember the error so we can report it. */
2336 global_crv = crv;
2337 }
2338 }
2339 }
2340 return global_crv;
2341 }
2342
2343 #define MAX_ATTRIBUTES 500
2344 static CK_RV
sftkdb_mergeObject(SFTKDBHandle * handle,CK_OBJECT_HANDLE id,SECItem * key)2345 sftkdb_mergeObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id,
2346 SECItem *key)
2347 {
2348 CK_ATTRIBUTE template[MAX_ATTRIBUTES];
2349 CK_ATTRIBUTE *ptemplate;
2350 CK_ULONG max_attributes = MAX_ATTRIBUTES;
2351 CK_OBJECT_CLASS objectType;
2352 SDB *source = handle->update;
2353 SDB *target = handle->db;
2354 unsigned int i;
2355 CK_OBJECT_HANDLE newID = CK_INVALID_HANDLE;
2356 CK_RV crv;
2357 PLArenaPool *arena = NULL;
2358
2359 arena = PORT_NewArena(256);
2360 if (arena == NULL) {
2361 return CKR_HOST_MEMORY;
2362 }
2363
2364 ptemplate = &template[0];
2365 id &= SFTK_OBJ_ID_MASK;
2366 crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes);
2367 if (crv == CKR_BUFFER_TOO_SMALL) {
2368 ptemplate = PORT_ArenaNewArray(arena, CK_ATTRIBUTE, max_attributes);
2369 if (ptemplate == NULL) {
2370 crv = CKR_HOST_MEMORY;
2371 } else {
2372 crv = sftkdb_GetObjectTemplate(source, id,
2373 ptemplate, &max_attributes);
2374 }
2375 }
2376 if (crv != CKR_OK) {
2377 goto loser;
2378 }
2379
2380 for (i = 0; i < max_attributes; i++) {
2381 ptemplate[i].pValue = PORT_ArenaAlloc(arena, ptemplate[i].ulValueLen);
2382 if (ptemplate[i].pValue == NULL) {
2383 crv = CKR_HOST_MEMORY;
2384 goto loser;
2385 }
2386 }
2387 crv = (*source->sdb_GetAttributeValue)(source, id,
2388 ptemplate, max_attributes);
2389 if (crv != CKR_OK) {
2390 goto loser;
2391 }
2392
2393 objectType = sftkdb_getULongFromTemplate(CKA_CLASS, ptemplate,
2394 max_attributes);
2395
2396 /*
2397 * Update Object updates the object template if necessary then returns
2398 * whether or not we need to actually write the object out to our target
2399 * database.
2400 */
2401 if (!handle->updateID) {
2402 crv = sftkdb_CreateObject(arena, handle, target, &newID,
2403 ptemplate, max_attributes);
2404 } else {
2405 sftkdbUpdateStatus update_status;
2406 update_status = sftkdb_updateObjectTemplate(arena, target,
2407 objectType, ptemplate, &max_attributes, &newID);
2408 switch (update_status) {
2409 case SFTKDB_ADD_OBJECT:
2410 crv = sftkdb_CreateObject(arena, handle, target, &newID,
2411 ptemplate, max_attributes);
2412 break;
2413 case SFTKDB_MODIFY_OBJECT:
2414 crv = sftkdb_setAttributeValue(arena, handle, target,
2415 newID, ptemplate, max_attributes);
2416 break;
2417 case SFTKDB_DO_NOTHING:
2418 case SFTKDB_DROP_ATTRIBUTE:
2419 break;
2420 }
2421 }
2422
2423 /* if keyDB copy any meta data hashes to target, Update for the new
2424 * object ID */
2425 if (crv == CKR_OK) {
2426 crv = sftkdb_updateIntegrity(arena, handle, source, id, target, newID,
2427 ptemplate, max_attributes);
2428 }
2429
2430 loser:
2431 if (arena) {
2432 PORT_FreeArena(arena, PR_TRUE);
2433 }
2434 return crv;
2435 }
2436
2437 #define MAX_IDS 10
2438 /*
2439 * update a new database from an old one, now that we have the key
2440 */
2441 CK_RV
sftkdb_Update(SFTKDBHandle * handle,SECItem * key)2442 sftkdb_Update(SFTKDBHandle *handle, SECItem *key)
2443 {
2444 SDBFind *find = NULL;
2445 CK_ULONG idCount = MAX_IDS;
2446 CK_OBJECT_HANDLE ids[MAX_IDS];
2447 SECItem *updatePasswordKey = NULL;
2448 CK_RV crv, crv2;
2449 PRBool inTransaction = PR_FALSE;
2450 unsigned int i;
2451
2452 if (handle == NULL) {
2453 return CKR_OK;
2454 }
2455 if (handle->update == NULL) {
2456 return CKR_OK;
2457 }
2458 /*
2459 * put the whole update under a transaction. This allows us to handle
2460 * any possible race conditions between with the updateID check.
2461 */
2462 crv = (*handle->db->sdb_Begin)(handle->db);
2463 if (crv != CKR_OK) {
2464 return crv;
2465 }
2466 inTransaction = PR_TRUE;
2467
2468 /* some one else has already updated this db */
2469 if (sftkdb_hasUpdate(sftkdb_TypeString(handle),
2470 handle->db, handle->updateID)) {
2471 crv = CKR_OK;
2472 goto done;
2473 }
2474
2475 updatePasswordKey = sftkdb_GetUpdatePasswordKey(handle);
2476 if (updatePasswordKey) {
2477 /* pass the source DB key to the legacy code,
2478 * so it can decrypt things */
2479 handle->oldKey = updatePasswordKey;
2480 }
2481
2482 /* find all the objects */
2483 crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find);
2484
2485 if (crv != CKR_OK) {
2486 goto loser;
2487 }
2488 while ((crv == CKR_OK) && (idCount == MAX_IDS)) {
2489 crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount);
2490 for (i = 0; (crv == CKR_OK) && (i < idCount); i++) {
2491 crv = sftkdb_mergeObject(handle, ids[i], key);
2492 }
2493 }
2494 crv2 = sftkdb_FindObjectsFinal(handle, find);
2495 if (crv == CKR_OK)
2496 crv = crv2;
2497
2498 loser:
2499 /* no longer need the old key value */
2500 handle->oldKey = NULL;
2501
2502 /* update the password - even if we didn't update objects */
2503 if (handle->type == SFTK_KEYDB_TYPE) {
2504 SECItem item1, item2;
2505 unsigned char data1[SDB_MAX_META_DATA_LEN];
2506 unsigned char data2[SDB_MAX_META_DATA_LEN];
2507
2508 item1.data = data1;
2509 item1.len = sizeof(data1);
2510 item2.data = data2;
2511 item2.len = sizeof(data2);
2512
2513 /* if the target db already has a password, skip this. */
2514 crv = (*handle->db->sdb_GetMetaData)(handle->db, "password",
2515 &item1, &item2);
2516 if (crv == CKR_OK) {
2517 goto done;
2518 }
2519
2520 /* nope, update it from the source */
2521 crv = (*handle->update->sdb_GetMetaData)(handle->update, "password",
2522 &item1, &item2);
2523 if (crv != CKR_OK) {
2524 /* if we get here, neither the source, nor the target has been initialized
2525 * with a password entry. Create a metadata table now so that we don't
2526 * mistake this for a partially updated database */
2527 item1.data[0] = 0;
2528 item2.data[0] = 0;
2529 item1.len = item2.len = 1;
2530 crv = (*handle->db->sdb_PutMetaData)(handle->db, "empty", &item1, &item2);
2531 goto done;
2532 }
2533 crv = (*handle->db->sdb_PutMetaData)(handle->db, "password", &item1,
2534 &item2);
2535 if (crv != CKR_OK) {
2536 goto done;
2537 }
2538 }
2539
2540 done:
2541 /* finally mark this up to date db up to date */
2542 /* some one else has already updated this db */
2543 if (crv == CKR_OK) {
2544 crv = sftkdb_putUpdate(sftkdb_TypeString(handle),
2545 handle->db, handle->updateID);
2546 }
2547
2548 if (inTransaction) {
2549 if (crv == CKR_OK) {
2550 crv = (*handle->db->sdb_Commit)(handle->db);
2551 } else {
2552 (*handle->db->sdb_Abort)(handle->db);
2553 }
2554 }
2555 if (handle->update) {
2556 (*handle->update->sdb_Close)(handle->update);
2557 handle->update = NULL;
2558 }
2559 if (handle->updateID) {
2560 PORT_Free(handle->updateID);
2561 handle->updateID = NULL;
2562 }
2563 sftkdb_FreeUpdatePasswordKey(handle);
2564 if (updatePasswordKey) {
2565 SECITEM_ZfreeItem(updatePasswordKey, PR_TRUE);
2566 }
2567 handle->updateDBIsInit = PR_FALSE;
2568 return crv;
2569 }
2570
2571 /******************************************************************
2572 * DB handle managing functions.
2573 *
2574 * These functions are called by softoken to initialize, acquire,
2575 * and release database handles.
2576 */
2577
2578 const char *
sftkdb_GetUpdateID(SFTKDBHandle * handle)2579 sftkdb_GetUpdateID(SFTKDBHandle *handle)
2580 {
2581 return handle->updateID;
2582 }
2583
2584 /* release a database handle */
2585 void
sftk_freeDB(SFTKDBHandle * handle)2586 sftk_freeDB(SFTKDBHandle *handle)
2587 {
2588 PRInt32 ref;
2589
2590 if (!handle)
2591 return;
2592 ref = PR_ATOMIC_DECREMENT(&handle->ref);
2593 if (ref == 0) {
2594 sftkdb_CloseDB(handle);
2595 }
2596 return;
2597 }
2598
2599 /*
2600 * acquire a database handle for a certificate db
2601 * (database for public objects)
2602 */
2603 SFTKDBHandle *
sftk_getCertDB(SFTKSlot * slot)2604 sftk_getCertDB(SFTKSlot *slot)
2605 {
2606 SFTKDBHandle *dbHandle;
2607
2608 PZ_Lock(slot->slotLock);
2609 dbHandle = slot->certDB;
2610 if (dbHandle) {
2611 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2612 }
2613 PZ_Unlock(slot->slotLock);
2614 return dbHandle;
2615 }
2616
2617 /*
2618 * acquire a database handle for a key database
2619 * (database for private objects)
2620 */
2621 SFTKDBHandle *
sftk_getKeyDB(SFTKSlot * slot)2622 sftk_getKeyDB(SFTKSlot *slot)
2623 {
2624 SFTKDBHandle *dbHandle;
2625
2626 SKIP_AFTER_FORK(PZ_Lock(slot->slotLock));
2627 dbHandle = slot->keyDB;
2628 if (dbHandle) {
2629 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2630 }
2631 SKIP_AFTER_FORK(PZ_Unlock(slot->slotLock));
2632 return dbHandle;
2633 }
2634
2635 /*
2636 * acquire the database for a specific object. NOTE: objectID must point
2637 * to a Token object!
2638 */
2639 SFTKDBHandle *
sftk_getDBForTokenObject(SFTKSlot * slot,CK_OBJECT_HANDLE objectID)2640 sftk_getDBForTokenObject(SFTKSlot *slot, CK_OBJECT_HANDLE objectID)
2641 {
2642 SFTKDBHandle *dbHandle;
2643
2644 PZ_Lock(slot->slotLock);
2645 dbHandle = objectID & SFTK_KEYDB_TYPE ? slot->keyDB : slot->certDB;
2646 if (dbHandle) {
2647 (void)PR_ATOMIC_INCREMENT(&dbHandle->ref);
2648 }
2649 PZ_Unlock(slot->slotLock);
2650 return dbHandle;
2651 }
2652
2653 /*
2654 * initialize a new database handle
2655 */
2656 static SFTKDBHandle *
sftk_NewDBHandle(SDB * sdb,int type,PRBool legacy)2657 sftk_NewDBHandle(SDB *sdb, int type, PRBool legacy)
2658 {
2659 SFTKDBHandle *handle = PORT_New(SFTKDBHandle);
2660 handle->ref = 1;
2661 handle->db = sdb;
2662 handle->update = NULL;
2663 handle->peerDB = NULL;
2664 handle->newKey = NULL;
2665 handle->oldKey = NULL;
2666 handle->updatePasswordKey = NULL;
2667 handle->updateID = NULL;
2668 handle->type = type;
2669 handle->usesLegacyStorage = legacy;
2670 handle->passwordKey.data = NULL;
2671 handle->passwordKey.len = 0;
2672 handle->passwordLock = NULL;
2673 if (type == SFTK_KEYDB_TYPE) {
2674 handle->passwordLock = PZ_NewLock(nssILockAttribute);
2675 }
2676 sdb->app_private = handle;
2677 return handle;
2678 }
2679
2680 /*
2681 * reset the key database to it's uninitialized state. This call
2682 * will clear all the key entried.
2683 */
2684 SECStatus
sftkdb_ResetKeyDB(SFTKDBHandle * handle)2685 sftkdb_ResetKeyDB(SFTKDBHandle *handle)
2686 {
2687 CK_RV crv;
2688
2689 /* only rest the key db */
2690 if (handle->type != SFTK_KEYDB_TYPE) {
2691 return SECFailure;
2692 }
2693 crv = sftkdb_ResetDB(handle);
2694 if (crv != CKR_OK) {
2695 /* set error */
2696 return SECFailure;
2697 }
2698 if (handle->passwordKey.data) {
2699 SECITEM_ZfreeItem(&handle->passwordKey, PR_FALSE);
2700 handle->passwordKey.data = NULL;
2701 }
2702 return SECSuccess;
2703 }
2704
2705 #ifndef NSS_DISABLE_DBM
2706 static PRBool
sftk_oldVersionExists(const char * dir,int version)2707 sftk_oldVersionExists(const char *dir, int version)
2708 {
2709 int i;
2710 PRStatus exists = PR_FAILURE;
2711 char *file = NULL;
2712
2713 for (i = version; i > 1; i--) {
2714 file = PR_smprintf("%s%d.db", dir, i);
2715 if (file == NULL) {
2716 continue;
2717 }
2718 exists = PR_Access(file, PR_ACCESS_EXISTS);
2719 PR_smprintf_free(file);
2720 if (exists == PR_SUCCESS) {
2721 return PR_TRUE;
2722 }
2723 }
2724 return PR_FALSE;
2725 }
2726
2727 #if defined(_WIN32)
2728 /*
2729 * Convert an sdb path (encoded in UTF-8) to a legacy path (encoded in the
2730 * current system codepage). Fails if the path contains a character outside
2731 * the current system codepage.
2732 */
2733 static char *
sftk_legacyPathFromSDBPath(const char * confdir)2734 sftk_legacyPathFromSDBPath(const char *confdir)
2735 {
2736 wchar_t *confdirWide;
2737 DWORD size;
2738 char *nconfdir;
2739 BOOL unmappable;
2740
2741 if (!confdir) {
2742 return NULL;
2743 }
2744 confdirWide = _NSSUTIL_UTF8ToWide(confdir);
2745 if (!confdirWide) {
2746 return NULL;
2747 }
2748
2749 size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
2750 NULL, 0, NULL, &unmappable);
2751 if (size == 0 || unmappable) {
2752 PORT_Free(confdirWide);
2753 return NULL;
2754 }
2755 nconfdir = PORT_Alloc(sizeof(char) * size);
2756 if (!nconfdir) {
2757 PORT_Free(confdirWide);
2758 return NULL;
2759 }
2760 size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, confdirWide, -1,
2761 nconfdir, size, NULL, &unmappable);
2762 PORT_Free(confdirWide);
2763 if (size == 0 || unmappable) {
2764 PORT_Free(nconfdir);
2765 return NULL;
2766 }
2767
2768 return nconfdir;
2769 }
2770 #else
2771 #define sftk_legacyPathFromSDBPath(confdir) PORT_Strdup((confdir))
2772 #endif
2773
2774 static PRBool
sftk_hasLegacyDB(const char * confdir,const char * certPrefix,const char * keyPrefix,int certVersion,int keyVersion)2775 sftk_hasLegacyDB(const char *confdir, const char *certPrefix,
2776 const char *keyPrefix, int certVersion, int keyVersion)
2777 {
2778 char *dir;
2779 PRBool exists;
2780
2781 if (certPrefix == NULL) {
2782 certPrefix = "";
2783 }
2784
2785 if (keyPrefix == NULL) {
2786 keyPrefix = "";
2787 }
2788
2789 dir = PR_smprintf("%s/%scert", confdir, certPrefix);
2790 if (dir == NULL) {
2791 return PR_FALSE;
2792 }
2793
2794 exists = sftk_oldVersionExists(dir, certVersion);
2795 PR_smprintf_free(dir);
2796 if (exists) {
2797 return PR_TRUE;
2798 }
2799
2800 dir = PR_smprintf("%s/%skey", confdir, keyPrefix);
2801 if (dir == NULL) {
2802 return PR_FALSE;
2803 }
2804
2805 exists = sftk_oldVersionExists(dir, keyVersion);
2806 PR_smprintf_free(dir);
2807 return exists;
2808 }
2809 #endif /* NSS_DISABLE_DBM */
2810
2811 /*
2812 * initialize certificate and key database handles as a pair.
2813 *
2814 * This function figures out what type of database we are opening and
2815 * calls the appropriate low level function to open the database.
2816 * It also figures out whether or not to setup up automatic update.
2817 */
2818 CK_RV
sftk_DBInit(const char * configdir,const char * certPrefix,const char * keyPrefix,const char * updatedir,const char * updCertPrefix,const char * updKeyPrefix,const char * updateID,PRBool readOnly,PRBool noCertDB,PRBool noKeyDB,PRBool forceOpen,PRBool isFIPS,SFTKDBHandle ** certDB,SFTKDBHandle ** keyDB)2819 sftk_DBInit(const char *configdir, const char *certPrefix,
2820 const char *keyPrefix, const char *updatedir,
2821 const char *updCertPrefix, const char *updKeyPrefix,
2822 const char *updateID, PRBool readOnly, PRBool noCertDB,
2823 PRBool noKeyDB, PRBool forceOpen, PRBool isFIPS,
2824 SFTKDBHandle **certDB, SFTKDBHandle **keyDB)
2825 {
2826 const char *confdir;
2827 NSSDBType dbType = NSS_DB_TYPE_NONE;
2828 char *appName = NULL;
2829 SDB *keySDB, *certSDB;
2830 CK_RV crv = CKR_OK;
2831 int flags = SDB_RDONLY;
2832 PRBool newInit = PR_FALSE;
2833 #ifndef NSS_DISABLE_DBM
2834 PRBool needUpdate = PR_FALSE;
2835 #endif /* NSS_DISABLE_DBM */
2836 char *nconfdir = NULL;
2837 PRBool legacy = PR_TRUE;
2838
2839 if (!readOnly) {
2840 flags = SDB_CREATE;
2841 }
2842 if (isFIPS) {
2843 flags |= SDB_FIPS;
2844 }
2845
2846 *certDB = NULL;
2847 *keyDB = NULL;
2848
2849 if (noKeyDB && noCertDB) {
2850 return CKR_OK;
2851 }
2852 confdir = _NSSUTIL_EvaluateConfigDir(configdir, &dbType, &appName);
2853
2854 /*
2855 * now initialize the appropriate database
2856 */
2857 switch (dbType) {
2858 #ifndef NSS_DISABLE_DBM
2859 case NSS_DB_TYPE_LEGACY:
2860 crv = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
2861 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
2862 break;
2863 case NSS_DB_TYPE_MULTIACCESS:
2864 crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags,
2865 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
2866 break;
2867 #endif /* NSS_DISABLE_DBM */
2868 case NSS_DB_TYPE_SQL:
2869 case NSS_DB_TYPE_EXTERN: /* SHOULD open a loadable db */
2870 crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags,
2871 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit);
2872 legacy = PR_FALSE;
2873
2874 #ifndef NSS_DISABLE_DBM
2875 /*
2876 * if we failed to open the DB's read only, use the old ones if
2877 * the exists.
2878 */
2879 if (crv != CKR_OK) {
2880 legacy = PR_TRUE;
2881 if ((flags & SDB_RDONLY) == SDB_RDONLY) {
2882 nconfdir = sftk_legacyPathFromSDBPath(confdir);
2883 }
2884 if (nconfdir &&
2885 sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
2886 /* we have legacy databases, if we failed to open the new format
2887 * DB's read only, just use the legacy ones */
2888 crv = sftkdbCall_open(nconfdir, certPrefix,
2889 keyPrefix, 8, 3, flags,
2890 noCertDB ? NULL : &certSDB, noKeyDB ? NULL : &keySDB);
2891 }
2892 /* Handle the database merge case.
2893 *
2894 * For the merge case, we need help from the application. Only
2895 * the application knows where the old database is, and what unique
2896 * identifier it has associated with it.
2897 *
2898 * If the client supplies these values, we use them to determine
2899 * if we need to update.
2900 */
2901 } else if (
2902 /* both update params have been supplied */
2903 updatedir && *updatedir && updateID && *updateID
2904 /* old dbs exist? */
2905 && sftk_hasLegacyDB(updatedir, updCertPrefix, updKeyPrefix, 8, 3)
2906 /* and they have not yet been updated? */
2907 && ((noKeyDB || !sftkdb_hasUpdate("key", keySDB, updateID)) || (noCertDB || !sftkdb_hasUpdate("cert", certSDB, updateID)))) {
2908 /* we need to update */
2909 confdir = updatedir;
2910 certPrefix = updCertPrefix;
2911 keyPrefix = updKeyPrefix;
2912 needUpdate = PR_TRUE;
2913 } else if (newInit) {
2914 /* if the new format DB was also a newly created DB, and we
2915 * succeeded, then need to update that new database with data
2916 * from the existing legacy DB */
2917 nconfdir = sftk_legacyPathFromSDBPath(confdir);
2918 if (nconfdir &&
2919 sftk_hasLegacyDB(nconfdir, certPrefix, keyPrefix, 8, 3)) {
2920 confdir = nconfdir;
2921 needUpdate = PR_TRUE;
2922 }
2923 }
2924 #endif /* NSS_DISABLE_DBM */
2925 break;
2926 default:
2927 crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST
2928 * return one of the types we already
2929 * specified. */
2930 }
2931 if (crv != CKR_OK) {
2932 goto done;
2933 }
2934 if (!noCertDB) {
2935 *certDB = sftk_NewDBHandle(certSDB, SFTK_CERTDB_TYPE, legacy);
2936 } else {
2937 *certDB = NULL;
2938 }
2939 if (!noKeyDB) {
2940 *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE, legacy);
2941 } else {
2942 *keyDB = NULL;
2943 }
2944
2945 /* link them together */
2946 if (*certDB) {
2947 (*certDB)->peerDB = *keyDB;
2948 }
2949 if (*keyDB) {
2950 (*keyDB)->peerDB = *certDB;
2951 }
2952
2953 #ifndef NSS_DISABLE_DBM
2954 /*
2955 * if we need to update, open the legacy database and
2956 * mark the handle as needing update.
2957 */
2958 if (needUpdate) {
2959 SDB *updateCert = NULL;
2960 SDB *updateKey = NULL;
2961 CK_RV crv2;
2962
2963 crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags,
2964 noCertDB ? NULL : &updateCert,
2965 noKeyDB ? NULL : &updateKey);
2966 if (crv2 == CKR_OK) {
2967 if (*certDB) {
2968 (*certDB)->update = updateCert;
2969 (*certDB)->updateID = updateID && *updateID
2970 ? PORT_Strdup(updateID)
2971 : NULL;
2972 updateCert->app_private = (*certDB);
2973 }
2974 if (*keyDB) {
2975 PRBool tokenRemoved = PR_FALSE;
2976 (*keyDB)->update = updateKey;
2977 (*keyDB)->updateID = updateID && *updateID ? PORT_Strdup(updateID) : NULL;
2978 updateKey->app_private = (*keyDB);
2979 (*keyDB)->updateDBIsInit = PR_TRUE;
2980 (*keyDB)->updateDBIsInit =
2981 (sftkdb_HasPasswordSet(*keyDB) == SECSuccess) ? PR_TRUE : PR_FALSE;
2982 /* if the password on the key db is NULL, kick off our update
2983 * chain of events */
2984 sftkdb_CheckPasswordNull((*keyDB), &tokenRemoved);
2985 } else {
2986 /* we don't have a key DB, update the certificate DB now */
2987 sftkdb_Update(*certDB, NULL);
2988 }
2989 }
2990 }
2991 #endif /* NSS_DISABLE_DBM */
2992
2993 done:
2994 if (appName) {
2995 PORT_Free(appName);
2996 }
2997 if (nconfdir) {
2998 PORT_Free(nconfdir);
2999 }
3000 return forceOpen ? CKR_OK : crv;
3001 }
3002
3003 CK_RV
sftkdb_Shutdown(void)3004 sftkdb_Shutdown(void)
3005 {
3006 s_shutdown();
3007 #ifndef NSS_DISABLE_DBM
3008 sftkdbCall_Shutdown();
3009 #endif /* NSS_DISABLE_DBM */
3010 return CKR_OK;
3011 }
3012