summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/smime
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/smime')
-rw-r--r--security/nss/lib/smime/cmsasn1.c55
-rw-r--r--security/nss/lib/smime/cmslocal.h24
-rw-r--r--security/nss/lib/smime/cmspubkey.c624
-rw-r--r--security/nss/lib/smime/cmsrecinfo.c78
-rw-r--r--security/nss/lib/smime/cmst.h17
5 files changed, 627 insertions, 171 deletions
diff --git a/security/nss/lib/smime/cmsasn1.c b/security/nss/lib/smime/cmsasn1.c
index 8ba95d044e..4758006998 100644
--- a/security/nss/lib/smime/cmsasn1.c
+++ b/security/nss/lib/smime/cmsasn1.c
@@ -23,6 +23,7 @@ SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
SEC_ASN1_MKSUB(SEC_BitStringTemplate)
SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+SEC_ASN1_MKSUB(SEC_GeneralizedTimeTemplate)
SEC_ASN1_MKSUB(SEC_PointerToOctetStringTemplate)
SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
@@ -269,27 +270,45 @@ static const SEC_ASN1Template NSSCMSOriginatorIdentifierOrKeyTemplate[] = {
offsetof(NSSCMSOriginatorIdentifierOrKey, id.issuerAndSN),
SEC_ASN1_SUB(CERT_IssuerAndSNTemplate),
NSSCMSOriginatorIDOrKey_IssuerSN },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
- SEC_ASN1_XTRN | 1,
+ { SEC_ASN1_POINTER | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
offsetof(NSSCMSOriginatorIdentifierOrKey, id.subjectKeyID),
- SEC_ASN1_SUB(SEC_PointerToOctetStringTemplate),
+ SEC_ASN1_SUB(SEC_OctetStringTemplate),
NSSCMSOriginatorIDOrKey_SubjectKeyID },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(NSSCMSOriginatorIdentifierOrKey, id.originatorPublicKey),
NSSCMSOriginatorPublicKeyTemplate,
NSSCMSOriginatorIDOrKey_OriginatorPublicKey },
{ 0 }
};
+const SEC_ASN1Template NSSCMSOtherKeyAttributeTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(NSSCMSOtherKeyAttribute) },
+ {
+ SEC_ASN1_OBJECT_ID,
+ offsetof(NSSCMSOtherKeyAttribute, keyAttrId),
+ },
+ {
+ SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+ offsetof(NSSCMSOtherKeyAttribute, keyAttr),
+ },
+ {
+ 0,
+ }
+};
+
const SEC_ASN1Template NSSCMSRecipientKeyIdentifierTemplate[] = {
{ SEC_ASN1_SEQUENCE,
0, NULL, sizeof(NSSCMSRecipientKeyIdentifier) },
- { SEC_ASN1_OCTET_STRING,
- offsetof(NSSCMSRecipientKeyIdentifier, subjectKeyIdentifier) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_OCTET_STRING,
- offsetof(NSSCMSRecipientKeyIdentifier, date) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_OCTET_STRING,
- offsetof(NSSCMSRecipientKeyIdentifier, other) },
+ { SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(NSSCMSRecipientKeyIdentifier, subjectKeyIdentifier),
+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(NSSCMSRecipientKeyIdentifier, date),
+ SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(NSSCMSRecipientKeyIdentifier, other),
+ NSSCMSOtherKeyAttributeTemplate },
{ 0 }
};
@@ -316,7 +335,7 @@ static const SEC_ASN1Template NSSCMSRecipientEncryptedKeyTemplate[] = {
NSSCMSKeyAgreeRecipientIdentifierTemplate },
{ SEC_ASN1_INLINE | SEC_ASN1_XTRN,
offsetof(NSSCMSRecipientEncryptedKey, encKey),
- SEC_ASN1_SUB(SEC_BitStringTemplate) },
+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
{ 0 }
};
@@ -350,10 +369,12 @@ static const SEC_ASN1Template NSSCMSKEKIdentifierTemplate[] = {
0, NULL, sizeof(NSSCMSKEKIdentifier) },
{ SEC_ASN1_OCTET_STRING,
offsetof(NSSCMSKEKIdentifier, keyIdentifier) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_OCTET_STRING,
- offsetof(NSSCMSKEKIdentifier, date) },
- { SEC_ASN1_OPTIONAL | SEC_ASN1_OCTET_STRING,
- offsetof(NSSCMSKEKIdentifier, other) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(NSSCMSKEKIdentifier, date),
+ SEC_ASN1_SUB(SEC_GeneralizedTimeTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_POINTER | SEC_ASN1_XTRN,
+ offsetof(NSSCMSKEKIdentifier, other),
+ NSSCMSOtherKeyAttributeTemplate },
{ 0 }
};
@@ -380,11 +401,11 @@ const SEC_ASN1Template NSSCMSRecipientInfoTemplate[] = {
{ SEC_ASN1_CHOICE,
offsetof(NSSCMSRecipientInfo, recipientInfoType), NULL,
sizeof(NSSCMSRecipientInfo) },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1,
offsetof(NSSCMSRecipientInfo, ri.keyAgreeRecipientInfo),
NSSCMSKeyAgreeRecipientInfoTemplate,
NSSCMSRecipientInfoID_KeyAgree },
- { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 2,
offsetof(NSSCMSRecipientInfo, ri.kekRecipientInfo),
NSSCMSKEKRecipientInfoTemplate,
NSSCMSRecipientInfoID_KEK },
diff --git a/security/nss/lib/smime/cmslocal.h b/security/nss/lib/smime/cmslocal.h
index ef7d500280..2cc91ac13d 100644
--- a/security/nss/lib/smime/cmslocal.h
+++ b/security/nss/lib/smime/cmslocal.h
@@ -164,14 +164,24 @@ NSS_CMSUtil_EncryptSymKey_RSAPubKey(PLArenaPool *poolp,
extern PK11SymKey *
NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOidTag bulkalgtag);
-extern SECStatus
-NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
- SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
- SECItem *originatorPubKey);
-
+/*
+ * NSS_CMSUtil_DecryptSymKey_RSA_OAEP is the same as NSS_CMSUtil_DecryptSymKey_RSA, except that
+ * it works with a symmetric key that was wrapped using RSA with OAEP padding rather than PKCS #1
+ * Version 1.5 padding.
+ */
extern PK11SymKey *
-NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey,
- SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag, void *pwfn_arg);
+NSS_CMSUtil_DecryptSymKey_RSA_OAEP(SECKEYPrivateKey *privkey, SECItem *parameters, SECItem *encKey, SECOidTag bulkalgtag);
+
+extern SECStatus
+NSS_CMSUtil_EncryptSymKey_ESECDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
+ SECItem *encKey, PRBool genUkm, SECItem *ukm,
+ SECAlgorithmID *keyEncAlg, SECItem *originatorPubKey, void *wincx);
+
+PK11SymKey *
+NSS_CMSUtil_DecryptSymKey_ECDH(SECKEYPrivateKey *privkey, SECItem *encKey,
+ SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag,
+ SECItem *ukm, NSSCMSOriginatorIdentifierOrKey *oiok,
+ void *wincx);
/************************************************************************
* cmsreclist.c - recipient list stuff
diff --git a/security/nss/lib/smime/cmspubkey.c b/security/nss/lib/smime/cmspubkey.c
index 8f18f60de1..0c494c3dd5 100644
--- a/security/nss/lib/smime/cmspubkey.c
+++ b/security/nss/lib/smime/cmspubkey.c
@@ -15,6 +15,8 @@
#include "secoid.h"
#include "pk11func.h"
#include "secerr.h"
+#include "secder.h"
+#include "prerr.h"
/* ====== RSA ======================================================================= */
@@ -106,180 +108,568 @@ NSS_CMSUtil_DecryptSymKey_RSA(SECKEYPrivateKey *privkey, SECItem *encKey, SECOid
return PK11_PubUnwrapSymKey(privkey, encKey, target, CKA_DECRYPT, 0);
}
-/* ====== ESDH (Ephemeral-Static Diffie-Hellman) ==================================== */
+typedef struct RSA_OAEP_CMS_paramsStr RSA_OAEP_CMS_params;
+struct RSA_OAEP_CMS_paramsStr {
+ SECAlgorithmID *hashFunc;
+ SECAlgorithmID *maskGenFunc;
+ SECAlgorithmID *pSourceFunc;
+};
+
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+
+static const SEC_ASN1Template seckey_PointerToAlgorithmIDTemplate[] = {
+ { SEC_ASN1_POINTER | SEC_ASN1_XTRN, 0,
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }
+};
+
+static const SEC_ASN1Template RSA_OAEP_CMS_paramsTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(RSA_OAEP_CMS_params) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
+ SEC_ASN1_CONTEXT_SPECIFIC | 0,
+ offsetof(RSA_OAEP_CMS_params, hashFunc),
+ seckey_PointerToAlgorithmIDTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
+ SEC_ASN1_CONTEXT_SPECIFIC | 1,
+ offsetof(RSA_OAEP_CMS_params, maskGenFunc),
+ seckey_PointerToAlgorithmIDTemplate },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT |
+ SEC_ASN1_CONTEXT_SPECIFIC | 2,
+ offsetof(RSA_OAEP_CMS_params, pSourceFunc),
+ seckey_PointerToAlgorithmIDTemplate },
+ { 0 }
+};
+/*
+ * NSS_CMSUtil_DecryptSymKey_RSA_OAEP - unwrap a RSA-wrapped symmetric key
+ *
+ * this function takes an RSA-OAEP-wrapped symmetric key and unwraps it, returning a symmetric
+ * key handle. Please note that the actual unwrapped key data may not be allowed to leave
+ * a hardware token...
+ */
+PK11SymKey *
+NSS_CMSUtil_DecryptSymKey_RSA_OAEP(SECKEYPrivateKey *privkey, SECItem *parameters, SECItem *encKey, SECOidTag bulkalgtag)
+{
+ CK_RSA_PKCS_OAEP_PARAMS oaep_params;
+ RSA_OAEP_CMS_params encoded_params;
+ SECAlgorithmID mgf1hashAlg;
+ SECOidTag mgfAlgtag, mgf1hashAlgtag, pSourcetag;
+ SECItem encoding_params, params;
+ PK11SymKey *bulkkey = NULL;
+ SECStatus rv;
+
+ CK_MECHANISM_TYPE target;
+ PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
+ target = PK11_AlgtagToMechanism(bulkalgtag);
+ if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return NULL;
+ }
+
+ PORT_Memset(&encoded_params, 0, sizeof(RSA_OAEP_CMS_params));
+ PORT_Memset(&mgf1hashAlg, 0, sizeof(SECAlgorithmID));
+ PORT_Memset(&encoding_params, 0, sizeof(SECItem));
+
+ /* Set default values for the OAEP parameters */
+ oaep_params.hashAlg = CKM_SHA_1;
+ oaep_params.mgf = CKG_MGF1_SHA1;
+ oaep_params.source = CKZ_DATA_SPECIFIED;
+ oaep_params.pSourceData = NULL;
+ oaep_params.ulSourceDataLen = 0;
+
+ if (parameters->len == 2) {
+ /* For some reason SEC_ASN1DecodeItem cannot process parameters if it is an emtpy SEQUENCE */
+ /* Just check that this is a properly encoded empty SEQUENCE */
+ if ((parameters->data[0] != 0x30) || (parameters->data[1] != 0)) {
+ return NULL;
+ }
+ } else {
+ rv = SEC_ASN1DecodeItem(NULL, &encoded_params, RSA_OAEP_CMS_paramsTemplate, parameters);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (encoded_params.hashFunc != NULL) {
+ oaep_params.hashAlg = PK11_AlgtagToMechanism(SECOID_GetAlgorithmTag(encoded_params.hashFunc));
+ }
+ if (encoded_params.maskGenFunc != NULL) {
+ mgfAlgtag = SECOID_GetAlgorithmTag(encoded_params.maskGenFunc);
+ if (mgfAlgtag != SEC_OID_PKCS1_MGF1) {
+ /* MGF1 is the only supported mask generation function */
+ goto loser;
+ }
+ /* The parameters field contains an AlgorithmIdentifier specifying the
+ * hash function to use with MGF1.
+ */
+ rv = SEC_ASN1DecodeItem(NULL, &mgf1hashAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate),
+ &encoded_params.maskGenFunc->parameters);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ mgf1hashAlgtag = SECOID_GetAlgorithmTag(&mgf1hashAlg);
+ switch (mgf1hashAlgtag) {
+ case SEC_OID_SHA1:
+ oaep_params.mgf = CKG_MGF1_SHA1;
+ break;
+ case SEC_OID_SHA224:
+ oaep_params.mgf = CKG_MGF1_SHA224;
+ break;
+ case SEC_OID_SHA256:
+ oaep_params.mgf = CKG_MGF1_SHA256;
+ break;
+ case SEC_OID_SHA384:
+ oaep_params.mgf = CKG_MGF1_SHA384;
+ break;
+ case SEC_OID_SHA512:
+ oaep_params.mgf = CKG_MGF1_SHA512;
+ break;
+ case SEC_OID_SHA3_224:
+ oaep_params.mgf = CKG_MGF1_SHA3_224;
+ break;
+ case SEC_OID_SHA3_256:
+ oaep_params.mgf = CKG_MGF1_SHA3_256;
+ break;
+ case SEC_OID_SHA3_384:
+ oaep_params.mgf = CKG_MGF1_SHA3_384;
+ break;
+ case SEC_OID_SHA3_512:
+ oaep_params.mgf = CKG_MGF1_SHA3_512;
+ break;
+ default:
+ goto loser;
+ break;
+ }
+ }
+ if (encoded_params.pSourceFunc != NULL) {
+ pSourcetag = SECOID_GetAlgorithmTag(encoded_params.pSourceFunc);
+ if (pSourcetag != SEC_OID_PKCS1_PSPECIFIED) {
+ goto loser;
+ }
+ /* The encoding parameters (P) are provided as an OCTET STRING in the parameters field. */
+ if (encoded_params.pSourceFunc->parameters.len != 0) {
+ rv = SEC_ASN1DecodeItem(NULL, &encoding_params, SEC_ASN1_GET(SEC_OctetStringTemplate),
+ &encoded_params.pSourceFunc->parameters);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ oaep_params.ulSourceDataLen = encoding_params.len;
+ oaep_params.pSourceData = encoding_params.data;
+ }
+ }
+ }
+ params.type = siBuffer;
+ params.data = (unsigned char *)&oaep_params;
+ params.len = sizeof(CK_RSA_PKCS_OAEP_PARAMS);
+ bulkkey = PK11_PubUnwrapSymKeyWithMechanism(privkey, CKM_RSA_PKCS_OAEP, &params,
+ encKey, target, CKA_DECRYPT, 0);
+
+loser:
+ PORT_Free(oaep_params.pSourceData);
+ if (encoded_params.hashFunc) {
+ SECOID_DestroyAlgorithmID(encoded_params.hashFunc, PR_TRUE);
+ }
+ if (encoded_params.maskGenFunc) {
+ SECOID_DestroyAlgorithmID(encoded_params.maskGenFunc, PR_TRUE);
+ }
+ if (encoded_params.pSourceFunc) {
+ SECOID_DestroyAlgorithmID(encoded_params.pSourceFunc, PR_TRUE);
+ }
+ SECOID_DestroyAlgorithmID(&mgf1hashAlg, PR_FALSE);
+ return bulkkey;
+}
+
+/* ====== ESECDH (Ephemeral-Static Elliptic Curve Diffie-Hellman) =========== */
+
+typedef struct ECC_CMS_SharedInfoStr ECC_CMS_SharedInfo;
+struct ECC_CMS_SharedInfoStr {
+ SECAlgorithmID *keyInfo; /* key-encryption algorithm */
+ SECItem entityUInfo; /* ukm */
+ SECItem suppPubInfo; /* length of KEK in bits as 32-bit number */
+};
+
+static const SEC_ASN1Template ECC_CMS_SharedInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(ECC_CMS_SharedInfo) },
+ { SEC_ASN1_XTRN | SEC_ASN1_POINTER,
+ offsetof(ECC_CMS_SharedInfo, keyInfo),
+ SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ offsetof(ECC_CMS_SharedInfo, entityUInfo),
+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
+ { SEC_ASN1_EXPLICIT | SEC_ASN1_CONSTRUCTED |
+ SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+ offsetof(ECC_CMS_SharedInfo, suppPubInfo),
+ SEC_ASN1_SUB(SEC_OctetStringTemplate) },
+ { 0 }
+};
+
+/* Inputs:
+ * keyInfo: key-encryption algorithm
+ * ukm: ukm field of KeyAgreeRecipientInfo
+ * KEKsize: length of KEK in bytes
+ *
+ * Output: DER encoded ECC-CMS-SharedInfo
+ */
+static SECItem *
+Create_ECC_CMS_SharedInfo(PLArenaPool *poolp,
+ SECAlgorithmID *keyInfo, SECItem *ukm, unsigned int KEKsize)
+{
+ ECC_CMS_SharedInfo SI;
+ unsigned char suppPubInfo[4] = { 0 };
+
+ SI.keyInfo = keyInfo;
+ SI.entityUInfo.type = ukm->type;
+ SI.entityUInfo.data = ukm->data;
+ SI.entityUInfo.len = ukm->len;
+
+ SI.suppPubInfo.type = siBuffer;
+ SI.suppPubInfo.data = suppPubInfo;
+ SI.suppPubInfo.len = sizeof(suppPubInfo);
+
+ if (KEKsize > 0x1FFFFFFF) { // ensure KEKsize * 8 fits in 4 bytes.
+ return NULL;
+ }
+ KEKsize *= 8;
+ suppPubInfo[0] = (KEKsize & 0xFF000000) >> 24;
+ suppPubInfo[1] = (KEKsize & 0xFF0000) >> 16;
+ suppPubInfo[2] = (KEKsize & 0xFF00) >> 8;
+ suppPubInfo[3] = KEKsize & 0xFF;
+
+ return SEC_ASN1EncodeItem(poolp, NULL, &SI, ECC_CMS_SharedInfoTemplate);
+}
+
+/* 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.
+ * The ukm is optional per RFC 5753. Pass a NULL value to request an empty ukm.
+ * Pass a SECItem with the size set to zero, to request allocating a random
+ * ukm of a default size. Or provide an explicit ukm that was defined by the caller.
+ */
SECStatus
-NSS_CMSUtil_EncryptSymKey_ESDH(PLArenaPool *poolp, CERTCertificate *cert, PK11SymKey *key,
- SECItem *encKey, SECItem **ukm, SECAlgorithmID *keyEncAlg,
- SECItem *pubKey)
+NSS_CMSUtil_EncryptSymKey_ESECDH(PLArenaPool *poolp, CERTCertificate *cert,
+ PK11SymKey *bulkkey, SECItem *encKey,
+ PRBool genUkm, SECItem *ukm,
+ SECAlgorithmID *keyEncAlg, SECItem *pubKey,
+ void *wincx)
{
-#if 0 /* not yet done */
- SECOidTag certalgtag; /* the certificate's encryption algorithm */
- SECOidTag encalgtag; /* the algorithm used for key exchange/agreement */
+ SECOidTag certalgtag; /* the certificate's encryption algorithm */
SECStatus rv;
- SECItem *params = NULL;
- int data_len;
SECStatus err;
- PK11SymKey *tek;
- CERTCertificate *ourCert;
- SECKEYPublicKey *ourPubKey;
- NSSCMSKEATemplateSelector whichKEA = NSSCMSKEAInvalid;
+ PK11SymKey *kek;
+ SECKEYPublicKey *publickey = NULL;
+ SECKEYPublicKey *ourPubKey = NULL;
+ SECKEYPrivateKey *ourPrivKey = NULL;
+ unsigned int bulkkey_size, kek_size;
+ SECAlgorithmID keyWrapAlg;
+ SECOidTag keyEncAlgtag;
+ SECItem keyWrapAlg_params, *keyEncAlg_params, *SharedInfo;
+ CK_MECHANISM_TYPE keyDerivationType, keyWrapMech;
+ CK_ULONG kdf;
+
+ if (genUkm && (ukm->len != 0 || ukm->data != NULL)) {
+ PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
+ return SECFailure;
+ }
certalgtag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
- PORT_Assert(certalgtag == SEC_OID_X942_DIFFIE_HELMAN_KEY);
-
- /* We really want to show our KEA tag as the key exchange algorithm tag. */
- encalgtag = SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN;
+ PORT_Assert(certalgtag == SEC_OID_ANSIX962_EC_PUBLIC_KEY);
+ if (certalgtag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
+ return SECFailure;
+ }
/* Get the public key of the recipient. */
publickey = CERT_ExtractPublicKey(cert);
- if (publickey == NULL) goto loser;
-
- /* XXXX generate a DH key pair on a PKCS11 module (XXX which parameters?) */
- /* XXXX */ourCert = PK11_FindBestKEAMatch(cert, wincx);
- if (ourCert == NULL) goto loser;
+ if (publickey == NULL)
+ goto loser;
- arena = PORT_NewArena(1024);
- if (arena == NULL) goto loser;
+ ourPrivKey = SECKEY_CreateECPrivateKey(&publickey->u.ec.DEREncodedParams,
+ &ourPubKey, wincx);
+ if (!ourPrivKey || !ourPubKey) {
+ goto loser;
+ }
- /* While we're here, extract the key pair's public key data and copy it into */
- /* the outgoing parameters. */
- /* XXXX */ourPubKey = CERT_ExtractPublicKey(ourCert);
- if (ourPubKey == NULL)
- {
+ rv = SECITEM_CopyItem(poolp, pubKey, &ourPubKey->u.ec.publicValue);
+ if (rv != SECSuccess) {
goto loser;
}
- SECITEM_CopyItem(arena, pubKey, /* XXX */&(ourPubKey->u.fortezza.KEAKey));
+
+ /* pubKey will be encoded as a BIT STRING, so pubKey->len must be length in bits
+ * rather than bytes */
+ pubKey->len = pubKey->len * 8;
+
SECKEY_DestroyPublicKey(ourPubKey); /* we only need the private key from now on */
ourPubKey = NULL;
- /* Extract our private key in order to derive the KEA key. */
- ourPrivKey = PK11_FindKeyByAnyCert(ourCert,wincx);
- CERT_DestroyCertificate(ourCert); /* we're done with this */
- if (!ourPrivKey) goto loser;
+ bulkkey_size = PK11_GetKeyLength(bulkkey);
+ if (bulkkey_size == 0) {
+ goto loser;
+ }
+
+ /* Parameters are supposed to be absent for AES key wrap algorithms.
+ * However, Microsoft Outlook cannot decrypt message unless
+ * parameters field is NULL. */
+ keyWrapAlg_params.len = 2;
+ keyWrapAlg_params.data = (unsigned char *)PORT_ArenaAlloc(poolp, keyWrapAlg_params.len);
+ if (keyWrapAlg_params.data == NULL)
+ goto loser;
- /* If ukm desired, prepare it - allocate enough space (filled with zeros). */
- if (ukm) {
- ukm->data = (unsigned char*)PORT_ArenaZAlloc(arena,/* XXXX */);
- ukm->len = /* XXXX */;
+ keyWrapAlg_params.data[0] = SEC_ASN1_NULL;
+ keyWrapAlg_params.data[1] = 0;
+
+ /* RFC5753 specifies id-aes128-wrap as the mandatory to support algorithm.
+ * So, use id-aes128-wrap unless bulkkey provides more than 128 bits of
+ * security. If bulkkey provides more than 128 bits of security, use
+ * the algorithms from KE Set 2 in RFC 6318. */
+
+ /* TODO: NIST Special Publication SP 800-56A requires the use of
+ * Cofactor ECDH. However, RFC 6318 specifies the use of
+ * dhSinglePass-stdDH-sha256kdf-scheme or dhSinglePass-stdDH-sha384kdf-scheme
+ * for Suite B. The reason for this is that all of the NIST recommended
+ * prime curves in FIPS 186-3 (including the Suite B curves) have a cofactor
+ * of 1, and so for these curves standard and cofactor ECDH are the same.
+ * This code should really look at the key's parameters and choose cofactor
+ * ECDH if the curve has a cofactor other than 1. */
+ if ((PK11_GetMechanism(bulkkey) == CKM_AES_CBC) && (bulkkey_size > 16)) {
+ rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_256_KEY_WRAP, &keyWrapAlg_params);
+ kek_size = 32;
+ keyWrapMech = CKM_NSS_AES_KEY_WRAP;
+ kdf = CKD_SHA384_KDF;
+ keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME;
+ keyDerivationType = CKM_ECDH1_DERIVE;
+ } else {
+ rv = SECOID_SetAlgorithmID(poolp, &keyWrapAlg, SEC_OID_AES_128_KEY_WRAP, &keyWrapAlg_params);
+ kek_size = 16;
+ keyWrapMech = CKM_NSS_AES_KEY_WRAP;
+ kdf = CKD_SHA256_KDF;
+ keyEncAlgtag = SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME;
+ keyDerivationType = CKM_ECDH1_DERIVE;
+ }
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* ukm is optional, but RFC 5753 says that originators SHOULD include the ukm.
+ * I made ukm 64 bytes, since RFC 2631 states that UserKeyingMaterial must
+ * contain 512 bits for Diffie-Hellman key agreement. */
+
+ if (genUkm) {
+ ukm->type = siBuffer;
+ ukm->len = 64;
+ ukm->data = (unsigned char *)PORT_ArenaAlloc(poolp, ukm->len);
+
+ if (ukm->data == NULL) {
+ goto loser;
+ }
+ rv = PK11_GenerateRandom(ukm->data, ukm->len);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
+ SharedInfo = Create_ECC_CMS_SharedInfo(poolp, &keyWrapAlg,
+ ukm,
+ kek_size);
+ if (!SharedInfo) {
+ goto loser;
}
- /* Generate the KEK (key exchange key) according to RFC2631 which we use
+ /* Generate the KEK (key exchange key) according to RFC5753 which we use
* to wrap the bulk encryption key. */
- kek = PK11_PubDerive(ourPrivKey, publickey, PR_TRUE,
- ukm, NULL,
- /* XXXX */CKM_KEA_KEY_DERIVE, /* XXXX */CKM_SKIPJACK_WRAP,
- CKA_WRAP, 0, wincx);
+ kek = PK11_PubDeriveWithKDF(ourPrivKey, publickey, PR_TRUE,
+ NULL, NULL,
+ keyDerivationType, keyWrapMech,
+ CKA_WRAP, kek_size, kdf, SharedInfo, NULL);
+ if (!kek) {
+ goto loser;
+ }
SECKEY_DestroyPublicKey(publickey);
SECKEY_DestroyPrivateKey(ourPrivKey);
publickey = NULL;
ourPrivKey = NULL;
- if (!kek)
- goto loser;
-
/* allocate space for the encrypted CEK (bulk key) */
- encKey->data = (unsigned char*)PORT_ArenaAlloc(poolp, SMIME_FORTEZZA_MAX_KEY_SIZE);
- encKey->len = SMIME_FORTEZZA_MAX_KEY_SIZE;
+ /* AES key wrap produces an output 64-bits longer than
+ * the input AES CEK (RFC 3565, Section 2.3.2) */
+ encKey->len = bulkkey_size + 8;
+ encKey->data = (unsigned char *)PORT_ArenaAlloc(poolp, encKey->len);
- if (encKey->data == NULL)
- {
+ if (encKey->data == NULL) {
PK11_FreeSymKey(kek);
goto loser;
}
+ err = PK11_WrapSymKey(keyWrapMech, NULL, kek, bulkkey, encKey);
- /* Wrap the bulk key using CMSRC2WRAP or CMS3DESWRAP, depending on the */
- /* bulk encryption algorithm */
- switch (/* XXXX */PK11_AlgtagToMechanism(enccinfo->encalg))
- {
- case /* XXXX */CKM_SKIPJACK_CFB8:
- err = PK11_WrapSymKey(/* XXXX */CKM_CMS3DES_WRAP, NULL, kek, bulkkey, encKey);
- whichKEA = NSSCMSKEAUsesSkipjack;
- break;
- case /* XXXX */CKM_SKIPJACK_CFB8:
- err = PK11_WrapSymKey(/* XXXX */CKM_CMSRC2_WRAP, NULL, kek, bulkkey, encKey);
- whichKEA = NSSCMSKEAUsesSkipjack;
- break;
- default:
- /* XXXX what do we do here? Neither RC2 nor 3DES... */
- err = SECFailure;
- /* set error */
- break;
- }
-
- PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
- if (err != SECSuccess)
+ PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
+ if (err != SECSuccess) {
goto loser;
+ }
- PORT_Assert(whichKEA != NSSCMSKEAInvalid);
-
- /* see RFC2630 12.3.1.1 "keyEncryptionAlgorithm must be ..." */
- /* params is the DER encoded key wrap algorithm (with parameters!) (XXX) */
- params = SEC_ASN1EncodeItem(arena, NULL, &keaParams, sec_pkcs7_get_kea_template(whichKEA));
- if (params == NULL)
+ keyEncAlg_params = SEC_ASN1EncodeItem(poolp, NULL, &keyWrapAlg, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate));
+ if (keyEncAlg_params == NULL)
goto loser;
+ keyEncAlg_params->type = siBuffer;
/* now set keyEncAlg */
- rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN, params);
- if (rv != SECSuccess)
+ rv = SECOID_SetAlgorithmID(poolp, keyEncAlg, keyEncAlgtag, keyEncAlg_params);
+ if (rv != SECSuccess) {
goto loser;
+ }
+
+ return SECSuccess;
- /* XXXXXXX this is not right yet */
loser:
- if (arena) {
- PORT_FreeArena(arena, PR_FALSE);
- }
if (publickey) {
SECKEY_DestroyPublicKey(publickey);
}
+ if (ourPubKey) {
+ SECKEY_DestroyPublicKey(ourPubKey);
+ }
if (ourPrivKey) {
SECKEY_DestroyPrivateKey(ourPrivKey);
}
-#endif
return SECFailure;
}
+/* TODO: Move to pk11wrap and export? */
+static int
+cms_GetKekSizeFromKeyWrapAlgTag(SECOidTag keyWrapAlgtag)
+{
+ switch (keyWrapAlgtag) {
+ case SEC_OID_AES_128_KEY_WRAP:
+ return 16;
+ case SEC_OID_AES_192_KEY_WRAP:
+ return 24;
+ case SEC_OID_AES_256_KEY_WRAP:
+ return 32;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/* TODO: Move to smimeutil and export? */
+static CK_ULONG
+cms_GetKdfFromKeyEncAlgTag(SECOidTag keyEncAlgtag)
+{
+ switch (keyEncAlgtag) {
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME:
+ return CKD_SHA1_KDF;
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME:
+ return CKD_SHA224_KDF;
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME:
+ return CKD_SHA256_KDF;
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME:
+ return CKD_SHA384_KDF;
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME:
+ return CKD_SHA512_KDF;
+ default:
+ break;
+ }
+ return 0;
+}
+
PK11SymKey *
-NSS_CMSUtil_DecryptSymKey_ESDH(SECKEYPrivateKey *privkey, SECItem *encKey,
+NSS_CMSUtil_DecryptSymKey_ECDH(SECKEYPrivateKey *privkey, SECItem *encKey,
SECAlgorithmID *keyEncAlg, SECOidTag bulkalgtag,
- void *pwfn_arg)
+ SECItem *ukm, NSSCMSOriginatorIdentifierOrKey *oiok,
+ void *wincx)
{
-#if 0 /* not yet done */
- SECStatus err;
- CK_MECHANISM_TYPE bulkType;
- PK11SymKey *tek;
- SECKEYPublicKey *originatorPubKey;
- NSSCMSSMIMEKEAParameters keaParams;
-
- /* XXXX get originator's public key */
- originatorPubKey = PK11_MakeKEAPubKey(keaParams.originatorKEAKey.data,
- keaParams.originatorKEAKey.len);
- if (originatorPubKey == NULL)
- goto loser;
-
- /* Generate the TEK (token exchange key) which we use to unwrap the bulk encryption key.
- The Derive function generates a shared secret and combines it with the originatorRA
- data to come up with an unique session key */
- tek = PK11_PubDerive(privkey, originatorPubKey, PR_FALSE,
- &keaParams.originatorRA, NULL,
- CKM_KEA_KEY_DERIVE, CKM_SKIPJACK_WRAP,
- CKA_WRAP, 0, pwfn_arg);
- SECKEY_DestroyPublicKey(originatorPubKey); /* not needed anymore */
- if (tek == NULL)
+ SECAlgorithmID keyWrapAlg;
+ SECOidTag keyEncAlgtag, keyWrapAlgtag;
+ CK_MECHANISM_TYPE target, keyDerivationType, keyWrapMech;
+ CK_ULONG kdf;
+ PK11SymKey *kek = NULL, *bulkkey = NULL;
+ int kek_size;
+ SECKEYPublicKey originatorpublickey;
+ SECItem *oiok_publicKey, *SharedInfo = NULL;
+ SECStatus rv;
+
+ PORT_Memset(&keyWrapAlg, 0, sizeof(SECAlgorithmID));
+
+ PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
+ target = PK11_AlgtagToMechanism(bulkalgtag);
+ if (bulkalgtag == SEC_OID_UNKNOWN || target == CKM_INVALID_MECHANISM) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ goto loser;
+ }
+
+ keyEncAlgtag = SECOID_GetAlgorithmTag(keyEncAlg);
+ keyDerivationType = PK11_AlgtagToMechanism(keyEncAlgtag);
+ if ((keyEncAlgtag == SEC_OID_UNKNOWN) ||
+ (keyDerivationType == CKM_INVALID_MECHANISM)) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
goto loser;
+ }
- /* Now that we have the TEK, unwrap the bulk key
- with which to decrypt the message. */
- /* Skipjack is being used as the bulk encryption algorithm.*/
- /* Unwrap the bulk key. */
- bulkkey = PK11_UnwrapSymKey(tek, CKM_SKIPJACK_WRAP, NULL,
- encKey, CKM_SKIPJACK_CBC64, CKA_DECRYPT, 0);
+ rv = SEC_ASN1DecodeItem(NULL, &keyWrapAlg,
+ SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), &(keyEncAlg->parameters));
+ if (rv != SECSuccess) {
+ goto loser;
+ }
- return bulkkey;
+ keyWrapAlgtag = SECOID_GetAlgorithmTag(&keyWrapAlg);
+ keyWrapMech = PK11_AlgtagToMechanism(keyWrapAlgtag);
+ if ((keyWrapAlgtag == SEC_OID_UNKNOWN) ||
+ (keyWrapMech == CKM_INVALID_MECHANISM)) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ goto loser;
+ }
+
+ kek_size = cms_GetKekSizeFromKeyWrapAlgTag(keyWrapAlgtag);
+ if (!kek_size) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ goto loser;
+ }
+ kdf = cms_GetKdfFromKeyEncAlgTag(keyEncAlgtag);
+ if (!kdf) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ goto loser;
+ }
+
+ /* Get originator's public key */
+ /* TODO: Add support for static-static ECDH */
+ if (oiok->identifierType != NSSCMSOriginatorIDOrKey_OriginatorPublicKey) {
+ PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE);
+ goto loser;
+ }
+
+ /* PK11_PubDeriveWithKDF only uses the keyType u.ec.publicValue.data
+ * and u.ec.publicValue.len from the originator's public key. */
+ oiok_publicKey = &(oiok->id.originatorPublicKey.publicKey);
+ originatorpublickey.keyType = ecKey;
+ originatorpublickey.u.ec.publicValue.data = oiok_publicKey->data;
+ originatorpublickey.u.ec.publicValue.len = oiok_publicKey->len / 8;
+
+ SharedInfo = Create_ECC_CMS_SharedInfo(NULL, &keyWrapAlg, ukm, kek_size);
+ if (!SharedInfo) {
+ goto loser;
+ }
+
+ /* Generate the KEK (key exchange key) according to RFC5753 which we use
+ * to wrap the bulk encryption key. */
+ kek = PK11_PubDeriveWithKDF(privkey, &originatorpublickey, PR_TRUE,
+ NULL, NULL,
+ keyDerivationType, keyWrapMech,
+ CKA_WRAP, kek_size, kdf, SharedInfo, wincx);
+
+ SECITEM_FreeItem(SharedInfo, PR_TRUE);
+
+ if (kek == NULL) {
+ goto loser;
+ }
+
+ bulkkey = PK11_UnwrapSymKey(kek, keyWrapMech, NULL, encKey, target, CKA_UNWRAP, 0);
+ PK11_FreeSymKey(kek); /* we do not need the KEK anymore */
loser:
-#endif
- return NULL;
+ SECOID_DestroyAlgorithmID(&keyWrapAlg, PR_FALSE);
+ return bulkkey;
}
diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c
index 6cf2c68c31..e3b383b5cd 100644
--- a/security/nss/lib/smime/cmsrecinfo.c
+++ b/security/nss/lib/smime/cmsrecinfo.c
@@ -157,7 +157,7 @@ nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
rv = SECFailure;
}
break;
- case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
PORT_Assert(type == NSSCMSRecipientID_IssuerSN);
if (type != NSSCMSRecipientID_IssuerSN) {
rv = SECFailure;
@@ -166,10 +166,6 @@ nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg,
/* 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
@@ -274,7 +270,7 @@ NSS_CMSRecipient_IsSupported(CERTCertificate *cert)
switch (certalgtag) {
case SEC_OID_PKCS1_RSA_ENCRYPTION:
- case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
return PR_TRUE;
default:
return PR_FALSE;
@@ -456,6 +452,7 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
PLArenaPool *poolp;
NSSCMSKeyTransRecipientInfoEx *extra = NULL;
PRBool usesSubjKeyID;
+ void *wincx = NULL;
poolp = ri->cmsg->poolp;
cert = ri->cert;
@@ -498,7 +495,7 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL);
break;
- case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0];
if (rek == NULL) {
rv = SECFailure;
@@ -510,7 +507,7 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
/* see RFC2630 12.3.1.1 */
if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier,
- SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) {
+ certalgtag, NULL) != SECSuccess) {
rv = SECFailure;
break;
}
@@ -518,12 +515,27 @@ NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey,
/* 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);
+ switch (certalgtag) {
+ case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
+ if (ri->cmsg) {
+ wincx = ri->cmsg->pwfn_arg;
+ } else {
+ wincx = PK11_GetWindow(bulkkey);
+ }
+ rv = NSS_CMSUtil_EncryptSymKey_ESECDH(poolp, cert, bulkkey,
+ &rek->encKey,
+ PR_TRUE,
+ &ri->ri.keyAgreeRecipientInfo.ukm,
+ &ri->ri.keyAgreeRecipientInfo.keyEncAlg,
+ &oiok->id.originatorPublicKey.publicKey,
+ wincx);
+ break;
+ default:
+ /* Not reached. Added to silence enum warnings. */
+ PORT_Assert(0);
+ break;
+ }
break;
default:
/* other algorithms not supported yet */
@@ -543,8 +555,10 @@ NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
{
PK11SymKey *bulkkey = NULL;
SECOidTag encalgtag;
- SECItem *enckey;
+ SECItem *enckey, *ukm, *parameters;
+ NSSCMSOriginatorIdentifierOrKey *oiok;
int error;
+ void *wincx = NULL;
ri->cert = CERT_DupCertificate(cert);
/* mark the recipientInfo so we can find it later */
@@ -559,6 +573,12 @@ NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
/* get the symmetric (bulk) key by unwrapping it using our private key */
bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag);
break;
+ case SEC_OID_PKCS1_RSA_OAEP_ENCRYPTION:
+ /* RSA OAEP encryption algorithm: */
+ /* get the symmetric (bulk) key by unwrapping it using our private key */
+ parameters = &(ri->ri.keyTransRecipientInfo.keyEncAlg.parameters);
+ bulkkey = NSS_CMSUtil_DecryptSymKey_RSA_OAEP(privkey, parameters, enckey, bulkalgtag);
+ break;
default:
error = SEC_ERROR_UNSUPPORTED_KEYALG;
goto loser;
@@ -567,19 +587,27 @@ NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex,
case NSSCMSRecipientInfoID_KeyAgree:
encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg));
enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey);
+ oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey);
+ ukm = &(ri->ri.keyAgreeRecipientInfo.ukm);
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;
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME:
+ case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME:
+ if (ri->cmsg) {
+ wincx = ri->cmsg->pwfn_arg;
+ }
+ bulkkey = NSS_CMSUtil_DecryptSymKey_ECDH(privkey, enckey,
+ &(ri->ri.keyAgreeRecipientInfo.keyEncAlg),
+ bulkalgtag, ukm, oiok, wincx);
break;
+
default:
error = SEC_ERROR_UNSUPPORTED_KEYALG;
goto loser;
diff --git a/security/nss/lib/smime/cmst.h b/security/nss/lib/smime/cmst.h
index 3d888bc041..1144f5571d 100644
--- a/security/nss/lib/smime/cmst.h
+++ b/security/nss/lib/smime/cmst.h
@@ -339,10 +339,17 @@ struct NSSCMSOriginatorIdentifierOrKeyStr {
};
typedef struct NSSCMSOriginatorIdentifierOrKeyStr NSSCMSOriginatorIdentifierOrKey;
+struct NSSCMSOtherKeyAttributeStr {
+ SECItem keyAttrId;
+ SECItem keyAttr; /* optional */
+};
+
+typedef struct NSSCMSOtherKeyAttributeStr NSSCMSOtherKeyAttribute;
+
struct NSSCMSRecipientKeyIdentifierStr {
SECItem *subjectKeyIdentifier;
- SECItem *date; /* optional */
- SECItem *other; /* optional */
+ SECItem *date; /* optional */
+ NSSCMSOtherKeyAttribute *other; /* optional */
};
typedef struct NSSCMSRecipientKeyIdentifierStr NSSCMSRecipientKeyIdentifier;
@@ -369,7 +376,7 @@ typedef struct NSSCMSRecipientEncryptedKeyStr NSSCMSRecipientEncryptedKey;
struct NSSCMSKeyAgreeRecipientInfoStr {
SECItem version;
NSSCMSOriginatorIdentifierOrKey originatorIdentifierOrKey;
- SECItem *ukm; /* optional */
+ SECItem ukm; /* optional */
SECAlgorithmID keyEncAlg;
NSSCMSRecipientEncryptedKey **recipientEncryptedKeys;
};
@@ -382,8 +389,8 @@ typedef struct NSSCMSKeyAgreeRecipientInfoStr NSSCMSKeyAgreeRecipientInfo;
*/
struct NSSCMSKEKIdentifierStr {
SECItem keyIdentifier;
- SECItem *date; /* optional */
- SECItem *other; /* optional */
+ SECItem *date; /* optional */
+ NSSCMSOtherKeyAttribute *other; /* optional */
};
typedef struct NSSCMSKEKIdentifierStr NSSCMSKEKIdentifier;