From 4c4276c4fcffc7f40169d579c8da013ba7021173 Mon Sep 17 00:00:00 2001 From: eabdullin Date: Fri, 17 Oct 2025 08:15:16 +0000 Subject: [PATCH] Import from CS git --- .firefox.metadata | 4 +- .gitignore | 4 +- SOURCES/D266159.1760530435.diff | 19 ++ ...fox-adapt-ml-dsa-support-to-rhel-nss.patch | 31 ++ ...sa-certificate-support-to-certviewer.patch | 323 ++++++++++++++++++ ...firefox-enable-ml-dsa-in-manager-ssl.patch | 48 +++ ...ion-for-certificate-chain-validation.patch | 239 +++++++++++++ ...or-pkix-certificate-chain-validation.patch | 244 +++++++++++++ SOURCES/process-official-tarball | 1 + SOURCES/wasi.patch | 2 +- SPECS/firefox.spec | 45 ++- 11 files changed, 949 insertions(+), 11 deletions(-) create mode 100644 SOURCES/D266159.1760530435.diff create mode 100644 SOURCES/firefox-adapt-ml-dsa-support-to-rhel-nss.patch create mode 100644 SOURCES/firefox-add-ml-dsa-certificate-support-to-certviewer.patch create mode 100644 SOURCES/firefox-enable-ml-dsa-in-manager-ssl.patch create mode 100644 SOURCES/firefox-enable-ml-dsa-signature-verification-for-certificate-chain-validation.patch create mode 100644 SOURCES/firefox-integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation.patch diff --git a/.firefox.metadata b/.firefox.metadata index 212acd5..922ec3c 100644 --- a/.firefox.metadata +++ b/.firefox.metadata @@ -1,6 +1,6 @@ bc4adac8f38f5103d8f88564a1545063dd8d6402 SOURCES/cbindgen-vendor.tar.xz -eee5a76bde5a92cb6f7999c5fc839a4bb83ca33c SOURCES/firefox-140.3.0esr.processed-source.tar.xz -8ffabd508d2b0631eab8cd49c1c26902f19bf71a SOURCES/firefox-langpacks-140.3.0esr-20250909.tar.xz +c25da23b50ddf8926a943f86f1180b6d96c0eff0 SOURCES/firefox-140.4.0esr.processed-source.tar.xz +22a42066c01a85b1264223041ed270b9e294d7e0 SOURCES/firefox-langpacks-140.4.0esr-20251010.tar.xz 2d8a6b2b30d5496735f49ffe8c8a7ede3a78a5ca SOURCES/mochitest-python.tar.gz 0d0ddbd2a73340b3cbc977997f57222946b1e775 SOURCES/nspr-4.36.0-2.el8_2.src.rpm fd3879b176634d66f8ef64d18fdaeec98e140c23 SOURCES/nss-3.112.0-1.el9_4.src.rpm diff --git a/.gitignore b/.gitignore index 7d5f062..521e9e5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ SOURCES/cbindgen-vendor.tar.xz -SOURCES/firefox-140.3.0esr.processed-source.tar.xz -SOURCES/firefox-langpacks-140.3.0esr-20250909.tar.xz +SOURCES/firefox-140.4.0esr.processed-source.tar.xz +SOURCES/firefox-langpacks-140.4.0esr-20251010.tar.xz SOURCES/mochitest-python.tar.gz SOURCES/nspr-4.36.0-2.el8_2.src.rpm SOURCES/nss-3.112.0-1.el9_4.src.rpm diff --git a/SOURCES/D266159.1760530435.diff b/SOURCES/D266159.1760530435.diff new file mode 100644 index 0000000..2abeb92 --- /dev/null +++ b/SOURCES/D266159.1760530435.diff @@ -0,0 +1,19 @@ +diff --git a/gfx/webrender_bindings/RenderCompositorSWGL.cpp b/gfx/webrender_bindings/RenderCompositorSWGL.cpp +--- a/gfx/webrender_bindings/RenderCompositorSWGL.cpp ++++ b/gfx/webrender_bindings/RenderCompositorSWGL.cpp +@@ -76,12 +76,14 @@ + const wr::DeviceIntRect* aOpaqueRects, size_t aNumOpaqueRects) { + // Request a new draw target to use from the widget... + MOZ_ASSERT(!mDT); + mDT = mWidget->StartRemoteDrawingInRegion(mDirtyRegion); + if (!mDT) { ++#if !defined(MOZ_WAYLAND) + gfxCriticalNoteOnce + << "RenderCompositorSWGL failed mapping default framebuffer, no dt"; ++#endif + return false; + } + // Attempt to lock the underlying buffer directly from the draw target. + // Verify that the size at least matches what the widget claims and that + // the format is BGRA8 as SWGL requires. + diff --git a/SOURCES/firefox-adapt-ml-dsa-support-to-rhel-nss.patch b/SOURCES/firefox-adapt-ml-dsa-support-to-rhel-nss.patch new file mode 100644 index 0000000..4349476 --- /dev/null +++ b/SOURCES/firefox-adapt-ml-dsa-support-to-rhel-nss.patch @@ -0,0 +1,31 @@ +diff --git a/security/nss/lib/mozpkix/lib/pkixnss.cpp b/security/nss/lib/mozpkix/lib/pkixnss.cpp +index 31aa1ddd67..6eb367eae4 100644 +--- a/security/nss/lib/mozpkix/lib/pkixnss.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixnss.cpp +@@ -323,13 +323,21 @@ VerifyMLDSASignedDataNSS(Input data, + SECItem dataItem(UnsafeMapInputToSECItem(data)); + CK_MECHANISM_TYPE mechanism; + +- switch (pubk->u.mldsa.paramSet) { +- case SEC_OID_ML_DSA_44: +- case SEC_OID_ML_DSA_65: +- case SEC_OID_ML_DSA_87: ++ switch (SEC_GetSignatureAlgorithmOidTag(pubk->keyType, pubk->u.mldsa.params)) { ++ case CKP_ML_DSA_44: ++ hashPolicyTag = SEC_OID_UNKNOWN; ++ mechanism = CKM_ML_DSA; ++ signaturePolicyTag = SEC_OID_PRIVATE_3; ++ break; ++ case CKP_ML_DSA_65: ++ hashPolicyTag = SEC_OID_UNKNOWN; + mechanism = CKM_ML_DSA; +- signaturePolicyTag = pubk->u.mldsa.paramSet; ++ signaturePolicyTag = SEC_OID_PRIVATE_4; ++ break; ++ case CKP_ML_DSA_87: + hashPolicyTag = SEC_OID_UNKNOWN; ++ mechanism = CKM_ML_DSA; ++ signaturePolicyTag = SEC_OID_PRIVATE_5; + break; + default: + return Result::ERROR_UNSUPPORTED_KEYALG; diff --git a/SOURCES/firefox-add-ml-dsa-certificate-support-to-certviewer.patch b/SOURCES/firefox-add-ml-dsa-certificate-support-to-certviewer.patch new file mode 100644 index 0000000..a61d2b3 --- /dev/null +++ b/SOURCES/firefox-add-ml-dsa-certificate-support-to-certviewer.patch @@ -0,0 +1,323 @@ +diff --git a/toolkit/components/certviewer/content/certDecoder.mjs b/toolkit/components/certviewer/content/certDecoder.mjs +--- a/toolkit/components/certviewer/content/certDecoder.mjs ++++ b/toolkit/components/certviewer/content/certDecoder.mjs +@@ -5,10 +5,11 @@ + import { + Certificate, + ECNamedCurves, + ECPublicKey, + RSAPublicKey, ++ MLDSAPublicKey, + } from "./vendor/pkijs.js"; + + const getTimeZone = () => { + let timeZone = new Date().toString().match(/\(([A-Za-z\s].*)\)/); + if (timeZone === null) { +@@ -45,10 +46,19 @@ + x, // x coordinate + y, // y coordinate + xy: `04:${x}:${y}`, // 04 (uncompressed) public key + }; + } ++ if (publicKey instanceof MLDSAPublicKey) { ++ let keyHex = publicKey.rhoT1.valueBlock.valueHex; ++ let keyBytes = new Uint8Array(keyHex); ++ return { ++ kty: publicKey.alg, ++ keysize: keyBytes.length, ++ rhoT1: hashify(keyHex), ++ }; ++ } + return { kty: "Unknown" }; + }; + + const getX509Ext = (extensions, v) => { + for (var extension in extensions) { +@@ -1132,10 +1142,13 @@ + "2.16.840.1.101.3.4.3.2": "DSA with SHA-256", + "1.2.840.10045.4.1": "ECDSA with SHA-1", + "1.2.840.10045.4.3.2": "ECDSA with SHA-256", + "1.2.840.10045.4.3.3": "ECDSA with SHA-384", + "1.2.840.10045.4.3.4": "ECDSA with SHA-512", ++ "2.16.840.1.101.3.4.3.17": "ML-DSA-44", ++ "2.16.840.1.101.3.4.3.18": "ML-DSA-65", ++ "2.16.840.1.101.3.4.3.19": "ML-DSA-87", + }, + + aia: { + "1.3.6.1.5.5.7.48.1": "Online Certificate Status Protocol (OCSP)", + "1.3.6.1.5.5.7.48.2": "CA Issuers", +diff --git a/toolkit/components/certviewer/content/certviewer.mjs b/toolkit/components/certviewer/content/certviewer.mjs +--- a/toolkit/components/certviewer/content/certviewer.mjs ++++ b/toolkit/components/certviewer/content/certviewer.mjs +@@ -74,10 +74,23 @@ + } + } + return result ? result : false; + }; + ++const getMLDSASecurityLevel = signatureName => { ++ switch (signatureName) { ++ case "ML-DSA-44": ++ return "Level 2 (NIST)"; ++ case "ML-DSA-65": ++ return "Level 3 (NIST)"; ++ case "ML-DSA-87": ++ return "Level 5 (NIST)"; ++ default: ++ return null; ++ } ++}; ++ + export const adjustCertInformation = cert => { + let certItems = []; + let tabName = cert?.subject?.cn || ""; + if (cert && !tabName) { + // No common name, use the value of the last item in the cert's entries. +@@ -173,10 +186,15 @@ + createEntryItem("key-size", cert.subjectPublicKeyInfo.keysize), + createEntryItem("curve", cert.subjectPublicKeyInfo.crv), + createEntryItem("public-value", cert.subjectPublicKeyInfo.xy, true), + createEntryItem("exponent", cert.subjectPublicKeyInfo.e), + createEntryItem("modulus", cert.subjectPublicKeyInfo.n, true), ++ createEntryItem( ++ "mldsa-public-value", ++ cert.subjectPublicKeyInfo.rhoT1, ++ true ++ ), + ].filter(elem => elem != null); + } + return items; + }, + certItems, +@@ -190,14 +208,23 @@ + createEntryItem("serial-number", cert.serialNumber, true), + createEntryItem( + "signature-algorithm", + cert.signature ? cert.signature.name : null + ), ++ ]; ++ ++ const secLvl = getMLDSASecurityLevel(cert.signature?.name); ++ if (secLvl) { ++ items.push(createEntryItem("security-level", secLvl)); ++ } ++ ++ items.push( + createEntryItem("version", cert.version), +- createEntryItem("download", cert.files ? cert.files.pem : null), +- ].filter(elem => elem != null); +- return items; ++ createEntryItem("download", cert.files ? cert.files.pem : null) ++ ); ++ ++ return items.filter(elem => elem != null); + }, + certItems, + "miscellaneous", + false + ); +diff --git a/toolkit/components/certviewer/content/vendor/pkijs.js b/toolkit/components/certviewer/content/vendor/pkijs.js +--- a/toolkit/components/certviewer/content/vendor/pkijs.js ++++ b/toolkit/components/certviewer/content/vendor/pkijs.js +@@ -8609,10 +8609,90 @@ + this.publicExponent = new Integer({ valueHex: stringToArrayBuffer(fromBase64(json.e, true)).slice(0, 3) }); + } + } + RSAPublicKey.CLASS_NAME = "RSAPublicKey"; + ++/* @see https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-11.html */ ++const RHO_T1 = "rhoT1"; ++const ALG = "alg"; ++const CLEAR_PROPS_MLDSA = [RHO_T1, ALG]; ++const MLDSA_MIN_LENGTH = 32; ++class MLDSAPublicKey extends PkiObject { ++ constructor(parameters = {}) { ++ super(); ++ ++ this.rhoT1 = getParametersValue(parameters, RHO_T1, MLDSAPublicKey.defaultValues(RHO_T1)); ++ this.alg = getParametersValue(parameters, ALG, MLDSAPublicKey.defaultValues(ALG)); ++ ++ if (parameters.json) { ++ this.fromJSON(parameters.json); ++ } ++ ++ if (parameters.schema) { ++ this.fromSchema(parameters.schema); ++ } ++ } ++ ++ static defaultValues(memberName) { ++ switch (memberName) { ++ case RHO_T1: ++ return new BitString(); ++ case ALG: ++ return ""; ++ default: ++ return super.defaultValues(memberName); ++ } ++ } ++ ++ static schema(parameters = {}) { ++ const names = getParametersValue(parameters, "names", {}); ++ return new BitString({ name: names.rhoT1 || RHO_T1 }); ++ } ++ ++ fromSchema(schema) { ++ clearProps(schema, CLEAR_PROPS_MLDSA); ++ ++ const asn1 = compareSchema(schema, schema, MLDSAPublicKey.schema({ ++ names: { rhoT1: RHO_T1 } ++ })); ++ ++ AsnError.assertSchema(asn1, this.className); ++ ++ const bitString = asn1.result.rhoT1; ++ const length = bitString.valueBlock.valueHexView.length; ++ ++ if (length < MLDSA_MIN_LENGTH || (length - MLDSA_MIN_LENGTH) % 320 !== 0) { ++ throw new Error(`Invalid ML-DSA key length: ${length} bytes`); ++ } ++ ++ this.rhoT1 = bitString; ++ } ++ ++ toSchema() { ++ return this.rhoT1; ++ } ++ ++ toJSON() { ++ return { ++ rhoT1: Convert.ToBase64Url(this.rhoT1.valueBlock.valueHexView), ++ alg: this.alg ++ }; ++ } ++ ++ fromJSON(json) { ++ ParameterError.assert("json", json, "rhoT1"); ++ const rawBuffer = stringToArrayBuffer(fromBase64(json.rhoT1, true)); ++ ++ if (rawBuffer.byteLength < MLDSA_MIN_LENGTH || (rawBuffer.byteLength - MLDSA_MIN_LENGTH) % 320 !== 0) { ++ throw new Error(`Invalid ML-DSA key length: ${rawBuffer.byteLength} bytes`); ++ } ++ ++ this.rhoT1 = new BitString({ valueHex: rawBuffer }); ++ } ++} ++MLDSAPublicKey.CLASS_NAME = "MLDSAPublicKey"; ++ + const ALGORITHM$1 = "algorithm"; + const SUBJECT_PUBLIC_KEY = "subjectPublicKey"; + const CLEAR_PROPS$1a = [ALGORITHM$1, SUBJECT_PUBLIC_KEY]; + class PublicKeyInfo extends PkiObject { + constructor(parameters = {}) { +@@ -8657,10 +8737,22 @@ + catch (ex) { + } + } + } + break; ++ case "2.16.840.1.101.3.4.3.17": ++ /* Already a bitstring */ ++ this._parsedKey = new MLDSAPublicKey({ rhoT1: this.subjectPublicKey, alg: "ML-DSA-44" }); ++ break; ++ case "2.16.840.1.101.3.4.3.18": ++ /* Already a bitstring */ ++ this._parsedKey = new MLDSAPublicKey({ rhoT1: this.subjectPublicKey, alg: "ML-DSA-65" }); ++ break; ++ case "2.16.840.1.101.3.4.3.19": ++ /* Already a bitstring */ ++ this._parsedKey = new MLDSAPublicKey({ rhoT1: this.subjectPublicKey, alg: "ML-DSA-87" }); ++ break; + } + this._parsedKey || (this._parsedKey = null); + } + return this._parsedKey || undefined; + } +@@ -8724,10 +8816,19 @@ + jwk.kty = "EC"; + break; + case "1.2.840.113549.1.1.1": + jwk.kty = "RSA"; + break; ++ case "2.16.840.1.101.3.4.3.17": ++ jwk.kty = "ML-DSA-44"; ++ break; ++ case "2.16.840.1.101.3.4.3.18": ++ jwk.kty = "ML-DSA-65"; ++ break; ++ case "2.16.840.1.101.3.4.3.19": ++ jwk.kty = "ML-DSA-87"; ++ break; + } + const publicKeyJWK = this.parsedKey.toJSON(); + Object.assign(jwk, publicKeyJWK); + return jwk; + } +@@ -8746,10 +8847,31 @@ + this.algorithm = new AlgorithmIdentifier({ + algorithmId: "1.2.840.113549.1.1.1", + algorithmParams: new Null() + }); + break; ++ case "ML-DSA-44": ++ this.parsedKey = new MLDSAPublicKey({ json }); ++ this.algorithm = new AlgorithmIdentifier({ ++ algorithmId: "2.16.840.1.101.3.4.3.17", ++ algorithmParams: new Null() ++ }); ++ break; ++ case "ML-DSA-65": ++ this.parsedKey = new MLDSAPublicKey({ json }); ++ this.algorithm = new AlgorithmIdentifier({ ++ algorithmId: "2.16.840.1.101.3.4.3.18", ++ algorithmParams: new Null() ++ }); ++ break; ++ case "ML-DSA-87": ++ this.parsedKey = new MLDSAPublicKey({ json }); ++ this.algorithm = new AlgorithmIdentifier({ ++ algorithmId: "2.16.840.1.101.3.4.3.19", ++ algorithmParams: new Null() ++ }); ++ break; + default: + throw new Error(`Invalid value for "kty" parameter: ${json.kty}`); + } + this.subjectPublicKey = new BitString({ valueHex: this.parsedKey.toSchema().toBER(false) }); + } +@@ -24078,6 +24200,6 @@ + } + } + + initCryptoEngine(); + +-export { AbstractCryptoEngine, AccessDescription, Accuracy, AlgorithmIdentifier, AltName, ArgumentError, AsnError, AttCertValidityPeriod, Attribute, AttributeCertificateInfoV1, AttributeCertificateInfoV2, AttributeCertificateV1, AttributeCertificateV2, AttributeTypeAndValue, AuthenticatedSafe, AuthorityKeyIdentifier, BasicConstraints, BasicOCSPResponse, CAVersion, CRLBag, CRLDistributionPoints, CertBag, CertID, Certificate, CertificateChainValidationEngine, CertificatePolicies, CertificateRevocationList, CertificateSet, CertificateTemplate, CertificationRequest, ChainValidationCode, ChainValidationError, ContentInfo, CryptoEngine, DigestInfo, DistributionPoint, ECCCMSSharedInfo, ECNamedCurves, ECPrivateKey, ECPublicKey, EncapsulatedContentInfo, EncryptedContentInfo, EncryptedData, EnvelopedData, ExtKeyUsage, Extension, ExtensionValueFactory, Extensions, GeneralName, GeneralNames, GeneralSubtree, HASHED_MESSAGE, HASH_ALGORITHM, Holder, InfoAccess, IssuerAndSerialNumber, IssuerSerial, IssuingDistributionPoint, KEKIdentifier, KEKRecipientInfo, KeyAgreeRecipientIdentifier, KeyAgreeRecipientInfo, KeyBag, KeyTransRecipientInfo, MICROS, MILLIS, MacData, MessageImprint, NameConstraints, OCSPRequest, OCSPResponse, ObjectDigestInfo, OriginatorIdentifierOrKey, OriginatorInfo, OriginatorPublicKey, OtherCertificateFormat, OtherKeyAttribute, OtherPrimeInfo, OtherRecipientInfo, OtherRevocationInfoFormat, PBES2Params, PBKDF2Params, PFX, PKCS8ShroudedKeyBag, PKIStatus, PKIStatusInfo, POLICY_IDENTIFIER, POLICY_QUALIFIERS, ParameterError, PasswordRecipientinfo, PkiObject, PolicyConstraints, PolicyInformation, PolicyMapping, PolicyMappings, PolicyQualifierInfo, PrivateKeyInfo, PrivateKeyUsagePeriod, PublicKeyInfo, QCStatement, QCStatements, RDN, RSAESOAEPParams, RSAPrivateKey, RSAPublicKey, RSASSAPSSParams, RecipientEncryptedKey, RecipientEncryptedKeys, RecipientIdentifier, RecipientInfo, RecipientKeyIdentifier, RelativeDistinguishedNames, Request, ResponseBytes, ResponseData, RevocationInfoChoices, RevokedCertificate, SECONDS, SafeBag, SafeBagValueFactory, SafeContents, SecretBag, Signature, SignedAndUnsignedAttributes, SignedCertificateTimestamp, SignedCertificateTimestampList, SignedData, SignedDataVerifyError, SignerInfo, SingleResponse, SubjectDirectoryAttributes, TBSRequest, TSTInfo, TYPE$4 as TYPE, TYPE_AND_VALUES, Time, TimeStampReq, TimeStampResp, TimeType, V2Form, VALUE$5 as VALUE, VALUE_BEFORE_DECODE, checkCA, createCMSECDSASignature, createECDSASignatureFromCMS, engine, getAlgorithmByOID, getAlgorithmParameters, getCrypto, getEngine, getHashAlgorithm, getOIDByAlgorithm, getRandomValues, id_AnyPolicy, id_AuthorityInfoAccess, id_AuthorityKeyIdentifier, id_BaseCRLNumber, id_BasicConstraints, id_CRLBag_X509CRL, id_CRLDistributionPoints, id_CRLNumber, id_CRLReason, id_CertBag_AttributeCertificate, id_CertBag_SDSICertificate, id_CertBag_X509Certificate, id_CertificateIssuer, id_CertificatePolicies, id_ContentType_Data, id_ContentType_EncryptedData, id_ContentType_EnvelopedData, id_ContentType_SignedData, id_ExtKeyUsage, id_FreshestCRL, id_InhibitAnyPolicy, id_InvalidityDate, id_IssuerAltName, id_IssuingDistributionPoint, id_KeyUsage, id_MicrosoftAppPolicies, id_MicrosoftCaVersion, id_MicrosoftCertTemplateV1, id_MicrosoftCertTemplateV2, id_MicrosoftPrevCaCertHash, id_NameConstraints, id_PKIX_OCSP_Basic, id_PolicyConstraints, id_PolicyMappings, id_PrivateKeyUsagePeriod, id_QCStatements, id_SignedCertificateTimestampList, id_SubjectAltName, id_SubjectDirectoryAttributes, id_SubjectInfoAccess, id_SubjectKeyIdentifier, id_ad, id_ad_caIssuers, id_ad_ocsp, id_eContentType_TSTInfo, id_pkix, id_sha1, id_sha256, id_sha384, id_sha512, kdf, setEngine, stringPrep, verifySCTsForCertificate }; ++export { AbstractCryptoEngine, AccessDescription, Accuracy, AlgorithmIdentifier, AltName, ArgumentError, AsnError, AttCertValidityPeriod, Attribute, AttributeCertificateInfoV1, AttributeCertificateInfoV2, AttributeCertificateV1, AttributeCertificateV2, AttributeTypeAndValue, AuthenticatedSafe, AuthorityKeyIdentifier, BasicConstraints, BasicOCSPResponse, CAVersion, CRLBag, CRLDistributionPoints, CertBag, CertID, Certificate, CertificateChainValidationEngine, CertificatePolicies, CertificateRevocationList, CertificateSet, CertificateTemplate, CertificationRequest, ChainValidationCode, ChainValidationError, ContentInfo, CryptoEngine, DigestInfo, DistributionPoint, ECCCMSSharedInfo, ECNamedCurves, ECPrivateKey, ECPublicKey, EncapsulatedContentInfo, EncryptedContentInfo, EncryptedData, EnvelopedData, ExtKeyUsage, Extension, ExtensionValueFactory, Extensions, GeneralName, GeneralNames, GeneralSubtree, HASHED_MESSAGE, HASH_ALGORITHM, Holder, InfoAccess, IssuerAndSerialNumber, IssuerSerial, IssuingDistributionPoint, KEKIdentifier, KEKRecipientInfo, KeyAgreeRecipientIdentifier, KeyAgreeRecipientInfo, KeyBag, KeyTransRecipientInfo, MICROS, MILLIS, MacData, MessageImprint, NameConstraints, OCSPRequest, OCSPResponse, ObjectDigestInfo, OriginatorIdentifierOrKey, OriginatorInfo, OriginatorPublicKey, OtherCertificateFormat, OtherKeyAttribute, OtherPrimeInfo, OtherRecipientInfo, OtherRevocationInfoFormat, PBES2Params, PBKDF2Params, PFX, PKCS8ShroudedKeyBag, PKIStatus, PKIStatusInfo, POLICY_IDENTIFIER, POLICY_QUALIFIERS, ParameterError, PasswordRecipientinfo, PkiObject, PolicyConstraints, PolicyInformation, PolicyMapping, PolicyMappings, PolicyQualifierInfo, PrivateKeyInfo, PrivateKeyUsagePeriod, PublicKeyInfo, QCStatement, QCStatements, RDN, RSAESOAEPParams, RSAPrivateKey, RSAPublicKey, RSASSAPSSParams, RecipientEncryptedKey, RecipientEncryptedKeys, RecipientIdentifier, RecipientInfo, RecipientKeyIdentifier, RelativeDistinguishedNames, Request, ResponseBytes, ResponseData, RevocationInfoChoices, RevokedCertificate, SECONDS, SafeBag, SafeBagValueFactory, SafeContents, SecretBag, Signature, SignedAndUnsignedAttributes, SignedCertificateTimestamp, SignedCertificateTimestampList, SignedData, SignedDataVerifyError, SignerInfo, SingleResponse, SubjectDirectoryAttributes, TBSRequest, TSTInfo, TYPE$4 as TYPE, TYPE_AND_VALUES, Time, TimeStampReq, TimeStampResp, TimeType, V2Form, VALUE$5 as VALUE, VALUE_BEFORE_DECODE, checkCA, createCMSECDSASignature, createECDSASignatureFromCMS, engine, getAlgorithmByOID, getAlgorithmParameters, getCrypto, getEngine, getHashAlgorithm, getOIDByAlgorithm, getRandomValues, id_AnyPolicy, id_AuthorityInfoAccess, id_AuthorityKeyIdentifier, id_BaseCRLNumber, id_BasicConstraints, id_CRLBag_X509CRL, id_CRLDistributionPoints, id_CRLNumber, id_CRLReason, id_CertBag_AttributeCertificate, id_CertBag_SDSICertificate, id_CertBag_X509Certificate, id_CertificateIssuer, id_CertificatePolicies, id_ContentType_Data, id_ContentType_EncryptedData, id_ContentType_EnvelopedData, id_ContentType_SignedData, id_ExtKeyUsage, id_FreshestCRL, id_InhibitAnyPolicy, id_InvalidityDate, id_IssuerAltName, id_IssuingDistributionPoint, id_KeyUsage, id_MicrosoftAppPolicies, id_MicrosoftCaVersion, id_MicrosoftCertTemplateV1, id_MicrosoftCertTemplateV2, id_MicrosoftPrevCaCertHash, id_NameConstraints, id_PKIX_OCSP_Basic, id_PolicyConstraints, id_PolicyMappings, id_PrivateKeyUsagePeriod, id_QCStatements, id_SignedCertificateTimestampList, id_SubjectAltName, id_SubjectDirectoryAttributes, id_SubjectInfoAccess, id_SubjectKeyIdentifier, id_ad, id_ad_caIssuers, id_ad_ocsp, id_eContentType_TSTInfo, id_pkix, id_sha1, id_sha256, id_sha384, id_sha512, kdf, setEngine, stringPrep, verifySCTsForCertificate, MLDSAPublicKey }; +diff --git a/toolkit/locales/en-US/toolkit/about/certviewer.ftl b/toolkit/locales/en-US/toolkit/about/certviewer.ftl +--- a/toolkit/locales/en-US/toolkit/about/certviewer.ftl ++++ b/toolkit/locales/en-US/toolkit/about/certviewer.ftl +@@ -45,20 +45,22 @@ + certificate-viewer-organization = Organization + certificate-viewer-organizational-unit = Organizational Unit + certificate-viewer-policy = Policy + certificate-viewer-protocol = Protocol + certificate-viewer-public-value = Public Value ++certificate-viewer-mldsa-public-value = Public Value + certificate-viewer-purposes = Purposes + certificate-viewer-qualifier = Qualifier + certificate-viewer-qualifiers = Qualifiers + certificate-viewer-required = Required + certificate-viewer-unsupported = <unsupported> + # Inc. means Incorporated, e.g GitHub is incorporated in Delaware + certificate-viewer-inc-state-province = Inc. State/Province + certificate-viewer-state-province = State/Province + certificate-viewer-sha-1 = SHA-1 + certificate-viewer-sha-256 = SHA-256 ++certificate-viewer-security-level = Security Level + certificate-viewer-serial-number = Serial Number + certificate-viewer-signature-algorithm = Signature Algorithm + certificate-viewer-signature-scheme = Signature Scheme + certificate-viewer-timestamp = Timestamp + certificate-viewer-value = Value + diff --git a/SOURCES/firefox-enable-ml-dsa-in-manager-ssl.patch b/SOURCES/firefox-enable-ml-dsa-in-manager-ssl.patch new file mode 100644 index 0000000..f130b7f --- /dev/null +++ b/SOURCES/firefox-enable-ml-dsa-in-manager-ssl.patch @@ -0,0 +1,48 @@ +diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp +index 2dc48c9f4c..0a7b84d787 100644 +--- a/security/manager/ssl/nsNSSCallbacks.cpp ++++ b/security/manager/ssl/nsNSSCallbacks.cpp +@@ -722,6 +722,15 @@ nsCString getSignatureName(uint32_t aSignatureScheme) { + case ssl_sig_rsa_pkcs1_sha1md5: + signatureName = "RSA-PKCS1-SHA1MD5"_ns; + break; ++ case ssl_sig_mldsa44: ++ signatureName = "ML-DSA-44"_ns; ++ break; ++ case ssl_sig_mldsa65: ++ signatureName = "ML-DSA-65"_ns; ++ break; ++ case ssl_sig_mldsa87: ++ signatureName = "ML-DSA-87"_ns; ++ break; + // All other groups are not enabled in Firefox. See sEnabledSignatureSchemes + // in nsNSSIOLayer.cpp. + default: +@@ -1061,6 +1070,13 @@ void HandshakeCallback(PRFileDesc* fd, void* client_data) { + glean::ssl::auth_ecdsa_curve_full.AccumulateSingleSample( + ECCCurve(channelInfo.authKeyBits)); + break; ++ case ssl_auth_mldsa44: ++ case ssl_auth_mldsa65: ++ case ssl_auth_mldsa87: ++ /* TODO: add auth_mldsa_key_size_full in ssl/metrics.yaml ++ glean::ssl::auth_mldsa_key_size_full.AccumulateSingleSample( ++ NonECCKeySize(channelInfo.authKeyBits)); */ ++ break; + default: + MOZ_CRASH("impossible auth algorithm"); + break; +diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp +index b1a5f5c2df..7443011b13 100644 +--- a/security/manager/ssl/nsNSSIOLayer.cpp ++++ b/security/manager/ssl/nsNSSIOLayer.cpp +@@ -1300,6 +1300,9 @@ static PRFileDesc* nsSSLIOLayerImportFD(PRFileDesc* fd, + // Please change getSignatureName in nsNSSCallbacks.cpp when changing the list + // here. See NOTE at SSL_SignatureSchemePrefSet call site. + static const SSLSignatureScheme sEnabledSignatureSchemes[] = { ++ ssl_sig_mldsa87, ++ ssl_sig_mldsa65, ++ ssl_sig_mldsa44, + ssl_sig_ecdsa_secp256r1_sha256, + ssl_sig_ecdsa_secp384r1_sha384, + ssl_sig_ecdsa_secp521r1_sha512, diff --git a/SOURCES/firefox-enable-ml-dsa-signature-verification-for-certificate-chain-validation.patch b/SOURCES/firefox-enable-ml-dsa-signature-verification-for-certificate-chain-validation.patch new file mode 100644 index 0000000..a14a70e --- /dev/null +++ b/SOURCES/firefox-enable-ml-dsa-signature-verification-for-certificate-chain-validation.patch @@ -0,0 +1,239 @@ +diff --git a/security/nss/lib/mozpkix/include/pkix/pkixder.h b/security/nss/lib/mozpkix/include/pkix/pkixder.h +index ac1ec24393..40eb5027af 100644 +--- a/security/nss/lib/mozpkix/include/pkix/pkixder.h ++++ b/security/nss/lib/mozpkix/include/pkix/pkixder.h +@@ -488,7 +488,7 @@ inline Result OptionalExtensions(Reader& input, uint8_t tag, + Result DigestAlgorithmIdentifier(Reader& input, + /*out*/ DigestAlgorithm& algorithm); + +-enum class PublicKeyAlgorithm { RSA_PKCS1, RSA_PSS, ECDSA }; ++enum class PublicKeyAlgorithm { RSA_PKCS1, RSA_PSS, ECDSA, MLDSA }; + + Result SignatureAlgorithmIdentifierValue( + Reader& input, +diff --git a/security/nss/lib/mozpkix/include/pkix/pkixnss.h b/security/nss/lib/mozpkix/include/pkix/pkixnss.h +index 6711959e71..b87e88a599 100644 +--- a/security/nss/lib/mozpkix/include/pkix/pkixnss.h ++++ b/security/nss/lib/mozpkix/include/pkix/pkixnss.h +@@ -50,6 +50,13 @@ Result VerifyECDSASignedDataNSS(Input data, DigestAlgorithm digestAlgorithm, + Input signature, Input subjectPublicKeyInfo, + void* pkcs11PinArg); + ++// Verifies the ML-DSA signature on the given data using the given ML-DSA ++// public key ++Result VerifyMLDSASignedDataNSS(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo, ++ void* pkcs11PinArg); ++ + // Computes the digest of the given data using the given digest algorithm. + // + // item contains the data to hash. +diff --git a/security/nss/lib/mozpkix/include/pkix/pkixtypes.h b/security/nss/lib/mozpkix/include/pkix/pkixtypes.h +index 6a07d6e885..f24bd546e4 100644 +--- a/security/nss/lib/mozpkix/include/pkix/pkixtypes.h ++++ b/security/nss/lib/mozpkix/include/pkix/pkixtypes.h +@@ -334,6 +334,10 @@ class TrustDomain { + Input signature, + Input subjectPublicKeyInfo) = 0; + ++ virtual Result VerifyMLDSASignedData(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo) = 0; ++ + // Check that the validity duration is acceptable. + // + // Return Success if the validity duration is acceptable, +diff --git a/security/nss/lib/mozpkix/lib/pkixc.cpp b/security/nss/lib/mozpkix/lib/pkixc.cpp +index 5dea13c43e..f797a3b3a1 100644 +--- a/security/nss/lib/mozpkix/lib/pkixc.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixc.cpp +@@ -143,6 +143,15 @@ class CodeSigningTrustDomain final : public TrustDomain { + subjectPublicKeyInfo, nullptr); + } + ++ virtual Result VerifyMLDSASignedData(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo) override { ++ return VerifyMLDSASignedDataNSS(data, ++ signature, ++ subjectPublicKeyInfo, ++ nullptr); ++ } ++ + virtual Result CheckValidityIsAcceptable(Time notBefore, Time notAfter, + EndEntityOrCA endEntityOrCA, + KeyPurposeId keyPurpose) override { +diff --git a/security/nss/lib/mozpkix/lib/pkixcheck.cpp b/security/nss/lib/mozpkix/lib/pkixcheck.cpp +index 8b7e1bf73e..4ce73f3944 100644 +--- a/security/nss/lib/mozpkix/lib/pkixcheck.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixcheck.cpp +@@ -118,6 +118,9 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain, + // for any curve that we support, the chances of us encountering a curve + // during path building is too low to be worth bothering with. + break; ++ ++ case der::PublicKeyAlgorithm::MLDSA: ++ break; + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM + } + +@@ -248,6 +251,24 @@ CheckSubjectPublicKeyInfoContents(Reader& input, TrustDomain& trustDomain, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 + }; + ++ // Params for pure ML-DSA-44 signature ++ // python DottedOIDToCode.py id-ml-dsa-44 2.16.840.1.101.3.4.3.17 ++ static const uint8_t id_ml_dsa_44[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11 ++ }; ++ ++ // Params for pure ML-DSA-65 signature ++ // python DottedOIDToCode.py id-ml-dsa-65 2.16.840.1.101.3.4.3.18 ++ static const uint8_t id_ml_dsa_65[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12 ++ }; ++ ++ // Params for pure ML-DSA-87 signature ++ // python DottedOIDToCode.py id-ml-dsa-87 2.16.840.1.101.3.4.3.19 ++ static const uint8_t id_ml_dsa_87[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13 ++ }; ++ + if (algorithmOID.MatchRest(id_ecPublicKey)) { + // An id-ecPublicKey AlgorithmIdentifier has a parameter that identifes + // the curve being used. Although RFC 5480 specifies multiple forms, we +@@ -361,6 +382,30 @@ CheckSubjectPublicKeyInfoContents(Reader& input, TrustDomain& trustDomain, + if (rv != Success) { + return rv; + } ++ } else if (algorithmOID.MatchRest(id_ml_dsa_44) || ++ algorithmOID.MatchRest(id_ml_dsa_65) || ++ algorithmOID.MatchRest(id_ml_dsa_87)) { ++ ++ /* ++ * The ML-DSA AlgorithmIdentifier is expected to contain only the OID, ++ * with no parameters field present. According to the Internet-Draft ++ * https://www.ietf.org/archive/id/draft-ietf-lamps-dilithium-certificates-11.html ++ * (Section 3), the AlgorithmIdentifier for ML-DSA variants must omit the `parameters` ++ * field entirely. ++ * In DER encoding, the absence of the parameters field means that after parsing the ++ * OID, no additional bytes should remain. Calling `der::End(algorithm)` confirms that ++ * this constraint is satisfied and that the structure is correctly encoded. ++ */ ++ rv = der::End(algorithm); ++ if (rv != Success) { ++ return rv; ++ } ++ ++ Input rawPublicKey; ++ rv = subjectPublicKeyReader.SkipToEnd(rawPublicKey); ++ if (rv != Success) { ++ return rv; ++ } + } else { + return Result::ERROR_UNSUPPORTED_KEYALG; + } +diff --git a/security/nss/lib/mozpkix/lib/pkixder.cpp b/security/nss/lib/mozpkix/lib/pkixder.cpp +index 59454c7d3c..4ff45ed566 100644 +--- a/security/nss/lib/mozpkix/lib/pkixder.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixder.cpp +@@ -211,6 +211,24 @@ SignatureAlgorithmIdentifierValue(Reader& input, + 0x00, 0xa2, 0x03, 0x02, 0x01, 0x40 + }; + ++ // Params for pure ML-DSA-44 signature ++ // python DottedOIDToCode.py id-ml-dsa-44 2.16.840.1.101.3.4.3.17 ++ static const uint8_t id_ml_dsa_44[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11 ++ }; ++ ++ // Params for pure ML-DSA-65 signature ++ // python DottedOIDToCode.py id-ml-dsa-65 2.16.840.1.101.3.4.3.18 ++ static const uint8_t id_ml_dsa_65[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12 ++ }; ++ ++ // Params for pure ML-DSA-87 signature ++ // python DottedOIDToCode.py id-ml-dsa-87 2.16.840.1.101.3.4.3.19 ++ static const uint8_t id_ml_dsa_87[] = { ++ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13 ++ }; ++ + // Matching is attempted based on a rough estimate of the commonality of the + // algorithm, to minimize the number of MatchRest calls. + if (algorithmID.MatchRest(sha256WithRSAEncryption)) { +@@ -252,6 +270,10 @@ SignatureAlgorithmIdentifierValue(Reader& input, + } else { + return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; + } ++ } else if (algorithmID.MatchRest(id_ml_dsa_44) || ++ algorithmID.MatchRest(id_ml_dsa_65) || ++ algorithmID.MatchRest(id_ml_dsa_87)) { ++ publicKeyAlgorithm = PublicKeyAlgorithm::MLDSA; + } else { + return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; + } +diff --git a/security/nss/lib/mozpkix/lib/pkixnss.cpp b/security/nss/lib/mozpkix/lib/pkixnss.cpp +index 606ef708d8..31aa1ddd67 100644 +--- a/security/nss/lib/mozpkix/lib/pkixnss.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixnss.cpp +@@ -303,6 +303,44 @@ DigestBufNSS(Input item, + return Success; + } + ++Result ++VerifyMLDSASignedDataNSS(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo, ++ void* pkcs11PinArg) ++{ ++ ScopedSECKEYPublicKey publicKey; ++ SECKEYPublicKey *pubk = NULL; ++ SECOidTag signaturePolicyTag, hashPolicyTag; ++ Result rv = SubjectPublicKeyInfoToSECKEYPublicKey(subjectPublicKeyInfo, ++ publicKey); ++ if (rv != Success) { ++ return rv; ++ } ++ ++ pubk = publicKey.get(); ++ SECItem signatureItem(UnsafeMapInputToSECItem(signature)); ++ SECItem dataItem(UnsafeMapInputToSECItem(data)); ++ CK_MECHANISM_TYPE mechanism; ++ ++ switch (pubk->u.mldsa.paramSet) { ++ case SEC_OID_ML_DSA_44: ++ case SEC_OID_ML_DSA_65: ++ case SEC_OID_ML_DSA_87: ++ mechanism = CKM_ML_DSA; ++ signaturePolicyTag = pubk->u.mldsa.paramSet; ++ hashPolicyTag = SEC_OID_UNKNOWN; ++ break; ++ default: ++ return Result::ERROR_UNSUPPORTED_KEYALG; ++ break; ++ } ++ ++ SECOidTag policyTags[2] = {signaturePolicyTag, hashPolicyTag}; ++ return VerifySignedData(pubk, mechanism, nullptr, &signatureItem, ++ &dataItem, policyTags, pkcs11PinArg); ++} ++ + Result + MapPRErrorCodeToResult(PRErrorCode error) + { +diff --git a/security/nss/lib/mozpkix/lib/pkixverify.cpp b/security/nss/lib/mozpkix/lib/pkixverify.cpp +index 8cb58bf7de..ff132d89df 100644 +--- a/security/nss/lib/mozpkix/lib/pkixverify.cpp ++++ b/security/nss/lib/mozpkix/lib/pkixverify.cpp +@@ -53,6 +53,9 @@ VerifySignedData(TrustDomain& trustDomain, + case der::PublicKeyAlgorithm::RSA_PSS: + return trustDomain.VerifyRSAPSSSignedData(signedData.data, + digestAlgorithm, signedData.signature, signerSubjectPublicKeyInfo); ++ case der::PublicKeyAlgorithm::MLDSA: ++ return trustDomain.VerifyMLDSASignedData(signedData.data, ++ signedData.signature, signerSubjectPublicKeyInfo); + MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM + } + } diff --git a/SOURCES/firefox-integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation.patch b/SOURCES/firefox-integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation.patch new file mode 100644 index 0000000..beb641e --- /dev/null +++ b/SOURCES/firefox-integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation.patch @@ -0,0 +1,244 @@ +diff --git a/netwerk/protocol/http/WebTransportCertificateVerifier.cpp b/netwerk/protocol/http/WebTransportCertificateVerifier.cpp +index cc77864..1e978ef 100644 +--- a/netwerk/protocol/http/WebTransportCertificateVerifier.cpp ++++ b/netwerk/protocol/http/WebTransportCertificateVerifier.cpp +@@ -53,6 +53,11 @@ class ServerCertHashesTrustDomain : public mozilla::pkix::TrustDomain { + mozilla::pkix::Input signature, + mozilla::pkix::Input subjectPublicKeyInfo) override; + ++ virtual mozilla::pkix::Result VerifyMLDSASignedData( ++ mozilla::pkix::Input data, ++ mozilla::pkix::Input signature, ++ mozilla::pkix::Input subjectPublicKeyInfo) override; ++ + virtual mozilla::pkix::Result DigestBuf( + mozilla::pkix::Input item, mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen) override; +@@ -151,6 +156,15 @@ mozilla::pkix::Result ServerCertHashesTrustDomain::VerifyECDSASignedData( + return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; + } + ++mozilla::pkix::Result ServerCertHashesTrustDomain::VerifyMLDSASignedData( ++ mozilla::pkix::Input data, ++ mozilla::pkix::Input signature, ++ mozilla::pkix::Input subjectPublicKeyInfo) { ++ MOZ_ASSERT_UNREACHABLE("not expecting this to be called"); ++ ++ return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; ++} ++ + mozilla::pkix::Result ServerCertHashesTrustDomain::DigestBuf( + mozilla::pkix::Input item, mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, size_t digestBufLen) { +diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp +index ca33077..cb96f58 100644 +--- a/security/certverifier/CertVerifier.cpp ++++ b/security/certverifier/CertVerifier.cpp +@@ -1048,10 +1048,14 @@ void HashSignatureParams(pkix::Input data, pkix::Input signature, + sizeof(publicKeyAlgorithm)))) { + return; + } +- if (NS_FAILED( ++ // Digest algorithm is expected to be null since ML-DSA is not an hash and ++ // sign algorithm. Skip digestAlgorithm for ML-DSA. ++ if (publicKeyAlgorithm != der::PublicKeyAlgorithm::MLDSA) { ++ if (NS_FAILED( + digest.Update(reinterpret_cast(&digestAlgorithm), + sizeof(digestAlgorithm)))) { +- return; ++ return; ++ } + } + nsTArray result; + if (NS_FAILED(digest.End(result))) { +@@ -1064,12 +1068,19 @@ Result VerifySignedDataWithCache( + der::PublicKeyAlgorithm publicKeyAlg, + mozilla::glean::impl::DenominatorMetric telemetryDenominator, + mozilla::glean::impl::NumeratorMetric telemetryNumerator, Input data, +- DigestAlgorithm digestAlgorithm, Input signature, ++ std::optional digestAlgorithm, Input signature, + Input subjectPublicKeyInfo, SignatureCache* signatureCache, void* pinArg) { + telemetryDenominator.Add(1); + Maybe> sha512Hash; ++ ++ // Currently, it is only acceptable for `digestAlgorithm` to be null when the ++ // public key algorithm is pure ML-DSA. Fail immediately otherwise. ++ if ((publicKeyAlg != der::PublicKeyAlgorithm::MLDSA) && !digestAlgorithm) { ++ return Result::ERROR_INVALID_ALGORITHM; ++ } ++ + HashSignatureParams(data, signature, subjectPublicKeyInfo, publicKeyAlg, +- digestAlgorithm, sha512Hash); ++ digestAlgorithm.value_or(pkix::DigestAlgorithm::sha512), sha512Hash); + // If hashing the signature parameters succeeded, see if this signature is in + // the signature cache. + if (sha512Hash.isSome() && +@@ -1080,16 +1091,23 @@ Result VerifySignedDataWithCache( + Result result; + switch (publicKeyAlg) { + case der::PublicKeyAlgorithm::ECDSA: +- result = VerifyECDSASignedDataNSS(data, digestAlgorithm, signature, +- subjectPublicKeyInfo, pinArg); ++ result = VerifyECDSASignedDataNSS(data, digestAlgorithm.value(), ++ signature, subjectPublicKeyInfo, ++ pinArg); + break; + case der::PublicKeyAlgorithm::RSA_PKCS1: +- result = VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm, signature, +- subjectPublicKeyInfo, pinArg); ++ result = VerifyRSAPKCS1SignedDataNSS(data, digestAlgorithm.value(), ++ signature, subjectPublicKeyInfo, ++ pinArg); + break; + case der::PublicKeyAlgorithm::RSA_PSS: +- result = VerifyRSAPSSSignedDataNSS(data, digestAlgorithm, signature, +- subjectPublicKeyInfo, pinArg); ++ result = VerifyRSAPSSSignedDataNSS(data, digestAlgorithm.value(), ++ signature, subjectPublicKeyInfo, ++ pinArg); ++ break; ++ case der::PublicKeyAlgorithm::MLDSA: ++ result = VerifyMLDSASignedDataNSS(data, signature, subjectPublicKeyInfo, ++ pinArg); + break; + default: + MOZ_ASSERT_UNREACHABLE("unhandled public key algorithm"); +diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h +index 6432547..f9a0365 100644 +--- a/security/certverifier/CertVerifier.h ++++ b/security/certverifier/CertVerifier.h +@@ -331,7 +331,7 @@ mozilla::pkix::Result VerifySignedDataWithCache( + mozilla::pkix::der::PublicKeyAlgorithm publicKeyAlg, + mozilla::glean::impl::DenominatorMetric telemetryDenominator, + mozilla::glean::impl::NumeratorMetric telemetryNumerator, +- mozilla::pkix::Input data, mozilla::pkix::DigestAlgorithm digestAlgorithm, ++ mozilla::pkix::Input data, std::optional digestAlgorithm, + mozilla::pkix::Input signature, mozilla::pkix::Input subjectPublicKeyInfo, + SignatureCache* signatureCache, void* pinArg); + +diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp +index 77c17c1..741892f 100644 +--- a/security/certverifier/NSSCertDBTrustDomain.cpp ++++ b/security/certverifier/NSSCertDBTrustDomain.cpp +@@ -1541,6 +1541,17 @@ Result NSSCertDBTrustDomain::VerifyECDSASignedData( + signature, subjectPublicKeyInfo, mSignatureCache, mPinArg); + } + ++Result NSSCertDBTrustDomain::VerifyMLDSASignedData(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo) ++{ ++ return VerifySignedDataWithCache( ++ der::PublicKeyAlgorithm::MLDSA, ++ mozilla::glean::cert_signature_cache::total, ++ mozilla::glean::cert_signature_cache::hits, data, std::nullopt, ++ signature, subjectPublicKeyInfo, mSignatureCache, mPinArg); ++} ++ + Result NSSCertDBTrustDomain::CheckValidityIsAcceptable( + Time notBefore, Time notAfter, EndEntityOrCA endEntityOrCA, + KeyPurposeId keyPurpose) { +diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h +index fc210f3..8d17a4f 100644 +--- a/security/certverifier/NSSCertDBTrustDomain.h ++++ b/security/certverifier/NSSCertDBTrustDomain.h +@@ -197,6 +197,11 @@ class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain { + mozilla::pkix::Input signature, + mozilla::pkix::Input subjectPublicKeyInfo) override; + ++ virtual Result VerifyMLDSASignedData( ++ mozilla::pkix::Input data, ++ mozilla::pkix::Input signature, ++ mozilla::pkix::Input subjectPublicKeyInfo) override; ++ + virtual Result DigestBuf(mozilla::pkix::Input item, + mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, +diff --git a/security/ct/CTLogVerifier.cpp b/security/ct/CTLogVerifier.cpp +index d5e665a..4712137 100644 +--- a/security/ct/CTLogVerifier.cpp ++++ b/security/ct/CTLogVerifier.cpp +@@ -99,6 +99,10 @@ class SignatureParamsTrustDomain final : public TrustDomain { + return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; + } + ++ pkix::Result VerifyMLDSASignedData(Input, Input, Input) override { ++ return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; ++ } ++ + pkix::Result CheckValidityIsAcceptable(Time, Time, EndEntityOrCA, + KeyPurposeId) override { + return pkix::Result::FATAL_ERROR_LIBRARY_FAILURE; +diff --git a/security/ct/tests/gtest/CTTestUtils.cpp b/security/ct/tests/gtest/CTTestUtils.cpp +index 6a25307..03d19f7 100644 +--- a/security/ct/tests/gtest/CTTestUtils.cpp ++++ b/security/ct/tests/gtest/CTTestUtils.cpp +@@ -807,6 +807,15 @@ class OCSPExtensionTrustDomain : public TrustDomain { + subjectPublicKeyInfo, nullptr); + } + ++ pkix::Result VerifyMLDSASignedData(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo) override { ++ return VerifyMLDSASignedDataNSS(data, ++ signature, ++ subjectPublicKeyInfo, ++ nullptr); ++ } ++ + pkix::Result CheckValidityIsAcceptable(Time, Time, EndEntityOrCA, + KeyPurposeId) override { + ADD_FAILURE(); +diff --git a/security/manager/ssl/AppTrustDomain.cpp b/security/manager/ssl/AppTrustDomain.cpp +index ab49d7e..36e7e19 100644 +--- a/security/manager/ssl/AppTrustDomain.cpp ++++ b/security/manager/ssl/AppTrustDomain.cpp +@@ -322,6 +322,16 @@ pkix::Result AppTrustDomain::VerifyECDSASignedData( + subjectPublicKeyInfo, nullptr); + } + ++pkix::Result AppTrustDomain::VerifyMLDSASignedData(Input data, ++ Input signature, ++ Input subjectPublicKeyInfo) ++{ ++ return VerifyMLDSASignedDataNSS(data, ++ signature, ++ subjectPublicKeyInfo, ++ nullptr); ++} ++ + pkix::Result AppTrustDomain::CheckValidityIsAcceptable( + Time /*notBefore*/, Time /*notAfter*/, EndEntityOrCA /*endEntityOrCA*/, + KeyPurposeId /*keyPurpose*/) { +diff --git a/security/manager/ssl/AppTrustDomain.h b/security/manager/ssl/AppTrustDomain.h +index 4b0212e..083d5fb 100644 +--- a/security/manager/ssl/AppTrustDomain.h ++++ b/security/manager/ssl/AppTrustDomain.h +@@ -80,6 +80,10 @@ class AppTrustDomain final : public mozilla::pkix::TrustDomain { + mozilla::pkix::DigestAlgorithm digestAlg, + /*out*/ uint8_t* digestBuf, + size_t digestBufLen) override; ++ virtual Result VerifyMLDSASignedData( ++ mozilla::pkix::Input data, ++ mozilla::pkix::Input signature, ++ mozilla::pkix::Input subjectPublicKeyInfo) override; + + private: + nsTArray> mTrustedRoots; +diff --git a/security/manager/ssl/TLSClientAuthCertSelection.cpp b/security/manager/ssl/TLSClientAuthCertSelection.cpp +index 3a84b15..8450076 100644 +--- a/security/manager/ssl/TLSClientAuthCertSelection.cpp ++++ b/security/manager/ssl/TLSClientAuthCertSelection.cpp +@@ -217,6 +217,12 @@ class ClientAuthCertNonverifyingTrustDomain final : public TrustDomain { + pkix::Input subjectPublicKeyInfo) override { + return pkix::Success; + } ++ virtual mozilla::pkix::Result VerifyMLDSASignedData( ++ pkix::Input data, ++ pkix::Input signature, ++ pkix::Input subjectPublicKeyInfo) override { ++ return pkix::Success; ++ } + virtual mozilla::pkix::Result CheckValidityIsAcceptable( + pkix::Time notBefore, pkix::Time notAfter, + pkix::EndEntityOrCA endEntityOrCA, diff --git a/SOURCES/process-official-tarball b/SOURCES/process-official-tarball index 73cb6b4..fed6a71 100755 --- a/SOURCES/process-official-tarball +++ b/SOURCES/process-official-tarball @@ -17,6 +17,7 @@ rm -vf ./process-tarball-dir/*/mobile/android/android-components/components/brow rm -vf ./process-tarball-dir/*/mobile/android/android-components/components/feature/addons/src/main/res/values-ur/strings.xml rm -vf ./process-tarball-dir/*/third_party/webkit/PerformanceTests/Speedometer3/resources/editors/dist/assets/codemirror-521de7ab.js rm -vf ./process-tarball-dir/*/third_party/python/pip/pip-24.0.dist-info/AUTHORS.txt +rm -vf ./process-tarball-dir/*/dom/locks/test/crashtests/1908240.js # We uses system freetype2 rm -vrf ./process-tarball-dir/*/modules/freetype2 diff --git a/SOURCES/wasi.patch b/SOURCES/wasi.patch index 51ada87..cb4dd86 100644 --- a/SOURCES/wasi.patch +++ b/SOURCES/wasi.patch @@ -6,7 +6,7 @@ diff -up firefox-121.0.1/toolkit/moz.configure.wasi firefox-121.0.1/toolkit/moz. if wasi_sysroot: log.info("Using wasi sysroot in %s", wasi_sysroot) - return ["--sysroot=%s" % wasi_sysroot] -+ return ["--sysroot=%s" % wasi_sysroot, "-nodefaultlibs", "-lc", "-lwasi-emulated-process-clocks", "-lc++", "-lc++abi", "/home/jhorak/r/firefox/firefox-140.2.0-build/firefox-140.2.0/wasi-sdk-20/build/compiler-rt/lib/wasi/libclang_rt.builtins-wasm32.a"] ++ return ["--sysroot=%s" % wasi_sysroot, "-nodefaultlibs", "-lc", "-lwasi-emulated-process-clocks", "-lc++", "-lc++abi", "/home/jhorak/r/firefox/firefox-140.4.0-build/firefox-140.4.0/wasi-sdk-20/build/compiler-rt/lib/wasi/libclang_rt.builtins-wasm32.a"] return [] set_config("WASI_SYSROOT", wasi_sysroot) diff --git a/SPECS/firefox.spec b/SPECS/firefox.spec index 6b335e3..75bb9f6 100644 --- a/SPECS/firefox.spec +++ b/SPECS/firefox.spec @@ -175,8 +175,8 @@ end} Summary: Mozilla Firefox Web browser Name: firefox -Version: 140.3.0 -Release: 1%{?dist} +Version: 140.4.0 +Release: 3%{?dist} URL: https://www.mozilla.org/firefox/ License: MPLv1.1 or GPLv2+ or LGPLv2+ @@ -206,7 +206,7 @@ ExcludeArch: aarch64 s390 ppc # Link to original tarball: https://archive.mozilla.org/pub/firefox/releases/%%{version}%%{?pre_version}/source/firefox-%%{version}%%{?pre_version}.source.tar.xz Source0: firefox-%{version}%{?pre_version}%{?buildnum}.processed-source.tar.xz %if %{with langpacks} -Source1: firefox-langpacks-%{version}%{?pre_version}-20250909.tar.xz +Source1: firefox-langpacks-%{version}%{?pre_version}-20251010.tar.xz %endif Source2: cbindgen-vendor.tar.xz Source3: process-official-tarball @@ -260,6 +260,8 @@ Patch51: mozilla-bmo1170092.patch Patch52: exceptionHandled-for-IO-error-processhandler.patch Patch53: D245908.clear-lang-bundles.diff Patch54: D249071.restoreWinState.diff +# Removed Crash Annotation GraphicsCriticalError +Patch55: D266159.1760530435.diff # -- Submitted upstream, not merged -- Patch101: mozilla-bmo1636168-fscreen.patch @@ -278,6 +280,18 @@ Patch109: mozilla-bmo1789216-disable-av1.patch Patch110: build-libaom.patch Patch111: av1-else-condition-add.patch +# ML-DSA support +# https://phabricator.services.mozilla.com/D262395 +Patch120: firefox-integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation.patch +# https://phabricator.services.mozilla.com/D262397 +Patch121: firefox-add-ml-dsa-certificate-support-to-certviewer.patch +# https://phabricator.services.mozilla.com/D264144 +Patch122: firefox-enable-ml-dsa-signature-verification-for-certificate-chain-validation.patch +# RHEL downstream only - adapts to ML-DSA support in NSS from RHEL 10 +Patch123: firefox-adapt-ml-dsa-support-to-rhel-nss.patch +# RHEL downstream only - enable ML-DSA in manager/ssl +Patch124: firefox-enable-ml-dsa-in-manager-ssl.patch + # ---- Fedora specific patches ---- Patch151: firefox-enable-addons.patch Patch152: rhbz-1173156.patch @@ -1307,6 +1321,7 @@ export LIBCLANG_RT=`pwd`/wasi-sdk-20/build/compiler-rt/lib/wasi/libclang_rt.buil %patch -P52 -p1 -b .exceptionHandled-for-IO-error-processhandler %patch -P53 -p1 -b .clear-lang-bundles %patch -P54 -p1 -b .restoreWinState +%patch -P55 -p1 -b .D266159.1760530435 # -- Submitted upstream, not merged -- %patch -P101 -p1 -b .mozilla-bmo1636168-fscreen @@ -1324,6 +1339,15 @@ export LIBCLANG_RT=`pwd`/wasi-sdk-20/build/compiler-rt/lib/wasi/libclang_rt.buil %patch -P110 -p1 -b .libaom %patch -P111 -p1 -b .av1-else-condition-add +%if 0%{?rhel} >= 10 && %{rhel_minor_version} >= 1 +# ML-DSA support +%patch -P120 -p1 -b .integrate-ml-dsa-signature-verification-for-pkix-certificate-chain-validation +%patch -P121 -p1 -b .add-ml-dsa-certificate-support-to-certviewer +%patch -P122 -p1 -b .enable-ml-dsa-signature-verification-for-certificate-chain-validation +%patch -P123 -p1 -b .adapt-ml-dsa-support-to-rhel-nss +%patch -P124 -p1 -b .enable-ml-dsa-in-manager-ssl +%endif + # ---- Fedora specific patches ---- %patch -P151 -p1 -b .addons %patch -P152 -p1 -b .rhbz-1173156 @@ -1382,9 +1406,13 @@ echo "ac_add_options --enable-debug" >> .mozconfig echo "ac_add_options --disable-optimize" >> .mozconfig %else %global optimize_flags "none" -%ifarch s390x -%global optimize_flags "-g -O1" + +%if 0%{?rhel} < 10 + %ifarch s390x + %global optimize_flags "-g -O1" + %endif %endif + %ifarch ppc64le aarch64 %global optimize_flags "-g -O2" %endif @@ -1419,9 +1447,10 @@ echo "ac_add_options --disable-jit" >> .mozconfig %ifarch ppc64 ppc64le echo "ac_add_options --disable-webrtc" >> .mozconfig +%endif +%if 0%{?rhel} < 10 echo "ac_add_options --disable-lto" >> .mozconfig %endif -echo "ac_add_options --disable-lto" >> .mozconfig # AV1 requires newer nasm that was rebased in 8.4 %if 0%{?rhel} == 7 || (0%{?rhel} == 8 && %{rhel_minor_version} < 4) @@ -1668,6 +1697,7 @@ echo "export CXX=g++" >> .mozconfig echo "export AR=\"gcc-ar\"" >> .mozconfig echo "export NM=\"gcc-nm\"" >> .mozconfig echo "export RANLIB=\"gcc-ranlib\"" >> .mozconfig +echo "export MALLOC_MMAP_MAX_=0" >> .mozconfig MOZ_SMP_FLAGS=-j1 # On x86_64 architectures, Mozilla can build up to 4 jobs at once in parallel, @@ -2079,6 +2109,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : #--------------------------------------------------------------------- %changelog +* Fri Oct 10 2025 Jan Horak - 140.4.0-3 +- Update to 140.4.0 ESR + * Wed Sep 10 2025 Jan Horak - 140.3.0-1 - Update to 140.3.0