comparison nss/lib/softoken/sftkdb.c @ 0:1e5118fa0cb1

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