Add Transactions (still need to add transactions on database upgrade).
authorrelyea%netscape.com
Thu, 16 May 2002 20:39:04 +0000
changeset 3137 1c356b43e7043e3b87a6c589fd7d3036f0174de3
parent 3134 3ed388b98ae439900dadb3a858342567ffe050a7 (current diff)
parent 3135 a3917dc19461a6170dd7ed09d147b1531387934d (diff)
child 3138 9c037d2e8864f5efe9ecf7c99c17b84545ccf5db
push idunknown
push userunknown
push dateunknown
Add Transactions (still need to add transactions on database upgrade). Make trust objects their own objects to reduce a couple of unnecessary cert decodes.
security/nss/lib/softoken/cdbhdl.h
security/nss/lib/softoken/dbinit.c
security/nss/lib/softoken/keydb.c
security/nss/lib/softoken/pcert.h
security/nss/lib/softoken/pcertdb.c
security/nss/lib/softoken/pcertt.h
security/nss/lib/softoken/pkcs11.c
security/nss/lib/softoken/pkcs11u.c
--- a/security/nss/lib/softoken/cdbhdl.h
+++ b/security/nss/lib/softoken/cdbhdl.h
@@ -63,9 +63,11 @@ struct NSSLOWCERTCertDBHandleStr {
 
 typedef DB * (*rdbfunc)(const char *appName, const char *prefix, 
 				const char *type, int flags);
 
 DB * rdbopen(const char *appName, const char *prefix, 
 				const char *type, int flags);
 
 SECStatus db_Copy(DB *dest,DB *src);
+int db_BeginTransaction(DB *db);
+int db_FinishTransaction(DB *db, PRBool abort);
 #endif
--- a/security/nss/lib/softoken/dbinit.c
+++ b/security/nss/lib/softoken/dbinit.c
@@ -251,16 +251,17 @@ pk11_DBShutdown(NSSLOWCERTCertDBHandle *
 
     if (keyHandle) {
     	nsslowkey_CloseKeyDB(keyHandle);
 	keyHandle= NULL;
     }
 }
 
 static rdbfunc pk11_rdbfunc;
+static void *pk11_tnx;
 
 /* NOTE: SHLIB_SUFFIX is defined on the command line */
 #define RDBLIB "rdb."SHLIB_SUFFIX
 
 DB * rdbopen(const char *appName, const char *prefix, 
 				const char *type, int flags)
 {
     PRLibrary *lib;
@@ -278,24 +279,57 @@ DB * rdbopen(const char *appName, const 
 
     if (!lib) {
 	return NULL;
     }
 
     /* get the entry point */
     pk11_rdbfunc = (rdbfunc) PR_FindSymbol(lib,"rdbopen");
     if (pk11_rdbfunc) {
-	return (*pk11_rdbfunc)(appName,prefix,type,flags);
+	db = (*pk11_rdbfunc)(appName,prefix,type,flags);
+	return db;
     }
 
     /* couldn't find the entry point, unload the library and fail */
     PR_UnloadLibrary(lib);
     return NULL;
 }
 
+struct RDBStr {
+    DB	db;
+    int (*xactstart)(DB *db);
+    int (*xactdone)(DB *db, PRBool abort);
+};
+
+#define DB_RDB ((DBTYPE) 0xff)
+
+int
+db_BeginTransaction(DB *db)
+{
+    RDB *rdb = (RDB *)db;
+    if (db->type != DB_RDB) {
+	return 0;
+    }
+
+    return rdb->xactstart(db);
+}
+
+int
+db_FinishTransaction(DB *db, PRBool abort)
+{
+    RDB *rdb = (RDB *)db;
+    if (db->type != DB_RDB) {
+	return 0;
+    }
+
+    return rdb->xactdone(db, abort);
+}
+
+
+
 SECStatus
 db_Copy(DB *dest,DB *src)
 {
     int ret;
     DBT key,data;
     ret = (*src->seq)(src, &key, &data, R_FIRST);
     if (ret)  {
 	return SECSuccess;
--- a/security/nss/lib/softoken/keydb.c
+++ b/security/nss/lib/softoken/keydb.c
@@ -2250,16 +2250,21 @@ ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle
     /* traverse the database, collecting the keys of all records */
     keylist.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if ( keylist.arena == NULL ) 
     {
 	PORT_SetError(SEC_ERROR_NO_MEMORY);
 	return(SECFailure);
     }
     keylist.head = NULL;
+
+    rv = db_BeginTransaction(handle->db);
+    if (rv != SECSuccess) {
+	goto loser;
+    }
     
     /* TNH - TraverseKeys should not be public, since it exposes
        the underlying DBT data type. */
     rv = nsslowkey_TraverseKeys(handle, sec_add_key_to_list, (void *)&keylist);
     if ( rv != SECSuccess ) 
 	goto loser;
 
     /* walk the list, re-encrypting each entry */
@@ -2294,17 +2299,20 @@ ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle
 	    newkey.data = privkey->u.dsa.publicValue.data;
 	    newkey.size = privkey->u.dsa.publicValue.len;
 	    break;
 	  case NSSLOWKEYDHKey:
 	    newkey.data = privkey->u.dh.publicValue.data;
 	    newkey.size = privkey->u.dh.publicValue.len;
 	    break;
 	  default:
-	    return SECFailure;
+	    /* should we continue here and loose the key? */
+	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
+	    rv = SECFailure;
+	    goto loser;
 	}
 
 	rv = seckey_put_private_key(handle, &newkey, newpwitem, privkey,
 				    nickname, PR_TRUE, new_algorithm);
 	
 	if ( rv != SECSuccess ) 
 	{
 	    PORT_SetError(SEC_ERROR_BAD_DATABASE);
@@ -2315,16 +2323,18 @@ ChangeKeyDBPasswordAlg(NSSLOWKEYDBHandle
 	/* next node */
 	node = node->next;
     }
 
     rv = nsslowkey_SetKeyDBPasswordAlg(handle, newpwitem, new_algorithm);
 
 loser:
 
+    db_FinishTransaction(handle->db,rv == SECSuccess);
+
     /* free the arena */
     if ( keylist.arena ) {
 	PORT_FreeArena(keylist.arena, PR_FALSE);
     }
     
     return(rv);
 }
 
--- a/security/nss/lib/softoken/pcert.h
+++ b/security/nss/lib/softoken/pcert.h
@@ -44,16 +44,18 @@ SEC_BEGIN_PROTOS
 ** Add a DER encoded certificate to the permanent database.
 **	"derCert" is the DER encoded certificate.
 **	"nickname" is the nickname to use for the cert
 **	"trust" is the trust parameters for the cert
 */
 SECStatus nsslowcert_AddPermCert(NSSLOWCERTCertDBHandle *handle, 
 			NSSLOWCERTCertificate *cert,
 				char *nickname, NSSLOWCERTCertTrust *trust);
+SECStatus nsslowcert_AddPermNickname(NSSLOWCERTCertDBHandle *dbhandle,
+				NSSLOWCERTCertificate *cert, char *nickname);
 
 SECStatus nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert);
 
 typedef SECStatus (PR_CALLBACK * PermCertCallback)(NSSLOWCERTCertificate *cert,
                                                    SECItem *k, void *pdata);
 /*
 ** Traverse the entire permanent database, and pass the certs off to a
 ** user supplied function.
@@ -83,36 +85,55 @@ NSSLOWCERTCertDBHandle *nsslowcert_GetDe
 NSSLOWKEYPublicKey *nsslowcert_ExtractPublicKey(NSSLOWCERTCertificate *);
 
 NSSLOWCERTCertificate *
 nsslowcert_NewTempCertificate(NSSLOWCERTCertDBHandle *handle, SECItem *derCert,
                         char *nickname, PRBool isperm, PRBool copyDER);
 NSSLOWCERTCertificate *
 nsslowcert_DupCertificate(NSSLOWCERTCertificate *cert);
 void nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert);
+void nsslowcert_DestroyTrust(NSSLOWCERTTrust *Trust);
 
 /*
  * Lookup a certificate in the databases without locking
  *	"certKey" is the database key to look for
  *
  * XXX - this should be internal, but pkcs 11 needs to call it during a
  * traversal.
  */
 NSSLOWCERTCertificate *
 nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey);
 
 /*
+ * Lookup trust for a certificate in the databases without locking
+ *	"certKey" is the database key to look for
+ *
+ * XXX - this should be internal, but pkcs 11 needs to call it during a
+ * traversal.
+ */
+NSSLOWCERTTrust *
+nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey);
+
+/*
 ** Generate a certificate key from the issuer and serialnumber, then look it
 ** up in the database.  Return the cert if found.
 **	"issuerAndSN" is the issuer and serial number to look for
 */
 extern NSSLOWCERTCertificate *
 nsslowcert_FindCertByIssuerAndSN (NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN);
 
 /*
+** Generate a certificate key from the issuer and serialnumber, then look it
+** up in the database.  Return the cert if found.
+**	"issuerAndSN" is the issuer and serial number to look for
+*/
+extern NSSLOWCERTTrust *
+nsslowcert_FindTrustByIssuerAndSN (NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN);
+
+/*
 ** Find a certificate in the database by a DER encoded certificate
 **	"derCert" is the DER encoded certificate
 */
 extern NSSLOWCERTCertificate *
 nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert);
 
 /* convert an email address to lower case */
 char *nsslowcert_FixupEmailAddr(char *emailAddr);
