diff --git a/security/nss/lib/smime/cms.h b/security/nss/lib/smime/cms.h index e410dd9c535b..1b1a33097246 100644 --- a/security/nss/lib/smime/cms.h +++ b/security/nss/lib/smime/cms.h @@ -34,7 +34,7 @@ /* * Interfaces of the CMS implementation. * - * $Id: cms.h,v 1.15 2002/12/17 01:39:45 wtc%netscape.com Exp $ + * $Id: cms.h,v 1.16 2003/02/28 23:32:29 relyea%netscape.com Exp $ */ #ifndef _CMS_H_ @@ -868,9 +868,35 @@ extern NSSCMSRecipientInfo * NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, CERTCertificate *cert); +/* + * NSS_CMSRecipientInfo_CreateNew - create a blank recipientinfo for + * applications which want to encode their own CMS structures and + * key exchange types. + */ +extern NSSCMSRecipientInfo * +NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg); + +/* + * NSS_CMSRecipientInfo_CreateFromDER - create a recipientinfo from partially + * decoded DER data for applications which want to encode their own CMS + * structures and key exchange types. + */ +extern NSSCMSRecipientInfo * +NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg); + extern void NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri); +/* + * NSS_CMSRecipientInfo_GetCertAndKey - retrieve the cert and key from the + * recipientInfo struct. If retcert or retkey are NULL, the cert or + * key (respectively) would not be returned). This function is a no-op if both + * retcert and retkey are NULL. Caller inherits ownership of the cert and key + * he requested (and is responsible to free them). + */ +SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, + CERTCertificate** retcert, SECKEYPrivateKey** retkey); + extern int NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri); diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c index 6b6911690d5d..ba5b1aaa49b3 100644 --- a/security/nss/lib/smime/cmsrecinfo.c +++ b/security/nss/lib/smime/cmsrecinfo.c @@ -34,7 +34,7 @@ /* * CMS recipientInfo methods. * - * $Id: cmsrecinfo.c,v 1.10 2003/01/17 02:49:07 wtc%netscape.com Exp $ + * $Id: cmsrecinfo.c,v 1.11 2003/02/28 23:32:29 relyea%netscape.com Exp $ */ #include "cmslocal.h" @@ -61,10 +61,11 @@ nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri) } +static SECOidData fakeContent = { 0 }; NSSCMSRecipientInfo * nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, CERTCertificate *cert, SECKEYPublicKey *pubKey, - SECItem *subjKeyID) + SECItem *subjKeyID, void* pwfn_arg, SECItem* DERinput) { NSSCMSRecipientInfo *ri; void *mark; @@ -77,6 +78,16 @@ nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, PLArenaPool *poolp; CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; NSSCMSRecipientIdentifier *rid; + extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; + + if (!cmsg) { + /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc + * and a private arena pool */ + cmsg = NSS_CMSMessage_Create(NULL); + cmsg->pwfn_arg = pwfn_arg; + /* mark it as a special cms message */ + cmsg->contentInfo.contentTypeTag = &fakeContent; + } poolp = cmsg->poolp; @@ -87,14 +98,43 @@ nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, goto loser; ri->cmsg = cmsg; - 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); + + if (DERinput) { + /* decode everything from DER */ + SECItem newinput; + SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); + if (SECSuccess != rv) + goto loser; + rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); + if (SECSuccess != rv) + goto loser; + } + + switch (type) { + case NSSCMSRecipientID_IssuerSN: + { + ri->cert = CERT_DupCertificate(cert); + if (NULL == ri->cert) + goto loser; + spki = &(cert->subjectPublicKeyInfo); + break; + } + + case NSSCMSRecipientID_SubjectKeyID: + { + PORT_Assert(pubKey); + spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); + break; + } + + case NSSCMSRecipientID_BrandNew: + goto done; + break; + + default: + /* unkown type */ + goto loser; + break; } certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); @@ -238,15 +278,20 @@ nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, NSSCMSRecipientIDSelector type, } +done: PORT_ArenaUnmark (poolp, mark); if (freeSpki) SECKEY_DestroySubjectPublicKeyInfo(freeSpki); return ri; loser: - if (freeSpki) + if (freeSpki) { SECKEY_DestroySubjectPublicKeyInfo(freeSpki); + } PORT_ArenaRelease (poolp, mark); + if (cmsg->contentInfo.contentTypeTag == &fakeContent) { + NSS_CMSMessage_Destroy(cmsg); + } return NULL; } @@ -261,16 +306,31 @@ NSSCMSRecipientInfo * NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert) { return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, - NULL, NULL); + NULL, NULL, NULL, NULL); } +NSSCMSRecipientInfo * +NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg) +{ + return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, + NULL, NULL, pwfn_arg, NULL); +} + +NSSCMSRecipientInfo * +NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg) +{ + return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, + NULL, NULL, pwfn_arg, input); +} + + NSSCMSRecipientInfo * NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID, SECKEYPublicKey *pubKey) { return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, - NULL, pubKey, subjKeyID); + NULL, pubKey, subjKeyID, NULL, NULL); } NSSCMSRecipientInfo * @@ -306,6 +366,9 @@ done: void NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) { + if (!ri) { + return; + } /* version was allocated on the pool, so no need to destroy it */ /* issuerAndSN was allocated on the pool, so no need to destroy it */ if (ri->cert != NULL) @@ -317,8 +380,10 @@ NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) if (extra->pubKey) SECKEY_DestroyPublicKey(extra->pubKey); } + if (ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { + NSS_CMSMessage_Destroy(ri->cmsg); + } - /* recipientInfo structure itself was allocated on the pool, so no need to destroy it */ /* we're done. */ } @@ -576,3 +641,78 @@ NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, loser: return NULL; } + +SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, + CERTCertificate** retcert, + SECKEYPrivateKey** retkey) +{ + CERTCertificate* cert = NULL; + NSSCMSRecipient** recipients = NULL; + NSSCMSRecipientInfo* recipientInfos[2]; + SECStatus rv = SECSuccess; + SECKEYPrivateKey* key = NULL; + + if (!ri) + return SECFailure; + + if (!retcert && !retkey) { + /* nothing requested, nothing found, success */ + return SECSuccess; + } + + if (retcert) { + *retcert = NULL; + } + if (retkey) { + *retkey = NULL; + } + + if (ri->cert) { + cert = CERT_DupCertificate(ri->cert); + if (!cert) { + rv = SECFailure; + } + } + if (SECSuccess == rv && !cert) { + /* we don't have the cert, we have to look for it */ + /* first build an NSS_CMSRecipient */ + recipientInfos[0] = ri; + recipientInfos[1] = NULL; + + recipients = nss_cms_recipient_list_create(recipientInfos); + if (recipients) { + /* now look for the cert and key */ + if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, + ri->cmsg->pwfn_arg)) { + cert = CERT_DupCertificate(recipients[0]->cert); + key = SECKEY_CopyPrivateKey(recipients[0]->privkey); + } else { + rv = SECFailure; + } + + nss_cms_recipient_list_destroy(recipients); + } + else { + rv = SECFailure; + } + } else if (SECSuccess == rv && cert && retkey) { + /* we have the cert, we just need the key now */ + key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); + } + if (retcert) { + *retcert = cert; + } else { + if (cert) { + CERT_DestroyCertificate(cert); + } + } + if (retkey) { + *retkey = key; + } else { + if (key) { + SECKEY_DestroyPrivateKey(key); + } + } + + return rv; +} diff --git a/security/nss/lib/smime/cmst.h b/security/nss/lib/smime/cmst.h index 8d4373edc3f2..8c42f88f6aba 100644 --- a/security/nss/lib/smime/cmst.h +++ b/security/nss/lib/smime/cmst.h @@ -34,7 +34,7 @@ /* * Header for CMS types. * - * $Id: cmst.h,v 1.7 2002/12/24 02:25:36 wtc%netscape.com Exp $ + * $Id: cmst.h,v 1.8 2003/02/28 23:32:29 relyea%netscape.com Exp $ */ #ifndef _CMST_H_ @@ -283,7 +283,8 @@ struct NSSCMSOriginatorInfoStr { */ typedef enum { NSSCMSRecipientID_IssuerSN = 0, - NSSCMSRecipientID_SubjectKeyID = 1 + NSSCMSRecipientID_SubjectKeyID = 1, + NSSCMSRecipientID_BrandNew = 2 } NSSCMSRecipientIDSelector; struct NSSCMSRecipientIdentifierStr { diff --git a/security/nss/lib/smime/smime.def b/security/nss/lib/smime/smime.def index c80e7e73a086..9cdeb658f19d 100644 --- a/security/nss/lib/smime/smime.def +++ b/security/nss/lib/smime/smime.def @@ -230,3 +230,11 @@ NSS_CMSRecipientInfo_UnwrapBulkKey; ;+ local: ;+ *; ;+}; +;+NSS_3.8 { # NSS 3.8 release +;+ global: +NSS_CMSRecipientInfo_CreateNew; +NSS_CMSRecipientInfo_CreateFromDER; +NSS_CMSRecipientInfo_GetCertAndKey; +;+ local: +;+ *; +;+};