Skip to content

Commit

Permalink
JNI: wrap Atomic Record VerifyDecrypt callback
Browse files Browse the repository at this point in the history
  • Loading branch information
cconlon committed Jan 30, 2025
1 parent 6ae9aab commit 1b44d7a
Show file tree
Hide file tree
Showing 13 changed files with 820 additions and 55 deletions.
11 changes: 11 additions & 0 deletions examples/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@ public void run(String[] args) {
MyDecryptVerifyCallback dvcb = new MyDecryptVerifyCallback();
sslCtx.setMacEncryptCb(mecb);
sslCtx.setDecryptVerifyCb(dvcb);

if (WolfSSL.encryptThenMacEnabled()) {
MyVerifyDecryptCallback vdcb =
new MyVerifyDecryptCallback();
sslCtx.setVerifyDecryptCb(vdcb);
}
}

/* register public key callbacks, ctx setup is later */
Expand Down Expand Up @@ -521,6 +527,11 @@ public void run(String[] args) {
MyAtomicDecCtx decCtx = new MyAtomicDecCtx();
ssl.setMacEncryptCtx(encCtx);
ssl.setDecryptVerifyCtx(decCtx);

if (WolfSSL.encryptThenMacEnabled()) {
MyAtomicDecCtx vdCtx = new MyAtomicDecCtx();
ssl.setVerifyDecryptCtx(vdCtx);
}
}