@@ -184,16 +205,16 @@ nsslowcert_SaveSMimeProfile(NSSLOWCERTCe
  * Change the trust attributes of a certificate and make them permanent
  * in the database.
  */
 SECStatus
 nsslowcert_ChangeCertTrust(NSSLOWCERTCertDBHandle *handle, 
 	  	NSSLOWCERTCertificate *cert, NSSLOWCERTCertTrust *trust);
 
 PRBool
-nsslowcert_hasTrust(NSSLOWCERTCertificate *cert);
+nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust);
 
 void
 nsslowcert_DestroyGlobalLocks(void);
 
 SEC_END_PROTOS
 
  #endif /* _PCERTDB_H_ */
--- a/security/nss/lib/softoken/pcertdb.c
+++ b/security/nss/lib/softoken/pcertdb.c
@@ -3744,36 +3744,45 @@ DeletePermCert(NSSLOWCERTCertificate *ce
 	rv = DeleteDBNicknameEntry(cert->dbhandle, cert->nickname);
 	if ( rv != SECSuccess ) {
 	    ret = SECFailure;
 	}
     }
     
     rv = RemovePermSubjectNode(cert);
 
+
     return(ret);
 }
 
 /*
  * Delete a certificate from the permanent database.
  */
 SECStatus
 nsslowcert_DeletePermCertificate(NSSLOWCERTCertificate *cert)
 {
     SECStatus rv;
     
     nsslowcert_LockDB(cert->dbhandle);
+
+    rv = db_BeginTransaction(cert->dbhandle->permCertDB);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
     /* delete the records from the permanent database */
     rv = DeletePermCert(cert);
 
     /* get rid of dbcert and stuff pointing to it */
     DestroyDBEntry((certDBEntry *)cert->dbEntry);
     cert->dbEntry = NULL;
     cert->trust = NULL;
 
+    db_FinishTransaction(cert->dbhandle->permCertDB,rv != SECSuccess);
+loser:
+	
     nsslowcert_UnlockDB(cert->dbhandle);
     return(rv);
 }
 
 /*
  * Traverse all of the entries in the database of a particular type
  * call the given function for each one.
  */
