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