Switch from EVP_[Sign|Verify] to EVP_Digest[Sign|Verify].
This switches Conscrypt's Signature implementations from the older
EVP_Sign/EVP_Verify API to the newer EVP_DigestSign/EVP_DigestVerify
API. The main factor driving this switch is to expose RSASSA-PSS
which does not work via the old API.
In particular, this change:
* adds EVP_DigestSign* and EVP_DigestVerify* to NativeCrypto. Some of
these NativeCrypto functions were already there but weren't used.
This made it easier to adjust their signatures to best results.
* switches Signature implementation from EVP_Sign/EVP_Verify to
EVP_DigestSign/EVP_DigestVerify.
* removes EVP_Sign* and EVP_Verify* from NativeCrypto because they are
no longer used.
* inlines NativeCrypto's evpInit into its EVP_DigestInit_ex because
the latter became the only user of evpInit after the cleanup.
Change-Id: Id29ea4fc2bc5b1cd81daaee8b475fd147616de51
diff --git a/src/main/java/org/conscrypt/NativeCrypto.java b/src/main/java/org/conscrypt/NativeCrypto.java
index ae02008..24f91db 100644
--- a/src/main/java/org/conscrypt/NativeCrypto.java
+++ b/src/main/java/org/conscrypt/NativeCrypto.java
@@ -256,38 +256,30 @@
public static native int EVP_DigestFinal_ex(NativeRef.EVP_MD_CTX ctx, byte[] hash,
int offset);
- // --- MAC handling functions ----------------------------------------------
-
- public static native void EVP_DigestSignInit(NativeRef.EVP_MD_CTX evp_md_ctx,
- long evp_md, NativeRef.EVP_PKEY evp_pkey);
-
- public static native void EVP_DigestSignUpdate(NativeRef.EVP_MD_CTX evp_md_ctx,
- byte[] in);
-
- public static native byte[] EVP_DigestSignFinal(NativeRef.EVP_MD_CTX evp_md_ctx);
-
// --- Signature handling functions ----------------------------------------
- public static native int EVP_SignInit(NativeRef.EVP_MD_CTX ctx, long evpRef);
+ public static native long EVP_DigestSignInit(NativeRef.EVP_MD_CTX ctx,
+ long evpMdRef, NativeRef.EVP_PKEY key);
- public static native void EVP_SignUpdate(NativeRef.EVP_MD_CTX ctx, byte[] buffer,
- int offset, int length);
+ public static native long EVP_DigestVerifyInit(NativeRef.EVP_MD_CTX ctx,
+ long evpMdRef, NativeRef.EVP_PKEY key);
- public static native void EVP_SignUpdateDirect(NativeRef.EVP_MD_CTX ctx, long ptr, int length);
-
- public static native int EVP_SignFinal(NativeRef.EVP_MD_CTX ctx, byte[] signature,
- int offset, NativeRef.EVP_PKEY key);
-
- public static native int EVP_VerifyInit(NativeRef.EVP_MD_CTX ctx, long evpRef);
-
- public static native void EVP_VerifyUpdate(NativeRef.EVP_MD_CTX ctx,
+ public static native void EVP_DigestSignUpdate(NativeRef.EVP_MD_CTX ctx,
byte[] buffer, int offset, int length);
- public static native void EVP_VerifyUpdateDirect(NativeRef.EVP_MD_CTX ctx,
+ public static native void EVP_DigestSignUpdateDirect(NativeRef.EVP_MD_CTX ctx,
long ptr, int length);
- public static native int EVP_VerifyFinal(NativeRef.EVP_MD_CTX ctx,
- byte[] signature, int offset, int length, NativeRef.EVP_PKEY key);
+ public static native void EVP_DigestVerifyUpdate(NativeRef.EVP_MD_CTX ctx,
+ byte[] buffer, int offset, int length);
+
+ public static native void EVP_DigestVerifyUpdateDirect(NativeRef.EVP_MD_CTX ctx,
+ long ptr, int length);
+
+ public static native byte[] EVP_DigestSignFinal(NativeRef.EVP_MD_CTX ctx);
+
+ public static native boolean EVP_DigestVerifyFinal(NativeRef.EVP_MD_CTX ctx,
+ byte[] signature, int offset, int length);
// --- Block ciphers -------------------------------------------------------
diff --git a/src/main/java/org/conscrypt/OpenSSLSignature.java b/src/main/java/org/conscrypt/OpenSSLSignature.java
index 8e30b5e..f3d0cc6 100644
--- a/src/main/java/org/conscrypt/OpenSSLSignature.java
+++ b/src/main/java/org/conscrypt/OpenSSLSignature.java
@@ -19,7 +19,6 @@
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
@@ -32,7 +31,7 @@
public class OpenSSLSignature extends SignatureSpi {
private static enum EngineType {
RSA, EC,
- };
+ }
private NativeRef.EVP_MD_CTX ctx;
@@ -47,9 +46,9 @@
private final EngineType engineType;
/**
- * Holds the OpenSSL name of the algorithm (lower case, no dashes).
+ * Digest algorithm (reference to {@code EVP_MD}).
*/
- private final long evpAlgorithm;
+ private final long evpMdRef;
/**
* Holds a dummy buffer for writing single bytes to the digest.
@@ -62,27 +61,42 @@
private boolean signing;
/**
+ * Public key algorithm context (reference to {@code EVP_PKEY_CTX}).
+ */
+ private long evpPkeyCtx;
+
+ /**
* Creates a new OpenSSLSignature instance for the given algorithm name.
*
- * @param algorithm OpenSSL name of the algorithm, e.g. "RSA-SHA1".
+ * @param evpMdRef digest algorithm ({@code EVP_MD} reference).
*/
- private OpenSSLSignature(long algorithm, EngineType engineType)
- throws NoSuchAlgorithmException {
+ private OpenSSLSignature(long evpMdRef, EngineType engineType) {
this.engineType = engineType;
- this.evpAlgorithm = algorithm;
+ this.evpMdRef = evpMdRef;
}
private final void resetContext() {
NativeRef.EVP_MD_CTX ctxLocal = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
if (signing) {
enableDSASignatureNonceHardeningIfApplicable();
- NativeCrypto.EVP_SignInit(ctxLocal, evpAlgorithm);
+ evpPkeyCtx = NativeCrypto.EVP_DigestSignInit(ctxLocal, evpMdRef, key.getNativeRef());
} else {
- NativeCrypto.EVP_VerifyInit(ctxLocal, evpAlgorithm);
+ evpPkeyCtx = NativeCrypto.EVP_DigestVerifyInit(ctxLocal, evpMdRef, key.getNativeRef());
}
+ configureEVP_PKEY_CTX(evpPkeyCtx);
this.ctx = ctxLocal;
}
+ /**
+ * Configures the public key algorithm context ({@code EVP_PKEY_CTX}) associated with this
+ * operation.
+ *
+ * <p>The default implementation does nothing.
+ *
+ * @param ctx reference to the context ({@code EVP_PKEY_CTX}).
+ */
+ protected void configureEVP_PKEY_CTX(long ctx) {}
+
@Override
protected void engineUpdate(byte input) {
singleByte[0] = input;
@@ -93,9 +107,9 @@
protected void engineUpdate(byte[] input, int offset, int len) {
final NativeRef.EVP_MD_CTX ctxLocal = ctx;
if (signing) {
- NativeCrypto.EVP_SignUpdate(ctxLocal, input, offset, len);
+ NativeCrypto.EVP_DigestSignUpdate(ctxLocal, input, offset, len);
} else {
- NativeCrypto.EVP_VerifyUpdate(ctxLocal, input, offset, len);
+ NativeCrypto.EVP_DigestVerifyUpdate(ctxLocal, input, offset, len);
}
}
@@ -136,13 +150,14 @@
final NativeRef.EVP_MD_CTX ctxLocal = ctx;
if (signing) {
- NativeCrypto.EVP_SignUpdateDirect(ctxLocal, ptr, len);
+ NativeCrypto.EVP_DigestSignUpdateDirect(ctxLocal, ptr, len);
} else {
- NativeCrypto.EVP_VerifyUpdateDirect(ctxLocal, ptr, len);
+ NativeCrypto.EVP_DigestVerifyUpdateDirect(ctxLocal, ptr, len);
}
input.position(position + len);
}
+ @Deprecated
@Override
protected Object engineGetParameter(String param) throws InvalidParameterException {
return null;
@@ -206,27 +221,16 @@
initInternal(OpenSSLKey.fromPublicKey(publicKey), false);
}
+ @Deprecated
@Override
protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
}
@Override
protected byte[] engineSign() throws SignatureException {
- if (key == null) {
- // This can't actually happen, but you never know...
- throw new SignatureException("Need RSA or EC private key");
- }
-
final NativeRef.EVP_MD_CTX ctxLocal = ctx;
try {
- byte[] buffer = new byte[NativeCrypto.EVP_PKEY_size(key.getNativeRef())];
- int bytesWritten = NativeCrypto.EVP_SignFinal(ctxLocal, buffer, 0,
- key.getNativeRef());
-
- byte[] signature = new byte[bytesWritten];
- System.arraycopy(buffer, 0, signature, 0, bytesWritten);
-
- return signature;
+ return NativeCrypto.EVP_DigestSignFinal(ctxLocal);
} catch (Exception ex) {
throw new SignatureException(ex);
} finally {
@@ -240,15 +244,9 @@
@Override
protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
- if (key == null) {
- // This can't actually happen, but you never know...
- throw new SignatureException("Need RSA or EC public key");
- }
-
+ final NativeRef.EVP_MD_CTX ctxLocal = ctx;
try {
- int result = NativeCrypto.EVP_VerifyFinal(ctx, sigBytes, 0, sigBytes.length,
- key.getNativeRef());
- return result == 1;
+ return NativeCrypto.EVP_DigestVerifyFinal(ctxLocal, sigBytes, 0, sigBytes.length);
} catch (Exception ex) {
throw new SignatureException(ex);
} finally {
@@ -262,67 +260,67 @@
public static final class MD5RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("MD5");
- public MD5RSA() throws NoSuchAlgorithmException {
+ public MD5RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA1RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA1");
- public SHA1RSA() throws NoSuchAlgorithmException {
+ public SHA1RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA224RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA224");
- public SHA224RSA() throws NoSuchAlgorithmException {
+ public SHA224RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA256RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA256");
- public SHA256RSA() throws NoSuchAlgorithmException {
+ public SHA256RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA384RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA384");
- public SHA384RSA() throws NoSuchAlgorithmException {
+ public SHA384RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA512RSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA512");
- public SHA512RSA() throws NoSuchAlgorithmException {
+ public SHA512RSA() {
super(EVP_MD, EngineType.RSA);
}
}
public static final class SHA1ECDSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA1");
- public SHA1ECDSA() throws NoSuchAlgorithmException {
+ public SHA1ECDSA() {
super(EVP_MD, EngineType.EC);
}
}
public static final class SHA224ECDSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA224");
- public SHA224ECDSA() throws NoSuchAlgorithmException {
+ public SHA224ECDSA() {
super(EVP_MD, EngineType.EC);
}
}
public static final class SHA256ECDSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA256");
- public SHA256ECDSA() throws NoSuchAlgorithmException {
+ public SHA256ECDSA() {
super(EVP_MD, EngineType.EC);
}
}
public static final class SHA384ECDSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA384");
- public SHA384ECDSA() throws NoSuchAlgorithmException {
+ public SHA384ECDSA() {
super(EVP_MD, EngineType.EC);
}
}
public static final class SHA512ECDSA extends OpenSSLSignature {
private static final long EVP_MD = NativeCrypto.EVP_get_digestbyname("SHA512");
- public SHA512ECDSA() throws NoSuchAlgorithmException {
+ public SHA512ECDSA() {
super(EVP_MD, EngineType.EC);
}
}
diff --git a/src/main/native/org_conscrypt_NativeCrypto.cpp b/src/main/native/org_conscrypt_NativeCrypto.cpp
index dac1f2b..7546b1a 100644
--- a/src/main/native/org_conscrypt_NativeCrypto.cpp
+++ b/src/main/native/org_conscrypt_NativeCrypto.cpp
@@ -4296,45 +4296,32 @@
return bytesWritten;
}
-static jint evpInit(JNIEnv* env, jobject evpMdCtxRef, jlong evpMdRef, const char* jniName,
- int (*init_func)(EVP_MD_CTX*, const EVP_MD*, ENGINE*)) {
+static jint NativeCrypto_EVP_DigestInit_ex(JNIEnv* env, jclass, jobject evpMdCtxRef,
+ jlong evpMdRef) {
EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef);
const EVP_MD* evp_md = reinterpret_cast<const EVP_MD*>(evpMdRef);
- JNI_TRACE_MD("%s(%p, %p)", jniName, ctx, evp_md);
+ JNI_TRACE_MD("EVP_DigestInit_ex(%p, %p)", ctx, evp_md);
if (ctx == NULL) {
- JNI_TRACE("%s(%p) => ctx == NULL", jniName, evp_md);
+ JNI_TRACE("EVP_DigestInit_ex(%p) => ctx == NULL", evp_md);
return 0;
} else if (evp_md == NULL) {
jniThrowNullPointerException(env, "evp_md == null");
return 0;
}
- int ok = init_func(ctx, evp_md, NULL);
+ int ok = EVP_DigestInit_ex(ctx, evp_md, NULL);
if (ok == 0) {
- bool exception = throwExceptionIfNecessary(env, jniName);
+ bool exception = throwExceptionIfNecessary(env, "EVP_DigestInit_ex");
if (exception) {
- JNI_TRACE("%s(%p) => threw exception", jniName, evp_md);
+ JNI_TRACE("EVP_DigestInit_ex(%p) => threw exception", evp_md);
return 0;
}
}
- JNI_TRACE_MD("%s(%p, %p) => %d", jniName, ctx, evp_md, ok);
+ JNI_TRACE_MD("EVP_DigestInit_ex(%p, %p) => %d", ctx, evp_md, ok);
return ok;
}
-static jint NativeCrypto_EVP_DigestInit_ex(JNIEnv* env, jclass, jobject evpMdCtxRef,
- jlong evpMdRef) {
- return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_DigestInit_ex", EVP_DigestInit_ex);
-}
-
-static jint NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jobject evpMdCtxRef, jlong evpMdRef) {
- return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_SignInit", EVP_DigestInit_ex);
-}
-
-static jint NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jobject evpMdCtxRef, jlong evpMdRef) {
- return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_VerifyInit", EVP_DigestInit_ex);
-}
-
/*
* public static native int EVP_get_digestbyname(java.lang.String)
*/
@@ -4423,34 +4410,51 @@
return result;
}
-static void NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jobject evpMdCtxRef,
- const jlong evpMdRef, jobject pkeyRef) {
+static jlong evpDigestSignVerifyInit(
+ JNIEnv* env,
+ int (*init_func)(EVP_MD_CTX*, EVP_PKEY_CTX**, const EVP_MD*, ENGINE*, EVP_PKEY*),
+ const char* jniName,
+ jobject evpMdCtxRef, jlong evpMdRef, jobject pkeyRef) {
EVP_MD_CTX* mdCtx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef);
if (mdCtx == NULL) {
- JNI_TRACE("EVP_DigestSignInit => mdCtx == NULL");
- return;
+ JNI_TRACE("%s => mdCtx == NULL", jniName);
+ return 0;
}
const EVP_MD* md = reinterpret_cast<const EVP_MD*>(evpMdRef);
EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
if (pkey == NULL) {
- JNI_TRACE("ctx=%p EVP_DigestSignInit => pkey == NULL", mdCtx);
- return;
+ JNI_TRACE("ctx=%p $s => pkey == NULL", mdCtx, jniName);
+ return 0;
}
- JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) <- ptr", mdCtx, md, pkey);
+ JNI_TRACE("%s(%p, %p, %p) <- ptr", jniName, mdCtx, md, pkey);
if (md == NULL) {
- JNI_TRACE("ctx=%p EVP_DigestSignInit => md == NULL", mdCtx);
+ JNI_TRACE("ctx=%p %s => md == NULL", mdCtx, jniName);
jniThrowNullPointerException(env, "md == null");
- return;
+ return 0;
}
- if (EVP_DigestSignInit(mdCtx, (EVP_PKEY_CTX **) NULL, md, (ENGINE *) NULL, pkey) <= 0) {
- JNI_TRACE("ctx=%p EVP_DigestSignInit => threw exception", mdCtx);
- throwExceptionIfNecessary(env, "EVP_DigestSignInit");
- return;
+ EVP_PKEY_CTX* pctx = NULL;
+ if (init_func(mdCtx, &pctx, md, (ENGINE *) NULL, pkey) <= 0) {
+ JNI_TRACE("ctx=%p %s => threw exception", mdCtx, jniName);
+ throwExceptionIfNecessary(env, jniName);
+ return 0;
}
- JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) => success", mdCtx, md, pkey);
+ JNI_TRACE("%s(%p, %p, %p) => success", jniName, mdCtx, md, pkey);
+ return reinterpret_cast<jlong>(pctx);
+}
+
+static jlong NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jobject evpMdCtxRef,
+ const jlong evpMdRef, jobject pkeyRef) {
+ return evpDigestSignVerifyInit(
+ env, EVP_DigestSignInit, "EVP_DigestSignInit", evpMdCtxRef, evpMdRef, pkeyRef);
+}
+
+static jlong NativeCrypto_EVP_DigestVerifyInit(JNIEnv* env, jclass, jobject evpMdCtxRef,
+ const jlong evpMdRef, jobject pkeyRef) {
+ return evpDigestSignVerifyInit(
+ env, EVP_DigestVerifyInit, "EVP_DigestVerifyInit", evpMdCtxRef, evpMdRef, pkeyRef);
}
static void evpUpdate(JNIEnv* env, jobject evpMdCtxRef, jlong inPtr, jint inLength,
@@ -4521,18 +4525,25 @@
static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef,
jbyteArray inJavaBytes, jint inOffset, jint inLength) {
evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_DigestSignUpdate",
- EVP_DigestUpdate);
+ EVP_DigestSignUpdate);
}
-static void NativeCrypto_EVP_SignUpdateDirect(JNIEnv* env, jclass, jobject evpMdCtxRef,
+static void NativeCrypto_EVP_DigestSignUpdateDirect(JNIEnv* env, jclass, jobject evpMdCtxRef,
jlong inPtr, jint inLength) {
- evpUpdate(env, evpMdCtxRef, inPtr, inLength, "EVP_SignUpdateDirect", EVP_DigestUpdate);
+ evpUpdate(env, evpMdCtxRef, inPtr, inLength, "EVP_DigestSignUpdateDirect",
+ EVP_DigestSignUpdate);
}
-static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef,
+static void NativeCrypto_EVP_DigestVerifyUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef,
jbyteArray inJavaBytes, jint inOffset, jint inLength) {
- evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_SignUpdate",
- EVP_DigestUpdate);
+ evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_DigestVerifyUpdate",
+ EVP_DigestVerifyUpdate);
+}
+
+static void NativeCrypto_EVP_DigestVerifyUpdateDirect(JNIEnv* env, jclass, jobject evpMdCtxRef,
+ jlong inPtr, jint inLength) {
+ evpUpdate(env, evpMdCtxRef, inPtr, inLength, "EVP_DigestVerifyUpdateDirect",
+ EVP_DigestVerifyUpdate);
}
static jbyteArray NativeCrypto_EVP_DigestSignFinal(JNIEnv* env, jclass, jobject evpMdCtxRef)
@@ -4544,163 +4555,78 @@
return NULL;
}
- size_t len;
- if (EVP_DigestSignFinal(mdCtx, NULL, &len) != 1) {
+ size_t maxLen;
+ if (EVP_DigestSignFinal(mdCtx, NULL, &maxLen) != 1) {
JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx);
throwExceptionIfNecessary(env, "EVP_DigestSignFinal");
+ return NULL;
+ }
+
+ UniquePtr<unsigned char[]> buffer(new unsigned char[maxLen]);
+ if (buffer.get() == NULL) {
+ jniThrowOutOfMemory(env, "Unable to allocate signature buffer");
return 0;
}
- ScopedLocalRef<jbyteArray> outJavaBytes(env, env->NewByteArray(len));
- if (outJavaBytes.get() == NULL) {
- return NULL;
- }
- ScopedByteArrayRW outBytes(env, outJavaBytes.get());
- if (outBytes.get() == NULL) {
- return NULL;
- }
- unsigned char *tmp = reinterpret_cast<unsigned char*>(outBytes.get());
- if (EVP_DigestSignFinal(mdCtx, tmp, &len) != 1) {
+ size_t actualLen;
+ if (EVP_DigestSignFinal(mdCtx, buffer.get(), &actualLen) != 1) {
JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx);
throwExceptionIfNecessary(env, "EVP_DigestSignFinal");
+ return NULL;
+ }
+ if (actualLen > maxLen) {
+ JNI_TRACE("ctx=%p EVP_DigestSignFinal => signature too long: %d vs %d",
+ actualLen, maxLen);
+ throwExceptionIfNecessary(env, "EVP_DigestSignFinal signature too long");
+ return NULL;
+ }
+
+ ScopedLocalRef<jbyteArray> sigJavaBytes(env, env->NewByteArray(actualLen));
+ if (sigJavaBytes.get() == NULL) {
+ jniThrowOutOfMemory(env, "Failed to allocate signature byte[]");
+ return NULL;
+ }
+ env->SetByteArrayRegion(
+ sigJavaBytes.get(), 0, actualLen, reinterpret_cast<jbyte*>(buffer.get()));
+
+ JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, sigJavaBytes.get());
+ return sigJavaBytes.release();
+}
+
+static jboolean NativeCrypto_EVP_DigestVerifyFinal(JNIEnv* env, jclass, jobject evpMdCtxRef,
+ jbyteArray signature, jint offset, jint len)
+{
+ EVP_MD_CTX* mdCtx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef);
+ JNI_TRACE("EVP_DigestVerifyFinal(%p)", mdCtx);
+
+ if (mdCtx == NULL) {
+ return 0;
+ }
+
+ ScopedByteArrayRO sigBytes(env, signature);
+ if (sigBytes.get() == NULL) {
return 0;
}
- JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, outJavaBytes.get());
- return outJavaBytes.release();
-}
-
-/*
- * public static native int EVP_SignFinal(long, byte[], int, long)
- */
-static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray signature,
- jint offset, jobject pkeyRef) {
- JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctxRef, signature, offset, pkeyRef);
- EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef);
- if (ctx == NULL) {
- return -1;
- }
- EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
- JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) <- ptr", ctx, signature, offset, pkey);
-
- if (pkey == NULL) {
- return -1;
+ if (ARRAY_OFFSET_LENGTH_INVALID(sigBytes, offset, len)) {
+ jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "signature");
+ return 0;
}
- ScopedByteArrayRW signatureBytes(env, signature);
- if (signatureBytes.get() == NULL) {
- return -1;
- }
- unsigned int bytesWritten = -1;
- int ok = EVP_SignFinal(ctx,
- reinterpret_cast<unsigned char*>(signatureBytes.get() + offset),
- &bytesWritten,
- pkey);
- if (ok != 1) {
- throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal");
- }
- JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u",
- ctx, signature, offset, pkey, bytesWritten);
-
- return bytesWritten;
-}
-
-/*
- * public static native void EVP_VerifyUpdateDirect(long, long, int)
- */
-static void NativeCrypto_EVP_VerifyUpdateDirect(JNIEnv* env, jclass, jobject ctxRef,
- jlong ptr, jint length) {
- EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef);
- const void *p = reinterpret_cast<const void *>(ptr);
- JNI_TRACE("NativeCrypto_EVP_VerifyUpdateDirect(%p, %p, %d)", ctx, p, length);
-
- if (ctx == NULL) {
- return;
+ const unsigned char *sigBuf = reinterpret_cast<const unsigned char *>(sigBytes.get());
+ int err = EVP_DigestVerifyFinal(mdCtx, sigBuf + offset, len);
+ jboolean result;
+ if (err == 1) {
+ result = 1;
+ } else if (err == 0) {
+ result = 0;
+ } else {
+ JNI_TRACE("ctx=%p EVP_DigestVerifyFinal => threw exception", mdCtx);
+ throwExceptionIfNecessary(env, "EVP_DigestVerifyFinal");
+ return 0;
}
- if (p == NULL) {
- jniThrowNullPointerException(env, NULL);
- return;
- }
-
- int ok = EVP_VerifyUpdate(ctx, p, length);
- if (ok == 0) {
- throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdateDirect");
- }
-}
-
-/*
- * public static native void EVP_VerifyUpdate(long, byte[], int, int)
- */
-static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jobject ctxRef,
- jbyteArray buffer, jint offset, jint length) {
- EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef);
- JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length);
-
- if (ctx == NULL) {
- return;
- } else if (buffer == NULL) {
- jniThrowNullPointerException(env, NULL);
- return;
- }
-
- ScopedByteArrayRO bufferBytes(env, buffer);
- if (bufferBytes.get() == NULL) {
- return;
- }
- if (ARRAY_OFFSET_LENGTH_INVALID(bufferBytes, offset, length)) {
- jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
- return;
- }
-
- int ok = EVP_VerifyUpdate(ctx,
- reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
- length);
- if (ok == 0) {
- throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate");
- }
-}
-
-/*
- * public static native int EVP_VerifyFinal(long, byte[], int, int, long)
- */
-static jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray buffer,
- jint offset, jint length, jobject pkeyRef) {
- JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)",
- ctxRef, buffer, offset, length, pkeyRef);
- EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef);
- if (ctx == NULL) {
- return -1;
- }
- EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef);
- if (pkey == NULL) {
- return -1;
- }
- JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) <- ptr",
- ctx, buffer, offset, length, pkey);
-
- if (buffer == NULL) {
- jniThrowNullPointerException(env, "buffer == null");
- return -1;
- }
-
- ScopedByteArrayRO bufferBytes(env, buffer);
- if (bufferBytes.get() == NULL) {
- return -1;
- }
-
- int ok = EVP_VerifyFinal(ctx,
- reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset),
- length,
- pkey);
- // The upper (Java language) layer should take care of throwing the
- // expected exceptions before calling to this, so we just clear
- // the OpenSSL/BoringSSL error stack here.
- freeOpenSslErrorState();
-
- JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d",
- ctx, buffer, offset, length, pkey, ok);
-
- return ok;
+ JNI_TRACE("EVP_DigestVerifyFinal(%p) => %d", mdCtx, result);
+ return result;
}
static jlong NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) {
@@ -11242,17 +11168,14 @@
NATIVE_METHOD(NativeCrypto, EVP_get_digestbyname, "(Ljava/lang/String;)J"),
NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(J)I"),
NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(J)I"),
- NATIVE_METHOD(NativeCrypto, EVP_SignInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J)I"),
- NATIVE_METHOD(NativeCrypto, EVP_SignUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"),
- NATIVE_METHOD(NativeCrypto, EVP_SignUpdateDirect, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;JI)V"),
- NATIVE_METHOD(NativeCrypto, EVP_SignFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BI" REF_EVP_PKEY ")I"),
- NATIVE_METHOD(NativeCrypto, EVP_VerifyInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J)I"),
- NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"),
- NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdateDirect, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;JI)V"),
- NATIVE_METHOD(NativeCrypto, EVP_VerifyFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII" REF_EVP_PKEY ")I"),
- NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J" REF_EVP_PKEY ")V"),
- NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[B)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J" REF_EVP_PKEY ")J"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdateDirect, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;JI)V"),
NATIVE_METHOD(NativeCrypto, EVP_DigestSignFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;)[B"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestVerifyInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J" REF_EVP_PKEY ")J"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestVerifyUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestVerifyUpdateDirect, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;JI)V"),
+ NATIVE_METHOD(NativeCrypto, EVP_DigestVerifyFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)Z"),
NATIVE_METHOD(NativeCrypto, EVP_get_cipherbyname, "(Ljava/lang/String;)J"),
NATIVE_METHOD(NativeCrypto, EVP_CipherInit_ex, "(" REF_EVP_CIPHER_CTX "J[B[BZ)V"),
NATIVE_METHOD(NativeCrypto, EVP_CipherUpdate, "(" REF_EVP_CIPHER_CTX "[BI[BII)I"),
diff --git a/src/test/java/org/conscrypt/NativeCryptoTest.java b/src/test/java/org/conscrypt/NativeCryptoTest.java
index b8f0bf9..bd66c32 100644
--- a/src/test/java/org/conscrypt/NativeCryptoTest.java
+++ b/src/test/java/org/conscrypt/NativeCryptoTest.java
@@ -2645,13 +2645,37 @@
}
}
- public void test_EVP_SignInit() throws Exception {
+ public void test_EVP_DigestSignInit() throws Exception {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ kpg.initialize(512);
+
+ KeyPair kp = kpg.generateKeyPair();
+ RSAPrivateCrtKey privKey = (RSAPrivateCrtKey) kp.getPrivate();
+
+ NativeRef.EVP_PKEY pkey;
+ pkey = new NativeRef.EVP_PKEY(NativeCrypto.EVP_PKEY_new_RSA(
+ privKey.getModulus().toByteArray(),
+ privKey.getPublicExponent().toByteArray(),
+ privKey.getPrivateExponent().toByteArray(),
+ privKey.getPrimeP().toByteArray(),
+ privKey.getPrimeQ().toByteArray(),
+ privKey.getPrimeExponentP().toByteArray(),
+ privKey.getPrimeExponentQ().toByteArray(),
+ privKey.getCrtCoefficient().toByteArray()));
+ assertNotNull(pkey);
+
final NativeRef.EVP_MD_CTX ctx = new NativeRef.EVP_MD_CTX(NativeCrypto.EVP_MD_CTX_create());
- assertEquals(1,
- NativeCrypto.EVP_SignInit(ctx, NativeCrypto.EVP_get_digestbyname("sha256")));
+ long evpMd = NativeCrypto.EVP_get_digestbyname("sha256");
+ NativeCrypto.EVP_DigestSignInit(ctx, evpMd, pkey);
try {
- NativeCrypto.EVP_SignInit(ctx, 0);
+ NativeCrypto.EVP_DigestSignInit(ctx, 0, pkey);
+ fail();
+ } catch (RuntimeException expected) {
+ }
+
+ try {
+ NativeCrypto.EVP_DigestSignInit(ctx, evpMd, null);
fail();
} catch (RuntimeException expected) {
}