@@ -3843,16 +3852,32 @@ DecodeACert(NSSLOWCERTCertDBHandle *hand
     cert->trust = &entry->trust;
 
     return(cert);
 
 loser:
     return(0);
 }
 
+static NSSLOWCERTTrust * 
+DecodeTrustEntry(NSSLOWCERTCertDBHandle *handle, certDBEntryCert *entry,				SECItem *dbKey)
+{
+    NSSLOWCERTTrust *trust = PORT_Alloc(sizeof(NSSLOWCERTTrust));
+    if (trust == NULL) {
+	return trust;
+    }
+    trust->dbhandle = handle;
+    trust->dbEntry = entry;
+    SECITEM_CopyItem(NULL, &trust->dbKey , dbKey);
+    trust->trust = &entry->trust;
+    trust->derCert = &entry->derCert;
+
+    return(trust);
+}
+
 typedef struct {
     PermCertCallback certfunc;
     NSSLOWCERTCertDBHandle *handle;
     void *data;
 } PermCertCallbackState;
 
 /*
  * traversal callback to decode certs and call callers callback
@@ -4038,16 +4063,21 @@ nsslowcert_AddPermCert(NSSLOWCERTCertDBH
     NSSLOWCERTCertificate *cert, char *nickname, NSSLOWCERTCertTrust *trust)
 {
     char *oldnn;
     certDBEntryCert *entry;
     PRBool conflict;
     SECStatus ret;
 
     nsslowcert_LockDB(dbhandle);
+    rv = db_BeginTransaction(dbhandle->permCertDB);
+    if (rv != SECSuccess) {
+	nsslowcert_UnlockDB(dbhandle);
+	return SECFailure;
+    }
     
     PORT_Assert(!cert->dbEntry);
 
     /* don't add a conflicting nickname */
     conflict = nsslowcert_CertNicknameConflict(nickname, &cert->derSubject,
 					dbhandle);
     if ( conflict ) {
 	ret = SECFailure;
@@ -4065,16 +4095,17 @@ nsslowcert_AddPermCert(NSSLOWCERTCertDBH
     }
     
     cert->nickname = (entry->nickname) ? PORT_ArenaStrdup(cert->arena,entry->nickname) : NULL;
     cert->trust = &entry->trust;
     cert->dbEntry = entry;
     
     ret = SECSuccess;
 done:
+    db_FinishTransaction(dbhandle->permCertDB, ret != SECSuccess);
     nsslowcert_UnlockDB(dbhandle);
     return(ret);
 }
 
 /*
  * Open the certificate database and index databases.  Create them if
  * they are not there or bad.
  */
@@ -4143,37 +4174,116 @@ FindCertByKey(NSSLOWCERTCertDBHandle *ha
     if ( entry == NULL ) {
  	goto loser;
     }
   
     /* inherit entry */  
     cert = DecodeACert(handle, entry);
 
 loser:
+    if (cert == NULL) {
+	if (entry) {
+	    DestroyDBEntry((certDBEntry *)entry);
+	}
+    }
+
     if ( locked ) {
 	nsslowcert_UnlockDB(handle);
     }
 
     if ( arena ) {
 	PORT_FreeArena(arena, PR_FALSE);
     }
     
     return(cert);
 }
 
 /*
+ * Lookup a certificate in the databases.
+ */
+static NSSLOWCERTTrust *
+FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey, PRBool lockdb)
+{
+    SECItem keyitem;
+    DBT key;
+    SECStatus rv;
+    NSSLOWCERTTrust *trust = NULL;
+    PRArenaPool *arena = NULL;
+    certDBEntryCert *entry;
+    PRBool locked = PR_FALSE;
+    
+    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+    if ( arena == NULL ) {
+	goto loser;
+    }
+    
+    rv = EncodeDBCertKey(certKey, arena, &keyitem);
+    if ( rv != SECSuccess ) {
+	goto loser;
+    }
+    
+    key.data = keyitem.data;
+    key.size = keyitem.len;
+    
+    if ( lockdb ) {
+	locked = PR_TRUE;
+	nsslowcert_LockDB(handle);
+    }
+	
+    /* find in perm database */
+    entry = ReadDBCertEntry(handle, certKey);
+	
+    if ( entry == NULL ) {
+ 	goto loser;
+    }
+
+    if (!nsslowcert_hasTrust(&entry->trust)) {
+	goto loser;
+    }
+  
+    /* inherit entry */  
+    trust = DecodeTrustEntry(handle, entry, certKey);
+
+loser:
+    if (trust == NULL) {
+	if (entry) {
+	    DestroyDBEntry((certDBEntry *)entry);
+	}
+    }
+
+    if ( locked ) {
+	nsslowcert_UnlockDB(handle);
+    }
+
+    if ( arena ) {
+	PORT_FreeArena(arena, PR_FALSE);
+    }
+    
+    return(trust);
+}
+
+/*
  * Lookup a certificate in the databases without locking
  */
 NSSLOWCERTCertificate *
 nsslowcert_FindCertByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
 {
     return(FindCertByKey(handle, certKey, PR_FALSE));
 }
 
 /*
+ * Lookup a trust object in the databases without locking
+ */
+NSSLOWCERTTrust *
+nsslowcert_FindTrustByKey(NSSLOWCERTCertDBHandle *handle, SECItem *certKey)
+{
+    return(FindTrustByKey(handle, certKey, PR_FALSE));
+}
+
+/*
  * Generate a key from an issuerAndSerialNumber, and find the
  * associated cert in the database.
  */
 NSSLOWCERTCertificate *
 nsslowcert_FindCertByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, NSSLOWCERTIssuerAndSN *issuerAndSN)
 {
     SECItem certKey;
     SECItem *sn = &issuerAndSN->serialNumber;
@@ -4246,16 +4356,104 @@ nsslowcert_FindCertByIssuerAndSN(NSSLOWC
     cert = nsslowcert_FindCertByKey(handle, &certKey);
     
     PORT_Free(certKey.data);
     
     return(cert);
 }
 
 /*
+ * Generate a key from an issuerAndSerialNumber, and find the
+ * associated cert in the database.
+ */
+NSSLOWCERTTrust *
+nsslowcert_FindTrustByIssuerAndSN(NSSLOWCERTCertDBHandle *handle, 
+					NSSLOWCERTIssuerAndSN *issuerAndSN)
+{
+    SECItem certKey;
+    SECItem *sn = &issuerAndSN->serialNumber;
+    SECItem *issuer = &issuerAndSN->derIssuer;
+    NSSLOWCERTTrust *trust;
+    int data_left = sn->len-1;
+    int data_len = sn->len;
+    int index = 0;
+
+    /* automatically detect DER encoded serial numbers and remove the der
+     * encoding since the database expects unencoded data. 
+     * if it's DER encoded, there must be at least 3 bytes, tag, len, data */
+    if ((sn->len >= 3) && (sn->data[0] == 0x2)) {
+	/* remove the der encoding of the serial number before generating the
+	 * key.. */
+	data_left = sn->len-2;
+	data_len = sn->data[1];
+	index = 2;
+
+	/* extended length ? (not very likely for a serial number) */
+	if (data_len & 0x80) {
+	    int len_count = data_len & 0x7f;
+
+	    data_len = 0;
+	    data_left -= len_count;
+	    if (data_left > 0) {
+		while (len_count --) {
+		    data_len = (data_len << 8) | sn->data[index++];
+		}
+	    } 
+	}
+	/* XXX leaving any leading zeros on the serial number for backwards
+	 * compatibility
+	 */
+	/* not a valid der, must be just an unlucky serial number value */
+	if (data_len != data_left) {
+	    data_len = sn->len;
+	    index = 0;
+	}
+    }
+
+    certKey.data = (unsigned char*)PORT_Alloc(sn->len + issuer->len);
+    certKey.len = data_len + issuer->len;
+    
+    if ( certKey.data == NULL ) {
+	return(0);
+    }
+
+    /* first try the serial number as hand-decoded above*/
+    /* copy the serialNumber */
+    PORT_Memcpy(certKey.data, &sn->data[index], data_len);
+
+    /* copy the issuer */
+    PORT_Memcpy( &certKey.data[data_len],issuer->data,issuer->len);
+
+    trust = nsslowcert_FindTrustByKey(handle, &certKey);
+    if (trust) {
+	PORT_Free(certKey.data);
+	return (trust);
+    }
+
+    if (index == 0) {
+	PORT_Free(certKey.data);
+	return NULL;
+    }
+
+    /* didn't find it, try by der encoded serial number */
+    /* copy the serialNumber */
+    PORT_Memcpy(certKey.data, sn->data, sn->len);
+
+    /* copy the issuer */
+    PORT_Memcpy( &certKey.data[sn->len], issuer->data, issuer->len);
+    certKey.len = sn->len + issuer->len;
+
+    trust = nsslowcert_FindTrustByKey(handle, &certKey);
+    
+    PORT_Free(certKey.data);
+    
+    return(trust);
+}
+
+/*
  * look for the given DER certificate in the database
  */
 NSSLOWCERTCertificate *
 nsslowcert_FindCertByDERCert(NSSLOWCERTCertDBHandle *handle, SECItem *derCert)
 {
     PRArenaPool *arena;
     SECItem certKey;
     SECStatus rv;
@@ -4325,16 +4523,32 @@ DestroyCertificate(NSSLOWCERTCertificate
 	    nsslowcert_UnlockDB(handle);
 	}
     }
 
     return;
 }
 
 void
+nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust)
+{
+    certDBEntryCert *entry  = trust->dbEntry;
+
+    if ( entry ) {
+	DestroyDBEntry((certDBEntry *)entry);
+    }
+    if (trust->dbKey.data) {
+	PORT_Free(trust->dbKey.data);
+    }
+    PORT_Free(trust);
+
+    return;
+}
+
+void
 nsslowcert_DestroyCertificate(NSSLOWCERTCertificate *cert)
 {
     DestroyCertificate(cert, PR_TRUE);
     return;
 }
 
 static void
 nsslowcert_DestroyCertificateNoLocking(NSSLOWCERTCertificate *cert)
@@ -4402,57 +4616,64 @@ loser:
 SECStatus
 nsslowcert_AddCrl(NSSLOWCERTCertDBHandle *handle, SECItem *derCrl, 
 			SECItem *crlKey, char *url, PRBool isKRL)
 {
     SECStatus rv = SECFailure;
     certDBEntryRevocation *entry = NULL;
     certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation  
 					: certDBEntryTypeRevocation;
+    rv = db_BeginTransaction(handle->permCertDB);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
     DeleteDBCrlEntry(handle, crlKey, crlType);
 
     /* Write the new entry into the data base */
     entry = NewDBCrlEntry(derCrl, url, crlType, 0);
     if (entry == NULL) goto done;
 
     rv = WriteDBCrlEntry(handle, entry, crlKey);
     if (rv != SECSuccess) goto done;
 
 done:
     if (entry) {
 	DestroyDBEntry((certDBEntry *)entry);
     }
+    db_FinishTransaction(handle->permCertDB, rv != SECSuccess);
     return rv;
 }
 
 SECStatus
 nsslowcert_DeletePermCRL(NSSLOWCERTCertDBHandle *handle, SECItem *derName,
 								 PRBool isKRL)
 {
     SECStatus rv;
     certDBEntryType crlType = isKRL ? certDBEntryTypeKeyRevocation  
 					: certDBEntryTypeRevocation;
+    rv = db_BeginTransaction(handle->permCertDB);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
     
     rv = DeleteDBCrlEntry(handle, derName, crlType);
     if (rv != SECSuccess) goto done;
   
 done:
+    db_FinishTransaction(handle->permCertDB, rv != SECSuccess);
     return rv;
 }
 
 
 PRBool
