Skip to content

Commit a64bbc4

Browse files
authored
Merge pull request #160 from cconlon/ecParamFix
JCE: Add P1363 ECDSA signature formats, fix parameter handling, and improve ECC defaults
2 parents 0a4b4f4 + 34bd3b9 commit a64bbc4

17 files changed

+1804
-128
lines changed

CLAUDE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@
4848
- Example .jks files are located under "examples/certs"
4949
- Example .wk files are located under "examples/certs"
5050
- Example .jks files are updated using the update-jks-wks.sh script
51+
52+
# Adding new JUnit test files
53+
- All new wolfCrypt JUnit test files must be added to src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java
54+
- All new wolfJCE JUnit test files must be added to src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java
55+
- New JUnit test classes must define TestRule like existing ones do
56+
57+
# Adding new Java files
58+
- MUST add all new JNI or JCE Java files to scripts/infer.sh for Infer static analysis

README_JCE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ The JCE provider currently supports the following algorithms:
153153
SHA3-256withECDSA
154154
SHA3-384withECDSA
155155
SHA3-512withECDSA
156+
SHA256withECDSAinP1363Format
157+
SHA384withECDSAinP1363Format
158+
SHA512withECDSAinP1363Format
159+
SHA3-256withECDSAinP1363Format
160+
SHA3-384withECDSAinP1363Format
161+
SHA3-512withECDSAinP1363Format
156162

157163
KeyAgreement Class
158164
DiffieHellman

jni/include/com_wolfssl_wolfcrypt_Ecc.h

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

jni/jni_ecc.c

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,3 +1769,261 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1get_1all_
17691769
return result;
17701770
}
17711771

