diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 088326eea1f..04cea1293ee 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -148,7 +148,7 @@ jobs: apt-architecture: 'i386' # Some multilib libraries do not have proper inter-dependencies, so we have to # install their dependencies manually. - apt-extra-packages: 'libfreetype6-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386' + apt-extra-packages: 'libfreetype6-dev:i386 libtiff-dev:i386 libcupsimage2-dev:i386 libc6-i386 libgcc-s1:i386 libstdc++6:i386' extra-conf-options: '--with-target-bits=32' configure-arguments: ${{ github.event.inputs.configure-arguments }} make-arguments: ${{ github.event.inputs.make-arguments }} diff --git a/bin/idea.sh b/bin/idea.sh index 3f64f789dec..c85ae294454 100644 --- a/bin/idea.sh +++ b/bin/idea.sh @@ -193,17 +193,7 @@ for root in $MODULE_ROOTS; do root=`wslpath -am $root` fi - VM_CI="jdk.internal.vm.ci/share/classes" - VM_COMPILER="src/jdk.internal.vm.compiler/share/classes" - if test "${root#*$VM_CI}" != "$root" || test "${root#*$VM_COMPILER}" != "$root"; then - for subdir in "$root"/*; do - if [ -d "$subdir" ]; then - SOURCES=$SOURCES" $SOURCE_PREFIX""$subdir"/src"$SOURCE_POSTFIX" - fi - done - else - SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX" - fi + SOURCES=$SOURCES" $SOURCE_PREFIX""$root""$SOURCE_POSTFIX" done add_replacement "###SOURCE_ROOTS###" "$SOURCES" @@ -274,4 +264,4 @@ $BOOT_JDK/bin/$JAVAC -d $JAVAC_CLASSES -sourcepath $JAVAC_SOURCE_PATH -cp $JAVAC if [ "x$WSL_DISTRO_NAME" != "x" ]; then rm -rf $ANT_TEMP -fi \ No newline at end of file +fi diff --git a/closed/openjdk-tag.gmk b/closed/openjdk-tag.gmk index 9192b8e0067..5b6e8de06c5 100644 --- a/closed/openjdk-tag.gmk +++ b/closed/openjdk-tag.gmk @@ -1 +1 @@ -OPENJDK_TAG := jdk-21+20 +OPENJDK_TAG := jdk-21+25 diff --git a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java index 5f185974775..6db21b437bc 100644 --- a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java +++ b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java @@ -52,8 +52,13 @@ public class NativeCrypto { public static final int ECField_Fp = 0; public static final int ECField_F2m = 1; + /* Define XDH curve constants used by OpenSSL. */ + public static final int X25519 = 1034; + public static final int X448 = 1035; + public static final long OPENSSL_VERSION_1_0_0 = 0x1_00_00_000L; public static final long OPENSSL_VERSION_1_1_0 = 0x1_01_00_000L; + public static final long OPENSSL_VERSION_1_1_1 = 0x1_01_01_000L; public static final long OPENSSL_VERSION_3_0_0 = 0x3_00_00_000L; private static final Cleaner ECKeyCleaner = CleanerFactory.cleaner(); @@ -399,4 +404,18 @@ public final native int PBEDerive(byte[] password, int id, int hashAlgorithm); + /* Native XDH (X25519, X448) interfaces. */ + public final native int XDHCreateKeys(byte[] privateKey, + int privateKeyLength, + byte[] publicKey, + int publicKeyLength, + int curveType); + + public final native int XDHGenerateSecret(byte[] privateKey, + int privateKeyLength, + byte[] publicKey, + int publicKeyLength, + byte[] computedSecret, + int computedSecretLength, + int curveType); } diff --git a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c index 0a5aac3c846..747cd3b5efb 100644 --- a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c +++ b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c @@ -44,6 +44,7 @@ #define OPENSSL_VERSION_1_0_0 OPENSSL_VERSION_CODE(1, 0, 0, 0) #define OPENSSL_VERSION_1_1_0 OPENSSL_VERSION_CODE(1, 1, 0, 0) +#define OPENSSL_VERSION_1_1_1 OPENSSL_VERSION_CODE(1, 1, 1, 0) #define OPENSSL_VERSION_2_0_0 OPENSSL_VERSION_CODE(2, 0, 0, 0) /* Per new OpenSSL naming convention starting from OpenSSL 3, all major versions are ABI and API compatible. */ #define OPENSSL_VERSION_3_0_0 OPENSSL_VERSION_CODE(3, 0, 0, 0) @@ -149,6 +150,20 @@ typedef int OSSL_EC_KEY_check_key_t(const EC_KEY *); typedef int EC_set_public_key_t(EC_KEY *, BIGNUM *, BIGNUM *, int); typedef const BIGNUM *OSSL_EC_KEY_get0_private_key_t(const EC_KEY *); +typedef EVP_PKEY_CTX *OSSL_EVP_PKEY_CTX_new_t(EVP_PKEY *, ENGINE *); +typedef EVP_PKEY_CTX *OSSL_EVP_PKEY_CTX_new_id_t(int, ENGINE *); +typedef int OSSL_EVP_PKEY_keygen_init_t(EVP_PKEY_CTX *); +typedef int OSSL_EVP_PKEY_keygen_t(EVP_PKEY_CTX *, EVP_PKEY **); +typedef void OSSL_EVP_PKEY_CTX_free_t(EVP_PKEY_CTX *); +typedef int OSSL_EVP_PKEY_get_raw_private_key_t(const EVP_PKEY *, unsigned char *, size_t *); +typedef int OSSL_EVP_PKEY_get_raw_public_key_t(const EVP_PKEY *, unsigned char *, size_t *); +typedef EVP_PKEY *OSSL_EVP_PKEY_new_raw_private_key_t(int, ENGINE *, const unsigned char *, size_t); +typedef EVP_PKEY *OSSL_EVP_PKEY_new_raw_public_key_t(int, ENGINE *, const unsigned char *, size_t); +typedef int OSSL_EVP_PKEY_derive_init_t(EVP_PKEY_CTX *); +typedef int OSSL_EVP_PKEY_derive_set_peer_t(EVP_PKEY_CTX *, EVP_PKEY *); +typedef int OSSL_EVP_PKEY_derive_t(EVP_PKEY_CTX *, unsigned char *, size_t *); +typedef void OSSL_EVP_PKEY_free_t(EVP_PKEY *); + typedef int OSSL_PKCS12_key_gen_t(const char *, int, unsigned char *, int, int, int, int, unsigned char *, const EVP_MD *); typedef int OSSL_CRYPTO_num_locks_t(); @@ -261,6 +276,21 @@ OSSL_EC_KEY_check_key_t* OSSL_EC_KEY_check_key; EC_set_public_key_t* EC_set_public_key; OSSL_EC_KEY_get0_private_key_t *OSSL_EC_KEY_get0_private_key; +/* Define pointers for OpenSSL functions to handle XDH algorithm. */ +OSSL_EVP_PKEY_CTX_new_t *OSSL_EVP_PKEY_CTX_new; +OSSL_EVP_PKEY_CTX_new_id_t *OSSL_EVP_PKEY_CTX_new_id; +OSSL_EVP_PKEY_keygen_init_t *OSSL_EVP_PKEY_keygen_init; +OSSL_EVP_PKEY_keygen_t *OSSL_EVP_PKEY_keygen; +OSSL_EVP_PKEY_CTX_free_t *OSSL_EVP_PKEY_CTX_free; +OSSL_EVP_PKEY_get_raw_private_key_t *OSSL_EVP_PKEY_get_raw_private_key; +OSSL_EVP_PKEY_get_raw_public_key_t *OSSL_EVP_PKEY_get_raw_public_key; +OSSL_EVP_PKEY_new_raw_private_key_t *OSSL_EVP_PKEY_new_raw_private_key; +OSSL_EVP_PKEY_new_raw_public_key_t *OSSL_EVP_PKEY_new_raw_public_key; +OSSL_EVP_PKEY_derive_init_t *OSSL_EVP_PKEY_derive_init; +OSSL_EVP_PKEY_derive_set_peer_t *OSSL_EVP_PKEY_derive_set_peer; +OSSL_EVP_PKEY_derive_t *OSSL_EVP_PKEY_derive; +OSSL_EVP_PKEY_free_t *OSSL_EVP_PKEY_free; + /* Define pointers for OpenSSL functions to handle PBE algorithm. */ OSSL_PKCS12_key_gen_t* OSSL_PKCS12_key_gen; @@ -528,6 +558,37 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto OSSL_ECGF2M = JNI_TRUE; } + /* Load the functions symbols for OpenSSL XDH algorithm. (Need OpenSSL 1.1.x or above). */ + if (ossl_ver >= OPENSSL_VERSION_1_1_1) { + OSSL_EVP_PKEY_CTX_new = (OSSL_EVP_PKEY_CTX_new_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_CTX_new"); + OSSL_EVP_PKEY_CTX_new_id = (OSSL_EVP_PKEY_CTX_new_id_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_CTX_new_id"); + OSSL_EVP_PKEY_keygen_init = (OSSL_EVP_PKEY_keygen_init_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_keygen_init"); + OSSL_EVP_PKEY_keygen = (OSSL_EVP_PKEY_keygen_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_keygen"); + OSSL_EVP_PKEY_CTX_free = (OSSL_EVP_PKEY_CTX_free_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_CTX_free"); + OSSL_EVP_PKEY_get_raw_private_key = (OSSL_EVP_PKEY_get_raw_private_key_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_get_raw_private_key"); + OSSL_EVP_PKEY_get_raw_public_key = (OSSL_EVP_PKEY_get_raw_public_key_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_get_raw_public_key"); + OSSL_EVP_PKEY_new_raw_private_key = (OSSL_EVP_PKEY_new_raw_private_key_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_new_raw_private_key"); + OSSL_EVP_PKEY_new_raw_public_key = (OSSL_EVP_PKEY_new_raw_public_key_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_new_raw_public_key"); + OSSL_EVP_PKEY_derive_init = (OSSL_EVP_PKEY_derive_init_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_derive_init"); + OSSL_EVP_PKEY_derive_set_peer = (OSSL_EVP_PKEY_derive_set_peer_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_derive_set_peer"); + OSSL_EVP_PKEY_derive = (OSSL_EVP_PKEY_derive_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_derive"); + OSSL_EVP_PKEY_free = (OSSL_EVP_PKEY_free_t *)find_crypto_symbol(crypto_library, "EVP_PKEY_free"); + } else { + OSSL_EVP_PKEY_CTX_new = NULL; + OSSL_EVP_PKEY_CTX_new_id = NULL; + OSSL_EVP_PKEY_keygen_init = NULL; + OSSL_EVP_PKEY_keygen = NULL; + OSSL_EVP_PKEY_CTX_free = NULL; + OSSL_EVP_PKEY_get_raw_private_key = NULL; + OSSL_EVP_PKEY_get_raw_public_key = NULL; + OSSL_EVP_PKEY_new_raw_private_key = NULL; + OSSL_EVP_PKEY_new_raw_public_key = NULL; + OSSL_EVP_PKEY_derive_init = NULL; + OSSL_EVP_PKEY_derive_set_peer = NULL; + OSSL_EVP_PKEY_derive = NULL; + OSSL_EVP_PKEY_free = NULL; + } + /* Load the functions symbols for OpenSSL PBE algorithm. */ OSSL_PKCS12_key_gen = (OSSL_PKCS12_key_gen_t*)find_crypto_symbol(crypto_library, "PKCS12_key_gen_uni"); @@ -596,6 +657,21 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto (NULL == OSSL_EC_KEY_set_public_key) || (NULL == OSSL_EC_KEY_check_key) || (NULL == OSSL_PKCS12_key_gen) || + /* Check symbols that are only available in OpenSSL 1.1.1 and above. */ + ((ossl_ver >= OPENSSL_VERSION_1_1_1) && + ((NULL == OSSL_EVP_PKEY_get_raw_private_key) || + (NULL == OSSL_EVP_PKEY_get_raw_public_key) || + (NULL == OSSL_EVP_PKEY_new_raw_private_key) || + (NULL == OSSL_EVP_PKEY_new_raw_public_key) || + (NULL == OSSL_EVP_PKEY_CTX_new) || + (NULL == OSSL_EVP_PKEY_CTX_new_id) || + (NULL == OSSL_EVP_PKEY_keygen_init) || + (NULL == OSSL_EVP_PKEY_keygen) || + (NULL == OSSL_EVP_PKEY_CTX_free) || + (NULL == OSSL_EVP_PKEY_derive_init) || + (NULL == OSSL_EVP_PKEY_derive_set_peer) || + (NULL == OSSL_EVP_PKEY_derive) || + (NULL == OSSL_EVP_PKEY_free))) || /* Check symbols that are only available in OpenSSL 1.1.x and above */ ((ossl_ver >= OPENSSL_VERSION_1_1_0) && ((NULL == OSSL_chacha20) || (NULL == OSSL_chacha20_poly1305))) || /* Check symbols that are only available in OpenSSL 1.0.x and above */ @@ -604,10 +680,11 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto ((NULL == OSSL_OPENSSL_malloc) && (ossl_ver < OPENSSL_VERSION_1_1_0)) || ((NULL == OSSL_OPENSSL_free) && (ossl_ver < OPENSSL_VERSION_1_1_0)) || ((NULL == OSSL_CRYPTO_THREADID_set_callback) && (ossl_ver < OPENSSL_VERSION_1_1_0)) || - ((NULL == OSSL_CRYPTO_set_locking_callback) && (ossl_ver < OPENSSL_VERSION_1_1_0))) { - if (trace) { - fprintf(stderr, "Error loading OpenSSL: One or more of the required symbols are missing in the crypto library: %s\n", openssl_version); - } + ((NULL == OSSL_CRYPTO_set_locking_callback) && (ossl_ver < OPENSSL_VERSION_1_1_0)) + ) { + if (trace) { + fprintf(stderr, "Error loading OpenSSL: One or more of the required symbols are missing in the crypto library: %s\n", openssl_version); + } unload_crypto_library(crypto_library); crypto_library = NULL; return -1; @@ -3054,3 +3131,163 @@ Java_jdk_crypto_jniprovider_NativeCrypto_PBEDerive return ret; } + +/* Create a pair of private and public keys for XDH Key Agreement. + * + * Class: jdk_crypto_jniprovider_NativeCrypto + * Method: XDHCreateKeys + * Signature: ([BI[BII)I + */ +JNIEXPORT jint JNICALL +Java_jdk_crypto_jniprovider_NativeCrypto_XDHCreateKeys + (JNIEnv *env, jclass obj, jbyteArray privateKey, jint privateKeyLength, jbyteArray publicKey, jint publicKeyLength, jint curveType) +{ + jint ret = -1; + + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *pctx = NULL; + + size_t priv_len = (size_t)privateKeyLength; + size_t pub_len = (size_t)publicKeyLength; + + unsigned char *privateKeyArray = NULL; + unsigned char *publicKeyArray = NULL; + + // Create PKEY (public/private pair) based on curve type (X25519 or X448) + pctx = (*OSSL_EVP_PKEY_CTX_new_id)(curveType, NULL); + + if (NULL == pctx) { + goto cleanup; + } + + (*OSSL_EVP_PKEY_keygen_init)(pctx); + (*OSSL_EVP_PKEY_keygen)(pctx, &pkey); + + if (NULL == pkey) { + goto cleanup; + } + + // Separate private and public and store into arrays + privateKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, privateKey, 0)); + if (NULL == privateKeyArray) { + goto cleanup; + } + publicKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, publicKey, 0)); + if (NULL == publicKeyArray) { + goto cleanup; + } + + if (0 >= (*OSSL_EVP_PKEY_get_raw_private_key)(pkey, privateKeyArray, &priv_len)) { + goto cleanup; + } + if (0 >= (*OSSL_EVP_PKEY_get_raw_public_key)(pkey, publicKeyArray, &pub_len)) { + goto cleanup; + } + + ret = 0; + +cleanup: + if (NULL != publicKeyArray) { + (*env)->ReleasePrimitiveArrayCritical(env, publicKey, publicKeyArray, 0); + } + if (NULL != privateKeyArray) { + (*env)->ReleasePrimitiveArrayCritical(env, privateKey, privateKeyArray, 0); + } + if (NULL != pkey) { + (*OSSL_EVP_PKEY_free)(pkey); + } + if (NULL != pctx) { + (*OSSL_EVP_PKEY_CTX_free)(pctx); + } + return ret; +} + +/* XDH key agreement, derive shared secret key. + * + * Class: jdk_crypto_jniprovider_NativeCrypto + * Method: XDHGenerateSecret + * Signature: ([BI[BI[BII)I + */ +JNIEXPORT jint JNICALL +Java_jdk_crypto_jniprovider_NativeCrypto_XDHGenerateSecret + (JNIEnv *env, jclass obj, jbyteArray privateKey, jint privateKeyLength, jbyteArray publicKey, jint publicKeyLength, jbyteArray sharedKey, jint sharedKeyLength, jint curveType) +{ + jint ret = -1; + + EVP_PKEY_CTX *pctx = NULL; + + EVP_PKEY *pkey = NULL; + EVP_PKEY *peerkey = NULL; + + size_t skeylen = (size_t)sharedKeyLength; + size_t privateKey_len = (size_t)privateKeyLength; + size_t publicKey_len = (size_t)publicKeyLength; + + unsigned char *privateKeyArray = NULL; + unsigned char *publicKeyArray = NULL; + unsigned char *sharedKeyArray = NULL; + + privateKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, privateKey, 0)); + if (NULL == privateKeyArray) { + goto cleanup; + } + publicKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, publicKey, 0)); + if (NULL == publicKeyArray) { + goto cleanup; + } + + // Setup EVP_PKEY instances for user private and peer public keys + pkey = (*OSSL_EVP_PKEY_new_raw_private_key)(curveType, NULL, privateKeyArray, privateKey_len); + peerkey = (*OSSL_EVP_PKEY_new_raw_public_key)(curveType, NULL, publicKeyArray, publicKey_len); + + if ((NULL == pkey) || (NULL == peerkey)) { + goto cleanup; + } + + // Create key agreement context + pctx = (*OSSL_EVP_PKEY_CTX_new)(pkey, NULL); + if (NULL == pctx) { + goto cleanup; + } + + // Initialize with user private key + if (0 >= (*OSSL_EVP_PKEY_derive_init)(pctx)) { + goto cleanup; + } + + // Set peer's public key + if (0 >= (*OSSL_EVP_PKEY_derive_set_peer)(pctx, peerkey)) { + goto cleanup; + } + + // Derive shared secret and save in sharedKeyArray + sharedKeyArray = (unsigned char *)((*env)->GetPrimitiveArrayCritical(env, sharedKey, 0)); + if (NULL == sharedKeyArray) { + goto cleanup; + } + if (0 >= (*OSSL_EVP_PKEY_derive)(pctx, sharedKeyArray, &skeylen)) { + goto cleanup; + } + + ret = 0; +cleanup: + if (NULL != sharedKeyArray) { + (*env)->ReleasePrimitiveArrayCritical(env, sharedKey, sharedKeyArray, 0); + } + if (NULL != pctx) { + (*OSSL_EVP_PKEY_CTX_free)(pctx); + } + if (NULL != peerkey) { + (*OSSL_EVP_PKEY_free)(peerkey); + } + if (NULL != pkey) { + (*OSSL_EVP_PKEY_free)(pkey); + } + if (NULL != publicKeyArray) { + (*env)->ReleasePrimitiveArrayCritical(env, publicKey, publicKeyArray, 0); + } + if (NULL != privateKeyArray) { + (*env)->ReleasePrimitiveArrayCritical(env, privateKey, privateKeyArray, 0); + } + return ret; +} diff --git a/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyAgreement.java b/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyAgreement.java new file mode 100644 index 00000000000..b74e1f6a063 --- /dev/null +++ b/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyAgreement.java @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved + * =========================================================================== + */ + +package sun.security.ec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.SecureRandom; +import java.security.interfaces.XECPrivateKey; +import java.security.interfaces.XECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; + +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.SecretKeySpec; + +import jdk.crypto.jniprovider.NativeCrypto; + +import sun.security.x509.X509Key; + +public class NativeXDHKeyAgreement extends KeyAgreementSpi { + private static NativeCrypto nativeCrypto; + private static final boolean nativeCryptTrace = NativeCrypto.isTraceEnabled(); + + private XECPrivateKey xecPrivateKey; + private byte[] privateKey; + private byte[] secret; + private XECOperations ops; + private final XECParameters lockedParams; + + private XDHKeyAgreement javaImplementation; + + public NativeXDHKeyAgreement() { + lockedParams = null; + } + + public NativeXDHKeyAgreement(AlgorithmParameterSpec paramSpec) { + lockedParams = XECParameters.get(ProviderException::new, paramSpec); + } + + @Override + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException { + + initImpl(key); + } + + @Override + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException { + + initImpl(key); + + // The private key parameters must match params, if present. + if (params != null) { + XECParameters xecParams = XECParameters.get( + InvalidAlgorithmParameterException::new, params); + if (!xecParams.oidEquals(ops.getParameters())) { + throw new InvalidKeyException("Incorrect private key parameters"); + } + } + } + + private void initImpl(Key key) throws InvalidKeyException { + + if (!(key instanceof XECPrivateKey)) { + throw new InvalidKeyException("Unsupported key type"); + } + xecPrivateKey = (XECPrivateKey) key; + XECParameters xecParams = XECParameters.get( + InvalidKeyException::new, xecPrivateKey.getParams()); + + if ((lockedParams != null) && (lockedParams != xecParams)) { + throw new InvalidKeyException("Parameters must be " + lockedParams.getName()); + } + + ops = new XECOperations(xecParams); + privateKey = xecPrivateKey.getScalar() + .orElseThrow(() -> new InvalidKeyException("No private key value")); + secret = null; + + if (!NativeCrypto.isAllowedAndLoaded()) { + if (nativeCryptTrace) { + System.err.println("OpenSSL library not loaded." + + " Using Java crypto implementation to generate secret."); + } + initializeJavaImplementation(); + } else { + /* Assign ID used by OpenSSL for different curves. */ + int curveType; + if (isX25519(ops.getParameters())) { + curveType = NativeCrypto.X25519; + } else { + curveType = NativeCrypto.X448; + } + + if ((curveType == NativeCrypto.X448) + && (NativeCrypto.getVersionIfAvailable() < NativeCrypto.OPENSSL_VERSION_3_0_0) + ) { + if (nativeCryptTrace) { + System.err.println("OpenSSL version too old for X448 key agreement (<3.x)," + + " using Java crypto implementation."); + } + initializeJavaImplementation(); + } + } + } + + @Override + protected Key engineDoPhase(Key key, boolean lastPhase) + throws InvalidKeyException, IllegalStateException { + byte[] computedSecret; + if (javaImplementation != null) { + computedSecret = javaImplComputeSecret(key, lastPhase); + } else { + if (privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (secret != null) { + throw new IllegalStateException("Phase already executed"); + } + if (!lastPhase) { + throw new IllegalStateException( + "Only two party agreement supported, lastPhase must be true"); + } + + if (!(key instanceof XDHPublicKeyImpl)) { + throw new InvalidKeyException("Unsupported key type"); + } + + XDHPublicKeyImpl publicKey = (XDHPublicKeyImpl) key; + + // Ensure public key parameters are compatible with private key. + XECParameters xecParams = XECParameters.get(InvalidKeyException::new, + publicKey.getParams()); + if (!ops.getParameters().oidEquals(xecParams)) { + throw new InvalidKeyException( + "Public key parameters are not compatible with private key."); + } + + /* Assign ID used by OpenSSL for different curves. */ + int curveType; + if (isX25519(ops.getParameters())) { + curveType = NativeCrypto.X25519; + } else { + curveType = NativeCrypto.X448; + } + + byte[] publicKeyArray = publicKey.getKeyAsByteArray(); + computedSecret = new byte[ops.getParameters().getBytes()]; + + if (nativeCrypto == null) { + nativeCrypto = NativeCrypto.getNativeCrypto(); + } + int result = nativeCrypto.XDHGenerateSecret(privateKey, privateKey.length, + publicKeyArray, publicKeyArray.length, + computedSecret, computedSecret.length, + curveType); + + if (result == -1) { + if (nativeCryptTrace) { + System.err.println("Shared secret generation by OpenSSL failed," + + " using Java crypto implementation."); + } + computedSecret = javaImplComputeSecret(key, lastPhase); + } + } + + // Test for contributory behavior. + if (allZero(computedSecret)) { + throw new InvalidKeyException("Point has small order"); + } + + secret = computedSecret; + return null; + } + + /* + * Constant-time check for an all-zero array. + */ + private static boolean allZero(byte[] arr) { + byte orValue = (byte) 0; + for (int i = 0; i < arr.length; i++) { + orValue |= arr[i]; + } + + return orValue == (byte) 0; + } + + @Override + protected byte[] engineGenerateSecret() throws IllegalStateException { + byte[] result = secret; + if (result == null) { + throw new IllegalStateException("Not initialized correctly"); + } + secret = null; + return result; + } + + @Override + protected int engineGenerateSecret(byte[] sharedSecret, int offset) + throws IllegalStateException, ShortBufferException { + + if (secret == null) { + throw new IllegalStateException("Not initialized correctly"); + } + int secretLen = secret.length; + if (secretLen > sharedSecret.length - offset) { + throw new ShortBufferException("Need " + secretLen + + " bytes, only " + (sharedSecret.length - offset) + + " available"); + } + + System.arraycopy(secret, 0, sharedSecret, offset, secretLen); + secret = null; + return secretLen; + } + + @Override + protected SecretKey engineGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + + if (algorithm == null) { + throw new NoSuchAlgorithmException("Algorithm must not be null"); + } + + if (!(algorithm.equals("TlsPremasterSecret"))) { + throw new NoSuchAlgorithmException("Only supported for algorithm TlsPremasterSecret"); + } + return new SecretKeySpec(engineGenerateSecret(), algorithm); + } + + /* + * Initializes the java implementation. + * + * Already set parameters are used to specify the curve type + * and previously set private key is used to initialize the + * engine. + */ + private void initializeJavaImplementation() throws InvalidKeyException { + synchronized (this) { + if (lockedParams == null) { + javaImplementation = new XDHKeyAgreement(); + } else { + if (isX25519(lockedParams)) { + javaImplementation = new XDHKeyAgreement.X25519(); + } else { + javaImplementation = new XDHKeyAgreement.X448(); + } + } + javaImplementation.engineInit(xecPrivateKey, null); + } + } + + /** + * Utilizes the java implementation to compute the shared secret. + * + * @param key the public key + * @param lastPhase value indicating whether this is the last phase + */ + private byte[] javaImplComputeSecret(Key key, boolean lastPhase) throws InvalidKeyException { + if (javaImplementation == null) { + initializeJavaImplementation(); + } + javaImplementation.engineDoPhase(key, lastPhase); + return javaImplementation.engineGenerateSecret(); + } + + private static boolean isX25519(XECParameters parameters) { + return "X25519".equals(parameters.getName()); + } + + static final class X25519 extends NativeXDHKeyAgreement { + public X25519() { + super(NamedParameterSpec.X25519); + } + } + + static final class X448 extends NativeXDHKeyAgreement { + public X448() { + super(NamedParameterSpec.X448); + } + } +} diff --git a/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyPairGenerator.java b/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyPairGenerator.java new file mode 100644 index 00000000000..2ea9b88b7c5 --- /dev/null +++ b/closed/src/jdk.crypto.ec/share/classes/sun/security/ec/NativeXDHKeyPairGenerator.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved + * =========================================================================== + */ + +package sun.security.ec; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGeneratorSpi; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; + +import jdk.crypto.jniprovider.NativeCrypto; + +import sun.security.util.BitArray; +import sun.security.x509.AlgorithmId; +import sun.security.x509.X509Key; + +public class NativeXDHKeyPairGenerator extends KeyPairGeneratorSpi { + private static NativeCrypto nativeCrypto; + private static final boolean nativeCryptTrace = NativeCrypto.isTraceEnabled(); + + private SecureRandom random; + private XECOperations ops; + private final XECParameters lockedParams; + + private XDHKeyPairGenerator javaImplementation; + + public NativeXDHKeyPairGenerator() { + tryInitialize(NamedParameterSpec.X25519); + lockedParams = null; + } + + private NativeXDHKeyPairGenerator(NamedParameterSpec paramSpec) { + tryInitialize(paramSpec); + lockedParams = ops.getParameters(); + } + + private void tryInitialize(NamedParameterSpec paramSpec) { + try { + initialize(paramSpec, null); + } catch (InvalidAlgorithmParameterException ex) { + String name = paramSpec.getName(); + throw new ProviderException(name + " not supported"); + } + } + + @Override + public void initialize(int keySize, SecureRandom random) { + XECParameters params = XECParameters.getBySize( + InvalidParameterException::new, keySize); + + initializeImpl(params, random); + } + + @Override + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException { + + XECParameters xecParams = XECParameters.get( + InvalidAlgorithmParameterException::new, params); + + initializeImpl(xecParams, random); + } + + private void initializeImpl(XECParameters params, SecureRandom random) { + + if ((lockedParams != null) && (lockedParams != params)) { + throw new InvalidParameterException( + "Parameters must be " + lockedParams.getName()); + } + + ops = new XECOperations(params); + } + + @Override + public KeyPair generateKeyPair() { + /* If library isn't loaded, use Java implementation. */ + if (!NativeCrypto.isAllowedAndLoaded()) { + if (nativeCryptTrace) { + System.err.println("OpenSSL library not loaded. Using Java crypto implementation to generate KeyPair."); + } + return javaImplGenerateKeyPair(); + } + + XECParameters params; + if (lockedParams != null) { + params = lockedParams; + } else { + params = ops.getParameters(); + } + + /* Find ID used by OpenSSL for different curves. */ + int curveType; + if (isX25519(params)) { + curveType = NativeCrypto.X25519; + } else { + curveType = NativeCrypto.X448; + } + + /* Create empty byte arrays for private and public keys. */ + byte[] privateKey = new byte[params.getBytes()]; + byte[] publicKey = new byte[params.getBytes()]; + + if (nativeCrypto == null) { + nativeCrypto = NativeCrypto.getNativeCrypto(); + } + + /* Compute private and public keys. */ + int result = nativeCrypto.XDHCreateKeys(privateKey, privateKey.length, publicKey, publicKey.length, curveType); + + /* If OpenSSL method fails, revert to Java implementation. */ + if (result == -1) { + if (nativeCryptTrace) { + System.err.println("KeyPair generation by OpenSSL failed, using Java crypto implementation."); + } + return javaImplGenerateKeyPair(); + } + try { + reverse(publicKey); + + // Clear the extra bits. + int bitsMod8 = params.getBits() % 8; + if (bitsMod8 != 0) { + int mask = (1 << bitsMod8) - 1; + publicKey[0] &= (byte) mask; + } + + BigInteger u = new BigInteger(1, publicKey); + + return new KeyPair( + new XDHPublicKeyImpl(params, u), + new XDHPrivateKeyImpl(params, privateKey) + ); + } catch (InvalidKeyException ex) { + throw new ProviderException(ex); + } + } + + /* + * Initializes the java implementation. + * Already set parameters are used to specify the curve type. + */ + private void initializeJavaImplementation() { + if (javaImplementation == null) { + if (isX25519(ops.getParameters())) { + javaImplementation = new XDHKeyPairGenerator.X25519(); + } else { + javaImplementation = new XDHKeyPairGenerator.X448(); + } + } + } + + /* + * Uses the java implementation to generate a KeyPair. + */ + private KeyPair javaImplGenerateKeyPair() { + initializeJavaImplementation(); + return javaImplementation.generateKeyPair(); + } + + private static void swap(byte[] arr, int i, int j) { + byte tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + private static void reverse(byte[] arr) { + int i = 0; + int j = arr.length - 1; + + while (i < j) { + swap(arr, i, j); + i++; + j--; + } + } + + private static boolean isX25519(XECParameters parameters) { + return "X25519".equals(parameters.getName()); + } + + static final class X25519 extends NativeXDHKeyPairGenerator { + public X25519() { + super(NamedParameterSpec.X25519); + } + } + + static final class X448 extends NativeXDHKeyPairGenerator { + public X448() { + super(NamedParameterSpec.X448); + } + } +} diff --git a/doc/building.html b/doc/building.html index f1f9047808b..54828da9991 100644 --- a/doc/building.html +++ b/doc/building.html @@ -80,6 +80,7 @@

Building the JDK

id="toc-external-library-requirements">External Library Requirements