Skip to content

Commit

Permalink
Get native EC key pointer during init through ECUtil instead of key impl
Browse files Browse the repository at this point in the history
The acquisition of a native pointer for an EC key, private or public, is
being moved to the ECUtil, instead of the implementation classes of said
keys. This allows use of interop keys, rather than just keys coming from
SunEC.

The methods to get the pointers to the native keys are called during the
initialization phases, to discover the possibility of not being able to
utilize the native code and revert to the Java implementation early.

The engineUpdate() methods of the RawECDSA subclass are, also, updated
to use the java implementation, if one has been initialized.

Signed-off by: Kostas Tsiounis <kostas.tsiounis@ibm.com>
  • Loading branch information
KostasTsiounis committed May 30, 2024
1 parent 7f763ae commit 06cfc6c
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 197 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.security.ProviderException;
import java.security.SecureRandom;
import java.security.interfaces.ECKey;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
Expand Down Expand Up @@ -74,13 +75,19 @@ public final class NativeECDHKeyAgreement extends KeyAgreementSpi {
private static final Map<String, Boolean> curveSupported = new ConcurrentHashMap<>();

/* private key, if initialized */
private ECPrivateKeyImpl privateKey;
private ECPrivateKey privateKey;

/* pointer to native private key, if initialized */
private long nativePrivateKey;

/* operations associated with private key, if initialized */
private ECOperations privateKeyOps;

/* public key, non-null between doPhase() & generateSecret() only */
private ECPublicKeyImpl publicKey;
private ECPublicKey publicKey;

/* pointer to native public key, if initialized */
private long nativePublicKey;

/* the type of EC curve */
private String curve;
Expand Down Expand Up @@ -109,16 +116,26 @@ private void init(Key key)
}
/* attempt to translate the key if it is not an ECKey */
ECKey ecKey = ECKeyFactory.toECKey(key);
if (ecKey instanceof ECPrivateKeyImpl keyImpl) {
if (ecKey instanceof ECPrivateKey ecPrivateKey) {
Optional<ECOperations> opsOpt =
ECOperations.forParameters(keyImpl.getParams());
ECOperations.forParameters(ecPrivateKey.getParams());
if (opsOpt.isEmpty()) {
NamedCurve nc = CurveDB.lookup(keyImpl.getParams());
NamedCurve nc = CurveDB.lookup(ecPrivateKey.getParams());
throw new InvalidAlgorithmParameterException(
"Curve not supported: " +
((nc != null) ? nc.toString() : "unknown"));
}
this.privateKey = keyImpl;

this.privateKey = ecPrivateKey;
this.nativePrivateKey = NativeECUtil.getPrivateKeyNativePtr(ecPrivateKey);
if (this.nativePrivateKey == -1) {
if (nativeCryptTrace) {
System.err.println("Init: Could not create a pointer to a native private key."
+ " Using Java implementation.");
}
this.initializeJavaImplementation(key);
return;
}
this.privateKeyOps = opsOpt.get();

ECParameterSpec params = this.privateKey.getParams();
Expand All @@ -132,8 +149,8 @@ private void init(Key key)
boolean absent = NativeECUtil.putCurveIfAbsent("ECKeyImpl", Boolean.FALSE);
/* only print the first time a curve is used */
if (absent && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl" +
" are supported by the native implementation, " +
System.err.println("Only ECPrivateKey" +
" is supported by the native implementation, " +
"using Java crypto implementation for key agreement.");
}
this.initializeJavaImplementation(key);
Expand Down Expand Up @@ -184,24 +201,26 @@ protected Key engineDoPhase(Key key, boolean lastPhase)
// Validate public key.
validate(privateKeyOps, ecKey);

if (ecKey instanceof ECPublicKeyImpl keyImpl) {
this.publicKey = keyImpl;

int keyLenBits = this.publicKey.getParams().getCurve().getField().getFieldSize();
this.secretLen = (keyLenBits + 7) >> 3;

return null;
} else {
boolean absent = NativeECUtil.putCurveIfAbsent("ECKeyImpl", Boolean.FALSE);
/* only print the first time a curve is used */
if (absent && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl" +
" are supported by the native implementation, " +
"using Java crypto implementation for key agreement.");
this.publicKey = ecKey;
this.nativePublicKey = NativeECUtil.getPublicKeyNativePtr(ecKey);
if (this.nativePublicKey == -1) {
if (nativeCryptTrace) {
System.err.println("DoPhase: Could not create a pointer to a native public key."
+ " Using Java implementation.");
}
try {
this.initializeJavaImplementation(this.privateKey);
this.javaImplementation.engineDoPhase(ecKey, true);
} catch (InvalidKeyException e) {
/* should not happen */
throw new InternalError(e);
}
this.initializeJavaImplementation(this.privateKey);
return this.javaImplementation.engineDoPhase(key, lastPhase);
}

int keyLenBits = this.publicKey.getParams().getCurve().getField().getFieldSize();
this.secretLen = (keyLenBits + 7) >> 3;

return null;
}

// Verify that x and y are integers in the interval [0, p - 1].
Expand Down Expand Up @@ -297,27 +316,7 @@ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
if ((this.privateKey == null) || (this.publicKey == null)) {
throw new IllegalStateException("Not initialized correctly");
}
long nativePublicKey = this.publicKey.getNativePtr();
long nativePrivateKey = this.privateKey.getNativePtr();
if ((nativePublicKey == -1) || (nativePrivateKey == -1)) {
absent = NativeECUtil.putCurveIfAbsent(this.curve, Boolean.FALSE);
if (!absent) {
throw new ProviderException("Could not convert keys to native format");
}
/* only print the first time a curve is used */
if (nativeCryptTrace) {
System.err.println(this.curve +
" is not supported by OpenSSL, using Java crypto implementation for preparing agreement.");
}
try {
this.initializeJavaImplementation(this.privateKey);
this.javaImplementation.engineDoPhase(this.publicKey, true);
} catch (InvalidKeyException e) {
/* should not happen */
throw new InternalError(e);
}
return this.javaImplementation.engineGenerateSecret(sharedSecret, offset);
}

absent = NativeECUtil.putCurveIfAbsent(this.curve, Boolean.TRUE);
if (absent && nativeCryptTrace) {
System.err.println(this.curve +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ abstract class NativeECDSASignature extends SignatureSpi {
// private key, if initialized for signing
private ECPrivateKey privateKey;

// private key impl, if initialized for signing
private ECPrivateKeyImpl privateKeyImpl;
// native private key pointer, if initialized for signing
private long nativePrivateKey;

// public key, if initialized for verifying
private ECPublicKey publicKey;

// public key impl, if initialized for verifying
private ECPublicKeyImpl publicKeyImpl;
// native public key pointer, if initialized for verifying
private long nativePublicKey;

// signature parameters
private ECParameterSpec sigParams;
Expand All @@ -118,7 +118,7 @@ abstract class NativeECDSASignature extends SignatureSpi {
private final boolean p1363Format;

// the Java implementation, if needed
private ECDSASignature javaImplementation;
ECDSASignature javaImplementation;

/**
* Constructs a new NativeECDSASignature.
Expand Down Expand Up @@ -182,51 +182,62 @@ static class RawECDSA extends NativeECDSASignature {
// Stores the precomputed message digest value.
@Override
protected void engineUpdate(byte b) throws SignatureException {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
if (this.javaImplementation != null) {
this.javaImplementation.engineUpdate(b);
} else {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
}
precomputedDigest[offset++] = b;
}
precomputedDigest[offset++] = b;
}

// Stores the precomputed message digest value.
@Override
protected void engineUpdate(byte[] b, int off, int len)
throws SignatureException {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
if (this.javaImplementation != null) {
this.javaImplementation.engineUpdate(b, off, len);
} else {
if (offset >= precomputedDigest.length) {
offset = RAW_ECDSA_MAX + 1;
return;
}
System.arraycopy(b, off, precomputedDigest, offset, len);
offset += len;
}
System.arraycopy(b, off, precomputedDigest, offset, len);
offset += len;
}

// Stores the precomputed message digest value.
@Override
protected void engineUpdate(ByteBuffer byteBuffer) {
int len = byteBuffer.remaining();
if (len <= 0) {
return;
}
if (len >= (precomputedDigest.length - offset)) {
offset = RAW_ECDSA_MAX + 1;
return;
if (this.javaImplementation != null) {
this.javaImplementation.engineUpdate(byteBuffer);
} else {
int len = byteBuffer.remaining();
if (len <= 0) {
return;
}
if (len >= (precomputedDigest.length - offset)) {
offset = RAW_ECDSA_MAX + 1;
return;
}
byteBuffer.get(precomputedDigest, offset, len);
offset += len;
}
byteBuffer.get(precomputedDigest, offset, len);
offset += len;
}

@Override
protected void resetDigest() {
void resetDigest() {
offset = 0;
}

// Returns the precomputed message digest value.
@Override
protected byte[] getDigestValue() throws SignatureException {
byte[] getDigestValue() throws SignatureException {
if (offset > RAW_ECDSA_MAX) {
throw new SignatureException("Message digest is too long");

}
byte[] result = new byte[offset];
System.arraycopy(precomputedDigest, 0, result, 0, offset);
Expand Down Expand Up @@ -391,16 +402,19 @@ protected void engineInitVerify(PublicKey publicKey)
this.privateKey = null;
resetDigest();

if (key instanceof ECPublicKeyImpl keyImpl) {
this.publicKeyImpl = keyImpl;
this.privateKeyImpl = null;
this.javaImplementation = null;
if (nativeCryptTrace) {
System.err.println("InitVerify: Using native crypto implementation for verifying signature.");
}
} else {
this.nativePublicKey = NativeECUtil.getPublicKeyNativePtr(key);
if (this.nativePublicKey == -1) {
this.javaImplementation = getJavaInstance();
this.javaImplementation.engineInitVerify(publicKey);
if (nativeCryptTrace) {
System.err.println("InitVerify: Could not create a pointer to a native key."
+ " Using Java implementation.");
}
return;
}
this.javaImplementation = null;
if (nativeCryptTrace) {
System.err.println("InitVerify: Keys were successfully converted to native OpenSSL format.");
}
}

Expand Down Expand Up @@ -449,23 +463,26 @@ protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
this.random = random;
resetDigest();

if (key instanceof ECPrivateKeyImpl keyImpl) {
this.publicKeyImpl = null;
this.privateKeyImpl = keyImpl;
this.javaImplementation = null;
if (nativeCryptTrace) {
System.err.println("InitSign: Using native crypto implementation for verifying signature.");
}
} else {
this.nativePrivateKey = NativeECUtil.getPrivateKeyNativePtr(key);
if (this.nativePrivateKey == -1) {
this.javaImplementation = getJavaInstance();
this.javaImplementation.engineInitSign(privateKey, random);
if (nativeCryptTrace) {
System.err.println("InitSign: Could not create a pointer to a native key."
+ " Using Java implementation.");
}
return;
}
this.javaImplementation = null;
if (nativeCryptTrace) {
System.err.println("InitSign: Keys were successfully converted to native OpenSSL format.");
}
}

/**
* Resets the message digest if needed.
*/
protected void resetDigest() {
void resetDigest() {
if (needsReset) {
if (messageDigest != null) {
messageDigest.reset();
Expand All @@ -477,7 +494,7 @@ protected void resetDigest() {
/**
* Returns the message digest value.
*/
protected byte[] getDigestValue() throws SignatureException {
byte[] getDigestValue() throws SignatureException {
needsReset = false;
return messageDigest.digest();
}
Expand Down Expand Up @@ -537,7 +554,6 @@ protected byte[] engineSign() throws SignatureException {
return this.javaImplementation.engineSign();
}

long nativePrivateKey = privateKeyImpl.getNativePtr();
byte[] digest = getDigestValue();
int digestLen = digest.length;
ECParameterSpec params = privateKey.getParams();
Expand All @@ -547,13 +563,6 @@ protected byte[] engineSign() throws SignatureException {
ECDSAOperations.forParameters(params)
.orElseThrow(() -> new SignatureException("Curve not supported: " + params));

if (nativePrivateKey == -1) {
throw new ProviderException("Keys could not be converted to native OpenSSL format");
}
if (nativeCryptTrace) {
System.err.println("Sign: Keys were successfully converted to native OpenSSL format.");
}

if (nativeCrypto == null) {
nativeCrypto = NativeCrypto.getNativeCrypto();
}
Expand Down Expand Up @@ -604,14 +613,6 @@ protected boolean engineVerify(byte[] signature) throws SignatureException {
}
}

long nativePublicKey = publicKeyImpl.getNativePtr();
if (nativePublicKey == -1) {
throw new ProviderException("Could not convert keys to native format");
}
if (nativeCryptTrace) {
System.err.println("Verify: Keys were successfully converted to native OpenSSL format.");
}

if (nativeCrypto == null) {
nativeCrypto = NativeCrypto.getNativeCrypto();
}
Expand Down
Loading

0 comments on commit 06cfc6c

Please sign in to comment.