Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: nss/lib/softoken/sftkdb.c

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

Powered by Google App Engine
This is Rietveld 408576698