Skip to content

Commit

Permalink
Merge pull request #354 from KostasTsiounis/nativepointer_check
Browse files Browse the repository at this point in the history
Get native EC key pointer during init through ECUtil instead of key impl
  • Loading branch information
keithc-ca authored May 31, 2024
2 parents 217e7d1 + 06cfc6c commit 249fed7
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 249fed7

Please sign in to comment.