1772+
JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1size(
1773+
JNIEnv* env, jobject this)
1774+
{
1775+
jint ret = 0;
1776+
1777+
#ifdef HAVE_ECC
1778+
ecc_key* ecc = NULL;
1779+
1780+
ecc = (ecc_key*) getNativeStruct(env, this);
1781+
if ((*env)->ExceptionOccurred(env)) {
1782+
/* getNativeStruct may throw exception, prevent throwing another */
1783+
return 0;
1784+
}
1785+
1786+
if (ecc == NULL) {
1787+
throwWolfCryptException(env, "ECC key is NULL");
1788+
return 0;
1789+
}
1790+
1791+
ret = wc_ecc_size(ecc);
1792+
1793+
LogStr("wc_ecc_size(ecc) = %d\n", ret);
1794+
1795+
#else
1796+
(void)this;
1797+
throwNotCompiledInException(env);
1798+
#endif
1799+
1800+
return ret;
1801+
}
1802+
1803+
/*
1804+
* Convert DER-encoded ECDSA signature to raw {r,s} values.
1805+
* Used for IEEE P1363 signature format conversion.
1806+
*
1807+
* Returns byte[][] where [0] is r value and [1] is s value, or NULL on error.
1808+
*/
1809+
JNIEXPORT jobjectArray JNICALL
1810+
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1sig_1to_1rs_1raw(
1811+
JNIEnv* env, jobject this, jbyteArray signature_object)
1812+
{
1813+
jobjectArray result = NULL;
1814+
1815+
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
1816+
int ret = 0;
1817+
ecc_key* ecc = NULL;
1818+
byte* signature = NULL;
1819+
byte* r = NULL;
1820+
byte* s = NULL;
1821+
word32 signatureSz = 0;
1822+
word32 rSz = 0;
1823+
word32 sSz = 0;
1824+
word32 keySz = 0;
1825+
jbyteArray rArray = NULL;
1826+
jbyteArray sArray = NULL;
1827+
jclass byteArrayClass = NULL;
1828+
1829+
ecc = (ecc_key*) getNativeStruct(env, this);
1830+
if ((*env)->ExceptionOccurred(env)) {
1831+
/* getNativeStruct may throw exception, prevent throwing another */
1832+
return NULL;
1833+
}
1834+
1835+
if (ecc == NULL) {
1836+
throwWolfCryptException(env, "ECC key is NULL");
1837+
return NULL;
1838+
}
1839+
1840+
signature = getByteArray(env, signature_object);
1841+
signatureSz = getByteArrayLength(env, signature_object);
1842+
1843+
if (signature == NULL) {
1844+
throwWolfCryptException(env, "Input signature is NULL");
1845+
return NULL;
1846+
}
1847+
1848+
/* Get key size to determine buffer sizes for r and s */
1849+
keySz = wc_ecc_size(ecc);
1850+
if (keySz == 0) {
1851+
releaseByteArray(env, signature_object, signature, JNI_ABORT);
1852+
throwWolfCryptException(env, "Invalid ECC key size");
1853+
return NULL;
1854+
}
1855+
1856+
/* Allocate buffers for r and s (should be at most key size) */
1857+
rSz = sSz = keySz;
1858+
r = (byte*)XMALLOC(rSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1859+
s = (byte*)XMALLOC(sSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1860+
1861+
if (r == NULL || s == NULL) {
1862+
ret = MEMORY_E;
1863+
1864+
} else {
1865+
XMEMSET(r, 0, rSz);
1866+
XMEMSET(s, 0, sSz);
1867+
}
1868+
1869+
if (ret == 0) {
1870+
ret = wc_ecc_sig_to_rs(signature, signatureSz, r, &rSz, s, &sSz);
1871+
}
1872+
1873+
if (ret == 0) {
1874+
byteArrayClass = (*env)->FindClass(env, "[B");
1875+
if (byteArrayClass == NULL) {
1876+
ret = MEMORY_E;
1877+
} else {
1878+
result = (*env)->NewObjectArray(env, 2, byteArrayClass, NULL);
1879+
}
1880+
}
1881+
1882+
if ((ret == 0) && (result != NULL)) {
1883+
rArray = (*env)->NewByteArray(env, rSz);
1884+
sArray = (*env)->NewByteArray(env, sSz);
1885+
1886+
if ((rArray != NULL) && (sArray != NULL)) {
1887+
(*env)->SetByteArrayRegion(env, rArray, 0, rSz, (const jbyte*)r);
1888+
(*env)->SetByteArrayRegion(env, sArray, 0, sSz, (const jbyte*)s);
1889+
(*env)->SetObjectArrayElement(env, result, 0, rArray);
1890+
(*env)->SetObjectArrayElement(env, result, 1, sArray);
1891+
} else {
1892+
ret = MEMORY_E;
1893+
}
1894+
}
1895+
1896+
/* Clean up */
1897+
if (r != NULL) {
1898+
XMEMSET(r, 0, keySz);
1899+
XFREE(r, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1900+
}
1901+
if (s != NULL) {
1902+
XMEMSET(s, 0, keySz);
1903+
XFREE(s, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1904+
}
1905+
1906+
releaseByteArray(env, signature_object, signature, JNI_ABORT);
1907+
1908+
if (ret != 0) {
1909+
throwWolfCryptExceptionFromError(env, ret);
1910+
return NULL;
1911+
}
1912+
1913+
LogStr("wc_ecc_sig_to_rs(sig, sigLen, r, &rLen, s, &sLen) = %d\n", ret);
1914+
1915+
#else
1916+
(void)this;
1917+
(void)signature_object;
1918+
throwNotCompiledInException(env);
1919+
#endif
1920+
1921+
return result;
1922+
}
1923+
1924+
/*
1925+
* Convert raw {r,s} values to DER-encoded ECDSA signature.
1926+
* Used for IEEE P1363 signature format conversion.
1927+
*
1928+
* Returns DER-encoded signature byte array, or NULL on error.
1929+
*/
1930+
JNIEXPORT jbyteArray JNICALL
1931+
Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1rs_1raw_1to_1sig(
1932+
JNIEnv* env, jobject this, jbyteArray r_object, jbyteArray s_object)
1933+
{
1934+
jbyteArray result = NULL;
1935+
1936+
#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN)
1937+
int ret = 0;
1938+
ecc_key* ecc = NULL;
1939+
byte* r = NULL;
1940+
byte* s = NULL;
1941+
byte* signature = NULL;
1942+
word32 rSz = 0;
1943+
word32 sSz = 0;
1944+
word32 signatureSz = 0;
1945+
word32 signatureBufSz = 0;
1946+
1947+
ecc = (ecc_key*) getNativeStruct(env, this);
1948+
if ((*env)->ExceptionOccurred(env)) {
1949+
/* getNativeStruct may throw exception, prevent throwing another */
1950+
return NULL;
1951+
}
1952+
1953+
if (ecc == NULL) {
1954+
throwWolfCryptException(env, "ECC key is NULL");
1955+
return NULL;
1956+
}
1957+
1958+
r = getByteArray(env, r_object);
1959+
rSz = getByteArrayLength(env, r_object);
1960+
s = getByteArray(env, s_object);
1961+
sSz = getByteArrayLength(env, s_object);
1962+
1963+
if (r == NULL || s == NULL) {
1964+
LogStr("Input r or s is NULL\n");
1965+
ret = BAD_FUNC_ARG;
1966+
}
1967+
1968+
if (ret == 0) {
1969+
/* Estimate signature size based on ECC key size */
1970+
signatureBufSz = wc_ecc_sig_size(ecc);
1971+
if (signatureBufSz == 0) {
1972+
LogStr("Invalid signature size estimate\n");
1973+
ret = BAD_FUNC_ARG;
1974+
}
1975+
}
1976+
1977+
if (ret == 0) {
1978+
signatureSz = signatureBufSz;
1979+
signature = (byte*)XMALLOC(signatureSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
1980+
if (signature == NULL) {
1981+
ret = MEMORY_E;
1982+
} else {
1983+
XMEMSET(signature, 0, signatureSz);
1984+
}
1985+
}
1986+
1987+
if (ret == 0) {
1988+
ret = wc_ecc_rs_raw_to_sig(r, rSz, s, sSz, signature, &signatureSz);
1989+
}
1990+
1991+
if (ret == 0) {
1992+
result = (*env)->NewByteArray(env, signatureSz);
1993+
if (result != NULL) {
1994+
(*env)->SetByteArrayRegion(env, result, 0, signatureSz,
1995+
(const jbyte*)signature);
1996+
} else {
1997+
ret = MEMORY_E;
1998+
}
1999+
}
2000+
2001+
LogStr("wc_ecc_rs_raw_to_sig(r, rSz, s, sSz, sig, &sigLen) = %d\n", ret);
2002+
2003+
if (signature != NULL) {
2004+
XMEMSET(signature, 0, signatureBufSz);
2005+
XFREE(signature, NULL, DYNAMIC_TYPE_TMP_BUFFER);
2006+
}
2007+
2008+
if (r != NULL) {
2009+
releaseByteArray(env, r_object, r, JNI_ABORT);
2010+
}
2011+
if (s != NULL) {
2012+
releaseByteArray(env, s_object, s, JNI_ABORT);
2013+
}
2014+
2015+
if (ret != 0) {
2016+
throwWolfCryptExceptionFromError(env, ret);
2017+
return NULL;
2018+
}
2019+
2020+
#else
2021+
(void)this;
2022+
(void)r_object;
2023+
(void)s_object;
2024+
throwNotCompiledInException(env);
2025+
#endif /* HAVE_ECC && HAVE_ECC_SIGN */
2026+
2027+
return result;
2028+
}
2029+

src/main/java/com/wolfssl/provider/jce/WolfCryptECKeyFactory.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import java.security.spec.X509EncodedKeySpec;
3535
import java.security.spec.ECPrivateKeySpec;
3636
import java.security.spec.ECPublicKeySpec;
37+
import java.security.spec.ECParameterSpec;
3738
import java.security.interfaces.ECPrivateKey;
3839
import java.security.interfaces.ECPublicKey;
3940
import java.security.InvalidAlgorithmParameterException;
@@ -442,7 +443,8 @@ else if (bytes.length < expectedSz) {
442443
* Convert BigInteger private key to byte[].
443444
*
444445
* @param privateValue private key BigInteger
445-
* @param curveName curve name for size validation
446+
* @param curveName curve name for size validation, used to get
447+
* expected byte array size
446448
*
447449
* @return properly formatted byte array for wolfCrypt import
448450
*
@@ -451,7 +453,8 @@ else if (bytes.length < expectedSz) {
451453
private byte[] convertPrivateValueToBytes(BigInteger privateValue,
452454
String curveName) throws InvalidKeySpecException {
453455

454-
/* Validate private key is within valid range (1 <= d < order) */
456+
/* Validate private key is positive. Other validation done at time of
457+
* use to match Sun behavior. */
455458
if (privateValue.signum() <= 0) {
456459
throw new InvalidKeySpecException(
457460
"Private key value must be positive");

0 commit comments

Comments
 (0)