-nsslowcert_hasTrust(NSSLOWCERTCertificate *cert)
+nsslowcert_hasTrust(NSSLOWCERTCertTrust *trust)
 {
-    NSSLOWCERTCertTrust *trust;
-
-    if (cert->trust == NULL) {
+    if (trust == NULL) {
 	return PR_FALSE;
     }
-    trust = cert->trust;
     return !((trust->sslFlags & CERTDB_TRUSTED_UNKNOWN) && 
 		(trust->emailFlags & CERTDB_TRUSTED_UNKNOWN) && 
 			(trust->objectSigningFlags & CERTDB_TRUSTED_UNKNOWN));
 }
 
 /*
  * This function has the logic that decides if another person's cert and
  * email profile from an S/MIME message should be saved.  It can deal with
@@ -4460,16 +4681,21 @@ nsslowcert_hasTrust(NSSLOWCERTCertificat
  */
 SECStatus
 nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, 
 	SECItem *derSubject, SECItem *emailProfile, SECItem *profileTime)
 {
     certDBEntrySMime *entry = NULL;
     SECStatus rv = SECFailure;;
 
+    rv = db_BeginTransaction(dbhandle->permCertDB);
+    if (rv != SECSuccess) {
+	return SECFailure;
+    }
+
     /* find our existing entry */
     entry = nsslowcert_ReadDBSMimeEntry(dbhandle, emailAddr);
 
     if ( entry ) {
 	/* keep our old db entry consistant for old applications. */
 	if (!SECITEM_ItemsAreEqual(derSubject, &entry->subjectName)) {
 	    UpdateSubjectWithEmailAddr(dbhandle, &entry->subjectName, NULL);
 	} 
@@ -4506,16 +4732,17 @@ nsslowcert_SaveSMimeProfile(NSSLOWCERTCe
     nsslowcert_UnlockDB(dbhandle);
 
     rv = SECSuccess;
     
 loser:
     if ( entry ) {
 	DestroyDBEntry((certDBEntry *)entry);
     }
+    db_FinishTransaction(dbhandle->permCertDB, rv != SECSuccess);
     return(rv);
 }
 
 void
 nsslowcert_DestroyGlobalLocks()
 {
     if (dbLock) {
 	PZ_DestroyLock(dbLock);
--- a/security/nss/lib/softoken/pcertt.h
+++ b/security/nss/lib/softoken/pcertt.h
@@ -48,16 +48,17 @@
 #include "prio.h"
 #include "prmon.h"
 
 
 /* Non-opaque objects */
 typedef struct NSSLOWCERTCertDBHandleStr               NSSLOWCERTCertDBHandle;
 typedef struct NSSLOWCERTCertKeyStr                    NSSLOWCERTCertKey;
 
+typedef struct NSSLOWCERTTrustStr                      NSSLOWCERTTrust;
 typedef struct NSSLOWCERTCertTrustStr                  NSSLOWCERTCertTrust;
 typedef struct NSSLOWCERTCertificateStr                NSSLOWCERTCertificate;
 typedef struct NSSLOWCERTCertificateListStr            NSSLOWCERTCertificateList;
 typedef struct NSSLOWCERTIssuerAndSNStr                NSSLOWCERTIssuerAndSN;
 typedef struct NSSLOWCERTSignedDataStr                 NSSLOWCERTSignedData;
 typedef struct NSSLOWCERTSubjectPublicKeyInfoStr       NSSLOWCERTSubjectPublicKeyInfo;
 typedef struct NSSLOWCERTValidityStr                   NSSLOWCERTValidity;
 
@@ -102,16 +103,27 @@ typedef struct _certDBEntryRevocation ce
 
 struct NSSLOWCERTCertTrustStr {
     unsigned int sslFlags;
     unsigned int emailFlags;
     unsigned int objectSigningFlags;
 };
 
 /*
+** PKCS11 Trust representation
+*/
+struct NSSLOWCERTTrustStr {
+    NSSLOWCERTCertDBHandle *dbhandle;
+    SECItem dbKey;			/* database key for this cert */
+    certDBEntryCert *dbEntry;		/* database entry struct */
+    NSSLOWCERTCertTrust *trust;
+    SECItem *derCert;			/* original DER for the cert */
+};
+
+/*
 ** An X.509 certificate object (the unsigned form)
 */
 struct NSSLOWCERTCertificateStr {
     /* the arena is used to allocate any data structures that have the same
      * lifetime as the cert.  This is all stuff that hangs off of the cert
      * structure, and is all freed at the same time.  I is used when the
      * cert is decoded, destroyed, and at some times when it changes
      * state
--- a/security/nss/lib/softoken/pkcs11.c
+++ b/security/nss/lib/softoken/pkcs11.c
@@ -3856,20 +3856,32 @@ pk11_searchCertsAndTrust(PK11Slot *slot,
 	int count;
 
 	count = nsslowcert_NumPermCertsForSubject(certHandle,derSubject);
 	pk11_CertSetupData(&certData,count);
 	nsslowcert_TraversePermCertsForSubject(certHandle,derSubject,
 				pk11_cert_collect, &certData);
     } else if ((issuerSN->derIssuer.data != NULL) && 
 			(issuerSN->serialNumber.data != NULL)) {
-	NSSLOWCERTCertificate *cert = 
+        if (classFlags & NSC_CERT) {
+	    NSSLOWCERTCertificate *cert = 
 		nsslowcert_FindCertByIssuerAndSN(certHandle,issuerSN);
 
-	pk11_searchSingleCert(&certData,cert);
+	    pk11_searchSingleCert(&certData,cert);
+	}
+	if (classFlags & NSC_TRUST) {
+	    NSSLOWCERTTrust *trust = 
+		nsslowcert_FindTrustByIssuerAndSN(certHandle, issuerSN);
+
+	    if (trust) {
+		pk11_addHandle(handles,
+		    pk11_mkHandle(slot,&trust->dbKey,PK11_TOKEN_TYPE_TRUST));
+		nsslowcert_DestroyTrust(trust);
+	    }
+	}
     } else if (email->data != NULL) {
 	char *tmp_name = (char*)PORT_Alloc(email->len+1);
 	certDBEntrySMime *entry = NULL;
 
 	if (tmp_name == NULL) {
 	    return;
 	}
 	PORT_Memcpy(tmp_name,email->data,email->len);
@@ -3902,17 +3914,17 @@ pk11_searchCertsAndTrust(PK11Slot *slot,
     for (i=0 ; i < certData.cert_count ; i++) {
 	NSSLOWCERTCertificate *cert = certData.certs[i];
 
 	/* if we filtered it would have been on the stuff above */
 	if (classFlags & NSC_CERT) {
 	    pk11_addHandle(handles,
 		pk11_mkHandle(slot,&cert->certKey,PK11_TOKEN_TYPE_CERT));
 	}
-	if ((classFlags & NSC_TRUST) && nsslowcert_hasTrust(cert)) {
+	if ((classFlags & NSC_TRUST) && nsslowcert_hasTrust(cert->trust)) {
 	    pk11_addHandle(handles,
 		pk11_mkHandle(slot,&cert->certKey,PK11_TOKEN_TYPE_TRUST));
 	}
 	nsslowcert_DestroyCertificate(cert);
     }
 
     if (certData.certs) PORT_Free(certData.certs);
     return;
--- a/security/nss/lib/softoken/pkcs11u.c
+++ b/security/nss/lib/softoken/pkcs11u.c
@@ -384,28 +384,47 @@ pk11_getUrl(PK11TokenObject *object)
     }
     return url;
 }
 
 static NSSLOWCERTCertificate *
 pk11_getCert(PK11TokenObject *object)
 {
     NSSLOWCERTCertificate *cert;
+    CK_OBJECT_CLASS objClass = object->obj.objclass;
 
-    if ((object->obj.objclass != CKO_CERTIFICATE) &&
-	 		(object->obj.objclass != CKO_NETSCAPE_TRUST)) {
+    if ((objClass != CKO_CERTIFICATE) && (objClass != CKO_NETSCAPE_TRUST)) {
+	return NULL;
+    }
+    if (objClass == CKO_CERTIFICATE && object->obj.objectInfo) {
+	return (NSSLOWCERTCertificate *)object->obj.objectInfo;
+    }
+    cert = nsslowcert_FindCertByKey(object->obj.slot->certDB,&object->dbKey);
+    if (objClass == CKO_CERTIFICATE) {
+	object->obj.objectInfo = (void *)cert;
+	object->obj.infoFree = (PK11Free) nsslowcert_DestroyCertificate ;
+    }
+    return cert;
+}
+
+static NSSLOWCERTTrust *
+pk11_getTrust(PK11TokenObject *object)
+{
+    NSSLOWCERTTrust *trust;
+
+    if (object->obj.objclass != CKO_NETSCAPE_TRUST) {
 	return NULL;
     }
     if (object->obj.objectInfo) {
-	return (NSSLOWCERTCertificate *)object->obj.objectInfo;
+	return (NSSLOWCERTTrust *)object->obj.objectInfo;
     }
-    cert = nsslowcert_FindCertByKey(object->obj.slot->certDB,&object->dbKey);
-    object->obj.objectInfo = (void *)cert;
-    object->obj.infoFree = (PK11Free) nsslowcert_DestroyCertificate ;
-    return cert;
+    trust = nsslowcert_FindTrustByKey(object->obj.slot->certDB,&object->dbKey);
+    object->obj.objectInfo = (void *)trust;
+    object->obj.infoFree = (PK11Free) nsslowcert_DestroyTrust ;
+    return trust;
 }
 
 static NSSLOWKEYPublicKey *
 pk11_GetPublicKey(PK11TokenObject *object)
 {
     NSSLOWKEYPublicKey *pubKey;
     NSSLOWKEYPrivateKey *privKey;
 
@@ -876,64 +895,53 @@ pk11_FindSMIMEAttribute(PK11TokenObject 
 	break;
     }
     return NULL;
 }
 
 static PK11Attribute *
 pk11_FindTrustAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
 {
-    NSSLOWCERTCertificate *cert;
+    NSSLOWCERTTrust *trust;
     unsigned char hash[SHA1_LENGTH];
-    SECItem *item;
-    PK11Attribute *attr;
     unsigned int trustFlags;
 
     switch (type) {
     case CKA_PRIVATE:
 	return (PK11Attribute *) &pk11_StaticFalseAttr;
     case CKA_MODIFIABLE:
 	return (PK11Attribute *) &pk11_StaticTrueAttr;
     case CKA_SENSITIVE:
 	return NULL;
     default:
 	break;
     }
-    cert = pk11_getCert(object);
-    if (cert == NULL) {
+    trust = pk11_getTrust(object);
+    if (trust == NULL) {
 	return NULL;
     }
     switch (type) {
     case CKA_CERT_SHA1_HASH:
-	SHA1_HashBuf(hash,cert->derCert.data,cert->derCert.len);
-	return pk11_NewTokenAttribute(type,hash,SHA1_LENGTH, PR_TRUE);
+	SHA1_HashBuf(hash,trust->derCert->data,trust->derCert->len);
+	return pk11_NewTokenAttribute(type, hash, SHA1_LENGTH, PR_TRUE);
     case CKA_CERT_MD5_HASH:
-	MD5_HashBuf(hash,cert->derCert.data,cert->derCert.len);
-	return pk11_NewTokenAttribute(type,hash,MD5_LENGTH, PR_TRUE);
-    case CKA_ISSUER:
-	return pk11_NewTokenAttribute(type,cert->derIssuer.data,
-						cert->derIssuer.len, PR_FALSE);
-    case CKA_SERIAL_NUMBER:
-	item = SEC_ASN1EncodeItem(NULL,NULL,cert,pk11_SerialTemplate);
-	if (item == NULL) break;
-	attr = pk11_NewTokenAttribute(type, item->data, item->len, PR_TRUE);
-	SECITEM_FreeItem(item,PR_TRUE);
-	return attr;
+	MD5_HashBuf(hash,trust->derCert->data,trust->derCert->len);
+	return pk11_NewTokenAttribute(type, hash, MD5_LENGTH, PR_TRUE);
     case CKA_TRUST_CLIENT_AUTH:
-	trustFlags = cert->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ?
-		cert->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ;
+	trustFlags = trust->trust->sslFlags & CERTDB_TRUSTED_CLIENT_CA ?
+		trust->trust->sslFlags | CERTDB_TRUSTED_CA : 0 ;
 	goto trust;
     case CKA_TRUST_SERVER_AUTH:
-	trustFlags = cert->trust->sslFlags;
+	trustFlags = trust->trust->sslFlags;
 	goto trust;
     case CKA_TRUST_EMAIL_PROTECTION:
-	trustFlags = cert->trust->emailFlags;
+	trustFlags = trust->trust->emailFlags;
 	goto trust;
     case CKA_TRUST_CODE_SIGNING:
-	trustFlags = cert->trust->objectSigningFlags;
+	trustFlags = trust->trust->objectSigningFlags;
 trust:
 	if (trustFlags & CERTDB_TRUSTED_CA ) {
 	    return (PK11Attribute *)&pk11_StaticTrustedDelegatorAttr;
 	}
 	if (trustFlags & CERTDB_TRUSTED) {
 	    return (PK11Attribute *)&pk11_StaticTrustedAttr;
 	}
 	if (trustFlags & CERTDB_NOT_TRUSTED) {
@@ -947,16 +955,38 @@ trust:
 	}
 	if (trustFlags & CERTDB_VALID_PEER) {
 	    return (PK11Attribute *)&pk11_StaticValidPeerAttr;
 	}
 	return (PK11Attribute *)&pk11_StaticMustVerifyAttr;
     default:
 	break;
     }
+
+#ifdef notdef
+    switch (type) {
+    case CKA_ISSUER:
+	cert = pk11_getCertObject(object);
+	if (cert == NULL) break;
+	attr = pk11_NewTokenAttribute(type,cert->derIssuer.data,
+						cert->derIssuer.len, PR_FALSE);
+	
+    case CKA_SERIAL_NUMBER:
+	cert = pk11_getCertObject(object);
+	if (cert == NULL) break;
+	item = SEC_ASN1EncodeItem(NULL,NULL,cert,pk11_SerialTemplate);
+	if (item == NULL) break;
+	attr = pk11_NewTokenAttribute(type, item->data, item->len, PR_TRUE);
+	SECITEM_FreeItem(item,PR_TRUE);
+    }
+    if (cert) {
+	NSSLOWCERTDestroyCertificate(cert);	
+	return attr;
+    }
+#endif
     return NULL;
 }
 
 static PK11Attribute *
 pk11_FindCrlAttribute(PK11TokenObject *object, CK_ATTRIBUTE_TYPE type)
 {
     SECItem *crl;
     char *url;
@@ -1175,17 +1205,16 @@ pk11_AddAttribute(PK11Object *object,PK1
  * copy an unsigned attribute into a SECItem. Secitem is allocated in
  * the specified arena.
  */
 CK_RV
 pk11_Attribute2SSecItem(PLArenaPool *arena,SECItem *item,PK11Object *object,
                                       CK_ATTRIBUTE_TYPE type)
 {
     PK11Attribute *attribute;
-    unsigned char *start;
 
     item->data = NULL;
 
     attribute = pk11_FindAttribute(object, type);
     if (attribute == NULL) return CKR_TEMPLATE_INCOMPLETE;
 
     (void)SECITEM_AllocItem(arena, item, attribute->attrib.ulValueLen);
     if (item->data == NULL) {