summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwtc%netscape.com <devnull@localhost>2002-12-17 05:35:07 +0000
committerwtc%netscape.com <devnull@localhost>2002-12-17 05:35:07 +0000
commit8fdcddee79fdc74043e47296b76a8f6a2e1303f7 (patch)
treecf18422ea2a1289d399df64782525838f3195b88
parent8703ea0ca7d05542047e4fc5e4743c30a86e7b89 (diff)
downloadnss-hg-8fdcddee79fdc74043e47296b76a8f6a2e1303f7.tar.gz
Bug 183612: added support for looking up a cert by subject key ID and
creating a CMS recipient info from a subject key ID. The patch was contributed by Javi Delgadillo <javi@netscape.com>. r=relyea, wtc. Modified Files: certdb/cert.h certdb/certdb.c certdb/certdb.h certdb/certv3.c certdb/stanpcertdb.c nss/nss.def nss/nssinit.c pk11wrap/pk11cert.c pk11wrap/pk11func.h pk11wrap/secmod.h pki/pki3hack.c smime/cms.h smime/cmslocal.h smime/cmspubkey.c smime/cmsrecinfo.c smime/cmssiginfo.c smime/cmst.h smime/smime.def Tag: NSS_3_7_BRANCH
-rw-r--r--security/nss/lib/certdb/cert.h5
-rw-r--r--security/nss/lib/certdb/certdb.c160
-rw-r--r--security/nss/lib/certdb/certdb.h22
-rw-r--r--security/nss/lib/certdb/certv3.c2
-rw-r--r--security/nss/lib/nss/nss.def2
-rw-r--r--security/nss/lib/nss/nssinit.c5
-rw-r--r--security/nss/lib/pk11wrap/pk11cert.c137
-rw-r--r--security/nss/lib/pk11wrap/pk11func.h3
-rw-r--r--security/nss/lib/pk11wrap/secmod.h16
-rw-r--r--security/nss/lib/pki/pki3hack.c2
-rw-r--r--security/nss/lib/smime/cms.h9
-rw-r--r--security/nss/lib/smime/cmslocal.h10
-rw-r--r--security/nss/lib/smime/cmspubkey.c39
-rw-r--r--security/nss/lib/smime/cmsrecinfo.c190
-rw-r--r--security/nss/lib/smime/cmssiginfo.c12
-rw-r--r--security/nss/lib/smime/cmst.h35
-rw-r--r--security/nss/lib/smime/smime.def7
17 files changed, 571 insertions, 85 deletions
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h
index da8c53777..39ab8e4a8 100644
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -478,6 +478,9 @@ CERT_FindCertByKeyID (CERTCertDBHandle *handle, SECItem *name, SECItem *keyID);
extern CERTCertificate *
CERT_FindCertByIssuerAndSN (CERTCertDBHandle *handle, CERTIssuerAndSN *issuerAndSN);
+extern CERTCertificate *
+CERT_FindCertBySubjKeyID (CERTCertDBHandle *handle, SECItem *subjKeyID);
+
/*
** Find a certificate in the database by a nickname
** "nickname" is the ascii string nickname to look for
@@ -922,7 +925,7 @@ extern SECStatus CERT_FindKeyUsageExtension (CERTCertificate *cert,
/* Return the decoded value of the subjectKeyID extension. The caller should
** free up the storage allocated in retItem->data.
*/
-extern SECStatus CERT_FindSubjectKeyIDExten (CERTCertificate *cert,
+extern SECStatus CERT_FindSubjectKeyIDExtension (CERTCertificate *cert,
SECItem *retItem);
/*
diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c
index 8bfe1a58c..270e6a05d 100644
--- a/security/nss/lib/certdb/certdb.c
+++ b/security/nss/lib/certdb/certdb.c
@@ -670,7 +670,7 @@ cert_GetKeyID(CERTCertificate *cert)
cert->subjectKeyID.len = 0;
/* see of the cert has a key identifier extension */
- rv = CERT_FindSubjectKeyIDExten(cert, &tmpitem);
+ rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
if ( rv == SECSuccess ) {
cert->subjectKeyID.data = (unsigned char*) PORT_ArenaAlloc(cert->arena, tmpitem.len);
if ( cert->subjectKeyID.data != NULL ) {
@@ -747,7 +747,7 @@ cert_IsRootCert(CERTCertificate *cert)
/* authority key identifier is present */
if (cert->authKeyID->keyID.len > 0) {
/* the keyIdentifier field is set, look for subjectKeyID */
- rv = CERT_FindSubjectKeyIDExten(cert, &tmpitem);
+ rv = CERT_FindSubjectKeyIDExtension(cert, &tmpitem);
if (rv == SECSuccess) {
PRBool match;
/* also present, they MUST match for it to be a root */
@@ -2737,3 +2737,159 @@ CERT_SetStatusConfig(CERTCertDBHandle *handle, CERTStatusConfig *statusConfig)
PORT_Assert(handle->statusConfig == NULL);
handle->statusConfig = statusConfig;
}
+
+/*
+ * Code for dealing with subjKeyID to cert mappings.
+ */
+
+static PLHashTable *gSubjKeyIDHash = NULL;
+static PRLock *gSubjKeyIDLock = NULL;
+
+static void *cert_AllocTable(void *pool, PRSize size)
+{
+ return PORT_Alloc(size);
+}
+
+static void cert_FreeTable(void *pool, void *item)
+{
+ PORT_Free(item);
+}
+
+static PLHashEntry* cert_AllocEntry(void *pool, const void *key)
+{
+ return PORT_New(PLHashEntry);
+}
+
+static void cert_FreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+ SECITEM_FreeItem((SECItem*)(he->value), PR_TRUE);
+ if (flag == HT_FREE_ENTRY) {
+ SECITEM_FreeItem((SECItem*)(he->key), PR_TRUE);
+ PORT_Free(he);
+ }
+}
+
+static PLHashAllocOps cert_AllocOps = {
+ cert_AllocTable, cert_FreeTable, cert_AllocEntry, cert_FreeEntry
+};
+
+SECStatus
+CERT_CreateSubjKeyIDHashTable(void)
+{
+ gSubjKeyIDHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ SECITEM_HashCompare,
+ &cert_AllocOps, NULL);
+ if (!gSubjKeyIDHash) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ gSubjKeyIDLock = PR_NewLock();
+ if (!gSubjKeyIDLock) {
+ PL_HashTableDestroy(gSubjKeyIDHash);
+ gSubjKeyIDHash = NULL;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+ return SECSuccess;
+
+}
+
+SECStatus
+CERT_AddSubjKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert)
+{
+ SECItem *newKeyID, *oldVal, *newVal;
+ SECStatus rv = SECFailure;
+
+ if (!gSubjKeyIDLock) {
+ /* If one is created, then both are there. So only check for one. */
+ return SECFailure;
+ }
+
+ newVal = SECITEM_DupItem(&cert->derCert);
+ if (!newVal) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto done;
+ }
+ newKeyID = SECITEM_DupItem(subjKeyID);
+ if (!newKeyID) {
+ SECITEM_FreeItem(newVal, PR_TRUE);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ goto done;
+ }
+
+ PR_Lock(gSubjKeyIDLock);
+ /* The hash table implementation does not free up the memory
+ * associated with the key of an already existing entry if we add a
+ * duplicate, so we would wind up leaking the previously allocated
+ * key if we don't remove before adding.
+ */
+ oldVal = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
+ if (oldVal) {
+ PL_HashTableRemove(gSubjKeyIDHash, subjKeyID);
+ }
+
+ rv = (PL_HashTableAdd(gSubjKeyIDHash, newKeyID, newVal)) ? SECSuccess :
+ SECFailure;
+ PR_Unlock(gSubjKeyIDLock);
+done:
+ return rv;
+}
+
+SECStatus
+CERT_RemoveSubjKeyIDMapping(SECItem *subjKeyID)
+{
+ SECStatus rv;
+ if (!gSubjKeyIDLock)
+ return SECFailure;
+
+ PR_Lock(gSubjKeyIDLock);
+ rv = (PL_HashTableRemove(gSubjKeyIDHash, subjKeyID)) ? SECSuccess :
+ SECFailure;
+ PR_Unlock(gSubjKeyIDLock);
+ return rv;
+}
+
+SECStatus
+CERT_DestroySubjKeyIDHashTable(void)
+{
+ if (gSubjKeyIDHash) {
+ PR_Lock(gSubjKeyIDLock);
+ PL_HashTableDestroy(gSubjKeyIDHash);
+ gSubjKeyIDHash = NULL;
+ PR_Unlock(gSubjKeyIDLock);
+ PR_DestroyLock(gSubjKeyIDLock);
+ gSubjKeyIDLock = NULL;
+ }
+ return SECSuccess;
+}
+
+SECItem*
+CERT_FindDERCertBySubjKeyID(SECItem *subjKeyID)
+{
+ SECItem *val;
+
+ if (!gSubjKeyIDLock)
+ return NULL;
+
+ PR_Lock(gSubjKeyIDLock);
+ val = (SECItem*)PL_HashTableLookup(gSubjKeyIDHash, subjKeyID);
+ if (val) {
+ val = SECITEM_DupItem(val);
+ }
+ PR_Unlock(gSubjKeyIDLock);
+ return val;
+}
+
+CERTCertificate*
+CERT_FindCertBySubjKeyID(CERTCertDBHandle *handle, SECItem *subjKeyID)
+{
+ CERTCertificate *cert = NULL;
+ SECItem *derCert;
+
+ derCert = CERT_FindDERCertBySubjKeyID(subjKeyID);
+ if (derCert) {
+ cert = CERT_FindCertByDERCert(handle, derCert);
+ SECITEM_FreeItem(derCert, PR_TRUE);
+ }
+ return cert;
+}
diff --git a/security/nss/lib/certdb/certdb.h b/security/nss/lib/certdb/certdb.h
index 7340961c2..2c6cdd9aa 100644
--- a/security/nss/lib/certdb/certdb.h
+++ b/security/nss/lib/certdb/certdb.h
@@ -154,6 +154,28 @@ SECStatus
SEC_CrlReplaceUrl(PCERTSignedCrl *crl,char *url);
#endif
+/*
+ * These functions are used to map subjectKeyID extension values to certs.
+ */
+SECStatus
+CERT_CreateSubjKeyIDHashTable(void);
+
+SECStatus
+CERT_AddSubjKeyIDMapping(SECItem *subjKeyID, CERTCertificate *cert);
+
+
+/*
+ * Call this function to remove an entry from the mapping table.
+ */
+SECStatus
+CERT_RemoveSubjKeyIDMapping(SECItem *subjKeyID);
+
+SECStatus
+CERT_DestroySubjKeyIDHashTable(void);
+
+SECItem*
+CERT_FindDERCertBySubjKeyID(SECItem *subjKeyID);
+
SEC_END_PROTOS
#endif /* _CERTDB_H_ */
diff --git a/security/nss/lib/certdb/certv3.c b/security/nss/lib/certdb/certv3.c
index 9b5979364..e50c66279 100644
--- a/security/nss/lib/certdb/certv3.c
+++ b/security/nss/lib/certdb/certv3.c
@@ -291,7 +291,7 @@ CERT_FindKeyUsageExtension(CERTCertificate *cert, SECItem *retItem)
* get the value of the X.509 v3 Key Usage Extension
*/
SECStatus
-CERT_FindSubjectKeyIDExten(CERTCertificate *cert, SECItem *retItem)
+CERT_FindSubjectKeyIDExtension(CERTCertificate *cert, SECItem *retItem)
{
SECItem encodedValue;
diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def
index 0bc28e972..473a45228 100644
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -718,6 +718,8 @@ SECKEY_CopyPublicKey;
;+ global:
CERT_CRLCacheRefreshIssuer;
CERT_EncodeAltNameExtension;
+CERT_FindCertBySubjKeyID;
+CERT_FindSubjectKeyIDExtension;
CERT_GetFirstEmailAddress;
CERT_GetNextEmailAddress;
CERT_VerifySignedDataWithPubKeyInfo;
diff --git a/security/nss/lib/nss/nssinit.c b/security/nss/lib/nss/nssinit.c
index 3d8b2d4c2..13bf7d702 100644
--- a/security/nss/lib/nss/nssinit.c
+++ b/security/nss/lib/nss/nssinit.c
@@ -41,6 +41,7 @@
#include "prprf.h"
#include "prmem.h"
#include "cert.h"
+#include "certdb.h"
#include "key.h"
#include "ssl.h"
#include "sslproto.h"
@@ -476,6 +477,8 @@ loser:
}
#endif
pk11sdr_Init();
+ CERT_CreateSubjKeyIDHashTable();
+ SECMOD_InitCallOnce();
nss_IsInitted = PR_TRUE;
}
return rv;
@@ -545,6 +548,8 @@ NSS_Shutdown(void)
ShutdownCRLCache();
SECOID_Shutdown();
STAN_Shutdown();
+ CERT_DestroySubjKeyIDHashTable();
+ SECMOD_CleanupCallOnce();
rv = SECMOD_Shutdown();
pk11sdr_Shutdown();
nss_IsInitted = PR_FALSE;
diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c
index abc8e55df..d4a192e1f 100644
--- a/security/nss/lib/pk11wrap/pk11cert.c
+++ b/security/nss/lib/pk11wrap/pk11cert.c
@@ -2153,11 +2153,16 @@ pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipien
for (i=0; (ri = recipientlist[i]) != NULL; i++) {
CERTCertificate *cert = NULL;
- /* XXXXX fixme - not yet implemented! */
- if (ri->kind == RLSubjKeyID)
- continue;
- cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN,
- pwarg);
+ if (ri->kind == RLSubjKeyID) {
+ SECItem *derCert = CERT_FindDERCertBySubjKeyID(ri->id.subjectKeyID);
+ if (derCert) {
+ cert = PK11_FindCertFromDERCertItem(slot, derCert, pwarg);
+ SECITEM_FreeItem(derCert, PR_TRUE);
+ }
+ } else {
+ cert = PK11_FindCertByIssuerAndSNOnToken(slot, ri->id.issuerAndSN,
+ pwarg);
+ }
if (cert) {
/* this isn't our cert */
if ((cert->trust == NULL) ||
@@ -2169,7 +2174,6 @@ pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipien
*rlIndex = i;
return cert;
}
-
}
*rlIndex = -1;
return NULL;
@@ -2335,6 +2339,34 @@ loser:
return NULL;
}
+static SECMODCallOnceType keyIDHashCallOnce;
+
+static SECStatus PR_CALLBACK
+pk11_keyIDHash_populate(void *wincx)
+{
+ CERTCertList *certList;
+ CERTCertListNode *node = NULL;
+ SECItem subjKeyID = {siBuffer, NULL, 0};
+
+ certList = PK11_ListCerts(PK11CertListUser, wincx);
+ if (!certList) {
+ return SECFailure;
+ }
+
+ for (node = CERT_LIST_HEAD(certList);
+ !CERT_LIST_END(node, certList);
+ node = CERT_LIST_NEXT(node)) {
+ if (CERT_FindSubjectKeyIDExtension(node->cert,
+ &subjKeyID) == SECSuccess &&
+ subjKeyID.data != NULL) {
+ CERT_AddSubjKeyIDMapping(&subjKeyID, node->cert);
+ SECITEM_FreeItem(&subjKeyID, PR_FALSE);
+ }
+ }
+ CERT_DestroyCertList(certList);
+ return SECSuccess;
+}
+
/*
* This is the new version of the above function for NSS SMIME code
* this stuff should REALLY be in the SMIME code, but some things in here are not public
@@ -2345,8 +2377,13 @@ PK11_FindCertAndKeyByRecipientListNew(NSSCMSRecipient **recipientlist, void *win
{
CERTCertificate *cert;
NSSCMSRecipient *rl;
+ SECStatus srv;
int rlIndex;
+ srv = SECMOD_CallOnce(&keyIDHashCallOnce, pk11_keyIDHash_populate, wincx);
+ if (srv != SECSuccess)
+ return -1;
+
cert = pk11_AllFindCertObjectByRecipientNew(recipientlist, wincx, &rlIndex);
if (!cert) {
return -1;
@@ -2888,43 +2925,21 @@ CERTCertificate *
PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx)
{
-#ifdef NSS_CLASSIC
- CK_OBJECT_CLASS certClass = CKO_CERTIFICATE;
- CK_ATTRIBUTE theTemplate[] = {
- { CKA_VALUE, NULL, 0 },
- { CKA_CLASS, NULL, 0 }
- };
- /* if you change the array, change the variable below as well */
- int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]);
- CK_OBJECT_HANDLE certh;
- CK_ATTRIBUTE *attrs = theTemplate;
- SECStatus rv;
-
- PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data,
- cert->derCert.len); attrs++;
- PK11_SETATTRS(attrs, CKA_CLASS, &certClass, sizeof(certClass));
+ return PK11_FindCertFromDERCertItem(slot, &cert->derCert, wincx);
+}
- /*
- * issue the find
- */
- if ( !PK11_IsFriendly(slot)) {
- rv = PK11_Authenticate(slot, PR_TRUE, wincx);
- if (rv != SECSuccess) return NULL;
- }
+CERTCertificate *
+PK11_FindCertFromDERCertItem(PK11SlotInfo *slot, SECItem *inDerCert,
+ void *wincx)
- certh = pk11_getcerthandle(slot,cert,theTemplate,tsize);
- if (certh == CK_INVALID_HANDLE) {
- return NULL;
- }
- return PK11_MakeCertFromHandle(slot, certh, NULL);
-#else
+{
CERTCertificate *rvCert = NULL;
NSSCertificate *c;
NSSDER derCert;
NSSToken *tok;
NSSTrustDomain *td = STAN_GetDefaultTrustDomain();
tok = PK11Slot_GetNSSToken(slot);
- NSSITEM_FROM_SECITEM(&derCert, &cert->derCert);
+ NSSITEM_FROM_SECITEM(&derCert, inDerCert);
if (!PK11_IsFriendly(slot)) {
if (PK11_Authenticate(slot, PR_TRUE, wincx) != SECSuccess) {
PK11_FreeSlot(slot);
@@ -2954,7 +2969,6 @@ PK11_FindCertFromDERCert(PK11SlotInfo *slot, CERTCertificate *cert,
rvCert = STAN_GetCERTCertificate(c);
}
return rvCert;
-#endif
}
/* mcgreer 3.4 -- nobody uses this, ignoring */
@@ -4137,3 +4151,54 @@ CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url,
}
return (crl);
}
+
+/*
+ * This code takes the NSPR CallOnce functionality and modifies it so
+ * that we can pass an argument to our function
+ */
+static struct {
+ PRLock *ml;
+ PRCondVar *cv;
+} mod_init;
+
+void SECMOD_InitCallOnce(void) {
+ mod_init.ml = PR_NewLock();
+ PORT_Assert(NULL != mod_init.ml);
+ mod_init.cv = PR_NewCondVar(mod_init.ml);
+ PORT_Assert(NULL != mod_init.cv);
+}
+
+void SECMOD_CleanupCallOnce()
+{
+ if (mod_init.ml) {
+ PR_DestroyLock(mod_init.ml);
+ mod_init.ml = NULL;
+ }
+ if (mod_init.cv) {
+ PR_DestroyCondVar(mod_init.cv);
+ mod_init.cv = NULL;
+ }
+}
+
+SECStatus SECMOD_CallOnce(SECMODCallOnceType *once,
+ SECMODCallOnceFN func,
+ void *arg)
+{
+
+ if (!once->initialized) {
+ if (PR_AtomicSet(&once->inProgress, 1) == 0) {
+ once->status = (PRStatus)(*func)(arg);
+ PR_Lock(mod_init.ml);
+ once->initialized = 1;
+ PR_NotifyAllCondVar(mod_init.cv);
+ PR_Unlock(mod_init.ml);
+ } else {
+ PR_Lock(mod_init.ml);
+ while (!once->initialized) {
+ PR_WaitCondVar(mod_init.cv, PR_INTERVAL_NO_TIMEOUT);
+ }
+ PR_Unlock(mod_init.ml);
+ }
+ }
+ return once->status;
+}
diff --git a/security/nss/lib/pk11wrap/pk11func.h b/security/nss/lib/pk11wrap/pk11func.h
index 0a450659c..9f91085cf 100644
--- a/security/nss/lib/pk11wrap/pk11func.h
+++ b/security/nss/lib/pk11wrap/pk11func.h
@@ -66,7 +66,6 @@ PK11SlotListElement *PK11_FindSlotElement(PK11SlotList *list,
* Generic Slot Management
************************************************************/
PK11SlotInfo *PK11_ReferenceSlot(PK11SlotInfo *slot);
-PK11SlotInfo *PK11_FindSlotByID(SECMODModuleID modID,CK_SLOT_ID slotID);
void PK11_FreeSlot(PK11SlotInfo *slot);
SECStatus PK11_DestroyObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object);
SECStatus PK11_DestroyTokenObject(PK11SlotInfo *slot,CK_OBJECT_HANDLE object);
@@ -461,6 +460,8 @@ SECStatus PK11_TraverseCertsForSubjectInSlot(CERTCertificate *cert,
void *arg);
CERTCertificate *PK11_FindCertFromDERCert(PK11SlotInfo *slot,
CERTCertificate *cert, void *wincx);
+CERTCertificate *PK11_FindCertFromDERCertItem(PK11SlotInfo *slot,
+ SECItem *derCert, void *wincx);
CERTCertificate *PK11_FindCertFromDERSubjectAndNickname(
PK11SlotInfo *slot,
CERTCertificate *cert, char *nickname,
diff --git a/security/nss/lib/pk11wrap/secmod.h b/security/nss/lib/pk11wrap/secmod.h
index fd8037e65..51fabec75 100644
--- a/security/nss/lib/pk11wrap/secmod.h
+++ b/security/nss/lib/pk11wrap/secmod.h
@@ -148,6 +148,22 @@ extern unsigned long SECMOD_InternaltoPubMechFlags(unsigned long internalFlags);
extern unsigned long SECMOD_PubCipherFlagstoInternal(unsigned long publicFlags);
extern unsigned long SECMOD_InternaltoPubCipherFlags(unsigned long internalFlags);
+typedef struct SECMODCallOnceType {
+ PRIntn initialized;
+ PRInt32 inProgress;
+ SECStatus status;
+} SECMODCallOnceType;
+
+typedef SECStatus (PR_CALLBACK *SECMODCallOnceFN)(void *arg);
+
+extern void SECMOD_InitCallOnce();
+
+extern SECStatus SECMOD_CallOnce(SECMODCallOnceType *once,
+ SECMODCallOnceFN func,
+ void *arg);
+
+extern void SECMOD_CleanupCallOnce();
+
SEC_END_PROTOS
#endif
diff --git a/security/nss/lib/pki/pki3hack.c b/security/nss/lib/pki/pki3hack.c
index 1d06b7f34..a828f98c8 100644
--- a/security/nss/lib/pki/pki3hack.c
+++ b/security/nss/lib/pki/pki3hack.c
@@ -248,7 +248,7 @@ nss3certificate_matchIdentifier(nssDecodedCert *dc, void *id)
/* keyIdentifier */
if (authKeyID->keyID.len > 0) {
- if (CERT_FindSubjectKeyIDExten(c, &skid) == SECSuccess) {
+ if (CERT_FindSubjectKeyIDExtension(c, &skid) == SECSuccess) {
PRBool skiEqual;
skiEqual = SECITEM_ItemsAreEqual(&authKeyID->keyID, &skid);
PORT_Free(skid.data);
diff --git a/security/nss/lib/smime/cms.h b/security/nss/lib/smime/cms.h
index 7035a3265..e5ce768c4 100644
--- a/security/nss/lib/smime/cms.h
+++ b/security/nss/lib/smime/cms.h
@@ -859,6 +859,15 @@ NSS_CMSEnvelopedData_Decode_AfterEnd(NSSCMSEnvelopedData *envd);
extern NSSCMSRecipientInfo *
NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert);
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
+ SECItem *subjKeyID,
+ SECKEYPublicKey *pubKey);
+
+extern NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
+ CERTCertificate *cert);
+
extern void
NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri);
diff --git a/security/nss/lib/smime/cmslocal.h b/security/nss/lib/smime/cmslocal.h
index e7f15c4e1..962871804 100644
--- a/security/nss/lib/smime/cmslocal.h
+++ b/security/nss/lib/smime/cmslocal.h
@@ -161,8 +161,14 @@ NSS_CMSCipherContext_Encrypt(NSSCMSCipherContext *cc, unsigned char *output,
* according to PKCS#1 and RFC2633 (S/MIME)
*/
extern SECStatus
-NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
- SECItem *encKey);
+NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
+ PK11SymKey *key,
+ SECItem *encKey);
+
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
+ SECKEYPublicKey *publickey,
+ PK11SymKey *bulkkey, SECItem *encKey);
/*
* NSS_CMSUtil_DecryptSymKey_RSA - unwrap a RSA-wrapped symmetric key
diff --git a/security/nss/lib/smime/cmspubkey.c b/security/nss/lib/smime/cmspubkey.c
index 3e06da556..1cf0336e4 100644
--- a/security/nss/lib/smime/cmspubkey.c
+++ b/security/nss/lib/smime/cmspubkey.c
@@ -56,29 +56,43 @@
* according to PKCS#1 and RFC2633 (S/MIME)
*/
SECStatus
-NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *bulkkey,
- SECItem *encKey)
+NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert,
+ PK11SymKey *bulkkey,
+ SECItem *encKey)
{
- SECOidTag certalgtag; /* the certificate's encryption algorithm */
- SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
SECStatus rv;
SECKEYPublicKey *publickey;
+
+ publickey = CERT_ExtractPublicKey(cert);
+ if (publickey == NULL)
+ return SECFailure;
+
+ rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, publickey, bulkkey, encKey);
+ SECKEY_DestroyPublicKey(publickey);
+ return rv;
+}
+
+SECStatus
+NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
+ SECKEYPublicKey *publickey,
+ PK11SymKey *bulkkey, SECItem *encKey)
+{
+ SECStatus rv;
int data_len;
+ KeyType keyType;
void *mark = NULL;
- /* sanity check */
- certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
- PORT_Assert(certalgtag == SEC_OID_PKCS1_RSA_ENCRYPTION);
- encalgtag = SEC_OID_PKCS1_RSA_ENCRYPTION;
- publickey = CERT_ExtractPublicKey(cert);
- if (publickey == NULL)
- goto loser;
-
mark = PORT_ArenaMark(poolp);
if (!mark)
goto loser;
+ /* sanity check */
+ keyType = SECKEY_GetPublicKeyType(publickey);
+ PORT_Assert(keyType == rsaKey);
+ if (keyType != rsaKey) {
+ goto loser;
+ }
/* allocate memory for the encrypted key */
data_len = SECKEY_PublicKeyStrength(publickey); /* block size (assumed to be > keylen) */
encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, data_len);
@@ -90,7 +104,6 @@ NSS_CMSUtil_EncryptSymKey_RSA(PLArenaPool *poolp, CERTCertificate *cert, PK11Sym
rv = PK11_PubWrapSymKey(PK11_AlgtagToMechanism(SEC_OID_PKCS1_RSA_ENCRYPTION),
publickey, bulkkey, encKey);
- SECKEY_DestroyPublicKey(publickey);
if (rv != SECSuccess)
goto loser;
diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c
index dfe05a07a..d6270da25 100644
--- a/security/nss/lib/smime/cmsrecinfo.c
+++ b/security/nss/lib/smime/cmsrecinfo.c
@@ -47,14 +47,24 @@
#include "pk11func.h"
#include "secerr.h"
-/*
- * NSS_CMSRecipientInfo_Create - create a recipientinfo
- *
- * we currently do not create KeyAgreement recipientinfos with multiple recipientEncryptedKeys
- * the certificate is supposed to have been verified by the caller
- */
+PRBool
+nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri)
+{
+ if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) {
+ NSSCMSRecipientIdentifier *rid;
+ rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
+ if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) {
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE;
+}
+
+
NSSCMSRecipientInfo *
-NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
+nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type,
+ CERTCertificate *cert, SECKEYPublicKey *pubKey,
+ SECItem *subjKeyID)
{
NSSCMSRecipientInfo *ri;
void *mark;
@@ -65,6 +75,8 @@ NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
unsigned long version;
SECItem *dummy;
PLArenaPool *poolp;
+ CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
+ NSSCMSRecipientIdentifier *rid;
poolp = cmsg->poolp;
@@ -75,26 +87,64 @@ NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
goto loser;
ri->cmsg = cmsg;
- ri->cert = CERT_DupCertificate(cert);
- if (ri->cert == NULL)
- goto loser;
+ if (type == NSSCMSRecipientID_IssuerSN) {
+ ri->cert = CERT_DupCertificate(cert);
+ if (ri->cert == NULL)
+ goto loser;
+ spki = &(cert->subjectPublicKeyInfo);
+ } else {
+ PORT_Assert(pubKey);
+ spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey);
+ }
- certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+ certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
+ rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier;
switch (certalgtag) {
case SEC_OID_PKCS1_RSA_ENCRYPTION:
ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
- /* hardcoded issuerSN choice for now */
- ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType = NSSCMSRecipientID_IssuerSN;
- ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
- if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) {
+ rid->identifierType = type;
+ if (type == NSSCMSRecipientID_IssuerSN) {
+ rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert);
+ if (rid->id.issuerAndSN == NULL) {
+ break;
+ }
+ } else if (type == NSSCMSRecipientID_SubjectKeyID){
+ NSSCMSKeyTransRecipientInfoEx *riExtra;
+
+ rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
+ if (rid->id.subjectKeyID == NULL) {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ break;
+ }
+ SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID);
+ if (rid->id.subjectKeyID->data == NULL) {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ break;
+ }
+ riExtra = &ri->ri.keyTransRecipientInfoEx;
+ riExtra->version = 0;
+ riExtra->pubKey = SECKEY_CopyPublicKey(pubKey);
+ if (riExtra->pubKey == NULL) {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ break;
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;
- break;
}
break;
case SEC_OID_MISSI_KEA_DSS_OLD:
case SEC_OID_MISSI_KEA_DSS:
case SEC_OID_MISSI_KEA:
+ PORT_Assert(type != NSSCMSRecipientID_SubjectKeyID);
+ if (type == NSSCMSRecipientID_SubjectKeyID) {
+ rv = SECFailure;
+ break;
+ }
/* backward compatibility - this is not really a keytrans operation */
ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans;
/* hardcoded issuerSN choice for now */
@@ -106,6 +156,11 @@ NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
}
break;
case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
+ PORT_Assert(type != NSSCMSRecipientID_SubjectKeyID);
+ if (type == NSSCMSRecipientID_SubjectKeyID) {
+ rv = SECFailure;
+ break;
+ }
/* a key agreement op */
ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree;
@@ -184,13 +239,70 @@ NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
}
PORT_ArenaUnmark (poolp, mark);
+ if (freeSpki)
+ SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
return ri;
loser:
+ if (freeSpki)
+ SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
PORT_ArenaRelease (poolp, mark);
return NULL;
}
+/*
+ * NSS_CMSRecipientInfo_Create - create a recipientinfo
+ *
+ * we currently do not create KeyAgreement recipientinfos with multiple
+ * recipientEncryptedKeys the certificate is supposed to have been
+ * verified by the caller
+ */
+NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert)
+{
+ return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert,
+ NULL, NULL);
+}
+
+NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg,
+ SECItem *subjKeyID,
+ SECKEYPublicKey *pubKey)
+{
+ return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID,
+ NULL, pubKey, subjKeyID);
+}
+
+NSSCMSRecipientInfo *
+NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg,
+ CERTCertificate *cert)
+{
+ SECKEYPublicKey *pubKey = NULL;
+ SECItem subjKeyID = {siBuffer, NULL, 0};
+ NSSCMSRecipientInfo *retVal = NULL;
+
+ if (!cmsg || !cert) {
+ return NULL;
+ }
+ pubKey = CERT_ExtractPublicKey(cert);
+ if (!pubKey) {
+ goto done;
+ }
+ if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess ||
+ subjKeyID.data == NULL) {
+ goto done;
+ }
+ retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey);
+done:
+ if (pubKey)
+ SECKEY_DestroyPublicKey(pubKey);
+
+ if (subjKeyID.data)
+ SECITEM_FreeItem(&subjKeyID, PR_FALSE);
+
+ return retVal;
+}
+
void
NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
{
@@ -198,6 +310,14 @@ NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri)
/* issuerAndSN was allocated on the pool, so no need to destroy it */
if (ri->cert != NULL)
CERT_DestroyCertificate(ri->cert);
+
+ if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) {
+ NSSCMSKeyTransRecipientInfoEx *extra;
+ extra = &ri->ri.keyTransRecipientInfoEx;
+ if (extra->pubKey)
+ SECKEY_DestroyPublicKey(extra->pubKey);
+ }
+
/* recipientInfo structure itself was allocated on the pool, so no need to destroy it */
/* we're done. */
}
@@ -275,7 +395,8 @@ NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri)
}
SECStatus
-NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, SECOidTag bulkalgtag)
+NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
+ SECOidTag bulkalgtag)
{
CERTCertificate *cert;
SECOidTag certalgtag;
@@ -283,22 +404,46 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, S
SECItem *params = NULL;
NSSCMSRecipientEncryptedKey *rek;
NSSCMSOriginatorIdentifierOrKey *oiok;
+ CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL;
PLArenaPool *poolp;
+ NSSCMSKeyTransRecipientInfoEx *extra;
+ PRBool usesSubjKeyID;
poolp = ri->cmsg->poolp;
cert = ri->cert;
- PORT_Assert (cert != NULL);
- if (cert == NULL)
+ usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri);
+ if (cert) {
+ spki = &cert->subjectPublicKeyInfo;
+ certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm));
+ } else if (usesSubjKeyID) {
+ extra = &ri->ri.keyTransRecipientInfoEx;
+ /* sanity check */
+ PORT_Assert(extra->pubKey);
+ if (!extra->pubKey) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey);
+ certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
+ } else {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
+ }
/* XXX set ri->recipientInfoType to the proper value here */
/* or should we look if it's been set already ? */
- certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
+ certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm);
switch (certalgtag) {
case SEC_OID_PKCS1_RSA_ENCRYPTION:
/* wrap the symkey */
- if (NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, &ri->ri.keyTransRecipientInfo.encKey) != SECSuccess) {
+ if (usesSubjKeyID) {
+ rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey,
+ bulkkey, &ri->ri.keyTransRecipientInfo.encKey);
+ if (rv != SECSuccess)
+ break;
+ } else if (NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey,
+ &ri->ri.keyTransRecipientInfo.encKey) != SECSuccess) {
rv = SECFailure;
break;
}
@@ -353,6 +498,9 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, S
rv = SECFailure;
break;
}
+ if (freeSpki)
+ SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
+
return rv;
}
diff --git a/security/nss/lib/smime/cmssiginfo.c b/security/nss/lib/smime/cmssiginfo.c
index a9c46d07e..a858f9ae6 100644
--- a/security/nss/lib/smime/cmssiginfo.c
+++ b/security/nss/lib/smime/cmssiginfo.c
@@ -566,6 +566,7 @@ CERTCertificate *
NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
{
CERTCertificate *cert;
+ NSSCMSSignerIdentifier *sid;
if (signerinfo->cert != NULL)
return signerinfo->cert;
@@ -580,16 +581,13 @@ NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDB
* we leave this function -- we let the clean-up of the entire
* cinfo structure later do the destroy of this cert.
*/
- switch (signerinfo->signerIdentifier.identifierType) {
+ sid = &signerinfo->signerIdentifier;
+ switch (sid->identifierType) {
case NSSCMSSignerID_IssuerSN:
- cert = CERT_FindCertByIssuerAndSN(certdb, signerinfo->signerIdentifier.id.issuerAndSN);
+ cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
break;
case NSSCMSSignerID_SubjectKeyID:
-#if 0 /* not yet implemented */
- cert = CERT_FindCertBySubjectKeyID(certdb, signerinfo->signerIdentifier.id.subjectKeyID);
-#else
- cert = NULL;
-#endif
+ cert = CERT_FindCertBySubjKeyID(certdb, sid->id.subjectKeyID);
break;
default:
cert = NULL;
diff --git a/security/nss/lib/smime/cmst.h b/security/nss/lib/smime/cmst.h
index 105ade583..2fa63a3b8 100644
--- a/security/nss/lib/smime/cmst.h
+++ b/security/nss/lib/smime/cmst.h
@@ -303,6 +303,18 @@ struct NSSCMSKeyTransRecipientInfoStr {
};
typedef struct NSSCMSKeyTransRecipientInfoStr NSSCMSKeyTransRecipientInfo;
+/*
+ * View comments before NSSCMSRecipientInfoStr for purpose of this
+ * structure.
+ */
+struct NSSCMSKeyTransRecipientInfoExStr {
+ NSSCMSKeyTransRecipientInfo recipientInfo;
+ int version;
+ SECKEYPublicKey *pubKey;
+};
+
+typedef struct NSSCMSKeyTransRecipientInfoExStr NSSCMSKeyTransRecipientInfoEx;
+
#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN 0 /* what we *create* */
#define NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY 2 /* what we *create* */
@@ -399,12 +411,35 @@ typedef enum {
NSSCMSRecipientInfoID_KEK = 2
} NSSCMSRecipientInfoIDSelector;
+/*
+ * In order to preserve backwards binary compatibility when implementing
+ * creation of Recipient Info's that uses subjectKeyID in the
+ * keyTransRecipientInfo we need to stash a public key pointer in this
+ * structure somewhere. We figured out that NSSCMSKeyTransRecipientInfo
+ * is the smallest member of the ri union. We're in luck since that's
+ * the very structure that would need to use the public key. So we created
+ * a new structure NSSCMSKeyTransRecipientInfoEx which has a member
+ * NSSCMSKeyTransRecipientInfo as the first member followed by a version
+ * and a public key pointer. This way we can keep backwards compatibility
+ * without changing the size of this structure.
+ *
+ * BTW, size of structure:
+ * NSSCMSKeyTransRecipientInfo: 9 ints, 4 pointers
+ * NSSCMSKeyAgreeRecipientInfo: 12 ints, 8 pointers
+ * NSSCMSKEKRecipientInfo: 10 ints, 7 pointers
+ *
+ * The new structure:
+ * NSSCMSKeyTransRecipientInfoEx: sizeof(NSSCMSKeyTransRecipientInfo) +
+ * 1 int, 1 pointer
+ */
+
struct NSSCMSRecipientInfoStr {
NSSCMSRecipientInfoIDSelector recipientInfoType;
union {
NSSCMSKeyTransRecipientInfo keyTransRecipientInfo;
NSSCMSKeyAgreeRecipientInfo keyAgreeRecipientInfo;
NSSCMSKEKRecipientInfo kekRecipientInfo;
+ NSSCMSKeyTransRecipientInfoEx keyTransRecipientInfoEx;
} ri;
/* --------- local; not part of encoding --------- */
NSSCMSMessage * cmsg; /* back pointer to message */
diff --git a/security/nss/lib/smime/smime.def b/security/nss/lib/smime/smime.def
index dde59aaad..87ba37f6d 100644
--- a/security/nss/lib/smime/smime.def
+++ b/security/nss/lib/smime/smime.def
@@ -216,3 +216,10 @@ NSS_CMSSignerInfo_CreateWithSubjKeyID;
;+ local:
;+ *;
;+};
+;+NSS_3.7 { # NSS 3.7 release
+;+ global:
+NSS_CMSRecipientInfo_CreateWithSubjKeyID;
+NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert;
+;+ local:
+;+ *;
+;+};