From 261c99b07974d623b584c00f5382bbcab3bc14d0 Mon Sep 17 00:00:00 2001 From: "rrelyea%redhat.com" Date: Tue, 15 May 2007 21:59:52 +0000 Subject: [PATCH] Add database upgrade support. git-svn-id: svn://10.0.0.236/branches/NSS_BOB_SHARED@226480 18797224-902f-48f8-a5cc-f745e15eee43 --- .../nss/lib/softoken/legacydb/lgattr.c | 43 +- .../nss/lib/softoken/legacydb/lgfind.c | 61 +- .../nss/lib/softoken/legacydb/lowcert.c | 218 +++++- .../nss/lib/softoken/legacydb/pcertdb.c | 3 +- .../nss/lib/softoken/legacydb/pcertt.h | 4 +- mozilla/security/nss/lib/softoken/lgglue.c | 341 +++++++++ mozilla/security/nss/lib/softoken/lgglue.h | 92 +++ mozilla/security/nss/lib/softoken/pkcs11u.c | 25 +- mozilla/security/nss/lib/softoken/sdb.c | 90 ++- mozilla/security/nss/lib/softoken/sdb.h | 2 +- mozilla/security/nss/lib/softoken/sftkdb.c | 693 ++++++++++++++++-- mozilla/security/nss/lib/softoken/sftkdbt.h | 4 +- mozilla/security/nss/lib/softoken/sftkpars.c | 33 +- 13 files changed, 1449 insertions(+), 160 deletions(-) create mode 100644 mozilla/security/nss/lib/softoken/lgglue.c create mode 100644 mozilla/security/nss/lib/softoken/lgglue.h diff --git a/mozilla/security/nss/lib/softoken/legacydb/lgattr.c b/mozilla/security/nss/lib/softoken/legacydb/lgattr.c index c6eee768f80..717b7805851 100644 --- a/mozilla/security/nss/lib/softoken/legacydb/lgattr.c +++ b/mozilla/security/nss/lib/softoken/legacydb/lgattr.c @@ -351,10 +351,9 @@ lg_getCert(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) } static NSSLOWCERTTrust * -lg_getTrust(LGObjectCache *obj) +lg_getTrust(LGObjectCache *obj, NSSLOWCERTCertDBHandle *certHandle) { NSSLOWCERTTrust *trust; - NSSLOWCERTCertDBHandle *certHandle; if (obj->objclass != CKO_NETSCAPE_TRUST) { return NULL; @@ -362,10 +361,6 @@ lg_getTrust(LGObjectCache *obj) if (obj->objectInfo) { return (NSSLOWCERTTrust *)obj->objectInfo; } - certHandle = lg_getCertDB(obj->sdb); - if (!certHandle) { - return NULL; - } trust = nsslowcert_FindTrustByKey(certHandle, &obj->dbKey); obj->objectInfo = (void *)trust; obj->infoFree = (LGFreeFunc) nsslowcert_DestroyTrust ; @@ -1086,8 +1081,11 @@ lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *attribute) { NSSLOWCERTTrust *trust; + NSSLOWCERTCertDBHandle *certHandle; + NSSLOWCERTCertificate *cert; unsigned char hash[SHA1_LENGTH]; unsigned int trustFlags; + CK_RV crv; switch (type) { case CKA_PRIVATE: @@ -1101,11 +1099,17 @@ lg_FindTrustAttribute(LGObjectCache *obj, CK_ATTRIBUTE_TYPE type, case CKA_TRUST_EMAIL_PROTECTION: case CKA_TRUST_CODE_SIGNING: case CKA_TRUST_STEP_UP_APPROVED: + case CKA_ISSUER: + case CKA_SERIAL_NUMBER: break; default: return lg_invalidAttribute(attribute); } - trust = lg_getTrust(obj); + certHandle = lg_getCertDB(obj->sdb); + if (!certHandle) { + return CKR_OBJECT_HANDLE_INVALID; + } + trust = lg_getTrust(obj, certHandle); if (trust == NULL) { return CKR_OBJECT_HANDLE_INVALID; } @@ -1161,27 +1165,28 @@ trust: break; } -#ifdef notdef + switch (type) { case CKA_ISSUER: - cert = lg_getCertObject(object); + cert = lg_getCert(obj, certHandle); if (cert == NULL) break; - attr = lg_CopyAttribute(attribute,type,cert->derIssuer.data, + crv = lg_CopyAttribute(attribute,type,cert->derIssuer.data, cert->derIssuer.len); - + break; case CKA_SERIAL_NUMBER: - cert = lg_getCertObject(object); + cert = lg_getCert(obj, certHandle); if (cert == NULL) break; - item = SEC_ASN1EncodeItem(NULL,NULL,cert,lg_SerialTemplate); - if (item == NULL) break; - attr = lg_CopyAttribute(attribute, type, item->data, item->len); - SECITEM_FreeItem(item,PR_TRUE); + crv = lg_CopyAttribute(attribute,type,cert->derSN.data, + cert->derSN.len); + break; + default: + cert = NULL; + break; } if (cert) { - NSSLOWCERTDestroyCertificate(cert); - return attr; + nsslowcert_DestroyCertificate(cert); + return crv; } -#endif return lg_invalidAttribute(attribute); } diff --git a/mozilla/security/nss/lib/softoken/legacydb/lgfind.c b/mozilla/security/nss/lib/softoken/legacydb/lgfind.c index fd112223939..b7029c7d5aa 100644 --- a/mozilla/security/nss/lib/softoken/legacydb/lgfind.c +++ b/mozilla/security/nss/lib/softoken/legacydb/lgfind.c @@ -98,22 +98,22 @@ lg_addHandle(SDBFind *search, CK_OBJECT_HANDLE handle) /* * structure to collect key handles. */ -typedef struct lgCrlDataStr { +typedef struct lgEntryDataStr { SDB *sdb; SDBFind *searchHandles; const CK_ATTRIBUTE *template; CK_ULONG templ_count; -} lgCrlData; +} lgEntryData; static SECStatus lg_crl_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) { - lgCrlData *crlData; + lgEntryData *crlData; CK_OBJECT_HANDLE class_handle; SDB *sdb; - crlData = (lgCrlData *)arg; + crlData = (lgEntryData *)arg; sdb = crlData->sdb; class_handle = (type == certDBEntryTypeRevocation) ? LG_TOKEN_TYPE_CRL : @@ -147,7 +147,7 @@ lg_searchCrls(SDB *sdb, SECItem *derSubject, PRBool isKrl, nsslowcert_DestroyDBEntry((certDBEntry *)crl); } } else { - lgCrlData crlData; + lgEntryData crlData; /* traverse */ crlData.sdb = sdb; @@ -195,9 +195,11 @@ lg_key_collect(DBT *key, DBT *data, void *arg) NSSLOWKEYPrivateKey *privKey = NULL; SECItem tmpDBKey; SDB *sdb; + unsigned long classFlags; keyData = (lgKeyData *)arg; sdb = keyData->sdb; + classFlags = keyData->classFlags; tmpDBKey.data = key->data; tmpDBKey.len = key->size; @@ -216,10 +218,11 @@ lg_key_collect(DBT *key, DBT *data, void *arg) privKey = nsslowkey_FindKeyByPublicKey(keyData->keyHandle, &tmpDBKey, keyData->sdb/*->password*/); if (privKey) { - haveMatch = isSecretKey(privKey) ? - (PRBool)(keyData->classFlags & LG_KEY) != 0: - (PRBool)(keyData->classFlags & - (LG_PRIVATE|LG_PUBLIC)) != 0; + /* turn off the unneeded class flags */ + classFlags &= isSecretKey(privKey) ? ~(LG_PRIVATE|LG_PUBLIC) : + ~LG_KEY; + haveMatch = (PRBool) + ((classFlags & (LG_KEY|LG_PRIVATE|LG_PUBLIC)) != 0); nsslowkey_DestroyPrivateKey(privKey); } } else { @@ -240,15 +243,15 @@ lg_key_collect(DBT *key, DBT *data, void *arg) } } if (haveMatch) { - if (keyData->classFlags & LG_PRIVATE) { + if (classFlags & LG_PRIVATE) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV)); } - if (keyData->classFlags & LG_PUBLIC) { + if (classFlags & LG_PUBLIC) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_PUB)); } - if (keyData->classFlags & LG_KEY) { + if (classFlags & LG_KEY) { lg_addHandle(keyData->searchHandles, lg_mkHandle(sdb,&tmpDBKey,LG_TOKEN_TYPE_KEY)); } @@ -263,20 +266,20 @@ lg_key_collect(DBT *key, DBT *data, void *arg) } if (isSecretKey(privKey)) { - if ((keyData->classFlags & LG_KEY) && + if ((classFlags & LG_KEY) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, lg_mkHandle(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_KEY)); } } else { - if ((keyData->classFlags & LG_PRIVATE) && + if ((classFlags & LG_PRIVATE) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PRIV, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, lg_mkHandle(keyData->sdb,&tmpDBKey,LG_TOKEN_TYPE_PRIV)); } - if ((keyData->classFlags & LG_PUBLIC) && + if ((classFlags & LG_PUBLIC) && lg_tokenMatch(keyData->sdb, &tmpDBKey, LG_TOKEN_TYPE_PUB, keyData->template, keyData->templ_count)) { lg_addHandle(keyData->searchHandles, @@ -579,6 +582,23 @@ lg_searchCertsAndTrust(SDB *sdb, SECItem *derCert, SECItem *name, return; } +static SECStatus +lg_smime_collect(SECItem *data, SECItem *key, certDBEntryType type, void *arg) +{ + lgEntryData *smimeData; + SDB *sdb; + + smimeData = (lgEntryData *)arg; + sdb = smimeData->sdb; + + if (lg_tokenMatch(sdb, key, LG_TOKEN_TYPE_SMIME, + smimeData->template, smimeData->templ_count)) { + lg_addHandle(smimeData->searchHandles, + lg_mkHandle(sdb,key,LG_TOKEN_TYPE_SMIME)); + } + return(SECSuccess); +} + static void lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles, const CK_ATTRIBUTE *pTemplate, CK_LONG ulCount) @@ -610,6 +630,17 @@ lg_searchSMime(SDB *sdb, SECItem *email, SDBFind *handles, nsslowcert_DestroyDBEntry((certDBEntry *)entry); } PORT_Free(tmp_name); + } else { + /* traverse */ + lgEntryData smimeData; + + /* traverse */ + smimeData.sdb = sdb; + smimeData.searchHandles = handles; + smimeData.template = pTemplate; + smimeData.templ_count = ulCount; + nsslowcert_TraverseDBEntries(certHandle, certDBEntryTypeSMimeProfile, + lg_smime_collect, (void *)&smimeData); } return; } diff --git a/mozilla/security/nss/lib/softoken/legacydb/lowcert.c b/mozilla/security/nss/lib/softoken/legacydb/lowcert.c index 44da0a330d5..81bc7a4df6d 100644 --- a/mozilla/security/nss/lib/softoken/legacydb/lowcert.c +++ b/mozilla/security/nss/lib/softoken/legacydb/lowcert.c @@ -38,7 +38,7 @@ /* * Certificate handling code * - * $Id: lowcert.c,v 1.1.2.1 2007-04-03 22:50:02 rrelyea%redhat.com Exp $ + * $Id: lowcert.c,v 1.1.2.2 2007-05-15 21:59:52 rrelyea%redhat.com Exp $ */ #include "seccomon.h" @@ -187,7 +187,7 @@ nsslowcert_GetValidityFields(unsigned char *buf,int buf_length, static int nsslowcert_GetCertFields(unsigned char *cert,int cert_length, SECItem *issuer, SECItem *serial, SECItem *derSN, SECItem *subject, - SECItem *valid, SECItem *subjkey) + SECItem *valid, SECItem *subjkey, SECItem *extensions) { unsigned char *buf; unsigned int buf_length; @@ -245,6 +245,21 @@ nsslowcert_GetCertFields(unsigned char *cert,int cert_length, if (subjkey->data == NULL) return SECFailure; buf_length -= (subjkey->data-buf) + subjkey->len; buf = subjkey->data + subjkey->len; + + extensions->data = NULL; + extensions->len = 0; + while (buf_length > 0) { + /* EXTENSIONS */ + if (buf[0] == 0xa3) { + extensions->data = nsslowcert_dataStart(buf,buf_length, + &extensions->len, PR_FALSE, NULL); + break; + } + dummy = nsslowcert_dataStart(buf,buf_length,&dummylen,PR_FALSE,NULL); + if (dummy == NULL) return SECFailure; + buf_length -= (dummy - buf) + dummylen; + buf = dummy + dummylen; + } return SECSuccess; } @@ -388,6 +403,196 @@ loser: } +static char * +nsslowcert_EmailName(SECItem *derDN, char *space, unsigned int len) +{ + unsigned char *buf; + unsigned int buf_length; + + /* unwrap outer sequence */ + buf=nsslowcert_dataStart(derDN->data,derDN->len,&buf_length,PR_FALSE,NULL); + if (buf == NULL) return NULL; + + /* Walk each RDN */ + while (buf_length > 0) { + unsigned char *rdn; + unsigned int rdn_length; + + /* grab next rdn */ + rdn=nsslowcert_dataStart(buf, buf_length, &rdn_length, PR_FALSE, NULL); + if (rdn == NULL) { return NULL; } + buf_length -= (rdn - buf) + rdn_length; + buf = rdn+rdn_length; + + while (rdn_length > 0) { + unsigned char *ava; + unsigned int ava_length; + unsigned char *oid; + unsigned int oid_length; + unsigned char *name; + unsigned int name_length; + SECItem oidItem; + SECOidTag type; + + /* unwrap the ava */ + ava=nsslowcert_dataStart(rdn, rdn_length, &ava_length, PR_FALSE, + NULL); + if (ava == NULL) return NULL; + rdn_length -= (ava-rdn)+ava_length; + rdn = ava + ava_length; + + oid=nsslowcert_dataStart(ava, ava_length, &oid_length, PR_FALSE, + NULL); + if (oid == NULL) { return NULL; } + ava_length -= (oid-ava)+oid_length; + ava = oid+oid_length; + + name=nsslowcert_dataStart(ava, ava_length, &name_length, PR_FALSE, + NULL); + if (oid == NULL) { return NULL; } + ava_length -= (name-ava)+name_length; + ava = name+name_length; + + oidItem.data = oid; + oidItem.len = oid_length; + type = SECOID_FindOIDTag(&oidItem); + if ((type == SEC_OID_PKCS9_EMAIL_ADDRESS) || + (type == SEC_OID_RFC1274_MAIL)) { + /* Email is supposed to be IA5String, so no + * translation necessary */ + char *emailAddr; + emailAddr = (char *)pkcs11_copyStaticData(name,name_length+1, + (unsigned char *)space,len); + if (emailAddr) { + emailAddr[name_length] = 0; + } + return emailAddr; + } + } + } + return NULL; +} + +static char * +nsslowcert_EmailAltName(NSSLOWCERTCertificate *cert, char *space, + unsigned int len) +{ + unsigned char *exts; + unsigned int exts_length; + + /* unwrap the sequence */ + exts = nsslowcert_dataStart(cert->extensions.data, cert->extensions.len, + &exts_length, PR_FALSE, NULL); + /* loop through extension */ + while (exts && exts_length > 0) { + unsigned char * ext; + unsigned int ext_length; + unsigned char *oid; + unsigned int oid_length; + unsigned char *nameList; + unsigned int nameList_length; + SECItem oidItem; + SECOidTag type; + + ext = nsslowcert_dataStart(exts, exts_length, &ext_length, + PR_FALSE, NULL); + if (ext == NULL) { break; } + exts_length -= (ext - exts) + ext_length; + exts = ext+ext_length; + + oid=nsslowcert_dataStart(ext, ext_length, &oid_length, PR_FALSE, NULL); + if (oid == NULL) { break; } + ext_length -= (oid - ext) + oid_length; + ext = oid+oid_length; + oidItem.data = oid; + oidItem.len = oid_length; + type = SECOID_FindOIDTag(&oidItem); + + /* get Alt Extension */ + if (type != SEC_OID_X509_SUBJECT_ALT_NAME) { + continue; + } + + /* skip passed the critical flag */ + if (ext[0] == 0x01) { /* BOOLEAN */ + unsigned char *dummy; + unsigned int dummy_length; + dummy = nsslowcert_dataStart(ext, ext_length, &dummy_length, + PR_FALSE, NULL); + if (dummy == NULL) { break; } + ext_length -= (dummy - ext) + dummy_length; + ext = dummy+dummy_length; + } + + + /* unwrap the name list */ + nameList = nsslowcert_dataStart(ext, ext_length, &nameList_length, + PR_FALSE, NULL); + if (nameList == NULL) { break; } + ext_length -= (nameList - ext) + nameList_length; + ext = nameList+nameList_length; + nameList = nsslowcert_dataStart(nameList, nameList_length, + &nameList_length, PR_FALSE, NULL); + /* loop through the name list */ + while (nameList && nameList_length > 0) { + unsigned char *thisName; + unsigned int thisName_length; + + thisName = nsslowcert_dataStart(nameList, nameList_length, + &thisName_length, PR_FALSE, NULL); + if (thisName == NULL) { break; } + if (nameList[0] == 0xa2) { /* DNS Name */ + SECItem dn; + char *emailAddr; + + dn.data = thisName; + dn.len = thisName_length; + emailAddr = nsslowcert_EmailName(&dn, space, len); + if (emailAddr) { + return emailAddr; + } + } + if (nameList[0] == 0x81) { /* RFC 822name */ + char *emailAddr; + emailAddr = (char *)pkcs11_copyStaticData(thisName, + thisName_length+1, (unsigned char *)space,len); + if (emailAddr) { + emailAddr[thisName_length] = 0; + } + return emailAddr; + } + nameList_length -= (thisName-nameList) + thisName_length; + nameList = thisName + thisName_length; + } + break; + } + return NULL; +} + +static char * +nsslowcert_GetCertificateEmailAddress(NSSLOWCERTCertificate *cert) +{ + char *emailAddr = NULL; + char *str; + + emailAddr = nsslowcert_EmailName(&cert->derSubject,cert->emailAddrSpace, + sizeof(cert->emailAddrSpace)); + /* couldn't find the email address in the DN, check the subject Alt name */ + if (!emailAddr && cert->extensions.data) { + emailAddr = nsslowcert_EmailAltName(cert, cert->emailAddrSpace, + sizeof(cert->emailAddrSpace)); + } + + + /* make it lower case */ + str = emailAddr; + while ( str && *str ) { + *str = tolower( *str ); + str++; + } + return emailAddr; + +} /* * take a DER certificate and decode it into a certificate structure @@ -414,7 +619,7 @@ nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) /* decode the certificate info */ rv = nsslowcert_GetCertFields(cert->derCert.data, cert->derCert.len, &cert->derIssuer, &cert->serialNumber, &cert->derSN, &cert->derSubject, - &cert->validity, &cert->derSubjKeyInfo); + &cert->validity, &cert->derSubjKeyInfo, &cert->extensions); /* cert->subjectKeyID; x509v3 subject key identifier */ cert->subjectKeyID.data = NULL; @@ -446,11 +651,11 @@ nsslowcert_DecodeDERCertificate(SECItem *derSignedCert, char *nickname) if ( rv != SECSuccess ) { goto loser; } +#endif /* set the email address */ - cert->emailAddr = CERT_GetCertificateEmailAddress(cert); + cert->emailAddr = nsslowcert_GetCertificateEmailAddress(cert); -#endif cert->referenceCount = 1; @@ -503,7 +708,8 @@ nsslowcert_KeyFromDERCert(PRArenaPool *arena, SECItem *derCert, SECItem *key) PORT_Memset(&certkey, 0, sizeof(NSSLOWCERTCertKey)); rv = nsslowcert_GetCertFields(derCert->data, derCert->len, - &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, NULL, NULL); + &certkey.derIssuer, &certkey.serialNumber, NULL, NULL, + NULL, NULL, NULL); if ( rv ) { goto loser; diff --git a/mozilla/security/nss/lib/softoken/legacydb/pcertdb.c b/mozilla/security/nss/lib/softoken/legacydb/pcertdb.c index 2ff87f34f2e..f1f0cc75a0f 100644 --- a/mozilla/security/nss/lib/softoken/legacydb/pcertdb.c +++ b/mozilla/security/nss/lib/softoken/legacydb/pcertdb.c @@ -37,7 +37,7 @@ /* * Permanent Certificate database handling code * - * $Id: pcertdb.c,v 1.1.2.1 2007-04-03 22:50:02 rrelyea%redhat.com Exp $ + * $Id: pcertdb.c,v 1.1.2.2 2007-05-15 21:59:52 rrelyea%redhat.com Exp $ */ #include "lowkeyti.h" #include "pcert.h" @@ -4972,6 +4972,7 @@ DestroyCertificate(NSSLOWCERTCertificate *cert, PRBool lockdb) } pkcs11_freeNickname(cert->nickname,cert->nicknameSpace); + pkcs11_freeNickname(cert->emailAddr,cert->emailAddrSpace); pkcs11_freeStaticData(cert->certKey.data,cert->certKeySpace); cert->certKey.data = NULL; cert->nickname = NULL; diff --git a/mozilla/security/nss/lib/softoken/legacydb/pcertt.h b/mozilla/security/nss/lib/softoken/legacydb/pcertt.h index 5712caf9508..387b52a16e1 100644 --- a/mozilla/security/nss/lib/softoken/legacydb/pcertt.h +++ b/mozilla/security/nss/lib/softoken/legacydb/pcertt.h @@ -36,7 +36,7 @@ /* * certt.h - public data structures for the certificate library * - * $Id: pcertt.h,v 1.1.2.1 2007-04-03 22:50:02 rrelyea%redhat.com Exp $ + * $Id: pcertt.h,v 1.1.2.2 2007-05-15 21:59:52 rrelyea%redhat.com Exp $ */ #ifndef _PCERTT_H_ #define _PCERTT_H_ @@ -146,6 +146,7 @@ struct NSSLOWCERTCertificateStr { SECItem validity; certDBEntryCert *dbEntry; /* database entry struct */ SECItem subjectKeyID; /* x509v3 subject key identifier */ + SECItem extensions; char *nickname; char *emailAddr; NSSLOWCERTCertTrust *trust; @@ -156,6 +157,7 @@ struct NSSLOWCERTCertificateStr { int referenceCount; char nicknameSpace[200]; + char emailAddrSpace[200]; unsigned char certKeySpace[512]; }; diff --git a/mozilla/security/nss/lib/softoken/lgglue.c b/mozilla/security/nss/lib/softoken/lgglue.c new file mode 100644 index 00000000000..93c98889b4b --- /dev/null +++ b/mozilla/security/nss/lib/softoken/lgglue.c @@ -0,0 +1,341 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * The following code handles the storage of PKCS 11 modules used by the + * NSS. This file is written to abstract away how the modules are + * stored so we can deside that later. + */ +#include "sftkdb.h" +#include "sdb.h" +#include "prsystem.h" +#include "prprf.h" +#include "lgglue.h" +#include "secerr.h" + +static LGOpenFunc legacy_glue_open = NULL; +static LGReadSecmodFunc legacy_glue_readSecmod = NULL; +static LGReleaseSecmodFunc legacy_glue_releaseSecmod = NULL; +static LGDeleteSecmodFunc legacy_glue_deleteSecmod = NULL; +static LGAddSecmodFunc legacy_glue_addSecmod = NULL; +static LGShutdownFunc legacy_glue_shutdown = NULL; + +/* + * The following 3 functions duplicate the work done by bl_LoadLibrary. + * We should make bl_LoadLibrary a global and replace the call to + * sftkdb_LoadLibrary(const char *libname) with it. + */ +#ifdef XP_UNIX +#include +#define LG_MAX_LINKS 20 +static char * +sftkdb_resolvePath(const char *orig) +{ + int count = 0; + int len =0; + int ret = -1; + char *resolved = NULL; + char *source = NULL; + + len = 1025; /* MAX PATH +1*/ + if (strlen(orig)+1 > len) { + /* PATH TOO LONG */ + return NULL; + } + resolved = PORT_Alloc(len); + if (!resolved) { + return NULL; + } + source = PORT_Alloc(len); + if (!source) { + goto loser; + } + PORT_Strcpy(source, orig); + /* Walk down all the links */ + while ( count++ < LG_MAX_LINKS) { + char *tmp; + /* swap our previous sorce out with resolved */ + /* read it */ + ret = readlink(source, resolved, len-1); + if (ret < 0) { + break; + } + resolved[ret] = 0; + tmp = source; source = resolved; resolved = tmp; + } + if (count > 1) { + ret = 0; + } +loser: + if (resolved) { + PORT_Free(resolved); + } + if (ret < 0) { + if (source) { + PORT_Free(source); + source = NULL; + } + } + return source; +} + +#endif + +static PRLibrary * +sftkdb_LoadFromPath(const char *path, const char *libname) +{ + char *c; + int pathLen, nameLen, fullPathLen; + char *fullPathName = NULL; + PRLibSpec libSpec; + PRLibrary *lib = NULL; + + + /* strip of our parent's library name */ + c = strrchr(path, PR_GetDirectorySeparator()); + if (!c) { + return NULL; /* invalid path */ + } + pathLen = (c-path)+1; + nameLen = strlen(libname); + fullPathLen = pathLen + nameLen +1; + fullPathName = (char *)PORT_Alloc(fullPathLen); + if (fullPathName == NULL) { + return NULL; /* memory allocation error */ + } + PORT_Memcpy(fullPathName, path, pathLen); + PORT_Memcpy(fullPathName+pathLen, libname, nameLen); + fullPathName[fullPathLen-1] = 0; + + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = fullPathName; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + PORT_Free(fullPathName); + return lib; +} + +static PRLibrary * +sftkdb_LoadLibrary(const char *libname) +{ + PRLibrary *lib = NULL; + PRFuncPtr fn_addr; + char *parentLibPath = NULL; + + fn_addr = (PRFuncPtr) &sftkdb_LoadLibrary; + parentLibPath = PR_GetLibraryFilePathname(SOFTOKEN_LIB_NAME, fn_addr); + + if (!parentLibPath) { + goto done; + } + + lib = sftkdb_LoadFromPath(parentLibPath, libname); +#ifdef XP_UNIX + /* handle symbolic link case */ + if (!lib) { + char *trueParentLibPath = sftkdb_resolvePath(parentLibPath); + if (!trueParentLibPath) { + goto done; + } + lib = sftkdb_LoadFromPath(trueParentLibPath, libname); + PORT_Free(trueParentLibPath); + } +#endif + PORT_Free(parentLibPath); + +done: + /* still couldn't load it, try the generic path */ + if (!lib) { + PRLibSpec libSpec; + libSpec.type = PR_LibSpec_Pathname; + libSpec.value.pathname = libname; + lib = PR_LoadLibraryWithFlags(libSpec, PR_LD_NOW | PR_LD_LOCAL); + } + return lib; +} + +static PRLibrary *legacy_glue_lib = NULL; +static SECStatus +sftkdbLoad_Legacy() +{ + PRLibrary *lib = NULL; + LGSetCryptFunc setCryptFunction = NULL; + + if (legacy_glue_lib) { + return SECSuccess; + } + + lib = sftkdb_LoadLibrary(SHLIB_PREFIX"lgdbm"SHLIB_VERSION"."SHLIB_SUFFIX); + if (lib == NULL) { + return SECFailure; + } + + legacy_glue_open = (LGOpenFunc)PR_FindFunctionSymbol(lib, "legacy_Open"); + legacy_glue_readSecmod = (LGReadSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_ReadSecmodDB"); + legacy_glue_releaseSecmod = (LGReleaseSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_ReleaseSecmodDBData"); + legacy_glue_deleteSecmod = (LGDeleteSecmodFunc) PR_FindFunctionSymbol(lib, + "legacy_DeleteSecmodDB"); + legacy_glue_addSecmod = (LGAddSecmodFunc)PR_FindFunctionSymbol(lib, + "legacy_AddSecmodDB"); + legacy_glue_shutdown = (LGShutdownFunc) PR_FindFunctionSymbol(lib, + "legacy_Shutdown"); + setCryptFunction = (LGSetCryptFunc) PR_FindFunctionSymbol(lib, + "legacy_SetCryptFunctions"); + + if (!legacy_glue_open || !legacy_glue_readSecmod || + !legacy_glue_releaseSecmod || !legacy_glue_deleteSecmod || + !legacy_glue_addSecmod || !setCryptFunction) { + PR_UnloadLibrary(lib); + return SECFailure; + } + setCryptFunction(sftkdb_encrypt_stub,sftkdb_decrypt_stub); + legacy_glue_lib = lib; + return SECSuccess; +} + +CK_RV +sftkdbCall_open(const char *dir, const char *certPrefix, const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return CKR_GENERAL_ERROR; + } + if (!legacy_glue_open) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_open)(dir, certPrefix, keyPrefix, + certVersion, keyVersion, + flags, certDB, keyDB); +} + +char ** +sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, + const char *dbname, char *params, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return NULL; + } + if (!legacy_glue_readSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + return (*legacy_glue_readSecmod)(appName, filename, dbname, params, rw); +} + +SECStatus +sftkdbCall_ReleaseSecmodDBData(const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_releaseSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_releaseSecmod)(appName, filename, dbname, + moduleSpecList, rw); +} + +SECStatus +sftkdbCall_DeleteSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_deleteSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_deleteSecmod)(appName, filename, dbname, args, rw); +} + +SECStatus +sftkdbCall_AddSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw) +{ + SECStatus rv; + + rv = sftkdbLoad_Legacy(); + if (rv != SECSuccess) { + return rv; + } + if (!legacy_glue_addSecmod) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return (*legacy_glue_addSecmod)(appName, filename, dbname, module, rw); +} + +CK_RV +sftkdbCall_Shutdown(void) +{ + CK_RV crv = CKR_OK; + if (legacy_glue_lib) { + return CKR_OK; + } + if (legacy_glue_shutdown) { + crv = (*legacy_glue_shutdown)(); + } + PR_UnloadLibrary(legacy_glue_lib); + legacy_glue_lib = NULL; + legacy_glue_open = NULL; + legacy_glue_readSecmod = NULL; + legacy_glue_releaseSecmod = NULL; + legacy_glue_deleteSecmod = NULL; + legacy_glue_addSecmod = NULL; + return crv; +} + + diff --git a/mozilla/security/nss/lib/softoken/lgglue.h b/mozilla/security/nss/lib/softoken/lgglue.h new file mode 100644 index 00000000000..8ced909d355 --- /dev/null +++ b/mozilla/security/nss/lib/softoken/lgglue.h @@ -0,0 +1,92 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1994-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +/* + * This code defines the glue layer between softoken and the legacy DB library + */ +#include "sdb.h" + +/* + * function prototypes for the callbacks into softoken from the legacyDB + */ + +typedef SECStatus (*LGEncryptFunc)(PRArenaPool *arena, SDB *sdb, + SECItem *plainText, SECItem **cipherText); +typedef SECStatus (*LGDecryptFunc)(SDB *sdb, SECItem *cipherText, + SECItem **plainText); + +/* + * function prototypes for the exported functions. + */ +typedef CK_RV (*LGOpenFunc) (const char *dir, const char *certPrefix, + const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB); +typedef char ** (*LGReadSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGReleaseSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char **params, PRBool rw); +typedef SECStatus (*LGDeleteSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGAddSecmodFunc)(const char *appName, + const char *filename, + const char *dbname, char *params, PRBool rw); +typedef SECStatus (*LGShutdownFunc)(void); +typedef void (*LGSetCryptFunc)(LGEncryptFunc, LGDecryptFunc); + + +/* + * Softoken Glue Functions + */ +CK_RV sftkdbCall_open(const char *dir, const char *certPrefix, + const char *keyPrefix, + int certVersion, int keyVersion, int flags, + SDB **certDB, SDB **keyDB); +char ** sftkdbCall_ReadSecmodDB(const char *appName, const char *filename, + const char *dbname, char *params, PRBool rw); +SECStatus sftkdbCall_ReleaseSecmodDBData(const char *appName, + const char *filename, const char *dbname, + char **moduleSpecList, PRBool rw); +SECStatus sftkdbCall_DeleteSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *args, PRBool rw); +SECStatus sftkdbCall_AddSecmodDB(const char *appName, + const char *filename, const char *dbname, + char *module, PRBool rw); +CK_RV sftkdbCall_Shutdown(void); + diff --git a/mozilla/security/nss/lib/softoken/pkcs11u.c b/mozilla/security/nss/lib/softoken/pkcs11u.c index a4ec4fe882b..1a3549861e4 100644 --- a/mozilla/security/nss/lib/softoken/pkcs11u.c +++ b/mozilla/security/nss/lib/softoken/pkcs11u.c @@ -815,7 +815,8 @@ sftk_PutObjectToList(SFTKObject *object, SFTKObjectFreeList *list, */ PRBool optimizeSpace = isSessionObject && ((SFTKSessionObject *)object)->optimizeSpace; - if (!optimizeSpace && (list->count < MAX_OBJECT_LIST_SIZE)) { + if (object->refLock && !optimizeSpace + && (list->count < MAX_OBJECT_LIST_SIZE)) { PZ_Lock(list->lock); object->next = list->head; list->head = object; @@ -1805,18 +1806,18 @@ sftk_addHandle(SFTKSearchResults *search, CK_OBJECT_HANDLE handle) search->size++; } -static CK_OBJECT_CLASS -handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle) +static CK_RV +handleToClass(SFTKSlot *slot, CK_OBJECT_HANDLE handle, + CK_OBJECT_CLASS *objClass) { SFTKDBHandle *dbHandle = sftk_getDBForObject(slot, handle); CK_ATTRIBUTE objClassTemplate; - CK_OBJECT_CLASS objClass = CKO_DATA; + *objClass = CKO_DATA; objClassTemplate.type = CKA_CLASS; - objClassTemplate.pValue = &objClass; - objClassTemplate.ulValueLen = sizeof(objClass); - sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); - return objClass; + objClassTemplate.pValue = objClass; + objClassTemplate.ulValueLen = sizeof(*objClass); + return sftkdb_GetAttributeValue(dbHandle, handle, &objClassTemplate, 1); } SFTKObject * @@ -1825,6 +1826,7 @@ sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) SFTKObject *object = NULL; SFTKTokenObject *tokObject = NULL; PRBool hasLocks = PR_FALSE; + CK_RV crv; object = sftk_GetObjectFromList(&hasLocks, PR_FALSE, &tokenObjectList, 0, PR_FALSE); @@ -1833,8 +1835,13 @@ sftk_NewTokenObject(SFTKSlot *slot, SECItem *dbKey, CK_OBJECT_HANDLE handle) } tokObject = (SFTKTokenObject *) object; - object->objclass = handleToClass(slot, handle); object->handle = handle; + /* every object must have a class, if we can't get it, the object + * doesn't exist */ + crv = handleToClass(slot, handle, &object->objclass); + if (crv != CKR_OK) { + goto loser; + } object->slot = slot; object->objectInfo = NULL; object->infoFree = NULL; diff --git a/mozilla/security/nss/lib/softoken/sdb.c b/mozilla/security/nss/lib/softoken/sdb.c index 3f97b646b3b..84b6b596442 100644 --- a/mozilla/security/nss/lib/softoken/sdb.c +++ b/mozilla/security/nss/lib/softoken/sdb.c @@ -136,7 +136,7 @@ static const CK_ATTRIBUTE_TYPE known_attributes[] = { CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST }; -int known_attributes_size= sizeof(known_attributes)/ +static int known_attributes_size= sizeof(known_attributes)/ sizeof(known_attributes[0]); /* Magic for an explicit NULL. NOTE: ideally this should be @@ -627,7 +627,60 @@ loser: return error; } -static CK_OBJECT_HANDLE next_obj = 0; +/* + * check to see if a candidate object handle already exists. + */ +static PRBool +sdb_objectExists(SDB *sdb, CK_OBJECT_HANDLE candidate) +{ + CK_RV crv; + CK_ATTRIBUTE template = { CKA_LABEL, NULL, 0 }; + + crv = sdb_GetAttributeValue(sdb,candidate,&template, 1); + if (crv == CKR_OBJECT_HANDLE_INVALID) { + return PR_FALSE; + } + return PR_TRUE; +} + +/* + * if we're here, we are in a transaction, so it's safe + * to examine the current state of the database + */ +static CK_OBJECT_HANDLE +sdb_getObjectId(SDB *sdb) +{ + CK_OBJECT_HANDLE candidate; + static CK_OBJECT_HANDLE next_obj = CK_INVALID_HANDLE; + int count; + /* + * get an initial object handle to use + */ + if (next_obj == CK_INVALID_HANDLE) { + PRTime time; + time = PR_Now(); + + next_obj = (CK_OBJECT_HANDLE)(time & 0x3fffffffL); + } + candidate = next_obj++; + /* detect that we've looped through all the handles... */ + for (count = 0; count < 0x40000000; count++, candidate = next_obj++) { + /* mask off excess bits */ + candidate &= 0x3fffffff; + /* if we hit zero, go to the next entry */ + if (candidate == CK_INVALID_HANDLE) { + continue; + } + /* make sure we aren't already using */ + if (!sdb_objectExists(sdb, candidate)) { + /* this one is free */ + return candidate; + } + } + + /* no handle is free, fail */ + return CK_INVALID_HANDLE; +} #define CREATE_CMD "INSERT INTO %s (id%s) VALUES($ID%s);" CK_RV @@ -642,6 +695,7 @@ sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, char *newStr = NULL; int sqlerr = SQLITE_OK; CK_RV error = CKR_OK; + CK_OBJECT_HANDLE this_object; int retry = 0; int i; @@ -650,17 +704,19 @@ sdb_CreateObject(SDB *sdb, CK_OBJECT_HANDLE *object_id, } LOCK_SQLITE() - /* This needs to get the next object ID from the database */ - /* SDB_FIX_ME reviewers don't let this code through as is */ - if (next_obj == 0) { - PRTime time; - time = PR_Now(); - - next_obj = (CK_ULONG)(time & 0x3ffffffL); + if ((*object_id != CK_INVALID_HANDLE) && + !sdb_objectExists(sdb, *object_id)) { + this_object = *object_id; + } else { + this_object = sdb_getObjectId(sdb); + } + if (this_object == CK_INVALID_HANDLE) { + UNLOCK_SQLITE(); + return CKR_HOST_MEMORY; } columnStr = sqlite3_mprintf(""); valueStr = sqlite3_mprintf(""); - *object_id = next_obj++; + *object_id = this_object; for (i=0; columnStr && valueStr && i < count; i++) { newStr = sqlite3_mprintf("%s,a%x", columnStr, template[i].type); sqlite3_free(columnStr); @@ -1186,7 +1242,7 @@ static int tableExists(sqlite3 *sqlDB, const char *tableName) CK_RV sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, - int *needUpdate, int flags, SDB **pSdb) + int *newInit, int flags, SDB **pSdb) { int i; char *initStr = NULL; @@ -1231,6 +1287,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, inTransaction = 1; } if (!tableExists(sqlDB,table)) { + *newInit = 1; if (flags != SDB_CREATE) { error = sdb_mapSQLError(type, SQLITE_CANTOPEN); goto loser; @@ -1272,7 +1329,7 @@ sdb_init(char *dbname, char *table, sdbDataType type, int *inUpdate, sdb_p->sqlXactDB = NULL; sdb_p->sqlXactThread = NULL; sdb->private = sdb_p; - sdb->sdb_type = SDB_SHARED; + sdb->sdb_type = SDB_SQL; sdb->sdb_flags = flags; sdb->sdb_FindObjectsInit = sdb_FindObjectsInit; sdb->sdb_FindObjects = sdb_FindObjects; @@ -1342,17 +1399,18 @@ static char *sdb_BuildFileName(const char * directory, CK_RV s_open(const char *directory, const char *certPrefix, const char *keyPrefix, int cert_version, int key_version, int flags, - SDB **certdb, SDB **keydb) + SDB **certdb, SDB **keydb, int *newInit) { char *cert = sdb_BuildFileName(directory, certPrefix, "cert", cert_version, flags); char *key = sdb_BuildFileName(directory, keyPrefix, "key", key_version, flags); CK_RV error = CKR_OK; - int inUpdate, needUpdate; + int inUpdate; *certdb = NULL; *keydb = NULL; + *newInit = 0; #ifdef SQLITE_UNSAFE_THREADS if (sqlite_lock == NULL) { @@ -1370,7 +1428,7 @@ s_open(const char *directory, const char *certPrefix, const char *keyPrefix, if (certdb) { /* initialize Certificate database */ error = sdb_init(cert, "nssPublic", SDB_CERT, &inUpdate, - &needUpdate, flags, certdb); + newInit, flags, certdb); if (error != CKR_OK) { goto loser; } @@ -1387,7 +1445,7 @@ s_open(const char *directory, const char *certPrefix, const char *keyPrefix, if (keydb) { /* initialize the Key database */ error = sdb_init(key, "nssPrivate", SDB_KEY, &inUpdate, - &needUpdate, flags, keydb); + newInit, flags, keydb); if (error != CKR_OK) { goto loser; } diff --git a/mozilla/security/nss/lib/softoken/sdb.h b/mozilla/security/nss/lib/softoken/sdb.h index 75408e22f96..818bc4bf10a 100644 --- a/mozilla/security/nss/lib/softoken/sdb.h +++ b/mozilla/security/nss/lib/softoken/sdb.h @@ -104,7 +104,7 @@ struct SDBPasswordEntryStr { CK_RV s_open(const char *directory, const char *certPrefix, const char *keyPrefix, int cert_version, int key_version, - int flags, SDB **certdb, SDB **keydb); + int flags, SDB **certdb, SDB **keydb, int *newInit); CK_RV s_shutdown(); /* flags */ diff --git a/mozilla/security/nss/lib/softoken/sftkdb.c b/mozilla/security/nss/lib/softoken/sftkdb.c index 73ed64fbc3c..621d18cd632 100644 --- a/mozilla/security/nss/lib/softoken/sftkdb.c +++ b/mozilla/security/nss/lib/softoken/sftkdb.c @@ -35,8 +35,19 @@ * ***** END LICENSE BLOCK ***** */ /* * The following code handles the storage of PKCS 11 modules used by the - * NSS. This file is written to abstract away how the modules are - * stored so we can deside that later. + * NSS. For the rest of NSS, only one kind of database handle exists: + * + * SFTKDBHandle + * + * There is one SFTKDBHandle for the each key database and one for each cert + * database. These databases are opened as associated pairs, one pair per + * slot. SFTKDBHandles are reference counted objects. + * + * Each SFTKDBHandle points to a low level database handle (SDB). This handle + * represents the underlying physical database. These objects are not + * reference counted, an are 'owned' by their respective SFTKDBHandles. + * + * */ #include "sftkdb.h" #include "pkcs11t.h" @@ -60,9 +71,11 @@ struct SFTKDBHandleStr { SDB *db; PRInt32 ref; - CK_OBJECT_HANDLE type; + CK_OBJECT_HANDLE type; SECItem passwordKey; PZLock *passwordLock; + SFTKDBHandle *peerDB; + SDB *update; }; #define SFTK_KEYDB_TYPE 0x40000000 @@ -294,6 +307,37 @@ sftkdb_fixupTemplateOut(CK_ATTRIBUTE *template, CK_ATTRIBUTE *ntemplate, return crv; } +static CK_RV +sftkdb_CreateObject(SFTKDBHandle *handle, SDB *db, CK_OBJECT_HANDLE *objectID, + CK_ATTRIBUTE *template, CK_ULONG count) +{ + PRBool inTransaction = PR_FALSE; + CK_RV crv; + + crv = (*db->sdb_Begin)(db); + if (crv != CKR_OK) { + goto loser; + } + inTransaction = PR_TRUE; + crv = (*db->sdb_CreateObject)(db, objectID, template, count); + if (crv != CKR_OK) { + goto loser; + } + crv = (*db->sdb_Commit)(db); + inTransaction = PR_FALSE; + +loser: + if (inTransaction) { + (*handle->db->sdb_Abort)(handle->db); + /* It is trivial to show the following code cannot + * happen unless something is horribly wrong with our compilier or + * hardware */ + PORT_Assert(crv != CKR_OK); + if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; + } + return crv; +} + CK_ATTRIBUTE * sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, SFTKDBHandle *handle,CK_ULONG *pcount, @@ -396,6 +440,8 @@ sftk_ExtractTemplate(PLArenaPool *arena, SFTKObject *object, } +#define GET_SDB(handle) ((handle)->update ? (handle)->update : (handle)->db) + CK_RV sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, CK_OBJECT_HANDLE *objectID) @@ -403,12 +449,15 @@ sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, CK_ATTRIBUTE *template; PLArenaPool *arena; CK_ULONG count; - PRBool inTransaction = PR_FALSE; CK_RV crv; + SDB *db; + + *objectID = CK_INVALID_HANDLE; if (handle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } + db = GET_SDB(handle); arena = PORT_NewArena(256); if (arena == NULL) { @@ -419,18 +468,8 @@ sftkdb_write(SFTKDBHandle *handle, SFTKObject *object, if (!template) { goto loser; } - crv = (*handle->db->sdb_Begin)(handle->db); - if (crv != CKR_OK) { - goto loser; - } - inTransaction = PR_TRUE; - crv = (*handle->db->sdb_CreateObject)(handle->db, objectID, - template, count); - if (crv != CKR_OK) { - goto loser; - } - crv = (*handle->db->sdb_Commit)(handle->db); - inTransaction = PR_FALSE; + + crv = sftkdb_CreateObject(handle, db, objectID, template, count); loser: if (arena) { @@ -439,14 +478,6 @@ loser: if (crv == CKR_OK) { *objectID |= (handle->type | SFTK_TOKEN_TYPE); } - if (inTransaction) { - (*handle->db->sdb_Abort)(handle->db); - /* It should be trivial to show the following code cannot - * happen unless something is horribly wrong with our compilier or - * hardware */ - PORT_Assert(crv != CKR_OK); - if (crv == CKR_OK) crv = CKR_GENERAL_ERROR; - } return crv; } @@ -460,10 +491,12 @@ sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, unsigned char *data = NULL; CK_ATTRIBUTE *ntemplate = NULL; CK_RV crv; + SDB *db; if (handle == NULL) { return CKR_OK; } + db = GET_SDB(handle); if (count != 0) { ntemplate = sftkdb_fixupTemplateIn(template, count, &data); @@ -472,7 +505,7 @@ sftkdb_FindObjectsInit(SFTKDBHandle *handle, const CK_ATTRIBUTE *template, } } - crv = (*handle->db->sdb_FindObjectsInit)(handle->db, ntemplate, + crv = (*db->sdb_FindObjectsInit)(db, ntemplate, count, find); if (data) { PORT_Free(ntemplate); @@ -486,12 +519,15 @@ sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, CK_OBJECT_HANDLE *ids, int arraySize, CK_ULONG *count) { CK_RV crv; + SDB *db; + if (handle == NULL) { *count = 0; return CKR_OK; } + db = GET_SDB(handle); - crv = (*handle->db->sdb_FindObjects)(handle->db, find, ids, + crv = (*db->sdb_FindObjects)(db, find, ids, arraySize, count); if (crv == CKR_OK) { int i; @@ -504,10 +540,12 @@ sftkdb_FindObjects(SFTKDBHandle *handle, SDBFind *find, CK_RV sftkdb_FindObjectsFinal(SFTKDBHandle *handle, SDBFind *find) { + SDB *db; if (handle == NULL) { return CKR_OK; } - return (*handle->db->sdb_FindObjectsFinal)(handle->db, find); + db = GET_SDB(handle); + return (*db->sdb_FindObjectsFinal)(db, find); } CK_RV @@ -517,10 +555,13 @@ sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, CK_RV crv,crv2; CK_ATTRIBUTE *ntemplate; unsigned char *data = NULL; + SDB *db; if (handle == NULL) { return CKR_GENERAL_ERROR; } + + db = GET_SDB(handle); /* nothing to do */ if (count == 0) { return CKR_OK; @@ -530,7 +571,7 @@ sftkdb_GetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, return CKR_HOST_MEMORY; } object_id &= SFTK_OBJ_ID_MASK; - crv = (*handle->db->sdb_GetAttributeValue)(handle->db, object_id, + crv = (*db->sdb_GetAttributeValue)(db, object_id, ntemplate, count); crv2 = sftkdb_fixupTemplateOut(template, ntemplate, count, handle); if (crv == CKR_OK) crv = crv2; @@ -549,10 +590,13 @@ sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, CK_RV crv = CKR_OK; CK_ATTRIBUTE *ntemplate; unsigned char *data = NULL; + SDB *db; if (handle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } + + db = GET_SDB(handle); /* nothing to do */ if (count == 0) { return CKR_OK; @@ -562,19 +606,19 @@ sftkdb_SetAttributeValue(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id, return CKR_HOST_MEMORY; } object_id &= SFTK_OBJ_ID_MASK; - crv = (*handle->db->sdb_Begin)(handle->db); + crv = (*db->sdb_Begin)(db); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_SetAttributeValue)(handle->db, object_id, + crv = (*db->sdb_SetAttributeValue)(db, object_id, ntemplate, count); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_Commit)(handle->db); + crv = (*db->sdb_Commit)(db); loser: if (crv != CKR_OK) { - (*handle->db->sdb_Abort)(handle->db); + (*db->sdb_Abort)(db); } if (data) { PORT_Free(ntemplate); @@ -587,22 +631,25 @@ CK_RV sftkdb_DestroyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE object_id) { CK_RV crv = CKR_OK; + SDB *db; + if (handle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } + db = GET_SDB(handle); object_id &= SFTK_OBJ_ID_MASK; - crv = (*handle->db->sdb_Begin)(handle->db); + crv = (*db->sdb_Begin)(db); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_DestroyObject)(handle->db, object_id); + crv = (*db->sdb_DestroyObject)(db, object_id); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_Commit)(handle->db); + crv = (*db->sdb_Commit)(db); loser: if (crv != CKR_OK) { - (*handle->db->sdb_Abort)(handle->db); + (*db->sdb_Abort)(db); } return crv; } @@ -613,6 +660,9 @@ sftkdb_CloseDB(SFTKDBHandle *handle) if (handle == NULL) { return CKR_OK; } + if (handle->update) { + (*handle->update->sdb_Close)(handle->update); + } if (handle->db) { (*handle->db->sdb_Close)(handle->db); } @@ -627,21 +677,23 @@ static CK_RV sftkdb_ResetDB(SFTKDBHandle *handle) { CK_RV crv = CKR_OK; + SDB *db; if (handle == NULL) { return CKR_TOKEN_WRITE_PROTECTED; } - crv = (*handle->db->sdb_Begin)(handle->db); + db = GET_SDB(handle); + crv = (*db->sdb_Begin)(db); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_Reset)(handle->db); + crv = (*db->sdb_Reset)(db); if (crv != CKR_OK) { goto loser; } - crv = (*handle->db->sdb_Commit)(handle->db); + crv = (*db->sdb_Commit)(db); loser: if (crv != CKR_OK) { - (*handle->db->sdb_Abort)(handle->db); + (*db->sdb_Abort)(db); } return crv; } @@ -650,40 +702,49 @@ loser: CK_RV sftkdb_Begin(SFTKDBHandle *handle) { + CK_RV crv = CKR_OK; + SDB *db; + if (handle == NULL) { return CKR_OK; } - if (handle->db) { - (*handle->db->sdb_Begin)(handle->db); + db = GET_SDB(handle); + if (db) { + crv = (*db->sdb_Begin)(db); } - PORT_Free(handle); - return CKR_OK; + return crv; } CK_RV sftkdb_Commit(SFTKDBHandle *handle) { + CK_RV crv = CKR_OK; + SDB *db; + if (handle == NULL) { return CKR_OK; } - if (handle->db) { - (*handle->db->sdb_Commit)(handle->db); + db = GET_SDB(handle); + if (db) { + (*db->sdb_Commit)(db); } - PORT_Free(handle); - return CKR_OK; + return crv; } CK_RV sftkdb_Abort(SFTKDBHandle *handle) { + CK_RV crv = CKR_OK; + SDB *db; + if (handle == NULL) { return CKR_OK; } - if (handle->db) { - (*handle->db->sdb_Abort)(handle->db); + db = GET_SDB(handle); + if (db) { + crv = (db->sdb_Abort)(db); } - PORT_Free(handle); - return CKR_OK; + return crv; } @@ -783,10 +844,49 @@ sftkdb_releaseSpecList(char **moduleSpecList) } #define SECMOD_STEP 10 +static SECStatus +sftkdb_growList(char ***pModuleList, int *useCount, int last) +{ + char **newModuleList; + + *useCount += SECMOD_STEP; + newModuleList = (char **)PORT_Realloc(*pModuleList, + *useCount*sizeof(char *)); + if (newModuleList == NULL) { + return SECFailure; + } + PORT_Memset(&newModuleList[last],0, sizeof(char *)*SECMOD_STEP); + *pModuleList = newModuleList; + return SECSuccess; +} + +static +char *sftk_getOldSecmodName(const char *dbname,const char *filename) +{ + char *file = NULL; + char *dirPath = PORT_Strdup(dbname); + char *sep; + + sep = PORT_Strrchr(dirPath,*PATH_SEPARATOR); +#ifdef WINDOWS + if (!sep) { + sep = PORT_Strrchr(dirPath,'/'); + } +#endif + if (sep) { + *(sep)=0; + } + file= PR_smprintf("%s"PATH_SEPARATOR"%s", dirPath, filename); + PORT_Free(dirPath); + return file; +} + #define MAX_LINE_LENGTH 2048 #define SFTK_DEFAULT_INTERNAL_INIT1 "library= name=\"NSS Internal PKCS #11 Module\" parameters=" #define SFTK_DEFAULT_INTERNAL_INIT2 " NSS=\"Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={" #define SFTK_DEFAULT_INTERNAL_INIT3 " askpw=any timeout=30})\"" + +#include /* * Read all the existing modules in out of the file. */ @@ -796,7 +896,7 @@ sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, char *params, PRBool rw) { FILE *fd = NULL; - char **moduleList = NULL, **newModuleList = NULL; + char **moduleList = NULL; int moduleCount = 1; int useCount = SECMOD_STEP; char line[MAX_LINE_LENGTH]; @@ -946,14 +1046,13 @@ sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, } if ((moduleCount+1) >= useCount) { - useCount += SECMOD_STEP; - newModuleList = - (char **)PORT_Realloc(moduleList,useCount*sizeof(char *)); - if (newModuleList == NULL) goto loser; - moduleList = newModuleList; - PORT_Memset(&moduleList[moduleCount+1],0, - sizeof(char *)*SECMOD_STEP); + SECStatus rv; + rv = sftkdb_growList(&moduleList, &useCount, moduleCount+1); + if (rv != SECSuccess) { + goto loser; + } } + if (internal) { moduleList[0] = moduleString; } else { @@ -970,6 +1069,61 @@ sftkdb_ReadSecmodDB(SDBType dbType, const char *appName, moduleString = NULL; } done: + /* if we couldn't open a pkcs11 database, look for the old one */ + if (fd == NULL) { + char *olddbname = sftk_getOldSecmodName(dbname,filename); + PRStatus status; + char **oldModuleList; + int i; + + /* couldn't get the old name */ + if (!olddbname) { + goto bail; + } + + /* old one doesn't exist */ + status = PR_Access(olddbname, PR_ACCESS_EXISTS); + if (status != PR_SUCCESS) { + goto bail; + } + + oldModuleList = sftkdbCall_ReadSecmodDB(appName, filename, + olddbname, params, rw); + /* old one had no modules */ + if (!oldModuleList) { + goto bail; + } + + /* count the modules */ + for (i=0; oldModuleList[i]; i++) { } + + /* grow the moduleList if necessary */ + if (i >= useCount) { + SECStatus rv; + rv = sftkdb_growList(&moduleList,&useCount,moduleCount+1); + if (rv != SECSuccess) { + goto loser; + } + } + + /* write each module out, and copy it */ + for (i=0; oldModuleList[i]; i++) { + if (rw) { + sftkdb_AddSecmodDB(dbType,appName,filename,dbname, + oldModuleList[i],rw); + } + if (moduleList[i]) { + PORT_Free(moduleList[i]); + } + moduleList[i] = PORT_Strdup(oldModuleList[i]); + } + + /* done with the old module list */ + sftkdbCall_ReleaseSecmodDBData(appName, filename, olddbname, + oldModuleList, rw); + } +bail: + if (!moduleList[0]) { char * newParams; moduleString = PORT_Strdup(SFTK_DEFAULT_INTERNAL_INIT1); @@ -1071,8 +1225,6 @@ sftkdb_DeleteSecmodDB(SDBType dbType, const char *appName, fd2 = fopen(dbname2, "w+"); if (fd2 == NULL) goto loser; -printf("args=|%s|\n", args); - name = sftk_argGetParamValue("name",args); if (name) { name_len = PORT_Strlen(name); @@ -1082,8 +1234,6 @@ printf("args=|%s|\n", args); lib_len = PORT_Strlen(lib); } -if (name) printf("name=|%s|\n",name); -if (lib) printf("lib=|%s|\n",lib); /* * the following loop takes line separated config files and colapses @@ -1178,6 +1328,9 @@ sftkdb_AddSecmodDB(SDBType dbType, const char *appName, return SECFailure; } + /* remove the previous version if it exists */ + (void) sftkdb_DeleteSecmodDB(dbType, appName, filename, dbname, module, rw); + /* do we really want to use streams here */ fd = fopen(dbname, "a+"); if (fd == NULL) { @@ -1524,6 +1677,15 @@ sftkdb_encrypt_stub(PRArenaPool *arena, SDB *sdb, SECItem *plainText, SFTKDBHandle *handle = sdb->app_private; SECStatus rv; + if (handle == NULL) { + return SECFailure; + } + + /* if we aren't th handle, try the other handle */ + if (handle->type != SFTK_KEYDB_TYPE) { + handle = handle->peerDB; + } + /* not a key handle */ if (handle == NULL || handle->passwordLock == NULL) { return SECFailure; @@ -1551,6 +1713,16 @@ sftkdb_decrypt_stub(SDB *sdb, SECItem *cipherText, SECItem **plainText) SFTKDBHandle *handle = sdb->app_private; SECStatus rv; + if (handle == NULL) { + return SECFailure; + } + + /* if we aren't th handle, try the other handle */ + if (handle->type != SFTK_KEYDB_TYPE) { + handle = handle->peerDB; + } + + /* not a key handle */ if (handle == NULL || handle->passwordLock == NULL) { return SECFailure; } @@ -1595,7 +1767,237 @@ sftkdb_switchKeys(SFTKDBHandle *keydb, SECItem *passKey) passKey->len = len; PZ_Unlock(keydb->passwordLock); } + +/* + * known attributes + */ +static const CK_ATTRIBUTE_TYPE known_attributes[] = { + CKA_CLASS, CKA_TOKEN, CKA_PRIVATE, CKA_LABEL, CKA_APPLICATION, + CKA_VALUE, CKA_OBJECT_ID, CKA_CERTIFICATE_TYPE, CKA_ISSUER, + CKA_SERIAL_NUMBER, CKA_AC_ISSUER, CKA_OWNER, CKA_ATTR_TYPES, CKA_TRUSTED, + CKA_CERTIFICATE_CATEGORY, CKA_JAVA_MIDP_SECURITY_DOMAIN, CKA_URL, + CKA_HASH_OF_SUBJECT_PUBLIC_KEY, CKA_HASH_OF_ISSUER_PUBLIC_KEY, + CKA_CHECK_VALUE, CKA_KEY_TYPE, CKA_SUBJECT, CKA_ID, CKA_SENSITIVE, + CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP, CKA_SIGN, CKA_SIGN_RECOVER, + CKA_VERIFY, CKA_VERIFY_RECOVER, CKA_DERIVE, CKA_START_DATE, CKA_END_DATE, + CKA_MODULUS, CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_PRIVATE_EXPONENT, + CKA_PRIME_1, CKA_PRIME_2, CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, + CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_PRIME_BITS, + CKA_SUB_PRIME_BITS, CKA_VALUE_BITS, CKA_VALUE_LEN, CKA_EXTRACTABLE, + CKA_LOCAL, CKA_NEVER_EXTRACTABLE, CKA_ALWAYS_SENSITIVE, + CKA_KEY_GEN_MECHANISM, CKA_MODIFIABLE, CKA_EC_PARAMS, + CKA_EC_POINT, CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, + CKA_ALWAYS_AUTHENTICATE, CKA_WRAP_WITH_TRUSTED, CKA_WRAP_TEMPLATE, + CKA_UNWRAP_TEMPLATE, CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, + CKA_HAS_RESET, CKA_PIXEL_X, CKA_PIXEL_Y, CKA_RESOLUTION, CKA_CHAR_ROWS, + CKA_CHAR_COLUMNS, CKA_COLOR, CKA_BITS_PER_PIXEL, CKA_CHAR_SETS, + CKA_ENCODING_METHODS, CKA_MIME_TYPES, CKA_MECHANISM_TYPE, + CKA_REQUIRED_CMS_ATTRIBUTES, CKA_DEFAULT_CMS_ATTRIBUTES, + CKA_SUPPORTED_CMS_ATTRIBUTES, CKA_NETSCAPE_URL, CKA_NETSCAPE_EMAIL, + CKA_NETSCAPE_SMIME_INFO, CKA_NETSCAPE_SMIME_TIMESTAMP, + CKA_NETSCAPE_PKCS8_SALT, CKA_NETSCAPE_PASSWORD_CHECK, CKA_NETSCAPE_EXPIRES, + CKA_NETSCAPE_KRL, CKA_NETSCAPE_PQG_COUNTER, CKA_NETSCAPE_PQG_SEED, + CKA_NETSCAPE_PQG_H, CKA_NETSCAPE_PQG_SEED_BITS, CKA_NETSCAPE_MODULE_SPEC, + CKA_TRUST_DIGITAL_SIGNATURE, CKA_TRUST_NON_REPUDIATION, + CKA_TRUST_KEY_ENCIPHERMENT, CKA_TRUST_DATA_ENCIPHERMENT, + CKA_TRUST_KEY_AGREEMENT, CKA_TRUST_KEY_CERT_SIGN, CKA_TRUST_CRL_SIGN, + CKA_TRUST_SERVER_AUTH, CKA_TRUST_CLIENT_AUTH, CKA_TRUST_CODE_SIGNING, + CKA_TRUST_EMAIL_PROTECTION, CKA_TRUST_IPSEC_END_SYSTEM, + CKA_TRUST_IPSEC_TUNNEL, CKA_TRUST_IPSEC_USER, CKA_TRUST_TIME_STAMPING, + CKA_TRUST_STEP_UP_APPROVED, CKA_CERT_SHA1_HASH, CKA_CERT_MD5_HASH, + CKA_NETSCAPE_DB, CKA_NETSCAPE_TRUST +}; + +static int known_attributes_size= sizeof(known_attributes)/ + sizeof(known_attributes[0]); + +static CK_RV +sftkdb_GetObjectTemplate(SDB *source, CK_OBJECT_HANDLE id, + CK_ATTRIBUTE *ptemplate, CK_ULONG *max) +{ + int i,j; + CK_RV crv; + + if (*max < known_attributes_size) { + *max = known_attributes_size; + return CKR_BUFFER_TOO_SMALL; + } + for (i=0; i < known_attributes_size; i++) { + ptemplate[i].type = known_attributes[i]; + ptemplate[i].pValue = NULL; + ptemplate[i].ulValueLen = 0; + } + + crv = (*source->sdb_GetAttributeValue)(source, id, + ptemplate, known_attributes_size); + + if ((crv != CKR_OK) && (crv != CKR_ATTRIBUTE_TYPE_INVALID)) { + return crv; + } + + for (i=0, j=0; i < known_attributes_size; i++, j++) { + while (i < known_attributes_size && (ptemplate[i].ulValueLen == -1)) { + i++; + } + if (i >= known_attributes_size) { + break; + } + /* cheap optimization */ + if (i == j) { + continue; + } + ptemplate[j] = ptemplate[i]; + } + *max = j; + return CKR_OK; +} + +#ifdef notdef +static void +dump_attribute(CK_ATTRIBUTE *attr) +{ + unsigned char *buf = attr->pValue; + int count,i; + + printf("%08x: (%d) ",attr->type, attr->ulValueLen); + count = attr->ulValueLen; + if (count > 10) count = 10; + for (i=0; i < count; i++) { + printf("%02x",buf[i]); + } + printf("\n"); +} +#endif + + +#define MAX_ATTRIBUTES 500 +static CK_RV +sftkdb_copyObject(SFTKDBHandle *handle, CK_OBJECT_HANDLE id, SECItem *key) +{ + CK_ATTRIBUTE template[MAX_ATTRIBUTES]; + CK_ATTRIBUTE *ptemplate; + CK_ULONG max_attributes = MAX_ATTRIBUTES; + SDB *source = handle->update; + SDB *target = handle->db; + int i; + CK_RV crv; + + ptemplate = &template[0]; + id &= SFTK_OBJ_ID_MASK; + crv = sftkdb_GetObjectTemplate(source, id, ptemplate, &max_attributes); + if (crv == CKR_BUFFER_TOO_SMALL) { + ptemplate = PORT_NewArray(CK_ATTRIBUTE, max_attributes); + if (ptemplate == NULL) { + crv = CKR_HOST_MEMORY; + } else { + crv = sftkdb_GetObjectTemplate(source, id, + ptemplate, &max_attributes); + } + } + if (crv != CKR_OK) { + goto loser; + } + + for (i=0; i < max_attributes; i++) { + ptemplate[i].pValue = PORT_Alloc(ptemplate[i].ulValueLen); + if (ptemplate[i].pValue == NULL) { + crv = CKR_HOST_MEMORY; + goto loser; + } + } + crv = (*source->sdb_GetAttributeValue)(source, id, + ptemplate, max_attributes); + if (crv != CKR_OK) { + goto loser; + } + + crv = sftkdb_CreateObject(handle, target, &id, ptemplate, max_attributes); + if (ptemplate && ptemplate != template) { + PORT_Free(ptemplate); + } + +loser: + if (ptemplate) { + for (i=0; i < max_attributes; i++) { + if (ptemplate[i].pValue) { + PORT_Memset(ptemplate[i].pValue, 0, ptemplate[i].ulValueLen); + PORT_Free(ptemplate[i].pValue); + } + } + if (ptemplate != template) { + PORT_Free(ptemplate); + } + } + return crv; +} + + +#define MAX_IDS 10 +/* + * update a new database from an old one, now that we have the key + */ +static CK_RV +sftkdb_update(SFTKDBHandle *handle, SECItem *key) +{ + SDBFind *find = NULL; + CK_ULONG idCount = MAX_IDS; + CK_OBJECT_HANDLE ids[MAX_IDS]; + CK_RV crv, crv2; + PRBool inTransaction = PR_FALSE; + int i; + + if (handle == NULL) { + return CKR_OK; + } + if (handle->update == NULL) { + return CKR_OK; + } + /* find all the objects */ + crv = sftkdb_FindObjectsInit(handle, NULL, 0, &find); + + if (crv != CKR_OK) { + goto loser; + } + while ((crv == CKR_OK) && (idCount == MAX_IDS)) { + crv = sftkdb_FindObjects(handle, find, ids, MAX_IDS, &idCount); + for (i=0; (crv == CKR_OK) && (i < idCount); i++) { + crv = sftkdb_copyObject(handle, ids[i], key); + } + } + crv2 = sftkdb_FindObjectsFinal(handle, find); + if (crv == CKR_OK) crv = crv2; + +loser: + /* update Meta data - even if we didn't update objects */ + if (handle->type == SFTK_KEYDB_TYPE) { + SDBPasswordEntry entry; + crv = (*handle->db->sdb_Begin)(handle->db); + if (crv != CKR_OK) { + goto loser2; + } + inTransaction = PR_TRUE; + crv = (*handle->update->sdb_GetPWEntry)(handle->update, & entry); + if (crv != CKR_OK) { + goto loser2; + } + crv = (*handle->db->sdb_PutPWEntry)(handle->db, &entry); + if (crv != CKR_OK) { + goto loser2; + } + crv = (*handle->db->sdb_Commit)(handle->db); + inTransaction = PR_FALSE; + } +loser2: + if (inTransaction) { + (*handle->db->sdb_Abort)(handle->db); + } + if (handle->update) { + (*handle->update->sdb_Close)(handle->update); + handle->update = NULL; + } + return crv; +} /* * return success if we have a valid password entry. @@ -1607,11 +2009,18 @@ sftkdb_HasPasswordSet(SFTKDBHandle *keydb) { SDBPasswordEntry entry; CK_RV crv; + SDB *db; - if (keydb == NULL || keydb->db == NULL) { + if (keydb == NULL) { return SECFailure; } - crv = (*keydb->db->sdb_GetPWEntry)(keydb->db, &entry); + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } + + crv = (*db->sdb_GetPWEntry)(db, &entry); return (crv == CKR_OK) ? SECSuccess : SECFailure; } @@ -1628,15 +2037,25 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw) SDBPasswordEntry entry; SECItem key; SECItem *result = NULL; + SDB *db; CK_RV crv; + if (keydb == NULL) { + return SECFailure; + } + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } + key.data = NULL; key.len = 0; if (pw == NULL) pw=""; /* get the entry from the database */ - crv = (*keydb->db->sdb_GetPWEntry)(keydb->db, &entry); + crv = (*db->sdb_GetPWEntry)(db, &entry); if (crv != CKR_OK) { rv = SECFailure; goto loser; @@ -1658,7 +2077,15 @@ sftkdb_CheckPassword(SFTKDBHandle *keydb, const char *pw) * return Success */ if ((result->len == SFTK_PW_CHECK_LEN) && PORT_Memcmp(result->data, SFTK_PW_CHECK_STRING, SFTK_PW_CHECK_LEN) == 0){ + /* load the keys, so the keydb can parse it's key set */ sftkdb_switchKeys(keydb, &key); + if (keydb->update) { + /* update the peer certdb if it exists */ + if (keydb->peerDB) { + sftkdb_update(keydb->peerDB, &key); + } + sftkdb_update(keydb, &key); + } } else { rv = SECFailure; /*PORT_SetError( bad password); */ @@ -1816,7 +2243,6 @@ loser: /* * must be called with the old key active. */ -#define MAX_IDS 10 SECStatus sftkdb_convertPrivateObjects(SFTKDBHandle *keydb, SECItem *newKey) { @@ -1866,6 +2292,16 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin) SECItem *result = NULL; SDBPasswordEntry entry; CK_RV crv; + SDB *db; + + if (keydb == NULL) { + return SECFailure; + } + + db = GET_SDB(keydb); + if (db == NULL) { + return SECFailure; + } newKey.data = NULL; @@ -1875,7 +2311,7 @@ sftkdb_ChangePassword(SFTKDBHandle *keydb, char *oldPin, char *newPin) rv = SECFailure; goto loser; } - crv = (*keydb->db->sdb_GetPWEntry)(keydb->db, &entry); + crv = (*db->sdb_GetPWEntry)(db, &entry); if (crv == CKR_OK) { rv = sftkdb_CheckPassword(keydb, oldPin); if (rv == SECFailure) { @@ -2037,6 +2473,8 @@ sftk_NewDBHandle(SDB *sdb, int type) SFTKDBHandle *handle = PORT_New(SFTKDBHandle); handle->ref = 1; handle->db = sdb; + handle->update = NULL; + handle->peerDB = NULL; handle->type = type; handle->passwordKey.data = NULL; handle->passwordKey.len = 0; @@ -2069,8 +2507,61 @@ sftkdb_ResetKeyDB(SFTKDBHandle *handle) return SECSuccess; } +static PRBool +sftk_oldVersionExists(const char *dir, int version) +{ + int i; + PRStatus exists = PR_FAILURE; + char *file = NULL; + + for (i=version; i > 1 ; i--) { + file = PR_smprintf("%s%d.db",dir,i); + if (file == NULL) { + continue; + } + exists = PR_Access(file, PR_ACCESS_EXISTS); + PR_smprintf_free(file); + if (exists == PR_SUCCESS) { + return PR_TRUE; + } + } + return PR_FALSE; +} + +static PRBool +sftk_hasLegacyDB(const char *confdir, const char *certPrefix, + const char *keyPrefix, int certVersion, int keyVersion) +{ + char *dir; + PRBool exists; + + dir= PR_smprintf("%s/%scert", confdir, certPrefix); + if (dir == NULL) { + return PR_FALSE; + } + + exists = sftk_oldVersionExists(dir, certVersion); + PR_smprintf_free(dir); + if (exists) { + return PR_TRUE; + } + + dir= PR_smprintf("%s/%skey", confdir, keyPrefix); + if (dir == NULL) { + return PR_FALSE; + } + + exists = sftk_oldVersionExists(dir, keyVersion); + PR_smprintf_free(dir); + return exists; +} + /* - * initialize certificate and key database handles + * initialize certificate and key database handles as a pair. + * + * This function figures out what type of database we are opening and + * calls the appropriate low level function to open the database. + * It also figures out whether or not to setup up automatic update. */ CK_RV sftk_DBInit(const char *configdir, const char *certPrefix, @@ -2084,6 +2575,8 @@ sftk_DBInit(const char *configdir, const char *certPrefix, SDB *keySDB, *certSDB; CK_RV crv = CKR_OK; int flags = SDB_RDONLY; + PRBool newInit = PR_FALSE; + PRBool needUpdate = PR_FALSE; if (!readOnly) { flags = SDB_CREATE; @@ -2109,10 +2602,31 @@ sftk_DBInit(const char *configdir, const char *certPrefix, crv = sftkdbCall_open(configdir, certPrefix, keyPrefix, 8, 3, flags, noCertDB? NULL : &certSDB, noKeyDB ? NULL: &keySDB); break; - case SDB_SHARED: - case SDB_LOADABLE: /* SHOULD open a loadable db */ + case SDB_SQL: + case SDB_EXTERN: /* SHOULD open a loadable db */ crv = s_open(confdir, certPrefix, keyPrefix, 9, 4, flags, - noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB); + noCertDB? NULL : &certSDB, noKeyDB ? NULL : &keySDB, &newInit); + + /* + * if we failed to open the DB's read only, use the old ones if + * the exists. + */ + if (crv != CKR_OK && (flags == SDB_RDONLY)) { + if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { + /* we have legacy databases, if we failed to open the new format + * DB's read only, just use the legacy ones */ + crv = sftkdbCall_open(confdir, certPrefix, + keyPrefix, 8, 3, flags, noCertDB? NULL : &certSDB, + noKeyDB ? NULL : &keySDB); + } + } else if (newInit && crv == CKR_OK) { + /* if the new format DB was also a newly created DB, and we + * succeeded, then need to update that new database with data + * from the existing legacy DB */ + if (sftk_hasLegacyDB(confdir, certPrefix, keyPrefix, 8, 3)) { + needUpdate = 1; + } + } break; default: crv = CKR_GENERAL_ERROR; /* can't happen, EvaluationConfigDir MUST @@ -2129,13 +2643,39 @@ sftk_DBInit(const char *configdir, const char *certPrefix, } if (!noKeyDB) { *keyDB = sftk_NewDBHandle(keySDB, SFTK_KEYDB_TYPE); - if (certSDB) { - certSDB->app_private = *keyDB; - } } else { *keyDB = NULL; } + /* link them together */ + if (*certDB) { + (*certDB)->peerDB = *keyDB; + } + if (*keyDB) { + (*keyDB)->peerDB = *certDB; + } + + if (needUpdate) { + SDB *updateCert = NULL; + SDB *updateKey = NULL; + CK_RV crv2; + + crv2 = sftkdbCall_open(confdir, certPrefix, keyPrefix, 8, 3, flags, + noCertDB ? NULL : &updateCert, noKeyDB ? NULL : &updateKey); + if (crv2 == CKR_OK) { + if (*certDB) { + (*certDB)->update = updateCert; + updateCert->app_private = (*certDB); + } + if (*keyDB) { + (*keyDB)->update = updateKey; + updateKey->app_private = (*keyDB); + } else { + /* we don't have a key DB, update the certificate DB now */ + sftkdb_update(*certDB, NULL); + } + } + } loser: if (appName) { PORT_Free(appName); @@ -2148,5 +2688,6 @@ sftkdb_Shutdown(void) { s_shutdown(); sftkdbCall_Shutdown(); + return CKR_OK; } diff --git a/mozilla/security/nss/lib/softoken/sftkdbt.h b/mozilla/security/nss/lib/softoken/sftkdbt.h index 655c0e4e804..f9d7c9eaa89 100644 --- a/mozilla/security/nss/lib/softoken/sftkdbt.h +++ b/mozilla/security/nss/lib/softoken/sftkdbt.h @@ -8,8 +8,8 @@ typedef struct SFTKDBHandleStr SFTKDBHandle; typedef enum { - SDB_SHARED, - SDB_LOADABLE, + SDB_SQL, + SDB_EXTERN, SDB_LEGACY, SDB_MULTIACCESS } SDBType; diff --git a/mozilla/security/nss/lib/softoken/sftkpars.c b/mozilla/security/nss/lib/softoken/sftkpars.c index 30334c2c0ae..96189937eeb 100644 --- a/mozilla/security/nss/lib/softoken/sftkpars.c +++ b/mozilla/security/nss/lib/softoken/sftkpars.c @@ -518,8 +518,8 @@ sftk_freeParams(sftk_parameters *params) FREE_CLEAR(params->tokens); } -#define SHAREDB "shared:" -#define LOADABLE "load:" +#define SQLDB "sql:" +#define EXTERNDB "extern:" #define LEGACY "dbm:" const char * sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName) @@ -543,12 +543,12 @@ sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName) cdir++; } configdir = cdir; - } else if (PORT_Strncmp(configdir, SHAREDB, sizeof(SHAREDB)-1) == 0) { - *dbType = SDB_SHARED; - configdir = configdir + sizeof(SHAREDB) -1; - } else if (PORT_Strncmp(configdir, LOADABLE, sizeof(LOADABLE)-1) == 0) { - *dbType = SDB_LOADABLE; - configdir = configdir + sizeof(LOADABLE) -1; + } else if (PORT_Strncmp(configdir, SQLDB, sizeof(SQLDB)-1) == 0) { + *dbType = SDB_SQL; + configdir = configdir + sizeof(SQLDB) -1; + } else if (PORT_Strncmp(configdir, EXTERNDB, sizeof(EXTERNDB)-1) == 0) { + *dbType = SDB_EXTERN; + configdir = configdir + sizeof(EXTERNDB) -1; } else if (PORT_Strncmp(configdir, LEGACY, sizeof(LEGACY)-1) == 0) { *dbType = SDB_LEGACY; configdir = configdir + sizeof(LEGACY) -1; @@ -559,10 +559,10 @@ sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName) /* none specified, go with the legacy */ return configdir; } - if (PORT_Strncmp(defaultType, SHAREDB, sizeof(SHAREDB)-2) == 0) { - *dbType = SDB_SHARED; - } else if (PORT_Strncmp(defaultType,LOADABLE,sizeof(LOADABLE)-2)==0) { - *dbType = SDB_LOADABLE; + if (PORT_Strncmp(defaultType, SQLDB, sizeof(SQLDB)-2) == 0) { + *dbType = SDB_SQL; + } else if (PORT_Strncmp(defaultType,EXTERNDB,sizeof(EXTERNDB)-2)==0) { + *dbType = SDB_EXTERN; } else if (PORT_Strncmp(defaultType, LEGACY, sizeof(LEGACY)-2) == 0) { *dbType = SDB_LEGACY; } @@ -572,7 +572,7 @@ sftk_EvaluateConfigDir(const char *configdir, SDBType *dbType, char **appName) char * sftk_getSecmodName(char *param, SDBType *dbType, char **appName, - char **filename,PRBool *rw) + char **filename, PRBool *rw) { int next; char *configdir = NULL; @@ -597,10 +597,15 @@ sftk_getSecmodName(char *param, SDBType *dbType, char **appName, if (secmodName) PORT_Free(secmodName); secmodName = PORT_Strdup(SECMOD_DB); } - *filename = secmodName; + *filename = secmodName; lconfigdir = sftk_EvaluateConfigDir(configdir, dbType, appName); + /* only use the renamed secmod for legacy databases */ + if ((*dbType != SDB_LEGACY) && (*dbType != SDB_MULTIACCESS)) { + secmodName="pkcs11.txt"; + } + if (lconfigdir) { value = PR_smprintf("%s" PATH_SEPARATOR "%s",lconfigdir,secmodName); } else {