diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-12 05:43:14 +0000 |
commit | 8dd16259287f58f9273002717ec4d27e97127719 (patch) | |
tree | 3863e62a53829a84037444beab3abd4ed9dfc7d0 /security/nss/lib/smime | |
parent | Releasing progress-linux version 126.0.1-1~progress7.99u1. (diff) | |
download | firefox-8dd16259287f58f9273002717ec4d27e97127719.tar.xz firefox-8dd16259287f58f9273002717ec4d27e97127719.zip |
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/nss/lib/smime')
-rw-r--r-- | security/nss/lib/smime/cmsasn1.c | 55 | ||||
-rw-r--r-- | security/nss/lib/smime/cmslocal.h | 24 | ||||
-rw-r--r-- | security/nss/lib/smime/cmspubkey.c | 624 | ||||
-rw-r--r-- | security/nss/lib/smime/cmsrecinfo.c | 78 | ||||
-rw-r--r-- | security/nss/lib/smime/cmst.h | 17 |
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, ¶ms, + 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; |