F-4368: zero native password copy before release in PBKDF2 and PKCS12 PBKDF JNI

pull/245/head
Chris Conlon 2026-07-23 11:56:20 -06:00
parent 4043b2eaf1
commit 4d2cb5edbb
3 changed files with 160 additions and 2 deletions

View File

@ -48,6 +48,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PKCS12_1PBK
byte* pass = NULL;
byte* salt = NULL;
byte* outKey = NULL;
jboolean passIsCopy = JNI_FALSE;
jbyteArray result = NULL;
(void)jcl;
@ -64,7 +65,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PKCS12_1PBK
XMEMSET(outKey, 0, kLen);
if (passBuf != NULL) {
pass = (byte*)(*env)->GetByteArrayElements(env, passBuf, NULL);
pass = (byte*)(*env)->GetByteArrayElements(env, passBuf, &passIsCopy);
}
if (saltBuf != NULL) {
salt = (byte*)(*env)->GetByteArrayElements(env, saltBuf, NULL);
@ -96,6 +97,15 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PKCS12_1PBK
}
if (pass != NULL) {
/* Zero native copy of password, JNI_ABORT does not copy back */
if (passIsCopy == JNI_TRUE && passBufLen > 0) {
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \
!defined(WOLFSSL_NO_FORCE_ZERO)
wc_ForceZero(pass, passBufLen);
#else
XMEMSET(pass, 0, passBufLen);
#endif
}
(*env)->ReleaseByteArrayElements(env, passBuf, (jbyte*)pass, JNI_ABORT);
}
if (salt != NULL) {
@ -133,6 +143,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PBKDF2
byte* pass = NULL;
byte* salt = NULL;
byte* outKey = NULL;
jboolean passIsCopy = JNI_FALSE;
jbyteArray result = NULL;
(void)jcl;
@ -149,7 +160,7 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PBKDF2
XMEMSET(outKey, 0, kLen);
if ((passBuf != NULL) && (passBufLen > 0)) {
pass = (byte*)(*env)->GetByteArrayElements(env, passBuf, NULL);
pass = (byte*)(*env)->GetByteArrayElements(env, passBuf, &passIsCopy);
}
if (saltBuf != NULL) {
@ -182,6 +193,15 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Pwdbased_wc_1PBKDF2
}
if (pass != NULL) {
/* Zero native copy of password, JNI_ABORT does not copy back */
if (passIsCopy == JNI_TRUE && passBufLen > 0) {
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \
!defined(WOLFSSL_NO_FORCE_ZERO)
wc_ForceZero(pass, passBufLen);
#else
XMEMSET(pass, 0, passBufLen);
#endif
}
(*env)->ReleaseByteArrayElements(env, passBuf, (jbyte*)pass, JNI_ABORT);
}
if (salt != NULL) {

View File

@ -0,0 +1,137 @@
/* PwdbasedTest.java
*
* Copyright (C) 2006-2026 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 3 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
*/
package com.wolfssl.wolfcrypt.test;
import static org.junit.Assert.*;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Rule;
import org.junit.rules.TestRule;
import com.wolfssl.wolfcrypt.WolfCrypt;
import com.wolfssl.wolfcrypt.Pwdbased;
import com.wolfssl.wolfcrypt.FeatureDetect;
import com.wolfssl.wolfcrypt.Fips;
import com.wolfssl.wolfcrypt.WolfCryptError;
import com.wolfssl.wolfcrypt.WolfCryptException;
/**
* Tests for the Pwdbased PBKDF2 and PKCS12 PBKDF JNI wrappers.
*/
public class PwdbasedTest {
@Rule(order = Integer.MIN_VALUE)
public TestRule testWatcher = TimedTestWatcher.create();
@BeforeClass
public static void testSetup() {
System.out.println("JNI Pwdbased Class");
}
/* Password with distinctive pattern, used to detect modification */
private static byte[] makePassword() {
byte[] pass = new byte[32];
for (int i = 0; i < pass.length; i++) {
pass[i] = (byte)(0x41 + ((i * 7) % 26));
}
return pass;
}
/**
* PBKDF2-HMAC-SHA256 known answer test from RFC 7914 Section 11.
*/
@Test
public void testPbkdf2KnownAnswer() {
Assume.assumeTrue("PBKDF2 not compiled in native wolfSSL",
FeatureDetect.Pbkdf2Enabled());
/* RFC 7914 vector uses a 6 byte key and 4 byte salt, below the FIPS
* HMAC key and salt minimums, skip this known answer test in FIPS */
Assume.assumeTrue("RFC 7914 KAT inputs below FIPS minimums",
!Fips.enabled);
byte[] pass = "passwd".getBytes();
byte[] salt = "salt".getBytes();
byte[] expected = Util.h2b(
"55AC046E56E3089FEC1691C22544B605" +
"F94185216DDE0465E68B9D57C20DACBC" +
"49CA9CCCF179B645991664B39D77EF31" +
"7C71B845B1E30BD509112041D3A19783");
byte[] key = Pwdbased.PBKDF2(pass, salt, 1, 64,
WolfCrypt.WC_HASH_TYPE_SHA256);
assertArrayEquals(expected, key);
}
/**
* PBKDF2 must not modify the caller's password array, and repeated
* calls with the same password must derive the same key.
*/
@Test
public void testPbkdf2DoesNotModifyPassword() {
Assume.assumeTrue("PBKDF2 not compiled in native wolfSSL",
FeatureDetect.Pbkdf2Enabled());
byte[] pass = makePassword();
byte[] passCopy = pass.clone();
byte[] salt = new byte[] {1, 2, 3, 4, 5, 6, 7, 8};
byte[] key1 = Pwdbased.PBKDF2(pass, salt, 1000, 32,
WolfCrypt.WC_HASH_TYPE_SHA256);
assertArrayEquals("PBKDF2 modified caller password array",
passCopy, pass);
byte[] key2 = Pwdbased.PBKDF2(pass, salt, 1000, 32,
WolfCrypt.WC_HASH_TYPE_SHA256);
assertArrayEquals("repeated PBKDF2 derived different key",
key1, key2);
}
/**
* PKCS12 PBKDF must not modify the caller's password array.
*/
@Test
public void testPkcs12PbkdfDoesNotModifyPassword() {
byte[] pass = makePassword();
byte[] passCopy = pass.clone();
byte[] salt = new byte[] {1, 2, 3, 4, 5, 6, 7, 8};
byte[] key = null;
try {
key = Pwdbased.PKCS12_PBKDF(pass, salt, 100, 24,
WolfCrypt.WC_HASH_TYPE_SHA256, 1);
} catch (WolfCryptException e) {
Assume.assumeTrue("PKCS12 PBKDF not compiled in native wolfSSL",
e.getError() != WolfCryptError.NOT_COMPILED_IN);
throw e;
}
assertNotNull(key);
assertArrayEquals("PKCS12_PBKDF modified caller password array",
passCopy, pass);
}
}

View File

@ -47,6 +47,7 @@ import org.junit.runners.Suite.SuiteClasses;
Sha512Test.class,
Sha3Test.class,
HmacTest.class,
PwdbasedTest.class,
RngTest.class,
RsaTest.class,
DhTest.class,