1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 * The following code handles the storage of PKCS 11 modules used by the
38 * NSS. For the rest of NSS, only one kind of database handle exists:
42 * There is one SFTKDBHandle for the each key database and one for each cert
43 * database. These databases are opened as associated pairs, one pair per
44 * slot. SFTKDBHandles are reference counted objects.
46 * Each SFTKDBHandle points to a low level database handle (SDB). This handle
47 * represents the underlying physical database. These objects are not
48 * reference counted, an are 'owned' by their respective SFTKDBHandles.
71 struct SFTKDBHandleStr
{
74 CK_OBJECT_HANDLE type
;
82 #define SFTK_KEYDB_TYPE 0x40000000
83 #define SFTK_CERTDB_TYPE 0x00000000
84 #define SFTK_OBJ_TYPE_MASK 0xc0000000
85 #define SFTK_OBJ_ID_MASK (~SFTK_OBJ_TYPE_MASK)
86 #define SFTK_TOKEN_TYPE 0x80000000
88 static SECStatus
sftkdb_decrypt(SECItem
*passKey
, SECItem
*cipherText
,
90 static SECStatus
sftkdb_encrypt(PLArenaPool
*arena
, SECItem
*passKey
,
91 SECItem
*plainText
, SECItem
**cipherText
);
95 * We want all databases to have the same binary representation independent of
96 * endianness or length of the host architecture. In general PKCS #11 attributes
97 * are endian/length independent except those attributes that pass CK_ULONG.
99 * The following functions fixes up the CK_ULONG type attributes so that the data
100 * base sees a machine independent view. CK_ULONGs are stored as 4 byte network
101 * byte order values (big endian).
103 #define DB_ULONG_SIZE 4
107 sftkdb_isULONG(CK_ATTRIBUTE_TYPE type
)
111 case CKA_CERTIFICATE_TYPE
:
112 case CKA_CERTIFICATE_CATEGORY
:
114 case CKA_JAVA_MIDP_SECURITY_DOMAIN
:
116 case CKA_TRUST_DIGITAL_SIGNATURE
:
117 case CKA_TRUST_NON_REPUDIATION
:
118 case CKA_TRUST_KEY_ENCIPHERMENT
:
119 case CKA_TRUST_DATA_ENCIPHERMENT
:
120 case CKA_TRUST_KEY_AGREEMENT
:
121 case CKA_TRUST_KEY_CERT_SIGN
:
122 case CKA_TRUST_CRL_SIGN
:
124 case CKA_TRUST_SERVER_AUTH
:
125 case CKA_TRUST_CLIENT_AUTH
:
126 case CKA_TRUST_CODE_SIGNING
:
127 case CKA_TRUST_EMAIL_PROTECTION
:
128 case CKA_TRUST_IPSEC_END_SYSTEM
:
129 case CKA_TRUST_IPSEC_TUNNEL
:
130 case CKA_TRUST_IPSEC_USER
:
131 case CKA_TRUST_TIME_STAMPING
:
132 case CKA_TRUST_STEP_UP_APPROVED
:
141 /* are the attributes private? */
143 sftkdb_isPrivate(CK_ATTRIBUTE_TYPE type
)
147 case CKA_PRIVATE_EXPONENT
:
152 case CKA_COEFFICIENT
:
161 * fix up the input templates. Our fixed up ints are stored in data and must
162 * be freed by the caller. The new template must also be freed. If there are no
163 * CK_ULONG attributes, the orignal template is passed in as is.
165 static CK_ATTRIBUTE
*
166 sftkdb_fixupTemplateIn(const CK_ATTRIBUTE
*template, int count
,
167 unsigned char **dataOut
)
172 CK_ATTRIBUTE
*ntemplate
;
176 /* first count the number of CK_ULONG attributes */
177 for (i
=0; i
< count
; i
++) {
178 /* Don't 'fixup' NULL values */
179 if (!template[i
].pValue
) {
182 if (template[i
].ulValueLen
== sizeof (CK_ULONG
)) {
183 if ( sftkdb_isULONG(template[i
].type
)) {
188 /* no attributes to fixup, just call on through */
189 if (ulongCount
== 0) {
190 return (CK_ATTRIBUTE
*)template;
193 /* allocate space for new ULONGS */
194 data
= (unsigned char *)PORT_Alloc(DB_ULONG_SIZE
*ulongCount
);
199 /* allocate new template */
200 ntemplate
= PORT_NewArray(CK_ATTRIBUTE
,count
);
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
) {
213 if (template[i
].ulValueLen
== sizeof (CK_ULONG
)) {
214 if ( sftkdb_isULONG(template[i
].type
) ) {
215 CK_ULONG value
= *(CK_ULONG
*) template[i
].pValue
;
216 for (j
=0; j
< DB_ULONG_SIZE
; j
++) {
217 data
[j
] = (value
>> (DB_ULONG_SIZE
-1-j
)*BBP
) & 0xff;
219 ntemplate
[i
].pValue
= data
;
220 ntemplate
[i
].ulValueLen
= DB_ULONG_SIZE
;
221 data
+= DB_ULONG_SIZE
;
231 * fix up returned data. NOTE: sftkdb_fixupTemplateIn has already allocated
232 * separate data sections for the database ULONG values.
235 sftkdb_fixupTemplateOut(CK_ATTRIBUTE
*template, CK_ATTRIBUTE
*ntemplate
,
236 int count
, SFTKDBHandle
*handle
)
241 for (i
=0; i
< count
; i
++) {
242 CK_ULONG length
= template[i
].ulValueLen
;
243 template[i
].ulValueLen
= ntemplate
[i
].ulValueLen
;
245 if (ntemplate
[i
].ulValueLen
== DB_ULONG_SIZE
) {
246 if (sftkdb_isULONG(template[i
].type
)) {
247 if (template[i
].pValue
) {
251 data
= (unsigned char *)ntemplate
[i
].pValue
;
252 for (j
=0; j
< DB_ULONG_SIZE
; j
++) {
253 value
|= (((CK_ULONG
)data
[j
]) << (DB_ULONG_SIZE
-1-j
)*BBP
);
255 if (length
< sizeof(CK_ULONG
)) {
256 template[i
].ulValueLen
= -1;
257 crv
= CKR_BUFFER_TOO_SMALL
;
260 PORT_Memcpy(template[i
].pValue
,&value
,sizeof(CK_ULONG
));
262 template[i
].ulValueLen
= sizeof(CK_ULONG
);
265 /* fixup private attributes */
266 if ((handle
!= NULL
) && (handle
->type
== SFTK_KEYDB_TYPE
) &&
267 (template[i
].pValue
!= NULL
) && (template[i
].ulValueLen
!= -1)
268 && sftkdb_isPrivate(ntemplate
[i
].type
)) {
269 /* we have a private attribute */
270 /* This code depends on the fact that the cipherText is bigger
271 * than the plain text */
276 cipherText
.data
= ntemplate
[i
].pValue
;
277 cipherText
.len
= ntemplate
[i
].ulValueLen
;
278 PZ_Lock(handle
->passwordLock
);
279 if (handle
->passwordKey
.data
== NULL
) {
280 PZ_Unlock(handle
->passwordLock
);
281 template[i
].ulValueLen
= -1;
282 crv
= CKR_USER_NOT_LOGGED_IN
;
285 rv
= sftkdb_decrypt(&handle
->passwordKey
, &cipherText
, &plainText
);
286 PZ_Unlock(handle
->passwordLock
);
287 if (rv
!= SECSuccess
) {
288 PORT_Memset(template[i
].pValue
, 0, template[i
].ulValueLen
);
289 template[i
].ulValueLen
= -1;
290 crv
= CKR_GENERAL_ERROR
;
293 PORT_Assert(template[i
].ulValueLen
>= plainText
->len
);
294 if (template[i
].ulValueLen
< plainText
->len
) {
295 SECITEM_FreeItem(plainText
,PR_TRUE
);
296 PORT_Memset(template[i
].pValue
, 0, template[i
].ulValueLen
);
297 template[i
].ulValueLen
= -1;
298 crv
= CKR_GENERAL_ERROR
;
302 /* copy the plain text back into the template */
303 PORT_Memcpy(template[i
].pValue
, plainText
->data
, plainText
->len
);
304 template[i
].ulValueLen
= plainText
->len
;
305 SECITEM_FreeItem(plainText
,PR_TRUE
);
312 sftkdb_CreateObject(SFTKDBHandle
*handle
, SDB
*db
, CK_OBJECT_HANDLE
*objectID
,
313 CK_ATTRIBUTE
*template, CK_ULONG count
)
315 PRBool inTransaction
= PR_FALSE
;
318 crv
= (*db
->sdb_Begin
)(db
);
322 inTransaction
= PR_TRUE
;
323 crv
= (*db
->sdb_CreateObject
)(db
, objectID
, template, count
);
327 crv
= (*db
->sdb_Commit
)(db
);
328 inTransaction
= PR_FALSE
;
332 (*handle
->db
->sdb_Abort
)(handle
->db
);
333 /* It is trivial to show the following code cannot
334 * happen unless something is horribly wrong with our compilier or
336 PORT_Assert(crv
!= CKR_OK
);
337 if (crv
== CKR_OK
) crv
= CKR_GENERAL_ERROR
;
343 sftk_ExtractTemplate(PLArenaPool
*arena
, SFTKObject
*object
,
344 SFTKDBHandle
*handle
,CK_ULONG
*pcount
,
348 CK_ATTRIBUTE
*template;
349 int i
, templateIndex
;
350 SFTKSessionObject
*sessObject
= sftk_narrowToSessionObject(object
);
354 if (sessObject
== NULL
) {
355 *crv
= CKR_GENERAL_ERROR
; /* internal programming error */
359 PZ_Lock(sessObject
->attributeLock
);
361 for (i
=0; i
< sessObject
->hashSize
; i
++) {
363 for (attr
=sessObject
->head
[i
]; attr
; attr
=attr
->next
) {
367 template = PORT_ArenaNewArray(arena
, CK_ATTRIBUTE
, count
);
368 if (template == NULL
) {
369 PZ_Unlock(sessObject
->attributeLock
);
370 *crv
= CKR_HOST_MEMORY
;
374 for (i
=0; i
< sessObject
->hashSize
; i
++) {
376 for (attr
=sessObject
->head
[i
]; attr
; attr
=attr
->next
) {
377 CK_ATTRIBUTE
*tp
= &template[templateIndex
++];
378 /* copy the attribute */
382 if ((tp
->ulValueLen
== sizeof (CK_ULONG
)) &&
383 (sftkdb_isULONG(tp
->type
)) ) {
384 CK_ULONG value
= *(CK_ULONG
*) tp
->pValue
;
388 tp
->pValue
= PORT_ArenaAlloc(arena
, DB_ULONG_SIZE
);
389 data
= (unsigned char *)tp
->pValue
;
391 *crv
= CKR_HOST_MEMORY
;
394 for (j
=0; j
< DB_ULONG_SIZE
; j
++) {
395 data
[j
] = (value
>> (DB_ULONG_SIZE
-1-j
)*BBP
) & 0xff;
397 tp
->ulValueLen
= DB_ULONG_SIZE
;
400 /* encrypt private attributes */
401 if ((handle
!= NULL
) && (handle
->type
== SFTK_KEYDB_TYPE
) &&
402 sftkdb_isPrivate(tp
->type
)) {
404 /* we have a private attribute */
409 plainText
.data
= tp
->pValue
;
410 plainText
.len
= tp
->ulValueLen
;
411 PZ_Lock(handle
->passwordLock
);
412 if (handle
->passwordKey
.data
== NULL
) {
413 PZ_Unlock(handle
->passwordLock
);
414 *crv
= CKR_USER_NOT_LOGGED_IN
;
417 rv
= sftkdb_encrypt(arena
, &handle
->passwordKey
, &plainText
,
419 PZ_Unlock(handle
->passwordLock
);
420 if (rv
== SECSuccess
) {
421 tp
->pValue
= cipherText
->data
;
422 tp
->ulValueLen
= cipherText
->len
;
424 *crv
= CKR_GENERAL_ERROR
; /* better error code here? */
427 PORT_Memset(plainText
.data
, 0, plainText
.len
);
431 PORT_Assert(templateIndex
<= count
);
432 PZ_Unlock(sessObject
->attributeLock
);
434 if (*crv
!= CKR_OK
) {
444 #define GET_SDB(handle) ((handle)->update ? (handle)->update : (handle)->db)
447 sftkdb_write(SFTKDBHandle
*handle
, SFTKObject
*object
,
448 CK_OBJECT_HANDLE
*objectID
)
450 CK_ATTRIBUTE
*template;
456 *objectID
= CK_INVALID_HANDLE
;
458 if (handle
== NULL
) {
459 return CKR_TOKEN_WRITE_PROTECTED
;
461 db
= GET_SDB(handle
);
463 arena
= PORT_NewArena(256);
465 return CKR_HOST_MEMORY
;
468 template = sftk_ExtractTemplate(arena
, object
, handle
, &count
, &crv
);
473 crv
= sftkdb_CreateObject(handle
, db
, objectID
, template, count
);
477 PORT_FreeArena(arena
,PR_FALSE
);
480 *objectID
|= (handle
->type
| SFTK_TOKEN_TYPE
);
489 sftkdb_FindObjectsInit(SFTKDBHandle
*handle
, const CK_ATTRIBUTE
*template,
490 CK_ULONG count
, SDBFind
**find
)
492 unsigned char *data
= NULL
;
493 CK_ATTRIBUTE
*ntemplate
= NULL
;
497 if (handle
== NULL
) {
500 db
= GET_SDB(handle
);
503 ntemplate
= sftkdb_fixupTemplateIn(template, count
, &data
);
504 if (ntemplate
== NULL
) {
505 return CKR_HOST_MEMORY
;
509 crv
= (*db
->sdb_FindObjectsInit
)(db
, ntemplate
,
512 PORT_Free(ntemplate
);
519 sftkdb_FindObjects(SFTKDBHandle
*handle
, SDBFind
*find
,
520 CK_OBJECT_HANDLE
*ids
, int arraySize
, CK_ULONG
*count
)
525 if (handle
== NULL
) {
529 db
= GET_SDB(handle
);
531 crv
= (*db
->sdb_FindObjects
)(db
, find
, ids
,
535 for (i
=0; i
< *count
; i
++) {
536 ids
[i
] |= (handle
->type
| SFTK_TOKEN_TYPE
);
542 CK_RV
sftkdb_FindObjectsFinal(SFTKDBHandle
*handle
, SDBFind
*find
)
545 if (handle
== NULL
) {
548 db
= GET_SDB(handle
);
549 return (*db
->sdb_FindObjectsFinal
)(db
, find
);
553 sftkdb_GetAttributeValue(SFTKDBHandle
*handle
, CK_OBJECT_HANDLE object_id
,
554 CK_ATTRIBUTE
*template, CK_ULONG count
)
557 CK_ATTRIBUTE
*ntemplate
;
558 unsigned char *data
= NULL
;
561 if (handle
== NULL
) {
562 return CKR_GENERAL_ERROR
;
565 /* short circuit common attributes */
567 (template[0].type
== CKA_TOKEN
||
568 template[0].type
== CKA_PRIVATE
||
569 template[0].type
== CKA_SENSITIVE
)) {
570 CK_BBOOL boolVal
= CK_TRUE
;
572 if (template[0].pValue
== NULL
) {
573 template[0].ulValueLen
= sizeof(CK_BBOOL
);
576 if (template[0].ulValueLen
< sizeof(CK_BBOOL
)) {
577 template[0].ulValueLen
= -1;
578 return CKR_BUFFER_TOO_SMALL
;
581 if ((template[0].type
== CKA_PRIVATE
) &&
582 (handle
->type
!= SFTK_KEYDB_TYPE
)) {
585 if ((template[0].type
== CKA_SENSITIVE
) &&
586 (handle
->type
!= SFTK_KEYDB_TYPE
)) {
589 *(CK_BBOOL
*)template[0].pValue
= boolVal
;
590 template[0].ulValueLen
= sizeof(CK_BBOOL
);
594 db
= GET_SDB(handle
);
599 ntemplate
= sftkdb_fixupTemplateIn(template, count
, &data
);
600 if (ntemplate
== NULL
) {
601 return CKR_HOST_MEMORY
;
603 object_id
&= SFTK_OBJ_ID_MASK
;
604 crv
= (*db
->sdb_GetAttributeValue
)(db
, object_id
,
606 crv2
= sftkdb_fixupTemplateOut(template, ntemplate
, count
, handle
);
607 if (crv
== CKR_OK
) crv
= crv2
;
609 PORT_Free(ntemplate
);
617 sftkdb_SetAttributeValue(SFTKDBHandle
*handle
, CK_OBJECT_HANDLE object_id
,
618 const CK_ATTRIBUTE
*template, CK_ULONG count
)
621 CK_ATTRIBUTE
*ntemplate
;
622 unsigned char *data
= NULL
;
625 if (handle
== NULL
) {
626 return CKR_TOKEN_WRITE_PROTECTED
;
629 db
= GET_SDB(handle
);
634 ntemplate
= sftkdb_fixupTemplateIn(template, count
, &data
);
635 if (ntemplate
== NULL
) {
636 return CKR_HOST_MEMORY
;
638 object_id
&= SFTK_OBJ_ID_MASK
;
639 crv
= (*db
->sdb_Begin
)(db
);
643 crv
= (*db
->sdb_SetAttributeValue
)(db
, object_id
,
648 crv
= (*db
->sdb_Commit
)(db
);
651 (*db
->sdb_Abort
)(db
);
654 PORT_Free(ntemplate
);
661 sftkdb_DestroyObject(SFTKDBHandle
*handle
, CK_OBJECT_HANDLE object_id
)
666 if (handle
== NULL
) {
667 return CKR_TOKEN_WRITE_PROTECTED
;
669 db
= GET_SDB(handle
);
670 object_id
&= SFTK_OBJ_ID_MASK
;
671 crv
= (*db
->sdb_Begin
)(db
);
675 crv
= (*db
->sdb_DestroyObject
)(db
, object_id
);
679 crv
= (*db
->sdb_Commit
)(db
);
682 (*db
->sdb_Abort
)(db
);
688 sftkdb_CloseDB(SFTKDBHandle
*handle
)
690 if (handle
== NULL
) {
693 if (handle
->update
) {
694 (*handle
->update
->sdb_Close
)(handle
->update
);
697 (*handle
->db
->sdb_Close
)(handle
->db
);
699 if (handle
->passwordLock
) {
700 PZ_DestroyLock(handle
->passwordLock
);
707 * reset a database to it's uninitialized state.
710 sftkdb_ResetDB(SFTKDBHandle
*handle
)
714 if (handle
== NULL
) {
715 return CKR_TOKEN_WRITE_PROTECTED
;
717 db
= GET_SDB(handle
);
718 crv
= (*db
->sdb_Begin
)(db
);
722 crv
= (*db
->sdb_Reset
)(db
);
726 crv
= (*db
->sdb_Commit
)(db
);
729 (*db
->sdb_Abort
)(db
);
736 sftkdb_Begin(SFTKDBHandle
*handle
)
741 if (handle
== NULL
) {
744 db
= GET_SDB(handle
);
746 crv
= (*db
->sdb_Begin
)(db
);
752 sftkdb_Commit(SFTKDBHandle
*handle
)
757 if (handle
== NULL
) {
760 db
= GET_SDB(handle
);
762 (*db
->sdb_Commit
)(db
);
768 sftkdb_Abort(SFTKDBHandle
*handle
)
773 if (handle
== NULL
) {
776 db
= GET_SDB(handle
);
778 crv
= (db
->sdb_Abort
)(db
);
784 /****************************************************************
788 * The new secmod database is simply a text file with each of the module
789 * entries. in the following form:
792 * # This is a comment The next line is the library to load
793 * library=libmypkcs11.so
794 * name="My PKCS#11 module"
795 * params="my library's param string"
796 * nss="NSS parameters"
797 * other="parameters for other libraries and applications"
799 * library=libmynextpk11.so
800 * name="My other PKCS#11 module"
804 sftkdb_quote(const char *string
, char quote
)
807 int escapes
= 0, size
= 0;
812 for (src
=string
; *src
; src
++) {
813 if ((*src
== quote
) || (*src
== '\\')) escapes
++;
817 dest
= newString
= PORT_ZAlloc(escapes
+size
+1);
818 if (newString
== NULL
) {
823 for (src
=string
; *src
; src
++,dest
++) {
824 if ((*src
== '\\') || (*src
== quote
)) {
835 * Smart string cat functions. Automatically manage the memory.
836 * The first parameter is the source string. If it's null, we
837 * allocate memory for it. If it's not, we reallocate memory
838 * so the the concanenated string fits.
841 sftkdb_DupnCat(char *baseString
, const char *str
, int str_len
)
843 int len
= (baseString
? PORT_Strlen(baseString
) : 0) + 1;
847 newString
= (char *) PORT_Realloc(baseString
,len
);
848 if (newString
== NULL
) {
849 PORT_Free(baseString
);
852 if (baseString
== NULL
) *newString
= 0;
853 return PORT_Strncat(newString
,str
, str_len
);
856 /* Same as sftkdb_DupnCat except it concatenates the full string, not a
859 sftkdb_DupCat(char *baseString
, const char *str
)
861 return sftkdb_DupnCat(baseString
, str
, PORT_Strlen(str
));
864 /* function to free up all the memory associated with a null terminated
865 * array of module specs */
867 sftkdb_releaseSpecList(char **moduleSpecList
)
869 if (moduleSpecList
) {
871 for(index
= moduleSpecList
; *index
; index
++) {
874 PORT_Free(moduleSpecList
);
879 #define SECMOD_STEP 10
881 sftkdb_growList(char ***pModuleList
, int *useCount
, int last
)
883 char **newModuleList
;
885 *useCount
+= SECMOD_STEP
;
886 newModuleList
= (char **)PORT_Realloc(*pModuleList
,
887 *useCount
*sizeof(char *));
888 if (newModuleList
== NULL
) {
891 PORT_Memset(&newModuleList
[last
],0, sizeof(char *)*SECMOD_STEP
);
892 *pModuleList
= newModuleList
;
897 char *sftk_getOldSecmodName(const char *dbname
,const char *filename
)
900 char *dirPath
= PORT_Strdup(dbname
);
903 sep
= PORT_Strrchr(dirPath
,*PATH_SEPARATOR
);
906 sep
= PORT_Strrchr(dirPath
,'/');
912 file
= PR_smprintf("%s"PATH_SEPARATOR
"%s", dirPath
, filename
);
917 #define MAX_LINE_LENGTH 2048
918 #define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters="
919 #define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={"
920 #define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\""
926 * Read all the existing modules in out of the file.
929 sftkdb_ReadSecmodDB(SDBType dbType
, const char *appName
,
930 const char *filename
, const char *dbname
,
931 char *params
, PRBool rw
)
934 char **moduleList
= NULL
;
936 int useCount
= SECMOD_STEP
;
937 char line
[MAX_LINE_LENGTH
];
938 PRBool internal
= PR_FALSE
;
939 PRBool skipParams
= PR_FALSE
;
940 char *moduleString
= NULL
;
941 char *paramsValue
=NULL
;
942 PRBool failed
= PR_TRUE
;
944 if ((dbType
== SDB_LEGACY
) || (dbType
== SDB_MULTIACCESS
)) {
945 return sftkdbCall_ReadSecmodDB(appName
, filename
, dbname
, params
, rw
);
948 moduleList
= (char **) PORT_ZAlloc(useCount
*sizeof(char **));
949 if (moduleList
== NULL
) return NULL
;
951 /* do we really want to use streams here */
952 fd
= fopen(dbname
, "r");
953 if (fd
== NULL
) goto done
;
956 * the following loop takes line separated config lines and colapses
957 * the lines to a single string, escaping and quoting as necessary.
959 /* loop state variables */
960 moduleString
= NULL
; /* current concatenated string */
961 internal
= PR_FALSE
; /* is this an internal module */
962 skipParams
= PR_FALSE
; /* did we find an override parameter block*/
963 paramsValue
= NULL
; /* the current parameter block value */
964 while (fgets(line
, sizeof(line
), fd
) != NULL
) {
965 int len
= PORT_Strlen(line
);
967 /* remove the ending newline */
968 if (len
&& line
[len
-1] == '\n') {
977 * The PKCS #11 group standard assumes blocks of strings
978 * separated by new lines, clumped by new lines. Internally
979 * we take strings separated by spaces, so we may need to escape
982 char *value
= PORT_Strchr(line
,'=');
984 /* there is no value, write out the stanza as is */
985 if (value
== NULL
|| value
[1] == 0) {
987 moduleString
= sftkdb_DupnCat(moduleString
," ", 1);
988 if (moduleString
== NULL
) goto loser
;
990 moduleString
= sftkdb_DupCat(moduleString
, line
);
991 if (moduleString
== NULL
) goto loser
;
992 /* value is already quoted, just write it out */
993 } else if (value
[1] == '"') {
995 moduleString
= sftkdb_DupnCat(moduleString
," ", 1);
996 if (moduleString
== NULL
) goto loser
;
998 moduleString
= sftkdb_DupCat(moduleString
, line
);
999 if (moduleString
== NULL
) goto loser
;
1000 /* we have an override parameter section, remember that
1001 * we found this (see following comment about why this
1003 if (PORT_Strncasecmp(line
, "parameters", 10) == 0) {
1004 skipParams
= PR_TRUE
;
1007 * The internal token always overrides it's parameter block
1008 * from the passed in parameters, so wait until then end
1009 * before we include the parameter block in case we need to
1010 * override it. NOTE: if the parameter block is quoted with ("),
1011 * this override does not happen. This allows you to override
1012 * the application's parameter configuration.
1014 * parameter block state is controlled by the following variables:
1015 * skipParams - Bool : set to true of we have an override param
1016 * block (all other blocks, either implicit or explicit are
1018 * paramsValue - char * : pointer to the current param block. In
1019 * the absence of overrides, paramsValue is set to the first
1020 * parameter block we find. All subsequent blocks are ignored.
1021 * When we find an internal token, the application passed
1022 * parameters take precident.
1024 } else if (PORT_Strncasecmp(line
, "parameters", 10) == 0) {
1025 /* already have parameters */
1029 paramsValue
= sftkdb_quote(&value
[1], '"');
1030 if (paramsValue
== NULL
) goto loser
;
1033 /* may need to quote */
1036 moduleString
= sftkdb_DupnCat(moduleString
," ", 1);
1037 if (moduleString
== NULL
) goto loser
;
1039 moduleString
= sftkdb_DupnCat(moduleString
,line
,value
-line
+1);
1040 if (moduleString
== NULL
) goto loser
;
1041 newLine
= sftkdb_quote(&value
[1],'"');
1042 if (newLine
== NULL
) goto loser
;
1043 moduleString
= sftkdb_DupCat(moduleString
,newLine
);
1045 if (moduleString
== NULL
) goto loser
;
1048 /* check to see if it's internal? */
1049 if (PORT_Strncasecmp(line
, "NSS=", 4) == 0) {
1050 /* This should be case insensitive! reviewers make
1051 * me fix it if it's not */
1052 if (PORT_Strstr(line
,"internal")) {
1054 /* override the parameters */
1056 PORT_Free(paramsValue
);
1058 paramsValue
= sftkdb_quote(params
, '"');
1063 if ((moduleString
== NULL
) || (*moduleString
== 0)) {
1068 * if we are here, we have found a complete stanza. Now write out
1069 * any param section we may have found.
1072 /* we had an override */
1074 moduleString
= sftkdb_DupnCat(moduleString
," parameters=", 12);
1075 if (moduleString
== NULL
) goto loser
;
1076 moduleString
= sftkdb_DupCat(moduleString
, paramsValue
);
1077 if (moduleString
== NULL
) goto loser
;
1079 PORT_Free(paramsValue
);
1083 if ((moduleCount
+1) >= useCount
) {
1085 rv
= sftkdb_growList(&moduleList
, &useCount
, moduleCount
+1);
1086 if (rv
!= SECSuccess
) {
1092 moduleList
[0] = moduleString
;
1094 moduleList
[moduleCount
] = moduleString
;
1097 moduleString
= NULL
;
1098 internal
= PR_FALSE
;
1099 skipParams
= PR_FALSE
;
1103 PORT_Free(moduleString
);
1104 moduleString
= NULL
;
1107 /* if we couldn't open a pkcs11 database, look for the old one */
1109 char *olddbname
= sftk_getOldSecmodName(dbname
,filename
);
1111 char **oldModuleList
;
1114 /* couldn't get the old name */
1119 /* old one doesn't exist */
1120 status
= PR_Access(olddbname
, PR_ACCESS_EXISTS
);
1121 if (status
!= PR_SUCCESS
) {
1125 oldModuleList
= sftkdbCall_ReadSecmodDB(appName
, filename
,
1126 olddbname
, params
, rw
);
1127 /* old one had no modules */
1128 if (!oldModuleList
) {
1132 /* count the modules */
1133 for (i
=0; oldModuleList
[i
]; i
++) { }
1135 /* grow the moduleList if necessary */
1136 if (i
>= useCount
) {
1138 rv
= sftkdb_growList(&moduleList
,&useCount
,moduleCount
+1);
1139 if (rv
!= SECSuccess
) {
1144 /* write each module out, and copy it */
1145 for (i
=0; oldModuleList
[i
]; i
++) {
1147 sftkdb_AddSecmodDB(dbType
,appName
,filename
,dbname
,
1148 oldModuleList
[i
],rw
);
1150 if (moduleList
[i
]) {
1151 PORT_Free(moduleList
[i
]);
1153 moduleList
[i
] = PORT_Strdup(oldModuleList
[i
]);
1156 /* done with the old module list */
1157 sftkdbCall_ReleaseSecmodDBData(appName
, filename
, olddbname
,
1162 if (!moduleList
[0]) {
1164 moduleString
= PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1
);
1165 newParams
= sftkdb_quote(params
,'"');
1166 if (newParams
== NULL
) goto loser
;
1167 moduleString
= sftkdb_DupCat(moduleString
, newParams
);
1168 PORT_Free(newParams
);
1169 if (moduleString
== NULL
) goto loser
;
1170 moduleString
= sftkdb_DupCat(moduleString
, SFTK_DEFAULT_INTERNAL_INIT2
);
1171 if (moduleString
== NULL
) goto loser
;
1172 moduleString
= sftkdb_DupCat(moduleString
, SECMOD_SLOT_FLAGS
);
1173 if (moduleString
== NULL
) goto loser
;
1174 moduleString
= sftkdb_DupCat(moduleString
, SFTK_DEFAULT_INTERNAL_INIT3
);
1175 if (moduleString
== NULL
) goto loser
;
1176 moduleList
[0] = moduleString
;
1177 moduleString
= NULL
;
1185 /* deal with trust cert db here */
1187 PORT_Free(moduleString
);
1188 moduleString
= NULL
;
1191 PORT_Free(paramsValue
);
1194 if (failed
|| (moduleList
[0] == NULL
)) {
1195 /* This is wrong! FIXME */
1196 sftkdb_releaseSpecList(moduleList
);
1202 } else if (!failed
&& rw
) {
1203 /* update our internal module */
1204 sftkdb_AddSecmodDB(dbType
,appName
,filename
,dbname
,moduleList
[0],rw
);
1210 sftkdb_ReleaseSecmodDBData(SDBType dbType
, const char *appName
,
1211 const char *filename
, const char *dbname
,
1212 char **moduleSpecList
, PRBool rw
)
1214 if ((dbType
== SDB_LEGACY
) || (dbType
== SDB_MULTIACCESS
)) {
1215 return sftkdbCall_ReleaseSecmodDBData(appName
, filename
, dbname
,
1216 moduleSpecList
, rw
);
1218 if (moduleSpecList
) {
1219 sftkdb_releaseSpecList(moduleSpecList
);
1226 * Delete a module from the Data Base
1229 sftkdb_DeleteSecmodDB(SDBType dbType
, const char *appName
,
1230 const char *filename
, const char *dbname
,
1231 char *args
, PRBool rw
)
1233 /* SHDB_FIXME implement */
1236 char line
[MAX_LINE_LENGTH
];
1237 char *dbname2
= NULL
;
1241 int name_len
, lib_len
;
1242 PRBool skip
= PR_FALSE
;
1243 PRBool found
= PR_FALSE
;
1245 if ((dbType
== SDB_LEGACY
) || (dbType
== SDB_MULTIACCESS
)) {
1246 return sftkdbCall_DeleteSecmodDB(appName
, filename
, dbname
, args
, rw
);
1253 dbname2
= strdup(dbname
);
1254 if (dbname2
== NULL
) goto loser
;
1255 dbname2
[strlen(dbname
)-1]++;
1257 /* do we really want to use streams here */
1258 fd
= fopen(dbname
, "r");
1259 if (fd
== NULL
) goto loser
;
1260 fd2
= fopen(dbname2
, "w+");
1261 if (fd2
== NULL
) goto loser
;
1263 name
= sftk_argGetParamValue("name",args
);
1265 name_len
= PORT_Strlen(name
);
1267 lib
= sftk_argGetParamValue("library",args
);
1269 lib_len
= PORT_Strlen(lib
);
1274 * the following loop takes line separated config files and colapses
1275 * the lines to a single string, escaping and quoting as necessary.
1277 /* loop state variables */
1280 while (fgets(line
, sizeof(line
), fd
) != NULL
) {
1281 /* If we are processing a block (we haven't hit a blank line yet */
1282 if (*line
!= '\n') {
1283 /* skip means we are in the middle of a block we are deleting */
1287 /* if we haven't found the block yet, check to see if this block
1288 * matches our requirements */
1289 if (!found
&& ((name
&& (PORT_Strncasecmp(line
,"name=",5) == 0) &&
1290 (PORT_Strncmp(line
+5,name
,name_len
) == 0)) ||
1291 (lib
&& (PORT_Strncasecmp(line
,"library=",8) == 0) &&
1292 (PORT_Strncmp(line
+8,lib
,lib_len
) == 0)))) {
1294 /* yup, we don't need to save any more data, */
1297 /* we don't need to collect more of this block */
1299 /* we don't need to continue searching for the block */
1303 /* not our match, continue to collect data in this block */
1304 block
= sftkdb_DupCat(block
,line
);
1307 /* we've collected a block of data that wasn't the module we were
1308 * looking for, write it out */
1310 fwrite(block
, PORT_Strlen(block
), 1, fd2
);
1314 /* If we didn't just delete the this block, keep the blank line */
1318 /* we are definately not in a deleted block anymore */
1323 /* rename dbname2 to dbname */
1326 PR_Rename(dbname2
,dbname
);
1346 * Add a module to the Data base
1349 sftkdb_AddSecmodDB(SDBType dbType
, const char *appName
,
1350 const char *filename
, const char *dbname
,
1351 char *module
, PRBool rw
)
1355 PRBool libFound
= PR_FALSE
;
1357 if ((dbType
== SDB_LEGACY
) || (dbType
== SDB_MULTIACCESS
)) {
1358 return sftkdbCall_AddSecmodDB(appName
, filename
, dbname
, module
, rw
);
1361 /* can't write to a read only module */
1366 /* remove the previous version if it exists */
1367 (void) sftkdb_DeleteSecmodDB(dbType
, appName
, filename
, dbname
, module
, rw
);
1369 /* do we really want to use streams here */
1370 fd
= fopen(dbname
, "a+");
1374 module
= sftk_argStrip(module
);
1377 char *keyEnd
= PORT_Strchr(module
,'=');
1380 if (PORT_Strncmp(module
, "library=", 8) == 0) {
1383 if (keyEnd
== NULL
) {
1384 block
= sftkdb_DupCat(block
, module
);
1387 value
= sftk_argFetchValue(&keyEnd
[1], &count
);
1388 block
= sftkdb_DupnCat(block
, module
, keyEnd
-module
+1);
1389 if (block
== NULL
) { goto loser
; }
1391 block
= sftkdb_DupCat(block
, sftk_argStrip(value
));
1394 if (block
== NULL
) { goto loser
; }
1395 block
= sftkdb_DupnCat(block
, "\n", 1);
1396 module
= keyEnd
+ 1 + count
;
1397 module
= sftk_argStrip(module
);
1401 fprintf(fd
,"library=\n");
1403 fwrite(block
, PORT_Strlen(block
), 1, fd
);
1417 /******************************************************************
1419 * Key DB password handling functions
1421 * These functions manage the key db password (set, reset, initialize, use).
1423 * The key is managed on 'this side' of the database. All private data is
1424 * encrypted before it is sent to the database itself. Besides PBE's, the
1425 * database management code can also mix in various fixed keys so the data
1426 * in the database is no longer considered 'plain text'.
1430 /* take string password and turn it into a key. The key is dependent
1431 * on a global salt entry acquired from the database. This salted
1432 * value will be based to a pkcs5 pbe function before it is used
1433 * in an actual encryption */
1435 sftkdb_passwordToKey(SFTKDBHandle
*keydb
, SDBPasswordEntry
*entry
,
1436 const char *pw
, SECItem
*key
)
1438 SHA1Context
*cx
= NULL
;
1439 SECStatus rv
= SECFailure
;
1441 key
->data
= PORT_Alloc(SHA1_LENGTH
);
1442 if (key
->data
== NULL
) {
1445 key
->len
= SHA1_LENGTH
;
1447 cx
= SHA1_NewContext();
1452 if (entry
&& entry
->salt
.data
) {
1453 SHA1_Update(cx
, entry
->salt
.data
, entry
->salt
.len
);
1455 SHA1_Update(cx
, (unsigned char *)pw
, PORT_Strlen(pw
));
1456 SHA1_End(cx
, key
->data
, &key
->len
, key
->len
);
1461 SHA1_DestroyContext(cx
, PR_TRUE
);
1463 if (rv
!= SECSuccess
) {
1464 if (key
->data
!= NULL
) {
1465 PORT_ZFree(key
->data
,key
->len
);
1473 * Cipher text stored in the database contains 3 elements:
1474 * 1) an identifier describing the encryption algorithm.
1475 * 2) an entry specific salt value.
1476 * 3) the encrypted value.
1478 * The following data structure represents the encrypted data in a decoded
1479 * (but still encrypted) form.
1481 typedef struct sftkCipherValueStr sftkCipherValue
;
1482 struct sftkCipherValueStr
{
1485 NSSPKCS5PBEParameter
*param
;
1490 #define SFTK_CIPHERTEXT_VERSION 3
1492 struct SFTKDBEncryptedDataInfoStr
{
1493 SECAlgorithmID algorithm
;
1494 SECItem encryptedData
;
1496 typedef struct SFTKDBEncryptedDataInfoStr SFTKDBEncryptedDataInfo
;
1498 const SEC_ASN1Template sftkdb_EncryptedDataInfoTemplate
[] = {
1499 { SEC_ASN1_SEQUENCE
,
1500 0, NULL
, sizeof(SFTKDBEncryptedDataInfo
) },
1502 offsetof(SFTKDBEncryptedDataInfo
,algorithm
),
1503 SECOID_AlgorithmIDTemplate
},
1504 { SEC_ASN1_OCTET_STRING
,
1505 offsetof(SFTKDBEncryptedDataInfo
,encryptedData
) },
1510 * This parses the cipherText into cipher value. NOTE: cipherValue will point
1511 * to data in cipherText, if cipherText is freed, cipherValue will be invalid.
1513 * Use existing NSS data record: (sizes and offsets in bytes)
1515 * offset size label Description
1516 * 0 1 version Data base version number must be 3
1517 * 1 1 slen Length of Salt
1518 * 2 1 nlen Length of optional nickname
1519 * 3 slen sdata Salt data
1520 * 3+slen nlen ndata Optional nickname data
1521 * 3+nlen+slen 1 olen Length of algorithm OID
1522 * 4+nlen+slen olen odata Algorithm OID data.
1524 * olen rest vdata Encrypted data.
1526 * rest is the rest of the block passed into us.
1529 sftkdb_decodeCipherText(SECItem
*cipherText
, sftkCipherValue
*cipherValue
)
1531 PLArenaPool
*arena
= NULL
;
1532 SFTKDBEncryptedDataInfo edi
;
1535 arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1536 if (arena
== NULL
) {
1539 cipherValue
->arena
= NULL
;
1540 cipherValue
->param
= NULL
;
1542 rv
= SEC_QuickDERDecodeItem(arena
, &edi
, sftkdb_EncryptedDataInfoTemplate
,
1544 if (rv
!= SECSuccess
) {
1547 cipherValue
->alg
= SECOID_GetAlgorithmTag(&edi
.algorithm
);
1548 cipherValue
->param
= nsspkcs5_AlgidToParam(&edi
.algorithm
);
1549 if (cipherValue
->param
== NULL
) {
1552 cipherValue
->value
= edi
.encryptedData
;
1553 cipherValue
->arena
= arena
;
1557 if (cipherValue
->param
) {
1558 nsspkcs5_DestroyPBEParameter(cipherValue
->param
);
1559 cipherValue
->param
= NULL
;
1562 PORT_FreeArena(arena
,PR_FALSE
);
1570 * unlike decode, Encode actually allocates a SECItem the caller must free
1571 * The caller can pass an optional arena to to indicate where to place
1572 * the resultant cipherText.
1575 sftkdb_encodeCipherText(PLArenaPool
*arena
, sftkCipherValue
*cipherValue
,
1576 SECItem
**cipherText
)
1578 SFTKDBEncryptedDataInfo edi
;
1579 SECAlgorithmID
*algid
;
1581 PLArenaPool
*localArena
= NULL
;
1584 localArena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
1585 if (localArena
== NULL
) {
1589 algid
= nsspkcs5_CreateAlgorithmID(localArena
, cipherValue
->alg
,
1590 cipherValue
->param
);
1591 if (algid
== NULL
) {
1595 rv
= SECOID_CopyAlgorithmID(localArena
, &edi
.algorithm
, algid
);
1596 SECOID_DestroyAlgorithmID(algid
, PR_TRUE
);
1597 if (rv
!= SECSuccess
) {
1600 edi
.encryptedData
= cipherValue
->value
;
1602 *cipherText
= SEC_ASN1EncodeItem(arena
, NULL
, &edi
,
1603 sftkdb_EncryptedDataInfoTemplate
);
1604 if (*cipherText
== NULL
) {
1610 PORT_FreeArena(localArena
,PR_FALSE
);
1618 * Use our key to decode a cipherText block from the database.
1620 * plain text is allocated by nsspkcs5_CipherData and must be freed
1621 * with SECITEM_FreeItem by the caller.
1624 sftkdb_decrypt(SECItem
*passKey
, SECItem
*cipherText
, SECItem
**plain
)
1627 sftkCipherValue cipherValue
;
1629 /* First get the cipher type */
1630 rv
= sftkdb_decodeCipherText(cipherText
, &cipherValue
);
1631 if (rv
!= SECSuccess
) {
1635 *plain
= nsspkcs5_CipherData(cipherValue
.param
, passKey
, &cipherValue
.value
,
1637 if (*plain
== NULL
) {
1643 if (cipherValue
.param
) {
1644 nsspkcs5_DestroyPBEParameter(cipherValue
.param
);
1646 if (cipherValue
.arena
) {
1647 PORT_FreeArena(cipherValue
.arena
,PR_FALSE
);
1652 #define SALT_LENGTH 20
1655 * encrypt a block. This function returned the encrypted ciphertext which
1656 * the caller must free. If the caller provides an arena, cipherText will
1657 * be allocated out of that arena. This also generated the per entry
1658 * salt automatically.
1661 sftkdb_encrypt(PLArenaPool
*arena
, SECItem
*passKey
, SECItem
*plainText
,
1662 SECItem
**cipherText
)
1665 sftkCipherValue cipherValue
;
1666 SECItem
*cipher
= NULL
;
1667 NSSPKCS5PBEParameter
*param
= NULL
;
1668 unsigned char saltData
[SALT_LENGTH
];
1670 cipherValue
.alg
= SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC
;
1671 cipherValue
.salt
.len
= SALT_LENGTH
;
1672 cipherValue
.salt
.data
= saltData
;
1673 RNG_GenerateGlobalRandomBytes(saltData
,SALT_LENGTH
);
1675 param
= nsspkcs5_NewParam(cipherValue
.alg
, &cipherValue
.salt
, 1);
1676 if (param
== NULL
) {
1680 cipher
= nsspkcs5_CipherData(param
, passKey
, plainText
, PR_TRUE
, NULL
);
1681 if (cipher
== NULL
) {
1685 cipherValue
.value
= *cipher
;
1686 cipherValue
.param
= param
;
1688 rv
= sftkdb_encodeCipherText(arena
, &cipherValue
, cipherText
);
1689 if (rv
!= SECSuccess
) {
1695 SECITEM_FreeItem(cipher
, PR_TRUE
);
1698 nsspkcs5_DestroyPBEParameter(param
);
1705 * stub files for legacy db's to be able to encrypt and decrypt
1706 * various keys and attributes.
1709 sftkdb_encrypt_stub(PRArenaPool
*arena
, SDB
*sdb
, SECItem
*plainText
,
1710 SECItem
**cipherText
)
1712 SFTKDBHandle
*handle
= sdb
->app_private
;
1715 if (handle
== NULL
) {
1719 /* if we aren't th handle, try the other handle */
1720 if (handle
->type
!= SFTK_KEYDB_TYPE
) {
1721 handle
= handle
->peerDB
;
1724 /* not a key handle */
1725 if (handle
== NULL
|| handle
->passwordLock
== NULL
) {
1729 PZ_Lock(handle
->passwordLock
);
1730 if (handle
->passwordKey
.data
== NULL
) {
1731 PZ_Unlock(handle
->passwordLock
);
1736 rv
= sftkdb_encrypt(arena
,
1737 handle
->newKey
?handle
->newKey
:&handle
->passwordKey
,
1738 plainText
, cipherText
);
1739 PZ_Unlock(handle
->passwordLock
);
1745 * stub files for legacy db's to be able to encrypt and decrypt
1746 * various keys and attributes.
1749 sftkdb_decrypt_stub(SDB
*sdb
, SECItem
*cipherText
, SECItem
**plainText
)
1751 SFTKDBHandle
*handle
= sdb
->app_private
;
1754 if (handle
== NULL
) {
1758 /* if we aren't th handle, try the other handle */
1759 if (handle
->type
!= SFTK_KEYDB_TYPE
) {
1760 handle
= handle
->peerDB
;
1763 /* not a key handle */
1764 if (handle
== NULL
|| handle
->passwordLock
== NULL
) {
1768 PZ_Lock(handle
->passwordLock
);
1769 if (handle
->passwordKey
.data
== NULL
) {
1770 PZ_Unlock(handle
->passwordLock
);
1774 rv
= sftkdb_decrypt(&handle
->passwordKey
, cipherText
, plainText
);
1775 PZ_Unlock(handle
->passwordLock
);
1781 * safely swith the passed in key for the one caches in the keydb handle
1783 * A key attached to the handle tells us the the token is logged in.
1784 * We can used the key attached to the handle in sftkdb_encrypt
1785 * and sftkdb_decrypt calls.
1788 sftkdb_switchKeys(SFTKDBHandle
*keydb
, SECItem
*passKey
)
1790 unsigned char *data
;
1793 if (keydb
->passwordLock
== NULL
) {
1794 PORT_Assert(keydb
->type
!= SFTK_KEYDB_TYPE
);
1798 /* an atomic pointer set would be nice */
1799 PZ_Lock(keydb
->passwordLock
);
1800 data
= keydb
->passwordKey
.data
;
1801 len
= keydb
->passwordKey
.len
;
1802 keydb
->passwordKey
.data
= passKey
->data
;
1803 keydb
->passwordKey
.len
= passKey
->len
;
1804 passKey
->data
= data
;
1806 PZ_Unlock(keydb
->passwordLock
);
1812 static const CK_ATTRIBUTE_TYPE known_attributes
[] = {
1813 CKA_CLASS
, CKA_TOKEN
, CKA_PRIVATE
, CKA_LABEL
, CKA_APPLICATION
,
1814 CKA_VALUE
, CKA_OBJECT_ID
, CKA_CERTIFICATE_TYPE
, CKA_ISSUER
,
1815 CKA_SERIAL_NUMBER
, CKA_AC_ISSUER
, CKA_OWNER
, CKA_ATTR_TYPES
, CKA_TRUSTED
,
1816 CKA_CERTIFICATE_CATEGORY
, CKA_JAVA_MIDP_SECURITY_DOMAIN
, CKA_URL
,
1817 CKA_HASH_OF_SUBJECT_PUBLIC_KEY
, CKA_HASH_OF_ISSUER_PUBLIC_KEY
,
1818 CKA_CHECK_VALUE
, CKA_KEY_TYPE
, CKA_SUBJECT
, CKA_ID
, CKA_SENSITIVE
,
1819 CKA_ENCRYPT
, CKA_DECRYPT
, CKA_WRAP
, CKA_UNWRAP
, CKA_SIGN
, CKA_SIGN_RECOVER
,
1820 CKA_VERIFY
, CKA_VERIFY_RECOVER
, CKA_DERIVE
, CKA_START_DATE
, CKA_END_DATE
,
1821 CKA_MODULUS
, CKA_MODULUS_BITS
, CKA_PUBLIC_EXPONENT
, CKA_PRIVATE_EXPONENT
,
1822 CKA_PRIME_1
, CKA_PRIME_2
, CKA_EXPONENT_1
, CKA_EXPONENT_2
, CKA_COEFFICIENT
,
1823 CKA_PRIME
, CKA_SUBPRIME
, CKA_BASE
, CKA_PRIME_BITS
,
1824 CKA_SUB_PRIME_BITS
, CKA_VALUE_BITS
, CKA_VALUE_LEN
, CKA_EXTRACTABLE
,
1825 CKA_LOCAL
, CKA_NEVER_EXTRACTABLE
, CKA_ALWAYS_SENSITIVE
,
1826 CKA_KEY_GEN_MECHANISM
, CKA_MODIFIABLE
, CKA_EC_PARAMS
,
1827 CKA_EC_POINT
, CKA_SECONDARY_AUTH
, CKA_AUTH_PIN_FLAGS
,
1828 CKA_ALWAYS_AUTHENTICATE
, CKA_WRAP_WITH_TRUSTED
, CKA_WRAP_TEMPLATE
,
1829 CKA_UNWRAP_TEMPLATE
, CKA_HW_FEATURE_TYPE
, CKA_RESET_ON_INIT
,
1830 CKA_HAS_RESET
, CKA_PIXEL_X
, CKA_PIXEL_Y
, CKA_RESOLUTION
, CKA_CHAR_ROWS
,
1831 CKA_CHAR_COLUMNS
, CKA_COLOR
, CKA_BITS_PER_PIXEL
, CKA_CHAR_SETS
,
1832 CKA_ENCODING_METHODS
, CKA_MIME_TYPES
, CKA_MECHANISM_TYPE
,
1833 CKA_REQUIRED_CMS_ATTRIBUTES
, CKA_DEFAULT_CMS_ATTRIBUTES
,
1834 CKA_SUPPORTED_CMS_ATTRIBUTES
, CKA_NETSCAPE_URL
, CKA_NETSCAPE_EMAIL
,
1835 CKA_NETSCAPE_SMIME_INFO
, CKA_NETSCAPE_SMIME_TIMESTAMP
,
1836 CKA_NETSCAPE_PKCS8_SALT
, CKA_NETSCAPE_PASSWORD_CHECK
, CKA_NETSCAPE_EXPIRES
,
1837 CKA_NETSCAPE_KRL
, CKA_NETSCAPE_PQG_COUNTER
, CKA_NETSCAPE_PQG_SEED
,
1838 CKA_NETSCAPE_PQG_H
, CKA_NETSCAPE_PQG_SEED_BITS
, CKA_NETSCAPE_MODULE_SPEC
,
1839 CKA_TRUST_DIGITAL_SIGNATURE
, CKA_TRUST_NON_REPUDIATION
,
1840 CKA_TRUST_KEY_ENCIPHERMENT
, CKA_TRUST_DATA_ENCIPHERMENT
,
1841 CKA_TRUST_KEY_AGREEMENT
, CKA_TRUST_KEY_CERT_SIGN
, CKA_TRUST_CRL_SIGN
,
1842 CKA_TRUST_SERVER_AUTH
, CKA_TRUST_CLIENT_AUTH
, CKA_TRUST_CODE_SIGNING
,
1843 CKA_TRUST_EMAIL_PROTECTION
, CKA_TRUST_IPSEC_END_SYSTEM
,
1844 CKA_TRUST_IPSEC_TUNNEL
, CKA_TRUST_IPSEC_USER
, CKA_TRUST_TIME_STAMPING
,
1845 CKA_TRUST_STEP_UP_APPROVED
, CKA_CERT_SHA1_HASH
, CKA_CERT_MD5_HASH
,
1846 CKA_NETSCAPE_DB
, CKA_NETSCAPE_TRUST
, CKA_NSS_OVERRIDE_EXTENSIONS
1849 static int known_attributes_size
= sizeof(known_attributes
)/
1850 sizeof(known_attributes
[0]);
1853 sftkdb_GetObjectTemplate(SDB
*source
, CK_OBJECT_HANDLE id
,
1854 CK_ATTRIBUTE
*ptemplate
, CK_ULONG
*max
)
1859 if (*max
< known_attributes_size
) {
1860 *max
= known_attributes_size
;
1861 return CKR_BUFFER_TOO_SMALL
;
1863 for (i
=0; i
< known_attributes_size
; i
++) {
1864 ptemplate
[i
].type
= known_attributes
[i
];
1865 ptemplate
[i
].pValue
= NULL
;
1866 ptemplate
[i
].ulValueLen
= 0;
1869 crv
= (*source
->sdb_GetAttributeValue
)(source
, id
,
1870 ptemplate
, known_attributes_size
);
1872 if ((crv
!= CKR_OK
) && (crv
!= CKR_ATTRIBUTE_TYPE_INVALID
)) {
1876 for (i
=0, j
=0; i
< known_attributes_size
; i
++, j
++) {
1877 while (i
< known_attributes_size
&& (ptemplate
[i
].ulValueLen
== -1)) {
1880 if (i
>= known_attributes_size
) {
1883 /* cheap optimization */
1887 ptemplate
[j
] = ptemplate
[i
];
1895 dump_attribute(CK_ATTRIBUTE
*attr
)
1897 unsigned char *buf
= attr
->pValue
;
1900 printf("%08x: (%d) ",attr
->type
, attr
->ulValueLen
);
1901 count
= attr
->ulValueLen
;
1902 if (count
> 10) count
= 10;
1903 for (i
=0; i
< count
; i
++) {
1904 printf("%02x",buf
[i
]);
1911 #define MAX_ATTRIBUTES 500
1913 sftkdb_copyObject(SFTKDBHandle
*handle
, CK_OBJECT_HANDLE id
, SECItem
*key
)
1915 CK_ATTRIBUTE
template[MAX_ATTRIBUTES
];
1916 CK_ATTRIBUTE
*ptemplate
;
1917 CK_ULONG max_attributes
= MAX_ATTRIBUTES
;
1918 SDB
*source
= handle
->update
;
1919 SDB
*target
= handle
->db
;
1923 ptemplate
= &template[0];
1924 id
&= SFTK_OBJ_ID_MASK
;
1925 crv
= sftkdb_GetObjectTemplate(source
, id
, ptemplate
, &max_attributes
);
1926 if (crv
== CKR_BUFFER_TOO_SMALL
) {
1927 ptemplate
= PORT_NewArray(CK_ATTRIBUTE
, max_attributes
);
1928 if (ptemplate
== NULL
) {
1929 crv
= CKR_HOST_MEMORY
;
1931 crv
= sftkdb_GetObjectTemplate(source
, id
,
1932 ptemplate
, &max_attributes
);
1935 if (crv
!= CKR_OK
) {
1939 for (i
=0; i
< max_attributes
; i
++) {
1940 ptemplate
[i
].pValue
= PORT_Alloc(ptemplate
[i
].ulValueLen
);
1941 if (ptemplate
[i
].pValue
== NULL
) {
1942 crv
= CKR_HOST_MEMORY
;
1946 crv
= (*source
->sdb_GetAttributeValue
)(source
, id
,
1947 ptemplate
, max_attributes
);
1948 if (crv
!= CKR_OK
) {
1952 crv
= sftkdb_CreateObject(handle
, target
, &id
, ptemplate
, max_attributes
);
1953 if (ptemplate
&& ptemplate
!= template) {
1954 PORT_Free(ptemplate
);
1959 for (i
=0; i
< max_attributes
; i
++) {
1960 if (ptemplate
[i
].pValue
) {
1961 PORT_Memset(ptemplate
[i
].pValue
, 0, ptemplate
[i
].ulValueLen
);
1962 PORT_Free(ptemplate
[i
].pValue
);
1965 if (ptemplate
!= template) {
1966 PORT_Free(ptemplate
);
1975 * update a new database from an old one, now that we have the key
1978 sftkdb_update(SFTKDBHandle
*handle
, SECItem
*key
)
1980 SDBFind
*find
= NULL
;
1981 CK_ULONG idCount
= MAX_IDS
;
1982 CK_OBJECT_HANDLE ids
[MAX_IDS
];
1984 PRBool inTransaction
= PR_FALSE
;
1987 if (handle
== NULL
) {
1990 if (handle
->update
== NULL
) {
1994 /* find all the objects */
1995 crv
= sftkdb_FindObjectsInit(handle
, NULL
, 0, &find
);
1997 if (crv
!= CKR_OK
) {
2000 while ((crv
== CKR_OK
) && (idCount
== MAX_IDS
)) {
2001 crv
= sftkdb_FindObjects(handle
, find
, ids
, MAX_IDS
, &idCount
);
2002 for (i
=0; (crv
== CKR_OK
) && (i
< idCount
); i
++) {
2003 crv
= sftkdb_copyObject(handle
, ids
[i
], key
);
2006 crv2
= sftkdb_FindObjectsFinal(handle
, find
);
2007 if (crv
== CKR_OK
) crv
= crv2
;
2010 /* update Meta data - even if we didn't update objects */
2011 if (handle
->type
== SFTK_KEYDB_TYPE
) {
2012 SDBPasswordEntry entry
;
2013 crv
= (*handle
->db
->sdb_Begin
)(handle
->db
);
2014 if (crv
!= CKR_OK
) {
2017 inTransaction
= PR_TRUE
;
2018 crv
= (*handle
->update
->sdb_GetPWEntry
)(handle
->update
, & entry
);
2019 if (crv
!= CKR_OK
) {
2022 crv
= (*handle
->db
->sdb_PutPWEntry
)(handle
->db
, &entry
);
2023 if (crv
!= CKR_OK
) {
2026 crv
= (*handle
->db
->sdb_Commit
)(handle
->db
);
2027 inTransaction
= PR_FALSE
;
2030 if (inTransaction
) {
2031 (*handle
->db
->sdb_Abort
)(handle
->db
);
2033 if (handle
->update
) {
2034 (*handle
->update
->sdb_Close
)(handle
->update
);
2035 handle
->update
= NULL
;
2041 * return success if we have a valid password entry.
2042 * This is will show up outside of PKCS #11 as CKF_USER_PIN_INIT
2043 * in the token flags.
2046 sftkdb_HasPasswordSet(SFTKDBHandle
*keydb
)
2048 SDBPasswordEntry entry
;
2052 if (keydb
== NULL
) {
2056 db
= GET_SDB(keydb
);
2061 crv
= (*db
->sdb_GetPWEntry
)(db
, &entry
);
2062 return (crv
== CKR_OK
) ? SECSuccess
: SECFailure
;
2065 #define SFTK_PW_CHECK_STRING "password-check"
2066 #define SFTK_PW_CHECK_LEN 14
2069 * check if the supplied password is valid
2072 sftkdb_CheckPassword(SFTKDBHandle
*keydb
, const char *pw
)
2075 SDBPasswordEntry entry
;
2077 SECItem
*result
= NULL
;
2081 if (keydb
== NULL
) {
2085 db
= GET_SDB(keydb
);
2093 if (pw
== NULL
) pw
="";
2095 /* get the entry from the database */
2096 crv
= (*db
->sdb_GetPWEntry
)(db
, &entry
);
2097 if (crv
!= CKR_OK
) {
2102 /* get our intermediate key based on the entry salt value */
2103 rv
= sftkdb_passwordToKey(keydb
, &entry
, pw
, &key
);
2104 if (rv
!= SECSuccess
) {
2108 /* decrypt the entry value */
2109 rv
= sftkdb_decrypt(&key
, &entry
.value
, &result
);
2110 if (rv
!= SECSuccess
) {
2114 /* if it's what we expect, update our key in the database handle and
2116 if ((result
->len
== SFTK_PW_CHECK_LEN
) &&
2117 PORT_Memcmp(result
->data
, SFTK_PW_CHECK_STRING
, SFTK_PW_CHECK_LEN
) == 0){
2118 /* load the keys, so the keydb can parse it's key set */
2119 sftkdb_switchKeys(keydb
, &key
);
2120 if (keydb
->update
) {
2121 /* update the peer certdb if it exists */
2122 if (keydb
->peerDB
) {
2123 sftkdb_update(keydb
->peerDB
, &key
);
2125 sftkdb_update(keydb
, &key
);
2129 /*PORT_SetError( bad password); */
2134 PORT_ZFree(key
.data
,key
.len
);
2137 SECITEM_FreeItem(result
,PR_TRUE
);
2143 * return Success if the there is a cached password key.
2146 sftkdb_PWCached(SFTKDBHandle
*keydb
)
2148 return keydb
->passwordKey
.data
? SECSuccess
: SECFailure
;
2152 sftk_convertPrivateAttributes(SFTKDBHandle
*keydb
, CK_OBJECT_HANDLE id
,
2157 CK_ATTRIBUTE
*first
, *last
;
2158 CK_ATTRIBUTE privAttrs
[] = {
2159 {CKA_VALUE
, NULL
, 0},
2160 {CKA_PRIVATE_EXPONENT
, NULL
, 0},
2161 {CKA_PRIME_1
, NULL
, 0},
2162 {CKA_PRIME_2
, NULL
, 0},
2163 {CKA_EXPONENT_1
, NULL
, 0},
2164 {CKA_EXPONENT_2
, NULL
, 0},
2165 {CKA_COEFFICIENT
, NULL
, 0} };
2166 CK_ULONG privAttrCount
= sizeof(privAttrs
)/sizeof(CK_ATTRIBUTE
);
2167 PLArenaPool
*arena
= NULL
;
2171 /* get a new arena to simplify cleanup */
2172 arena
= PORT_NewArena(1024);
2178 * STEP 1. Read the old attributes in the clear.
2181 /* Get the attribute sizes.
2182 * ignore the error code, we will have unknown attributes here */
2183 crv2
= sftkdb_GetAttributeValue(keydb
, id
, privAttrs
, privAttrCount
);
2186 * find the valid block of attributes and fill allocate space for
2188 first
= last
= NULL
;
2189 for (i
=0; i
< privAttrCount
; i
++) {
2190 /* find the block of attributes that are appropriate for this
2191 * objects. There should only be once contiguous block, if not
2194 * find the first and last good entry.
2196 if ((privAttrs
[i
].ulValueLen
== -1) || (privAttrs
[i
].ulValueLen
== 0)){
2197 if (!first
) continue;
2199 /* previous entry was last good entry */
2200 last
= &privAttrs
[i
-1];
2205 first
= &privAttrs
[i
];
2208 /* OOPS, we've found another good entry beyond the end of the
2209 * last good entry, we need to fail here. */
2210 crv
= CKR_GENERAL_ERROR
;
2213 privAttrs
[i
].pValue
= PORT_ArenaAlloc(arena
,privAttrs
[i
].ulValueLen
);
2214 if (privAttrs
[i
].pValue
== NULL
) {
2215 crv
= CKR_HOST_MEMORY
;
2219 if (first
== NULL
) {
2220 /* no valid entries found, return error based on crv2 */
2225 last
= &privAttrs
[privAttrCount
-1];
2227 if (crv
!= CKR_OK
) {
2231 /* read the attributes */
2232 count
= (last
-first
)+1;
2233 crv
= sftkdb_GetAttributeValue(keydb
, id
, first
, count
);
2234 if (crv
!= CKR_OK
) {
2241 * STEP 2: read the encrypt the attributes with the new key.
2243 for (i
=0; i
< count
; i
++) {
2248 plainText
.data
= first
[i
].pValue
;
2249 plainText
.len
= first
[i
].ulValueLen
;
2250 rv
= sftkdb_encrypt(arena
, newKey
, &plainText
, &result
);
2251 if (rv
!= SECSuccess
) {
2254 first
[i
].pValue
= result
->data
;
2255 first
[i
].ulValueLen
= result
->len
;
2256 /* clear our sensitive data out */
2257 PORT_Memset(plainText
.data
, 0, plainText
.len
);
2262 * STEP 3: write the newly encrypted attributes out directly
2264 id
&= SFTK_OBJ_ID_MASK
;
2265 keydb
->newKey
= newKey
;
2266 crv
= (*keydb
->db
->sdb_SetAttributeValue
)(keydb
->db
, id
, first
, count
);
2267 keydb
->newKey
= NULL
;
2268 if (crv
!= CKR_OK
) {
2273 /* free up our mess */
2274 /* NOTE: at this point we know we've cleared out any unencrypted data */
2275 PORT_FreeArena(arena
, PR_FALSE
);
2279 /* there may be unencrypted data, clear it out down */
2280 PORT_FreeArena(arena
, PR_TRUE
);
2286 * must be called with the old key active.
2289 sftkdb_convertPrivateObjects(SFTKDBHandle
*keydb
, SECItem
*newKey
)
2291 SDBFind
*find
= NULL
;
2292 CK_ULONG idCount
= MAX_IDS
;
2293 CK_OBJECT_HANDLE ids
[MAX_IDS
];
2297 /* find all the private objects */
2298 crv
= sftkdb_FindObjectsInit(keydb
, NULL
, 0, &find
);
2300 if (crv
!= CKR_OK
) {
2304 while ((crv
== CKR_OK
) && (idCount
== MAX_IDS
)) {
2305 crv
= sftkdb_FindObjects(keydb
, find
, ids
, MAX_IDS
, &idCount
);
2306 for (i
=0; (crv
== CKR_OK
) && (i
< idCount
); i
++) {
2308 rv
= sftk_convertPrivateAttributes(keydb
, ids
[i
], newKey
);
2309 if (rv
!= SECSuccess
) {
2310 crv
= CKR_GENERAL_ERROR
;
2311 /* error should be already set here */
2315 crv2
= sftkdb_FindObjectsFinal(keydb
, find
);
2316 if (crv
== CKR_OK
) crv
= crv2
;
2317 if (crv
!= CKR_OK
) {
2326 * change the database password.
2329 sftkdb_ChangePassword(SFTKDBHandle
*keydb
, char *oldPin
, char *newPin
)
2331 SECStatus rv
= SECSuccess
;
2334 SECItem
*result
= NULL
;
2335 SDBPasswordEntry entry
;
2339 if (keydb
== NULL
) {
2343 db
= GET_SDB(keydb
);
2350 /* make sure we have a valid old pin */
2351 crv
= (*keydb
->db
->sdb_Begin
)(keydb
->db
);
2352 if (crv
!= CKR_OK
) {
2356 crv
= (*db
->sdb_GetPWEntry
)(db
, &entry
);
2357 if (crv
== CKR_OK
) {
2358 rv
= sftkdb_CheckPassword(keydb
, oldPin
);
2359 if (rv
== SECFailure
) {
2363 entry
.salt
.data
= entry
.data
;
2364 entry
.salt
.len
= SALT_LENGTH
;
2365 RNG_GenerateGlobalRandomBytes(entry
.data
,entry
.salt
.len
);
2368 rv
= sftkdb_passwordToKey(keydb
, &entry
, newPin
, &newKey
);
2369 if (rv
!= SECSuccess
) {
2375 * convert encrypted entries here.
2377 rv
= sftkdb_convertPrivateObjects(keydb
, &newKey
);
2378 if (rv
!= SECSuccess
) {
2383 plainText
.data
= (unsigned char *)SFTK_PW_CHECK_STRING
;
2384 plainText
.len
= SFTK_PW_CHECK_LEN
;
2386 rv
= sftkdb_encrypt(NULL
, &newKey
, &plainText
, &result
);
2387 if (rv
!= SECSuccess
) {
2390 entry
.value
.data
= result
->data
;
2391 entry
.value
.len
= result
->len
;
2392 crv
= (*keydb
->db
->sdb_PutPWEntry
)(keydb
->db
, &entry
);
2393 if (crv
!= CKR_OK
) {
2397 crv
= (*keydb
->db
->sdb_Commit
)(keydb
->db
);
2398 if (crv
!= CKR_OK
) {
2403 keydb
->newKey
= NULL
;
2405 sftkdb_switchKeys(keydb
, &newKey
);
2409 PORT_ZFree(newKey
.data
,newKey
.len
);
2412 SECITEM_FreeItem(result
, PR_FALSE
);
2414 if (rv
!= SECSuccess
) {
2415 (*keydb
->db
->sdb_Abort
)(keydb
->db
);
2422 * loose our cached password
2425 sftkdb_ClearPassword(SFTKDBHandle
*keydb
)
2430 sftkdb_switchKeys(keydb
, &oldKey
);
2432 PORT_ZFree(oldKey
.data
, oldKey
.len
);
2437 /******************************************************************
2438 * DB handle managing functions.
2440 * These functions are called by softoken to initialize, acquire,
2441 * and release database handles.
2444 /* release a database handle */
2446 sftk_freeDB(SFTKDBHandle
*handle
)
2450 if (!handle
) return;
2451 ref
= PR_AtomicDecrement(&handle
->ref
);
2453 sftkdb_CloseDB(handle
);
2460 * acquire a database handle for a certificate db
2461 * (database for public objects)
2464 sftk_getCertDB(SFTKSlot
*slot
)
2466 SFTKDBHandle
*dbHandle
;
2468 PZ_Lock(slot
->slotLock
);
2469 dbHandle
= slot
->certDB
;
2471 PR_AtomicIncrement(&dbHandle
->ref
);
2473 PZ_Unlock(slot
->slotLock
);
2478 * acquire a database handle for a key database
2479 * (database for private objects)
2482 sftk_getKeyDB(SFTKSlot
*slot
)
2484 SFTKDBHandle
*dbHandle
;
2486 PZ_Lock(slot
->slotLock
);
2487 dbHandle
= slot
->keyDB
;
2489 PR_AtomicIncrement(&dbHandle
->ref
);
2491 PZ_Unlock(slot
->slotLock
);
2496 * acquire the database for a specific object. NOTE: objectID must point
2497 * to a Token object!
2500 sftk_getDBForTokenObject(SFTKSlot
*slot
, CK_OBJECT_HANDLE objectID
)
2502 SFTKDBHandle
*dbHandle
;
2504 PZ_Lock(slot
->slotLock
);
2505 dbHandle
= objectID
& SFTK_KEYDB_TYPE
? slot
->keyDB
: slot
->certDB
;
2507 PR_AtomicIncrement(&dbHandle
->ref
);
2509 PZ_Unlock(slot
->slotLock
);
2514 * initialize a new database handle
2516 static SFTKDBHandle
*
2517 sftk_NewDBHandle(SDB
*sdb
, int type
)
2519 SFTKDBHandle
*handle
= PORT_New(SFTKDBHandle
);
2522 handle
->update
= NULL
;
2523 handle
->peerDB
= NULL
;
2524 handle
->newKey
= NULL
;
2525 handle
->type
= type
;
2526 handle
->passwordKey
.data
= NULL
;
2527 handle
->passwordKey
.len
= 0;
2528 handle
->passwordLock
= NULL
;
2529 if (type
== SFTK_KEYDB_TYPE
) {
2530 handle
->passwordLock
= PZ_NewLock();
2532 sdb
->app_private
= handle
;
2537 * reset the key database to it's uninitialized state. This call
2538 * will clear all the key entried.
2541 sftkdb_ResetKeyDB(SFTKDBHandle
*handle
)
2545 /* only rest the key db */
2546 if (handle
->type
!= SFTK_KEYDB_TYPE
) {
2549 crv
= sftkdb_ResetDB(handle
);
2550 if (crv
!= CKR_OK
) {
2558 sftk_oldVersionExists(const char *dir
, int version
)
2561 PRStatus exists
= PR_FAILURE
;
2564 for (i
=version
; i
> 1 ; i
--) {
2565 file
= PR_smprintf("%s%d.db",dir
,i
);
2569 exists
= PR_Access(file
, PR_ACCESS_EXISTS
);
2570 PR_smprintf_free(file
);
2571 if (exists
== PR_SUCCESS
) {
2579 sftk_hasLegacyDB(const char *confdir
, const char *certPrefix
,
2580 const char *keyPrefix
, int certVersion
, int keyVersion
)
2585 dir
= PR_smprintf("%s/%scert", confdir
, certPrefix
);
2590 exists
= sftk_oldVersionExists(dir
, certVersion
);
2591 PR_smprintf_free(dir
);
2596 dir
= PR_smprintf("%s/%skey", confdir
, keyPrefix
);
2601 exists
= sftk_oldVersionExists(dir
, keyVersion
);
2602 PR_smprintf_free(dir
);
2607 * initialize certificate and key database handles as a pair.
2609 * This function figures out what type of database we are opening and
2610 * calls the appropriate low level function to open the database.
2611 * It also figures out whether or not to setup up automatic update.
2614 sftk_DBInit(const char *configdir
, const char *certPrefix
,
2615 const char *keyPrefix
, PRBool readOnly
, PRBool noCertDB
,
2616 PRBool noKeyDB
, PRBool forceOpen
,
2617 SFTKDBHandle
**certDB
, SFTKDBHandle
**keyDB
)
2619 const char *confdir
;
2621 char *appName
= NULL
;
2622 SDB
*keySDB
, *certSDB
;
2624 int flags
= SDB_RDONLY
;
2625 PRBool newInit
= PR_FALSE
;
2626 PRBool needUpdate
= PR_FALSE
;
2635 if (noKeyDB
&& noCertDB
) {
2638 confdir
= sftk_EvaluateConfigDir(configdir
, &dbType
, &appName
);
2641 * now initialize the appropriate database
2645 crv
= sftkdbCall_open(confdir
, certPrefix
, keyPrefix
, 8, 3, flags
,
2646 noCertDB
? NULL
: &certSDB
, noKeyDB
? NULL
: &keySDB
);
2648 case SDB_MULTIACCESS
:
2649 crv
= sftkdbCall_open(configdir
, certPrefix
, keyPrefix
, 8, 3, flags
,
2650 noCertDB
? NULL
: &certSDB
, noKeyDB
? NULL
: &keySDB
);
2653 case SDB_EXTERN
: /* SHOULD open a loadable db */
2654 crv
= s_open(confdir
, certPrefix
, keyPrefix
, 9, 4, flags
,
2655 noCertDB
? NULL
: &certSDB
, noKeyDB
? NULL
: &keySDB
, &newInit
);
2658 * if we failed to open the DB's read only, use the old ones if
2661 if (crv
!= CKR_OK
&& (flags
== SDB_RDONLY
)) {
2662 if (sftk_hasLegacyDB(confdir
, certPrefix
, keyPrefix
, 8, 3)) {
2663 /* we have legacy databases, if we failed to open the new format
2664 * DB's read only, just use the legacy ones */
2665 crv
= sftkdbCall_open(confdir
, certPrefix
,
2666 keyPrefix
, 8, 3, flags
, noCertDB
? NULL
: &certSDB
,
2667 noKeyDB
? NULL
: &keySDB
);
2669 } else if (newInit
&& crv
== CKR_OK
) {
2670 /* if the new format DB was also a newly created DB, and we
2671 * succeeded, then need to update that new database with data
2672 * from the existing legacy DB */
2673 if (sftk_hasLegacyDB(confdir
, certPrefix
, keyPrefix
, 8, 3)) {
2679 crv
= CKR_GENERAL_ERROR
; /* can't happen, EvaluationConfigDir MUST
2680 * return one of the types we already
2683 if (crv
!= CKR_OK
) {
2687 *certDB
= sftk_NewDBHandle(certSDB
, SFTK_CERTDB_TYPE
);
2692 *keyDB
= sftk_NewDBHandle(keySDB
, SFTK_KEYDB_TYPE
);
2697 /* link them together */
2699 (*certDB
)->peerDB
= *keyDB
;
2702 (*keyDB
)->peerDB
= *certDB
;
2706 SDB
*updateCert
= NULL
;
2707 SDB
*updateKey
= NULL
;
2710 crv2
= sftkdbCall_open(confdir
, certPrefix
, keyPrefix
, 8, 3, flags
,
2711 noCertDB
? NULL
: &updateCert
, noKeyDB
? NULL
: &updateKey
);
2712 if (crv2
== CKR_OK
) {
2714 (*certDB
)->update
= updateCert
;
2715 updateCert
->app_private
= (*certDB
);
2718 (*keyDB
)->update
= updateKey
;
2719 updateKey
->app_private
= (*keyDB
);
2721 /* we don't have a key DB, update the certificate DB now */
2722 sftkdb_update(*certDB
, NULL
);
2730 return forceOpen
? CKR_OK
: crv
;
2734 sftkdb_Shutdown(void)
2737 sftkdbCall_Shutdown();