From a0e58b642285f8fb4aaf8b6ac7f1ab1746436150 Mon Sep 17 00:00:00 2001 From: Mark Atwood Date: Mon, 10 Aug 2026 13:52:30 -0700 Subject: [PATCH] fix: map invalid EC/DH key errors to JCE types --- .../provider/jce/WolfCryptECKeyFactory.java | 32 ++++++++-- .../provider/jce/WolfCryptKeyAgreement.java | 64 ++++++++++++++++++- 2 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptECKeyFactory.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptECKeyFactory.java index 6399cd8d..30223a69 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptECKeyFactory.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptECKeyFactory.java @@ -303,9 +303,19 @@ private PrivateKey generatePrivateFromECSpec(ECPrivateKeySpec keySpec) "ECParameterSpec cannot be null"); } - /* Validate ECParameterSpec is supported by wolfCrypt, - * throws WolfCryptException if invalid */ - WolfCryptECParameterSpec.validateParameters(keySpec.getParams()); + /* Validate ECParameterSpec is supported by wolfCrypt. + * validateParameters throws IllegalArgumentException (unchecked) + * when the curve is not recognized; wrap it as + * InvalidKeySpecException so callers see a + * GeneralSecurityException. */ + try { + WolfCryptECParameterSpec.validateParameters( + keySpec.getParams()); + } catch (IllegalArgumentException e) { + throw new InvalidKeySpecException( + "Unsupported curve parameters: " + + e.getMessage(), e); + } /* Get curve name from ECParameterSpec */ try { @@ -560,9 +570,19 @@ private PublicKey generatePublicFromECSpec(ECPublicKeySpec keySpec) "ECParameterSpec cannot be null"); } - /* Validate ECParameterSpec is supported by wolfCrypt, - * throws WolfCryptException if invalid */ - WolfCryptECParameterSpec.validateParameters(keySpec.getParams()); + /* Validate ECParameterSpec is supported by wolfCrypt. + * validateParameters throws IllegalArgumentException (unchecked) + * when the curve is not recognized; wrap it as + * InvalidKeySpecException so callers see a + * GeneralSecurityException. */ + try { + WolfCryptECParameterSpec.validateParameters( + keySpec.getParams()); + } catch (IllegalArgumentException e) { + throw new InvalidKeySpecException( + "Unsupported curve parameters: " + + e.getMessage(), e); + } /* Get curve name from ECParameterSpec */ try { diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java index 29bb8746..56465d18 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyAgreement.java @@ -71,6 +71,8 @@ enum EngineState { private Ecc ecPrivate = null; private int primeLen = 0; + private byte[] dhParamP = null; + private byte[] dhParamG = null; private int curveSize = 0; private String curveName = null; @@ -128,12 +130,31 @@ protected Key engineDoPhase(Key key, boolean lastPhase) "Key must be of type DHPublicKey"); } - pubKey = ((DHPublicKey)key).getY().toByteArray(); + DHPublicKey dhPubKey = (DHPublicKey)key; + + pubKey = dhPubKey.getY().toByteArray(); if (pubKey == null) { throw new InvalidKeyException( "Failed to get DH public key from Key object"); } + if (this.dhParamP == null || this.dhParamG == null) { + throw new InvalidKeyException( + "DH private key not initialized with parameters"); + } + + BigInteger privP = new BigInteger(this.dhParamP); + BigInteger privG = new BigInteger(this.dhParamG); + BigInteger pubPBig = dhPubKey.getParams().getP(); + BigInteger pubGBig = dhPubKey.getParams().getG(); + + if (!privP.equals(pubPBig) || !privG.equals(pubGBig)) { + throw new InvalidKeyException( + "DH public key parameters do not match " + + "private key parameters, cannot generate " + + "shared secret"); + } + /* Validate peer public key (SP 800-56A) before use */ try { this.dh.checkPublicKey(pubKey); @@ -162,10 +183,35 @@ protected Key engineDoPhase(Key key, boolean lastPhase) * the curve before use. */ try { this.ecPublic.publicKeyDecode(pubKey); + } catch (WolfCryptException e) { + throw new InvalidKeyException( + "EC public key could not be decoded", e); + } + + try { this.ecPublic.checkKey(); } catch (WolfCryptException e) { throw new InvalidKeyException( - "ECC public key failed validation", e); + "EC public key point is not on the curve", e); + } + + /* Verify the public key curve matches the private key curve. + * A curve mismatch (e.g. secp224r1 public against secp256r1 + * private) is caught here so the caller sees + * InvalidKeyException + * rather than a WolfCryptException from makeSharedSecret. */ + try { + int pubCurveId = this.ecPublic.getCurveId(); + int privCurveId = this.ecPrivate.getCurveId(); + if (pubCurveId != privCurveId) { + throw new InvalidKeyException( + "EC public key curve does not match private key " + + "curve (public curveId=" + pubCurveId + + ", private curveId=" + privCurveId + ")"); + } + } catch (WolfCryptException e) { + throw new InvalidKeyException( + "Failed to validate EC key curve compatibility", e); } break; @@ -326,7 +372,13 @@ protected int engineGenerateSecret(byte[] sharedSecret, int offset) case WC_ECDH: - tmp = this.ecPrivate.makeSharedSecret(this.ecPublic); + try { + tmp = this.ecPrivate.makeSharedSecret(this.ecPublic); + } catch (WolfCryptException e) { + throw new IllegalStateException( + "Native ECDH shared secret generation failed: " + + e.getMessage(), e); + } if (tmp == null) { throw new RuntimeException("Error when creating " + "ECDH shared secret"); @@ -477,6 +529,9 @@ private void wcInitDHParams(Key key, AlgorithmParameterSpec params) this.dh.setParams(paramP, paramG); + this.dhParamP = paramP; + this.dhParamG = paramG; + primeLen = paramP.length; /* prime may have leading zero */ @@ -505,6 +560,9 @@ private void wcInitDHParams(Key key, AlgorithmParameterSpec params) this.dh.setParams(paramP, paramG); + this.dhParamP = paramP; + this.dhParamG = paramG; + primeLen = paramP.length; /* prime may have leading zero */