Related: RHEL-131347

- fix a null in ml-dsa pkcs12 decode
- fix return code in ml-kem pct
This commit is contained in:
Robert Relyea 2026-01-12 08:25:48 -08:00
parent d23185094d
commit 64ea259561
2 changed files with 208 additions and 1 deletions

View File

@ -0,0 +1,202 @@
# HG changeset patch
# User Robert Relyea <rrelyea@redhat.com>
# Date 1767992040 28800
# Fri Jan 09 12:54:00 2026 -0800
# Branch RHEL10
# Node ID 15f1129c29c037cce7913eb62c0eca06b5aa51d1
# Parent 4bfb87c6e863957fc933e6dd5af8eae8a5cd0469
nss-3.112-pkcs12-ml-dsa-crash-fix.patch
diff --git a/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc b/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
--- a/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
+++ b/gtests/pk11_gtest/pk11_der_private_key_import_unittest.cc
@@ -7,16 +7,17 @@
#include <climits>
#include <memory>
#include "nss.h"
#include "pk11pub.h"
#include "secutil.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
+#define SEC_OID_ML_DSA_44 SEC_OID_PRIVATE_3
namespace nss_test {
const std::vector<uint8_t> kValidP256Key = {
0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
0xc9, 0xaf, 0xa9, 0xd8, 0x45, 0xba, 0x75, 0x16, 0x6b, 0x5c, 0x21, 0x57,
@@ -133,16 +134,69 @@ class DERPrivateKeyImportTest : public :
// no cert. This is expected, so clear it.
if (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) {
PORT_SetError(0);
}
}
return rv == SECSuccess;
}
+
+ SECStatus BuildPrivateKeyInfoAndImportIt(SECOidTag algTag) {
+ ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
+ EXPECT_TRUE(slot);
+ if (!slot) {
+ return SECFailure;
+ }
+
+ ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
+ EXPECT_TRUE(arena);
+ if (!arena) {
+ return SECFailure;
+ }
+
+ SECKEYPrivateKeyInfo* pki = (SECKEYPrivateKeyInfo*)PORT_ArenaZAlloc(
+ arena.get(), sizeof(SECKEYPrivateKeyInfo));
+ EXPECT_TRUE(pki);
+ if (!pki) {
+ return SECFailure;
+ }
+
+ pki->version.data = (unsigned char*)PORT_ArenaAlloc(arena.get(), 1);
+ EXPECT_TRUE(pki->version.data);
+ if (!pki->version.data) {
+ return SECFailure;
+ }
+
+ pki->version.data[0] = 0x00;
+ pki->version.len = 1;
+
+ EXPECT_EQ(
+ SECOID_SetAlgorithmID(arena.get(), &pki->algorithm, algTag, nullptr),
+ SECSuccess);
+
+ // Empty private key
+ pki->privateKey.data = (unsigned char*)PORT_ArenaAlloc(arena.get(), 1);
+ EXPECT_TRUE(pki->privateKey.data);
+ if (!pki->privateKey.data) {
+ return SECFailure;
+ }
+ pki->privateKey.len = 0;
+
+ SECKEYPrivateKey* privk = nullptr;
+ PORT_SetError(0);
+ SECStatus rv = PK11_ImportPrivateKeyInfoAndReturnKey(
+ slot.get(), pki, nullptr, nullptr, PR_FALSE, PR_FALSE, KU_ALL, &privk,
+ nullptr);
+
+ if (privk) {
+ SECKEY_DestroyPrivateKey(privk);
+ }
+ return rv;
+ }
};
TEST_F(DERPrivateKeyImportTest, ImportPrivateRSAKey) {
EXPECT_TRUE(ParsePrivateKey(kValidRSAKey, true));
EXPECT_FALSE(PORT_GetError()) << PORT_GetError();
}
TEST_F(DERPrivateKeyImportTest, ImportEcdsaKey) {
@@ -155,9 +209,15 @@ TEST_F(DERPrivateKeyImportTest, ImportIn
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_DER) << PORT_GetError();
}
TEST_F(DERPrivateKeyImportTest, ImportZeroLengthPrivateKey) {
EXPECT_FALSE(ParsePrivateKey(kInvalidZeroLengthKey, false));
EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY) << PORT_GetError();
}
+TEST_F(DERPrivateKeyImportTest,
+ ImportZeroLengthMLDSAPrivateKey) {
+ EXPECT_EQ(BuildPrivateKeyInfoAndImportIt(SEC_OID_ML_DSA_44), SECFailure);
+ EXPECT_EQ(PORT_GetError(), SEC_ERROR_BAD_KEY);
+}
+
} // namespace nss_test
diff --git a/lib/pk11wrap/pk11pk12.c b/lib/pk11wrap/pk11pk12.c
--- a/lib/pk11wrap/pk11pk12.c
+++ b/lib/pk11wrap/pk11pk12.c
@@ -323,17 +323,17 @@ PK11_ImportDERPrivateKeyInfoAndReturnKey
derPKI);
if (rv != SECSuccess) {
/* If SEC_ASN1DecodeItem fails, we cannot assume anything about the
* validity of the data in pki. The best we can do is free the arena
* and return. */
PORT_FreeArena(temparena, PR_TRUE);
return rv;
}
- if (pki->privateKey.data == NULL) {
+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
/* If SEC_ASN1DecodeItems succeeds but SECKEYPrivateKeyInfo.privateKey
* is a zero-length octet string, free the arena and return a failure
* to avoid trying to zero the corresponding SECItem in
* SECKEY_DestroyPrivateKeyInfo(). */
PORT_FreeArena(temparena, PR_TRUE);
PORT_SetError(SEC_ERROR_BAD_KEY);
return SECFailure;
}
@@ -753,16 +753,20 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK
keyTemplate = SECKEY_ECPrivateKeyExportTemplate;
paramTemplate = NULL;
paramDest = NULL;
lpk->keyType = ecKey;
break;
case SEC_OID_ML_DSA_44:
case SEC_OID_ML_DSA_65:
case SEC_OID_ML_DSA_87:
+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ goto loser;
+ }
/* choice */
switch (pki->privateKey.data[0]) {
case SEC_ASN1_CONTEXT_SPECIFIC|0:
keyTemplate = SECKEY_MLDSAPrivateKeySeedExportTemplate;
break;
case SEC_ASN1_OCTET_STRING:
keyTemplate = SECKEY_MLDSAPrivateKeyKeyExportTemplate;
break;
diff --git a/lib/softoken/pkcs11c.c b/lib/softoken/pkcs11c.c
--- a/lib/softoken/pkcs11c.c
+++ b/lib/softoken/pkcs11c.c
@@ -5815,17 +5815,17 @@ sftk_PairwiseConsistencyCheck(CK_SESSION
}
crv = NSC_Decapsulate(hSession, &mech, privateKey->handle,
cipher_text, cipher_text_length, &template, 1,
&key2);
if (crv != CKR_OK) {
goto kem_done;
}
if (!sftk_compareKeysEqual(hSession, key1, key2)) {
- crv = CKR_DEVICE_ERROR;
+ crv = CKR_GENERAL_ERROR;
goto kem_done;
}
kem_done:
/* PORT_Free already checks for NULL */
PORT_Free(cipher_text);
if (key1 != CK_INVALID_HANDLE) {
NSC_DestroyObject(hSession, key1);
}
@@ -7105,16 +7105,20 @@ sftk_unwrapPrivateKey(SFTKObject *key, S
paramSet = CKP_ML_DSA_44;
goto mldsa_next;
case SEC_OID_ML_DSA_65:
paramSet = CKP_ML_DSA_65;
goto mldsa_next;
case SEC_OID_ML_DSA_87:
paramSet = CKP_ML_DSA_87;
mldsa_next:
+ if (pki->privateKey.data == NULL || pki->privateKey.len == 0) {
+ PORT_SetError(SEC_ERROR_BAD_KEY);
+ goto loser;
+ }
switch (pki->privateKey.data[0]) {
case SEC_ASN1_CONTEXT_SPECIFIC|0:
keyTemplate = nsslowkey_PQSeedTemplate;
break;
case SEC_ASN1_OCTET_STRING:
keyTemplate = nsslowkey_PQPrivateKeyTemplate;
break;
case SEC_ASN1_CONSTRUCTED|SEC_ASN1_SEQUENCE:

View File

@ -3,7 +3,7 @@
# NOTE: To avoid NVR clashes of nspr* packages:
# - reset %%{nspr_release} to 1, when updating %%{nspr_version}
# - increment %%{nspr_version}, when updating the NSS part only
%global baserelease 5
%global baserelease 6
%global nss_release %baserelease
# use "%%global nspr_release %%[%%baserelease+n]" to handle offsets when
# release number between nss and nspr are different.
@ -184,6 +184,7 @@ Patch88: nss-3.112-fix-get-interface.patch
Patch89: nss-3.112-mlkem-fips-update.patch
Patch90: nss-3.112-update-fixes.patch
Patch91: nss-3.112-partial-pub-key-validate.patch
Patch92: nss-3.112-pkcs12-ml-dsa-crash-fix.patch
# NSS reverse patches
Patch300: nss-3.79-distrusted-certs.patch
@ -1171,6 +1172,10 @@ fi
%changelog
* Fri Jan 9 2026 Bob Relyea <rrelyea@redhat.com> - 3.112.0-6
- fix a null in ml-dsa pkcs12 decode
- fix return code in ml-kem pct
* Mon Nov 3 2025 Bob Relyea <rrelyea@redhat.com> - 3.112.0-5
- fips update
- Fix indicators for the new post-quantum algorithms