if (pkCallbacks == 1) {
Expand Down
34 changes: 17 additions & 17 deletions examples/MyDecryptVerifyCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
import java.nio.ByteBuffer;
import com.wolfssl.*;

/*
* Example Decrypt Verify callback implementation.
* NOTE: if native HAVE_ENCRYPT_THEN_MAC is defined, the VerifyDecrypt
* callback needs to be used.
*/
class MyDecryptVerifyCallback implements WolfSSLDecryptVerifyCallback
{
public int decryptVerifyCallback(WolfSSLSession ssl, ByteBuffer decOut,
Expand Down Expand Up @@ -115,23 +120,18 @@ public int decryptVerifyCallback(WolfSSLSession ssl, ByteBuffer decOut,
ssl.setTlsHmacInner(myInner, macInSz, macContent, macVerify);
int hmacType = ssl.getHmacType();

switch (hmacType) {
case WolfSSL.SHA:
hmacString = "HmacSHA1";
break;
case WolfSSL.SHA256:
hmacString = "HmacSHA256";
break;
case WolfSSL.SHA384:
hmacString = "HmacSHA384";
break;
case WolfSSL.SHA512:
hmacString = "HmacSHA512";
break;
default:
System.out.println("Unsupported HMAC hash type in " +
"MyDecryptVerifyCallback");
return -1;
if (hmacType == WolfSSL.SHA) {
hmacString = "HmacSHA1";
} else if (hmacType == WolfSSL.SHA256) {
hmacString = "HmacSHA256";
} else if (hmacType == WolfSSL.SHA384) {
hmacString = "HmacSHA384";
} else if (hmacType == WolfSSL.SHA512) {
hmacString = "HmacSHA512";
} else {
System.out.println("Unsupported HMAC hash type in " +
"MyDecryptVerifyCallback: " + hmacType);
return -1;
}

/* get Hmac SHA-1 key */
Expand Down
29 changes: 12 additions & 17 deletions examples/MyMacEncryptCallback.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,18 @@ public int macEncryptCallback(WolfSSLSession ssl, ByteBuffer macOut,
}

int hmacType = ssl.getHmacType();
switch (hmacType) {
case WolfSSL.SHA:
hmacString = "HmacSHA1";
break;
case WolfSSL.SHA256:
hmacString = "HmacSHA256";
break;
case WolfSSL.SHA384:
hmacString = "HmacSHA384";
break;
case WolfSSL.SHA512:
hmacString = "HmacSHA512";
break;
default:
System.out.println("Unsupported HMAC hash type in " +
"MyMacEncryptCallback");
return -1;
if (hmacType == WolfSSL.SHA) {
hmacString = "HmacSHA1";
} else if (hmacType == WolfSSL.SHA256) {
hmacString = "HmacSHA256";
} else if (hmacType == WolfSSL.SHA384) {
hmacString = "HmacSHA384";
} else if (hmacType == WolfSSL.SHA512) {
hmacString = "HmacSHA512";
} else {
System.out.println("Unsupported HMAC hash type in " +
"MyMacEncryptCallback");
return -1;
}

/* hmac, not needed if aead mode */
Expand Down
163 changes: 163 additions & 0 deletions examples/MyVerifyDecryptCallback.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/* MyVerifyDecryptCallback.java
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

import java.io.*;
import java.net.*;
import java.nio.*;
import java.util.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import java.nio.ByteBuffer;
import com.wolfssl.*;

/*
* Example Verify/Decrypt callback implementation. For use when
* HAVE_ENCRYPT_THEN_MAC is defined, which can be tested from Java using
* WolfSSL.encryptThenMacEnabled().
*
* This example callback has been modeled directly after the native wolfSSL
* example callback (myVerifyDecryptCb()) in wolfssl/test.h.
*
* NOTE: if native HAVE_ENCRYPT_THEN_MAC is not defined, the DecryptVerify
* callback needs to be set and used.
*/
class MyVerifyDecryptCallback implements WolfSSLVerifyDecryptCallback
{
public int verifyDecryptCallback(WolfSSLSession ssl, ByteBuffer decOut,
byte[] decIn, long decSz, int macContent, int macVerify,
long[] padSz, Object ctx) {

int hmacType = ssl.getHmacType();
int digestSz = ssl.getHmacSize();
byte[] myInner = new byte[WolfSSL.WOLFSSL_TLS_HMAC_INNER_SZ];
byte[] verify = null;
byte[] keyBytes = null;
byte[] ivBytes = null;
String hmacString;
String tlsStr = "TLS";

Cipher cipher = null;
MyAtomicDecCtx decCtx = (MyAtomicDecCtx) ctx;

/* example supports (d)tls AES */
if (ssl.getBulkCipher() != WolfSSL.wolfssl_aes) {
System.out.println("MyVerifyDecryptCallback not using AES");
return -1;
}

try {
if (!ssl.getVersion().contains(tlsStr)) {
System.out.println("MyVerifyDecryptCallback not using (D)TLS");
return -1;
}

ssl.setTlsHmacInner(myInner, decSz, macContent, macVerify);

if (hmacType == WolfSSL.SHA) {
hmacString = "HmacSHA1";
} else if (hmacType == WolfSSL.SHA256) {
hmacString = "HmacSHA256";
} else if (hmacType == WolfSSL.SHA384) {
hmacString = "HmacSHA384";
} else if (hmacType == WolfSSL.SHA512) {
hmacString = "HmacSHA512";
} else {
System.out.println("Unsupported HMAC hash type in " +
"MyVerifyDecryptCallback: " + hmacType);
return -1;
}

/* construct HMAC key */
SecretKeySpec hmacKey = new SecretKeySpec(
ssl.getMacSecret(macVerify), hmacString);

/* get Mac instance, initialize with key, compute */
Mac mac = Mac.getInstance(hmacString);
mac.init(hmacKey);
mac.update(myInner, 0, myInner.length);
mac.update(decIn, 0, (int)decSz);
verify = mac.doFinal();

/* Get MAC (digestSz bytes) off end of decOut for comparison */
byte[] verifyMac = new byte[digestSz];
int tmpPos = decOut.position();
decOut.position(decOut.limit() - digestSz);
decOut.get(verifyMac);
decOut.position(tmpPos);

if (verifyMac.length != verify.length) {
System.out.println("MyVerifyDecryptCallback verifyMac length " +
"different than calculated MAC length");
return -1;
}

if (!Arrays.equals(verify, verifyMac)) {
System.out.println("MyVerifyDecryptCallback MAC " +
"comparison failed");
return -1;
}

/* Setup AES for decrypt */
if(!decCtx.isCipherSetup()) {
int keyLen = ssl.getKeySize();
SecretKeySpec key = null;
cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");

/* Decrypt is from other side (peer) */
if (ssl.getSide() == WolfSSL.WOLFSSL_SERVER_END) {
keyBytes = ssl.getClientWriteKey();
ivBytes = ssl.getClientWriteIV();
} else {
keyBytes = ssl.getServerWriteKey();
ivBytes = ssl.getServerWriteIV();
}

key = new SecretKeySpec(keyBytes, "AES");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(ivBytes));
decCtx.setCipher(cipher);
decCtx.isCipherSetup(true);
} else {
cipher = decCtx.getCipher();

if (cipher == null) {
System.out.println("Cipher was not previously set up");
return -1;
}
}

/* Decrypt */
decOut.position(0);
decOut.put(cipher.doFinal(decIn, 0, (int)decSz));
decOut.flip();

byte padVal = decOut.get((int)decSz - 1);
padSz[0] = (long)padVal + 1;

} catch (Exception e) {
e.printStackTrace();
}

return 0;
}
}

13 changes: 12 additions & 1 deletion examples/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,12 @@ public void run(String[] args) {
new MyDecryptVerifyCallback();
sslCtx.setMacEncryptCb(mecb);
sslCtx.setDecryptVerifyCb(dvcb);

if (WolfSSL.encryptThenMacEnabled()) {
MyVerifyDecryptCallback vdc =
new MyVerifyDecryptCallback();
sslCtx.setVerifyDecryptCb(vdc);
}
}

/* register public key callbacks, ctx setup later */
Expand Down Expand Up @@ -515,6 +521,11 @@ public void run(String[] args) {
MyAtomicDecCtx decCtx = new MyAtomicDecCtx();
ssl.setMacEncryptCtx(encCtx);
ssl.setDecryptVerifyCtx(decCtx);

if (WolfSSL.encryptThenMacEnabled()) {
MyAtomicDecCtx vdCtx = new MyAtomicDecCtx();
ssl.setVerifyDecryptCtx(vdCtx);
}
}

if (pkCallbacks == 1) {
Expand Down Expand Up @@ -566,7 +577,7 @@ public void run(String[] args) {
(err == WolfSSL.SSL_ERROR_WANT_READ ||
err == WolfSSL.SSL_ERROR_WANT_WRITE));

if (input.length > 0) {
if (insz > 0) {
String cliMsg = new String(input, 0, insz);
System.out.println("client says: " + cliMsg);
} else {
Expand Down
58 changes: 58 additions & 0 deletions native/com_wolfssl_WolfSSL.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,51 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getBulkCipherAlgorithmEnumCAMELL
return wolfssl_camellia;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getHmacEnumMD5
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

return WC_HASH_TYPE_MD5;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getHmacEnumSHA1
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

return WC_HASH_TYPE_SHA;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getHmacEnumSHA256
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

return WC_HASH_TYPE_SHA256;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getHmacEnumSHA384
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

return WC_HASH_TYPE_SHA384;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getHmacEnumSHA512
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

return WC_HASH_TYPE_SHA512;
}

JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_getTls13SecretEnum_1CLIENT_1EARLY_1TRAFFIC_1SECRET
(JNIEnv* jenv, jclass jcl)
{
Expand Down Expand Up @@ -680,6 +725,19 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_secretCallbackEnabled
#endif
}

JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_encryptThenMacEnabled
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;

#ifdef HAVE_ENCRYPT_THEN_MAC
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}

JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_SSLv3_1ServerMethod
(JNIEnv* jenv, jclass jcl)
{
Expand Down
Loading

0 comments on commit 1b44d7a

Please sign in to comment.