Skip to content

Commit

Permalink
Update ECDSASignature to match expected behaviour
Browse files Browse the repository at this point in the history
The method engineSetParameter that gets an AlgorithmParameterSpec
as a parameter is implemented, thus overriding the existing
version that just throws an UnsupportedOperationException.

The engineSetParameter that gets String and Object parameters is
updated to match the behaviour of similar implementations from
other providers.

Override annotations are added to specific methods to enforce
checks.

A few more test cases are added to check the new functionality.

Signed-off-by: Kostas Tsiounis <[email protected]>
  • Loading branch information
KostasTsiounis committed Feb 3, 2025
1 parent 9d3b995 commit bb17d78
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 10 deletions.
49 changes: 39 additions & 10 deletions src/main/java/com/ibm/crypto/plus/provider/ECDSASignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@

import com.ibm.crypto.plus.provider.ock.Signature;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.SignatureSpi;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
import sun.security.util.ECUtil;
import sun.security.util.ObjectIdentifier;


abstract class ECDSASignature extends SignatureSpi {

private OpenJCEPlusProvider provider = null;
private Signature signature = null;
private ECPrivateKey privateKey = null;
private ECPublicKey publicKey = null;

ECDSASignature(OpenJCEPlusProvider provider, String ockDigestAlgo) {
try {
Expand All @@ -35,23 +40,23 @@ abstract class ECDSASignature extends SignatureSpi {

@Override
protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
ECPublicKey ecPublic = (ECPublicKey) ECKeyFactory.toECKey(provider, publicKey);
this.publicKey = (ECPublicKey) ECKeyFactory.toECKey(provider, publicKey);

try {
this.signature.initialize(ecPublic.getOCKKey(), false);
this.signature.initialize(this.publicKey.getOCKKey(), false);
} catch (Exception e) {
throw provider.providerException("Failure in engineInitVerify", e);
}
}

@Override
protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException {
ECPrivateKey ecPrivate = (ECPrivateKey) ECKeyFactory.toECKey(provider, privateKey);
ECUtils.checkPrivateKey(ecPrivate);
this.privateKey = (ECPrivateKey) ECKeyFactory.toECKey(provider, privateKey);
ECUtils.checkPrivateKey(this.privateKey);

if (this.provider.isFIPS()) {
ECNamedCurve ecNamedCurve = ECParameters
.getNamedCurve(ecPrivate.getParams());
.getNamedCurve(this.privateKey.getParams());
ObjectIdentifier oid = null;

oid = ECNamedCurve.getOIDFromName(ecNamedCurve.getName());
Expand All @@ -64,7 +69,7 @@ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException
}

try {
this.signature.initialize(ecPrivate.getOCKKey(), false);
this.signature.initialize(this.privateKey.getOCKKey(), false);
} catch (Exception e) {
throw provider.providerException("Failure in engineInitSign", e);
}
Expand Down Expand Up @@ -109,13 +114,37 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
}

@Deprecated
protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
throw new InvalidParameterException("No parameter accepted");
@Override
protected void engineSetParameter(String param, Object value)
throws InvalidParameterException {
throw new UnsupportedOperationException("setParameter() not supported");
}

@Override
protected void engineSetParameter(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
// Interop: some certificates include parameters in an ECDSA
// algorithm identifier. We only accept one matching the key.
if (params == null) {
return;
}
if (params instanceof ECParameterSpec) {
ECParameterSpec ecparams = (ECParameterSpec) params;
java.security.interfaces.ECKey key = (this.privateKey == null? this.publicKey : this.privateKey);
if ((key != null) && !ECUtil.equals(ecparams, key.getParams())) {
throw new InvalidAlgorithmParameterException(
"Signature params does not match key params");
}
} else {
throw new InvalidAlgorithmParameterException(
"Parameters must be of type ECParameterSpec");
}
}

@Deprecated
@Override
protected Object engineGetParameter(String param) throws InvalidParameterException {
return null;
throw new UnsupportedOperationException("getParameter(String param) not supported");
}

@Override
Expand Down
79 changes: 79 additions & 0 deletions src/test/java/ibm/jceplus/junit/base/BaseTestECDSASignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,24 @@
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPrivateKeySpec;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
Expand All @@ -35,6 +40,80 @@ public class BaseTestECDSASignature extends BaseTestJunit5Signature {

static final byte[] origMsg = "this is the original message to be signed".getBytes();

@Test
public void testEngineSetParameter_invalidSpec() throws Exception {
KeyPair keyPair = generateKeyPair(256);

String sigAlgo = "SHA256withECDSA";
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();

AlgorithmParameters pssParams = AlgorithmParameters.getInstance("RSASSA-PSS", getProviderName());
pssParams.init(new PSSParameterSpec("SHA-1", "MGF1", MGF1ParameterSpec.SHA1, 20, 1));
PSSParameterSpec pssParameterSpec = pssParams.getParameterSpec(PSSParameterSpec.class);

AlgorithmParameters ecParams = AlgorithmParameters.getInstance("EC", getProviderName());
ecParams.init(new ECGenParameterSpec("secp521r1"));
ECParameterSpec ecParameterSpec = ecParams.getParameterSpec(ECParameterSpec.class);

Signature signing = Signature.getInstance(sigAlgo, getProviderName());
signing.initSign(privateKey);

// Check with different type of AlgorithmParameterSpec.
try {
signing.setParameter(pssParameterSpec);
} catch (InvalidAlgorithmParameterException iape) {
if (!"Parameters must be of type ECParameterSpec".equals(iape.getMessage())) {
throw iape;
}
}

// Check against private key with same type of AlgorithmParameterSpec, but different curve.
try {
signing.setParameter(ecParameterSpec);
fail("InvalidAlgorithmParameterException expected.");
} catch (InvalidAlgorithmParameterException iape) {
if (!"Signature params does not match key params".equals(iape.getMessage())) {
throw iape;
}
}

Signature verifying = Signature.getInstance(sigAlgo, getProviderName());
verifying.initVerify(publicKey);

// Check against public key with same type of AlgorithmParameterSpec, but different curve.
try {
verifying.setParameter(ecParameterSpec);
fail("InvalidAlgorithmParameterException expected.");
} catch (InvalidAlgorithmParameterException iape) {
if (!"Signature params does not match key params".equals(iape.getMessage())) {
throw iape;
}
}
}

@Test
public void testEngineSetParameter_validSpec() throws Exception {
KeyPair keyPair = generateKeyPair(256);

String sigAlgo = "SHA256withECDSA";
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
AlgorithmParameters params = AlgorithmParameters.getInstance("EC", getProviderName());
params.init(new ECGenParameterSpec("secp256r1"));
ECParameterSpec ecParameters = params.getParameterSpec(ECParameterSpec.class);

Signature signing = Signature.getInstance(sigAlgo, getProviderName());
signing.initSign(privateKey);
// Check against private key with correct AlgorithmParameterSpec.
signing.setParameter(ecParameters);

Signature verifying = Signature.getInstance(sigAlgo, getProviderName());
verifying.initVerify(publicKey);
// Check against public key with correct AlgorithmParameterSpec.
verifying.setParameter(ecParameters);
}

@Test
public void testSHA1withECDSA_192() throws Exception {
if (getProviderName().equals("OpenJCEPlusFIPS")) {
Expand Down

0 comments on commit bb17d78

Please sign in to comment.