Skip to content

Commit 345b25f

Browse files
committed
Tolerate the optional fields in the ECPrivateKey sequence
The ECPrivateKey sequence defines two optional fields: parameters and publicKey. When parsing an ECPrivateKey, the code must allow cases where only one of these fields is present, or where both are absent or where both are presented. In addition, it seems that java does not automatically concatenate the cause’s message with the outer exception’s message, the detailed message associated with the cause is not merged into the current exception’s detail message. Therefore, getMessage() is explicitly included when throwing the exception in order to preserve and expose the underlying error details. Signed-off-by: JinhangZhang <Jinhang.Zhang@ibm.com>
1 parent 0fdb3c3 commit 345b25f

File tree

2 files changed

+40
-14
lines changed

2 files changed

+40
-14
lines changed

src/main/java/com/ibm/crypto/plus/provider/ECPrivateKey.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ final class ECPrivateKey extends PKCS8Key implements java.security.interfaces.EC
8787
this.ecKey = ECKey.createPrivateKey(provider.getOCKContext(), privateKeyBytes,
8888
paramBytes, provider);
8989
} catch (Exception exception) {
90-
throw new InvalidKeyException("Failed to create EC private key", exception);
90+
throw new InvalidKeyException("Failed to create EC private key, " + exception.getMessage(), exception);
9191
}
9292

9393
}
@@ -122,7 +122,7 @@ final class ECPrivateKey extends PKCS8Key implements java.security.interfaces.EC
122122
this.ecKey = ECKey.createPrivateKey(provider.getOCKContext(), privateKeyBytes,
123123
paramBytes, provider);
124124
} catch (Exception exception) {
125-
throw new InvalidKeyException("Failed to create EC private key", exception);
125+
throw new InvalidKeyException("Failed to create EC private key, " + exception.getMessage(), exception);
126126
}
127127
}
128128

@@ -194,16 +194,20 @@ private byte[] createEncodedPrivateKeyWithParams() throws IOException {
194194
outEncodedStream.putOctetString(privateKeyBytes);
195195

196196
byte[] encodedParams = this.getAlgorithmId().getEncodedParams();
197-
if (inputDerValue.length > 2) {
198-
if (!inputDerValue[2].isContextSpecific(TAG_PARAMETERS_ATTRS)) {
199-
throw new IOException("Decoding EC private key failed. Third element is not tagged as parameters");
200-
}
201-
DerInputStream paramDerInputStream = inputDerValue[2].getData();
202-
byte[] privateKeyParams = paramDerInputStream.toByteArray();
203-
204-
// Check against the existing parameters created by PKCS8Key.
205-
if (!Arrays.equals(privateKeyParams, encodedParams)) {
206-
throw new IOException("Decoding EC private key failed. The params are not the same as PKCS8Key's");
197+
if (inputDerValue.length > 2) {
198+
if (inputDerValue[2].isContextSpecific(TAG_PARAMETERS_ATTRS)) {
199+
DerInputStream paramDerInputStream = inputDerValue[2].getData();
200+
byte[] privateKeyParams = paramDerInputStream.toByteArray();
201+
// Check against the existing parameters created by PKCS8Key.
202+
if (!Arrays.equals(privateKeyParams, encodedParams)) {
203+
throw new IOException("Decoding EC private key failed. The params are not the same as PKCS8Key's");
204+
}
205+
} else if (inputDerValue[2].isContextSpecific(TAG_PUBLIC_KEY_ATTRS)) {
206+
; // Found [1] publicKey (optional) - ignore here
207+
} else {
208+
// Unknown third+ element: we can throw, or ignore.
209+
// Keeping old behavior would be to throw; but RFC allows only [0]/[1] here.
210+
throw new IOException("Decoding EC private key failed. Unexpected tagged field in ECPrivateKey");
207211
}
208212
}
209213
// The native library needs the ASN.1 DER decoding of the private key to contain the parameters (i.e., the OID).

src/test/java/ibm/jceplus/junit/base/BaseTestECKeyImport.java

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright IBM Corp. 2023, 2025
2+
* Copyright IBM Corp. 2023, 2026
33
*
44
* This code is free software; you can redistribute it and/or modify it
55
* under the terms provided by IBM in the LICENSE file that accompanied
@@ -24,11 +24,13 @@
2424
import java.security.spec.PKCS8EncodedKeySpec;
2525
import java.security.spec.X509EncodedKeySpec;
2626
import java.util.Arrays;
27+
import java.util.Base64;
2728
import java.util.HexFormat;
2829
import org.junit.jupiter.api.Test;
2930
import sun.security.pkcs.PKCS8Key;
3031
import sun.security.x509.X509Key;
3132
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
33+
import static org.junit.jupiter.api.Assertions.assertNotNull;
3234
import static org.junit.jupiter.api.Assertions.assertTrue;
3335

3436
public class BaseTestECKeyImport extends BaseTestJunit5 {
@@ -82,7 +84,14 @@ public class BaseTestECKeyImport extends BaseTestJunit5 {
8284
+ "9C57C30FAA2DEF09DDDAD4E8748C442325B8EDB94EF7AA9"
8385
+ "78D4A56F0B601448B0DDFA4CC4B0555EAE67354C442A3AC"
8486
+ "E9D04BE186765A1921962FC08D1A58C53A";
85-
87+
88+
private static final String private_secp256r1_no_parameters =
89+
"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgn5K03bpTLjEtFQRa" +
90+
"JUtx22gtmGEvvSUSQdimhGthdtihRANCAARv72fTmp9ed8dRvTG1Ak1Lgl5KLoiM" +
91+
"59bk2pyG8qd8l7L1WQnNHtAcu44RJ1/GVHurxghaCKHeJYsZ8H7DEeI6";
92+
private static final String private_secp256r1_no_parameters_no_public =
93+
"MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDlySzNwwln6W+zDiDk" +
94+
"K7OvyaalUUdkOd6CrThHqenrfg==";
8695

8796
/**
8897
* Generate a KeyPair using ECGEenParam and then import the key pair
@@ -305,5 +314,18 @@ public void testImportHardcoded() throws Exception {
305314

306315
assertTrue(((X509Key) importPublicKey).getAlgorithmId().toString().contains("secp521r1"), "Curve is not what is expected.");
307316
}
317+
318+
@Test
319+
public void testECPrivateKeyWithoutParametersPublicKey() throws Exception {
320+
KeyFactory kf = KeyFactory.getInstance("EC", getProviderName());
321+
322+
PKCS8EncodedKeySpec priKeySpecNoParameters = new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(private_secp256r1_no_parameters));
323+
PrivateKey priKeyNoParameters = kf.generatePrivate(priKeySpecNoParameters);
324+
assertNotNull(priKeyNoParameters);
325+
326+
PKCS8EncodedKeySpec priKeySpecNoParametersNoPublicKey = new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(private_secp256r1_no_parameters_no_public));
327+
PrivateKey priKeyNoParametersNoPublicKey = kf.generatePrivate(priKeySpecNoParametersNoPublicKey);
328+
assertNotNull(priKeyNoParametersNoPublicKey);
329+
}
308330
}
309331

0 commit comments

Comments
 (0)