summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/smime/cmsrecinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/smime/cmsrecinfo.c')
-rw-r--r--security/nss/lib/smime/cmsrecinfo.c669
1 files changed, 669 insertions, 0 deletions
diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c
new file mode 100644
index 000000000..2efb6b1f2
--- /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 "key.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;
+ 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));
+
+ 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;
+}