security/nss/lib/softoken/sftkdb.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial