From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- security/nss/lib/smime/cmsrecinfo.c | 669 ++++++++++++++++++++++++++++++++++++ 1 file changed, 669 insertions(+) create mode 100644 security/nss/lib/smime/cmsrecinfo.c (limited to 'security/nss/lib/smime/cmsrecinfo.c') diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c new file mode 100644 index 0000000000..20dd698e8f --- /dev/null +++ b/security/nss/lib/smime/cmsrecinfo.c @@ -0,0 +1,669 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* + * CMS recipientInfo methods. + */ + +#include "cmslocal.h" + +#include "cert.h" +#include "keyhi.h" +#include "secasn1.h" +#include "secitem.h" +#include "secoid.h" +#include "pk11func.h" +#include "secerr.h" + +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; +} + +/* + * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier + * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have + * been exported, and we would have added an ordinary enum to handle this + * check. Unfortunatly wo don't have that luxury so we are overloading the + * contentTypeTag field. NO code should every try to interpret this content tag + * as a real OID tag, or use any fields other than pwfn_arg or poolp of this + * CMSMessage for that matter */ +static const SECOidData fakeContent; +NSSCMSRecipientInfo * +nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, + NSSCMSRecipientIDSelector type, + CERTCertificate *cert, + SECKEYPublicKey *pubKey, + SECItem *subjKeyID, + void *pwfn_arg, + SECItem *DERinput) +{ + NSSCMSRecipientInfo *ri; + void *mark; + SECOidTag certalgtag; + SECStatus rv = SECSuccess; + NSSCMSRecipientEncryptedKey *rek; + NSSCMSOriginatorIdentifierOrKey *oiok; + unsigned long version; + SECItem *dummy; + 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 = (SECOidData *)&fakeContent; + } + + poolp = cmsg->poolp; + + mark = PORT_ArenaMark(poolp); + + ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); + if (ri == NULL) + goto loser; + + ri->cmsg = cmsg; + + if (DERinput) { + /* decode everything from DER */ + SECItem newinput; + 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)); + + rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; + switch (certalgtag) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; + 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; + } + rv = SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); + if (rv != SECSuccess || 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; + case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ + PORT_Assert(type == NSSCMSRecipientID_IssuerSN); + if (type != NSSCMSRecipientID_IssuerSN) { + rv = SECFailure; + break; + } + /* a key agreement op */ + ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; + + if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { + rv = SECFailure; + break; + } + /* we do not support the case where multiple recipients + * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys + * in this case, we would need to walk all the recipientInfos, take the + * ones that do KeyAgreement algorithms and join them, algorithm by algorithm + * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ + + /* only epheremal-static Diffie-Hellman is supported for now + * this is the only form of key agreement that provides potential anonymity + * of the sender, plus we do not have to include certs in the message */ + + /* force single recipientEncryptedKey for now */ + if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { + rv = SECFailure; + break; + } + + /* hardcoded IssuerSN choice for now */ + rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; + if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { + rv = SECFailure; + break; + } + + oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); + + /* see RFC2630 12.3.1.1 */ + oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; + + rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, + (void *)rek); + + break; + default: + /* other algorithms not supported yet */ + /* NOTE that we do not support any KEK algorithm */ + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + rv = SECFailure; + break; + } + + if (rv == SECFailure) + goto loser; + + /* set version */ + switch (ri->recipientInfoType) { + case NSSCMSRecipientInfoID_KeyTrans: + if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) + version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; + else + version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); + if (dummy == NULL) + goto loser; + break; + case NSSCMSRecipientInfoID_KeyAgree: + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), + NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); + if (dummy == NULL) + goto loser; + break; + case NSSCMSRecipientInfoID_KEK: + /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ + dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), + NSS_CMS_KEK_RECIPIENT_INFO_VERSION); + if (dummy == NULL) + goto loser; + break; + } + +done: + PORT_ArenaUnmark(poolp, mark); + if (freeSpki) + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); + return ri; + +loser: + if (ri && ri->cert) { + CERT_DestroyCertificate(ri->cert); + } + if (freeSpki) { + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); + } + PORT_ArenaRelease(poolp, mark); + if (cmsg->contentInfo.contentTypeTag == &fakeContent) { + NSS_CMSMessage_Destroy(cmsg); + } + 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, 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, NULL); +} + +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) +{ + 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) + CERT_DestroyCertificate(ri->cert); + + if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { + NSSCMSKeyTransRecipientInfoEx *extra; + extra = &ri->ri.keyTransRecipientInfoEx; + if (extra->pubKey) + SECKEY_DestroyPublicKey(extra->pubKey); + } + if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { + NSS_CMSMessage_Destroy(ri->cmsg); + } + + /* we're done. */ +} + +int +NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri) +{ + unsigned long version; + SECItem *versionitem = NULL; + + switch (ri->recipientInfoType) { + case NSSCMSRecipientInfoID_KeyTrans: + /* ignore subIndex */ + versionitem = &(ri->ri.keyTransRecipientInfo.version); + break; + case NSSCMSRecipientInfoID_KEK: + /* ignore subIndex */ + versionitem = &(ri->ri.kekRecipientInfo.version); + break; + case NSSCMSRecipientInfoID_KeyAgree: + versionitem = &(ri->ri.keyAgreeRecipientInfo.version); + break; + } + + PORT_Assert(versionitem); + if (versionitem == NULL) + return 0; + + /* always take apart the SECItem */ + if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess) + return 0; + else + return (int)version; +} + +SECItem * +NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex) +{ + SECItem *enckey = NULL; + + switch (ri->recipientInfoType) { + case NSSCMSRecipientInfoID_KeyTrans: + /* ignore subIndex */ + enckey = &(ri->ri.keyTransRecipientInfo.encKey); + break; + case NSSCMSRecipientInfoID_KEK: + /* ignore subIndex */ + enckey = &(ri->ri.kekRecipientInfo.encKey); + break; + case NSSCMSRecipientInfoID_KeyAgree: + enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); + break; + } + return enckey; +} + +SECOidTag +NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri) +{ + SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ + + switch (ri->recipientInfoType) { + case NSSCMSRecipientInfoID_KeyTrans: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); + break; + case NSSCMSRecipientInfoID_KeyAgree: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); + break; + case NSSCMSRecipientInfoID_KEK: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); + break; + } + return encalgtag; +} + +SECStatus +NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, + SECOidTag bulkalgtag) +{ + CERTCertificate *cert; + SECOidTag certalgtag; + SECStatus rv = SECSuccess; + NSSCMSRecipientEncryptedKey *rek; + NSSCMSOriginatorIdentifierOrKey *oiok; + CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; + PLArenaPool *poolp; + NSSCMSKeyTransRecipientInfoEx *extra = NULL; + PRBool usesSubjKeyID; + + poolp = ri->cmsg->poolp; + cert = ri->cert; + usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); + if (cert) { + spki = &cert->subjectPublicKeyInfo; + } 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); + } 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(&spki->algorithm); + switch (certalgtag) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + /* wrap the symkey */ + if (cert) { + rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, + &ri->ri.keyTransRecipientInfo.encKey); + if (rv != SECSuccess) + break; + } else if (usesSubjKeyID) { + PORT_Assert(extra != NULL); + rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, + bulkkey, &ri->ri.keyTransRecipientInfo.encKey); + if (rv != SECSuccess) + break; + } + + rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); + break; + case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ + rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; + if (rek == NULL) { + rv = SECFailure; + break; + } + + oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); + PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey); + + /* see RFC2630 12.3.1.1 */ + if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, + SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { + rv = SECFailure; + break; + } + + /* this will generate a key pair, compute the shared secret, */ + /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ + /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ + rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey, + &rek->encKey, + &ri->ri.keyAgreeRecipientInfo.ukm, + &ri->ri.keyAgreeRecipientInfo.keyEncAlg, + &oiok->id.originatorPublicKey.publicKey); + + break; + default: + /* other algorithms not supported yet */ + /* NOTE that we do not support any KEK algorithm */ + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + rv = SECFailure; + } + if (freeSpki) + SECKEY_DestroySubjectPublicKeyInfo(freeSpki); + + return rv; +} + +PK11SymKey * +NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, + CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag) +{ + PK11SymKey *bulkkey = NULL; + SECOidTag encalgtag; + SECItem *enckey; + int error; + + ri->cert = CERT_DupCertificate(cert); + /* mark the recipientInfo so we can find it later */ + + switch (ri->recipientInfoType) { + case NSSCMSRecipientInfoID_KeyTrans: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); + enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ + switch (encalgtag) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + /* RSA encryption algorithm: */ + /* get the symmetric (bulk) key by unwrapping it using our private key */ + bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag); + break; + default: + error = SEC_ERROR_UNSUPPORTED_KEYALG; + goto loser; + } + break; + case NSSCMSRecipientInfoID_KeyAgree: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); + enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); + switch (encalgtag) { + case SEC_OID_X942_DIFFIE_HELMAN_KEY: + /* Diffie-Helman key exchange */ + /* XXX not yet implemented */ + /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */ + /* we support ephemeral-static DH only, so if the recipientinfo */ + /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */ + /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */ + /* content encryption key using a Unwrap op */ + /* the derive operation has to generate the key using the algorithm in RFC2631 */ + error = SEC_ERROR_UNSUPPORTED_KEYALG; + goto loser; + break; + default: + error = SEC_ERROR_UNSUPPORTED_KEYALG; + goto loser; + } + break; + case NSSCMSRecipientInfoID_KEK: + encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); + enckey = &(ri->ri.kekRecipientInfo.encKey); + /* not supported yet */ + error = SEC_ERROR_UNSUPPORTED_KEYALG; + goto loser; + break; + } + /* XXXX continue here */ + return bulkkey; + +loser: + PORT_SetError(error); + 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; +} + +SECStatus +NSS_CMSRecipientInfo_Encode(PLArenaPool *poolp, + const NSSCMSRecipientInfo *src, + SECItem *returned) +{ + extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; + SECStatus rv = SECFailure; + if (!src || !returned) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + } else if (SEC_ASN1EncodeItem(poolp, returned, src, + NSSCMSRecipientInfoTemplate)) { + rv = SECSuccess; + } + return rv; +} -- cgit v1.2.3