Skip to content

Commit 0a90ee5

Browse files
authored
Merge pull request #179 from cconlon/pssParamFix
Fix PSS AlgorithmIdentifier decoding to accept absent parameters
2 parents 9be1f4e + 143a4e8 commit 0a90ee5

File tree

2 files changed

+200
-11
lines changed

2 files changed

+200
-11
lines changed

src/main/java/com/wolfssl/provider/jce/WolfCryptPssParameters.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -473,17 +473,16 @@ private String decodeAlgorithmIdentifier(byte[] data) throws IOException {
473473
System.arraycopy(data, idx, oid, 0, oidLen);
474474
idx += oidLen;
475475

476-
/* Verify NULL parameters follow OID (per RFC 4055).
477-
* Hash AlgorithmIdentifiers have NULL parameters. */
478-
if (idx + 2 > data.length) {
479-
throw new IOException(
480-
"Invalid AlgorithmIdentifier: missing parameters");
481-
}
482-
483-
if (data[idx] != WolfCryptASN1Util.ASN1_NULL ||
484-
data[idx + 1] != 0x00) {
485-
throw new IOException(
486-
"Invalid AlgorithmIdentifier: expected NULL parameters");
476+
/* Verify parameters follow OID (per RFC 4055), can be either
477+
* NULL or absent */
478+
if (idx < data.length) {
479+
/* Parameters are present, verify they are NULL */
480+
if ((idx + 2 > data.length) ||
481+
(data[idx] != WolfCryptASN1Util.ASN1_NULL) ||
482+
(data[idx + 1] != 0x00)) {
483+
throw new IOException(
484+
"Invalid AlgorithmIdentifier: expected NULL parameters");
485+
}
487486
}
488487

489488
/* Map OID to hash algorithm name */

src/test/java/com/wolfssl/provider/jce/test/WolfCryptAlgorithmParametersTest.java

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,5 +1165,195 @@ public void testRSAPSSParametersInitWithUnsupportedFormat()
11651165
/* expected */
11661166
}
11671167
}
1168+
1169+
/**
1170+
* Test that PSS parameters can be decoded when the hash
1171+
* AlgorithmIdentifier has absent parameters (no NULL).
1172+
*
1173+
* Per RFC 4055 Section 2.1, hash AlgorithmIdentifiers can have either:
1174+
* - Absent parameters (SHOULD per RFC)
1175+
* - NULL parameters (for backwards compatibility)
1176+
*
1177+
* This test verifies we correctly handle the absent parameters case
1178+
* which is the preferred encoding per RFC 4055.
1179+
*/
1180+
@Test
1181+
public void testRSAPSSParametersDecodingWithAbsentHashParams()
1182+
throws Exception {
1183+
1184+
/*
1185+
* Manually constructed DER encoding of PSS parameters with SHA-256
1186+
* hash AlgorithmIdentifier that has ABSENT parameters (no NULL).
1187+
*
1188+
* RSASSA-PSS-params ::= SEQUENCE {
1189+
* hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
1190+
* maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
1191+
* saltLength [2] INTEGER DEFAULT 20,
1192+
* trailerField [3] INTEGER DEFAULT 1
1193+
* }
1194+
*
1195+
* HashAlgorithm ::= AlgorithmIdentifier
1196+
* AlgorithmIdentifier ::= SEQUENCE {
1197+
* algorithm OBJECT IDENTIFIER,
1198+
* parameters ANY DEFINED BY algorithm OPTIONAL
1199+
* }
1200+
*
1201+
* This encoding has:
1202+
* - [0] hashAlgorithm: SHA-256 with ABSENT parameters
1203+
* - [1] maskGenAlgorithm: MGF1 with SHA-256 (also with absent params)
1204+
* - [2] saltLength: 32
1205+
*
1206+
* Structure breakdown:
1207+
* 30 30 ; SEQUENCE (48 bytes)
1208+
* A0 0D ; [0] context tag (13 bytes)
1209+
* 30 0B ; SEQUENCE (11 bytes) - AlgId
1210+
* 06 09 ; OID (9 bytes)
1211+
* 60 86 48 01 65 03 04 02 01 ; SHA-256 OID
1212+
* -- NOTE: no NULL here (absent parameters)
1213+
* A1 1A ; [1] context tag (26 bytes)
1214+
* 30 18 ; SEQUENCE (24 bytes) - MGF1 AlgId
1215+
* 06 09 ; OID (9 bytes)
1216+
* 2A 86 48 86 F7 0D 01 01 08 ; MGF1 OID
1217+
* 30 0B ; SEQUENCE (11 bytes) - Hash AlgId
1218+
* 06 09 ; OID (9 bytes)
1219+
* 60 86 48 01 65 03 04 02 01 ; SHA-256 OID
1220+
* -- NOTE: no NULL here (absent parameters)
1221+
* A2 03 ; [2] context tag (3 bytes)
1222+
* 02 01 20 ; INTEGER 32 (salt length)
1223+
*/
1224+
byte[] pssParamsAbsentHashParams = new byte[] {
1225+
0x30, 0x30, /* SEQUENCE 48 */
1226+
(byte)0xA0, 0x0D, /* [0] 13 */
1227+
0x30, 0x0B, /* SEQUENCE 11 */
1228+
0x06, 0x09, /* OID 9 */
1229+
0x60, (byte)0x86, 0x48, 0x01, 0x65,
1230+
0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1231+
/* NO NULL - absent parameters */
1232+
(byte)0xA1, 0x1A, /* [1] 26 */
1233+
0x30, 0x18, /* SEQUENCE 24 */
1234+
0x06, 0x09, /* OID 9 */
1235+
0x2A, (byte)0x86, 0x48, (byte)0x86,
1236+
(byte)0xF7, 0x0D, 0x01, 0x01, 0x08, /* MGF1 */
1237+
0x30, 0x0B, /* SEQUENCE 11 */
1238+
0x06, 0x09, /* OID 9 */
1239+
0x60, (byte)0x86, 0x48, 0x01,
1240+
0x65, 0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1241+
/* NO NULL - absent parameters */
1242+
(byte)0xA2, 0x03, /* [2] 3 */
1243+
0x02, 0x01, 0x20 /* INTEGER 32 */
1244+
};
1245+
1246+
/* Should not throw an exception, absent params are valid */
1247+
AlgorithmParameters params =
1248+
AlgorithmParameters.getInstance("RSASSA-PSS", "wolfJCE");
1249+
params.init(pssParamsAbsentHashParams);
1250+
1251+
/* Verify parameters were decoded correctly */
1252+
PSSParameterSpec spec =
1253+
params.getParameterSpec(PSSParameterSpec.class);
1254+
assertNotNull(spec);
1255+
assertEquals("SHA-256", spec.getDigestAlgorithm());
1256+
assertEquals("MGF1", spec.getMGFAlgorithm());
1257+
assertEquals(32, spec.getSaltLength());
1258+
assertEquals(1, spec.getTrailerField());
1259+
1260+
/* Verify MGF1 hash algorithm */
1261+
assertTrue(
1262+
spec.getMGFParameters() instanceof MGF1ParameterSpec);
1263+
MGF1ParameterSpec mgf1Spec =
1264+
(MGF1ParameterSpec) spec.getMGFParameters();
1265+
assertEquals("SHA-256", mgf1Spec.getDigestAlgorithm());
1266+
}
1267+
1268+
/**
1269+
* Test that PSS parameters with both absent and NULL parameters
1270+
* produce equivalent results.
1271+
*/
1272+
@Test
1273+
public void testRSAPSSParametersAbsentVsNullParams()
1274+
throws Exception {
1275+
1276+
/*
1277+
* PSS params with SHA-256 and NULL parameters in AlgorithmIdentifier.
1278+
*/
1279+
byte[] pssParamsWithNull = new byte[] {
1280+
0x30, 0x34, /* SEQUENCE 52 */
1281+
(byte)0xA0, 0x0F, /* [0] 15 */
1282+
0x30, 0x0D, /* SEQUENCE 13 */
1283+
0x06, 0x09, /* OID 9 */
1284+
0x60, (byte)0x86, 0x48, 0x01, 0x65,
1285+
0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1286+
0x05, 0x00, /* NULL */
1287+
(byte)0xA1, 0x1C, /* [1] 28 */
1288+
0x30, 0x1A, /* SEQUENCE 26 */
1289+
0x06, 0x09, /* OID 9 */
1290+
0x2A, (byte)0x86, 0x48, (byte)0x86,
1291+
(byte)0xF7, 0x0D, 0x01, 0x01, 0x08, /* MGF1 */
1292+
0x30, 0x0D, /* SEQUENCE 13 */
1293+
0x06, 0x09, /* OID 9 */
1294+
0x60, (byte)0x86, 0x48, 0x01,
1295+
0x65, 0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1296+
0x05, 0x00, /* NULL */
1297+
(byte)0xA2, 0x03, /* [2] 3 */
1298+
0x02, 0x01, 0x20 /* INTEGER 32 */
1299+
};
1300+
1301+
/*
1302+
* PSS params with SHA-256 and ABSENT parameters in AlgorithmIdentifier.
1303+
*/
1304+
byte[] pssParamsAbsent = new byte[] {
1305+
0x30, 0x30, /* SEQUENCE 48 */
1306+
(byte)0xA0, 0x0D, /* [0] 13 */
1307+
0x30, 0x0B, /* SEQUENCE 11 */
1308+
0x06, 0x09, /* OID 9 */
1309+
0x60, (byte)0x86, 0x48, 0x01, 0x65,
1310+
0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1311+
/* NO NULL - absent parameters */
1312+
(byte)0xA1, 0x1A, /* [1] 26 */
1313+
0x30, 0x18, /* SEQUENCE 24 */
1314+
0x06, 0x09, /* OID 9 */
1315+
0x2A, (byte)0x86, 0x48, (byte)0x86,
1316+
(byte)0xF7, 0x0D, 0x01, 0x01, 0x08, /* MGF1 */
1317+
0x30, 0x0B, /* SEQUENCE 11 */
1318+
0x06, 0x09, /* OID 9 */
1319+
0x60, (byte)0x86, 0x48, 0x01,
1320+
0x65, 0x03, 0x04, 0x02, 0x01, /* SHA-256 */
1321+
/* NO NULL - absent parameters */
1322+
(byte)0xA2, 0x03, /* [2] 3 */
1323+
0x02, 0x01, 0x20 /* INTEGER 32 */
1324+
};
1325+
1326+
/* Decode both encodings */
1327+
AlgorithmParameters paramsWithNull =
1328+
AlgorithmParameters.getInstance("RSASSA-PSS", "wolfJCE");
1329+
paramsWithNull.init(pssParamsWithNull);
1330+
1331+
AlgorithmParameters paramsAbsent =
1332+
AlgorithmParameters.getInstance("RSASSA-PSS", "wolfJCE");
1333+
paramsAbsent.init(pssParamsAbsent);
1334+
1335+
/* Get specs from both */
1336+
PSSParameterSpec specWithNull =
1337+
paramsWithNull.getParameterSpec(PSSParameterSpec.class);
1338+
PSSParameterSpec specAbsent =
1339+
paramsAbsent.getParameterSpec(PSSParameterSpec.class);
1340+
1341+
/* Both should decode to equivalent parameters */
1342+
assertEquals(specWithNull.getDigestAlgorithm(),
1343+
specAbsent.getDigestAlgorithm());
1344+
assertEquals(specWithNull.getMGFAlgorithm(),
1345+
specAbsent.getMGFAlgorithm());
1346+
assertEquals(specWithNull.getSaltLength(),
1347+
specAbsent.getSaltLength());
1348+
assertEquals(specWithNull.getTrailerField(),
1349+
specAbsent.getTrailerField());
1350+
1351+
MGF1ParameterSpec mgf1WithNull =
1352+
(MGF1ParameterSpec) specWithNull.getMGFParameters();
1353+
MGF1ParameterSpec mgf1Absent =
1354+
(MGF1ParameterSpec) specAbsent.getMGFParameters();
1355+
assertEquals(mgf1WithNull.getDigestAlgorithm(),
1356+
mgf1Absent.getDigestAlgorithm());
1357+
}
11681358
}
11691359

0 commit comments

Comments
 (0)