mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-28 07:41:10 +00:00
528 lines
16 KiB
C++
528 lines
16 KiB
C++
/*
|
|
* Copyright (c) 2009, 2018, 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.
|
|
*/
|
|
|
|
#include <jni.h>
|
|
#include "jni_util.h"
|
|
#include "impl/ecc_impl.h"
|
|
#include "sun_security_ec_ECDHKeyAgreement.h"
|
|
#include "sun_security_ec_ECKeyPairGenerator.h"
|
|
#include "sun_security_ec_ECDSASignature.h"
|
|
|
|
#define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
|
|
#define INVALID_ALGORITHM_PARAMETER_EXCEPTION \
|
|
"java/security/InvalidAlgorithmParameterException"
|
|
#define INVALID_PARAMETER_EXCEPTION \
|
|
"java/security/InvalidParameterException"
|
|
#define KEY_EXCEPTION "java/security/KeyException"
|
|
|
|
extern "C" {
|
|
|
|
/*
|
|
* Declare library specific JNI_Onload entry if static build
|
|
*/
|
|
DEF_STATIC_JNI_OnLoad
|
|
|
|
/*
|
|
* Throws an arbitrary Java exception.
|
|
*/
|
|
void ThrowException(JNIEnv *env, const char *exceptionName)
|
|
{
|
|
jclass exceptionClazz = env->FindClass(exceptionName);
|
|
if (exceptionClazz != NULL) {
|
|
env->ThrowNew(exceptionClazz, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Deep free of the ECParams struct
|
|
*/
|
|
void FreeECParams(ECParams *ecparams, jboolean freeStruct)
|
|
{
|
|
// Use B_FALSE to free the SECItem->data element, but not the SECItem itself
|
|
// Use B_TRUE to free both
|
|
|
|
SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->curve.a, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->curve.b, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->base, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->order, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE);
|
|
SECITEM_FreeItem(&ecparams->curveOID, B_FALSE);
|
|
if (freeStruct)
|
|
free(ecparams);
|
|
}
|
|
|
|
jbyteArray getEncodedBytes(JNIEnv *env, SECItem *hSECItem)
|
|
{
|
|
SECItem *s = (SECItem *)hSECItem;
|
|
|
|
jbyteArray jEncodedBytes = env->NewByteArray(s->len);
|
|
if (jEncodedBytes == NULL) {
|
|
return NULL;
|
|
}
|
|
// Copy bytes from a native SECItem buffer to Java byte array
|
|
env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
|
|
if (env->ExceptionCheck()) { // should never happen
|
|
return NULL;
|
|
}
|
|
return jEncodedBytes;
|
|
}
|
|
|
|
/*
|
|
* Class: sun_security_ec_ECKeyPairGenerator
|
|
* Method: isCurveSupported
|
|
* Signature: ([B)Z
|
|
*/
|
|
JNIEXPORT jboolean
|
|
JNICALL Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported
|
|
(JNIEnv *env, jclass clazz, jbyteArray encodedParams)
|
|
{
|
|
SECKEYECParams params_item;
|
|
ECParams *ecparams = NULL;
|
|
jboolean result = JNI_FALSE;
|
|
|
|
// The curve is supported if we can get parameters for it
|
|
params_item.len = env->GetArrayLength(encodedParams);
|
|
params_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
|
|
if (params_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Fill a new ECParams using the supplied OID
|
|
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
|
|
/* bad curve OID */
|
|
goto cleanup;
|
|
}
|
|
|
|
// If we make it to here, then the curve is supported
|
|
result = JNI_TRUE;
|
|
|
|
cleanup:
|
|
{
|
|
if (params_item.data) {
|
|
env->ReleaseByteArrayElements(encodedParams,
|
|
(jbyte *) params_item.data, JNI_ABORT);
|
|
}
|
|
if (ecparams) {
|
|
FreeECParams(ecparams, true);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Class: sun_security_ec_ECKeyPairGenerator
|
|
* Method: generateECKeyPair
|
|
* Signature: (I[B[B)[[B
|
|
*/
|
|
JNIEXPORT jobjectArray
|
|
JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
|
|
(JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
|
|
{
|
|
ECPrivateKey *privKey = NULL; // contains both public and private values
|
|
ECParams *ecparams = NULL;
|
|
SECKEYECParams params_item;
|
|
jint jSeedLength;
|
|
jbyte* pSeedBuffer = NULL;
|
|
jobjectArray result = NULL;
|
|
jclass baCls = NULL;
|
|
jbyteArray jba;
|
|
|
|
// Initialize the ECParams struct
|
|
params_item.len = env->GetArrayLength(encodedParams);
|
|
params_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
|
|
if (params_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Fill a new ECParams using the supplied OID
|
|
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
|
|
/* bad curve OID */
|
|
ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Copy seed from Java to native buffer
|
|
jSeedLength = env->GetArrayLength(seed);
|
|
pSeedBuffer = new jbyte[jSeedLength];
|
|
env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
|
|
|
|
// Generate the new keypair (using the supplied seed)
|
|
if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer,
|
|
jSeedLength, 0) != SECSuccess) {
|
|
ThrowException(env, KEY_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
jboolean isCopy;
|
|
baCls = env->FindClass("[B");
|
|
if (baCls == NULL) {
|
|
goto cleanup;
|
|
}
|
|
result = env->NewObjectArray(2, baCls, NULL);
|
|
if (result == NULL) {
|
|
goto cleanup;
|
|
}
|
|
jba = getEncodedBytes(env, &(privKey->privateValue));
|
|
if (jba == NULL) {
|
|
result = NULL;
|
|
goto cleanup;
|
|
}
|
|
env->SetObjectArrayElement(result, 0, jba); // big integer
|
|
if (env->ExceptionCheck()) { // should never happen
|
|
result = NULL;
|
|
goto cleanup;
|
|
}
|
|
|
|
jba = getEncodedBytes(env, &(privKey->publicValue));
|
|
if (jba == NULL) {
|
|
result = NULL;
|
|
goto cleanup;
|
|
}
|
|
env->SetObjectArrayElement(result, 1, jba); // encoded ec point
|
|
if (env->ExceptionCheck()) { // should never happen
|
|
result = NULL;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
{
|
|
if (params_item.data) {
|
|
env->ReleaseByteArrayElements(encodedParams,
|
|
(jbyte *) params_item.data, JNI_ABORT);
|
|
}
|
|
if (ecparams) {
|
|
FreeECParams(ecparams, true);
|
|
}
|
|
if (privKey) {
|
|
FreeECParams(&privKey->ecParams, false);
|
|
SECITEM_FreeItem(&privKey->version, B_FALSE);
|
|
SECITEM_FreeItem(&privKey->privateValue, B_FALSE);
|
|
SECITEM_FreeItem(&privKey->publicValue, B_FALSE);
|
|
free(privKey);
|
|
}
|
|
|
|
if (pSeedBuffer) {
|
|
delete [] pSeedBuffer;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Class: sun_security_ec_ECDSASignature
|
|
* Method: signDigest
|
|
* Signature: ([B[B[B[B)[B
|
|
*/
|
|
JNIEXPORT jbyteArray
|
|
JNICALL Java_sun_security_ec_ECDSASignature_signDigest
|
|
(JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing)
|
|
{
|
|
jbyte* pDigestBuffer = NULL;
|
|
jint jDigestLength = env->GetArrayLength(digest);
|
|
jbyteArray jSignedDigest = NULL;
|
|
|
|
SECItem signature_item;
|
|
jbyte* pSignedDigestBuffer = NULL;
|
|
jbyteArray temp;
|
|
|
|
jint jSeedLength = env->GetArrayLength(seed);
|
|
jbyte* pSeedBuffer = NULL;
|
|
|
|
// Copy digest from Java to native buffer
|
|
pDigestBuffer = new jbyte[jDigestLength];
|
|
env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
|
|
SECItem digest_item;
|
|
digest_item.data = (unsigned char *) pDigestBuffer;
|
|
digest_item.len = jDigestLength;
|
|
|
|
ECPrivateKey privKey;
|
|
privKey.privateValue.data = NULL;
|
|
|
|
// Initialize the ECParams struct
|
|
ECParams *ecparams = NULL;
|
|
SECKEYECParams params_item;
|
|
params_item.len = env->GetArrayLength(encodedParams);
|
|
params_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
|
|
if (params_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Fill a new ECParams using the supplied OID
|
|
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
|
|
/* bad curve OID */
|
|
ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Extract private key data
|
|
privKey.ecParams = *ecparams; // struct assignment
|
|
privKey.privateValue.len = env->GetArrayLength(privateKey);
|
|
privKey.privateValue.data =
|
|
(unsigned char *) env->GetByteArrayElements(privateKey, 0);
|
|
if (privKey.privateValue.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Prepare a buffer for the signature (twice the key length)
|
|
pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
|
|
signature_item.data = (unsigned char *) pSignedDigestBuffer;
|
|
signature_item.len = ecparams->order.len * 2;
|
|
|
|
// Copy seed from Java to native buffer
|
|
pSeedBuffer = new jbyte[jSeedLength];
|
|
env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
|
|
|
|
// Sign the digest (using the supplied seed)
|
|
if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
|
|
(unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) {
|
|
ThrowException(env, KEY_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Create new byte array
|
|
temp = env->NewByteArray(signature_item.len);
|
|
if (temp == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Copy data from native buffer
|
|
env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
|
|
jSignedDigest = temp;
|
|
|
|
cleanup:
|
|
{
|
|
if (params_item.data) {
|
|
env->ReleaseByteArrayElements(encodedParams,
|
|
(jbyte *) params_item.data, JNI_ABORT);
|
|
}
|
|
if (privKey.privateValue.data) {
|
|
env->ReleaseByteArrayElements(privateKey,
|
|
(jbyte *) privKey.privateValue.data, JNI_ABORT);
|
|
}
|
|
if (pDigestBuffer) {
|
|
delete [] pDigestBuffer;
|
|
}
|
|
if (pSignedDigestBuffer) {
|
|
delete [] pSignedDigestBuffer;
|
|
}
|
|
if (pSeedBuffer) {
|
|
delete [] pSeedBuffer;
|
|
}
|
|
if (ecparams) {
|
|
FreeECParams(ecparams, true);
|
|
}
|
|
}
|
|
|
|
return jSignedDigest;
|
|
}
|
|
|
|
/*
|
|
* Class: sun_security_ec_ECDSASignature
|
|
* Method: verifySignedDigest
|
|
* Signature: ([B[B[B[B)Z
|
|
*/
|
|
JNIEXPORT jboolean
|
|
JNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
|
|
(JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams)
|
|
{
|
|
jboolean isValid = false;
|
|
|
|
// Copy signedDigest from Java to native buffer
|
|
jbyte* pSignedDigestBuffer = NULL;
|
|
jint jSignedDigestLength = env->GetArrayLength(signedDigest);
|
|
pSignedDigestBuffer = new jbyte[jSignedDigestLength];
|
|
env->GetByteArrayRegion(signedDigest, 0, jSignedDigestLength,
|
|
pSignedDigestBuffer);
|
|
SECItem signature_item;
|
|
signature_item.data = (unsigned char *) pSignedDigestBuffer;
|
|
signature_item.len = jSignedDigestLength;
|
|
|
|
// Copy digest from Java to native buffer
|
|
jbyte* pDigestBuffer = NULL;
|
|
jint jDigestLength = env->GetArrayLength(digest);
|
|
pDigestBuffer = new jbyte[jDigestLength];
|
|
env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
|
|
SECItem digest_item;
|
|
digest_item.data = (unsigned char *) pDigestBuffer;
|
|
digest_item.len = jDigestLength;
|
|
|
|
// Extract public key data
|
|
ECPublicKey pubKey;
|
|
pubKey.publicValue.data = NULL;
|
|
ECParams *ecparams = NULL;
|
|
SECKEYECParams params_item;
|
|
|
|
// Initialize the ECParams struct
|
|
params_item.len = env->GetArrayLength(encodedParams);
|
|
params_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
|
|
if (params_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Fill a new ECParams using the supplied OID
|
|
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
|
|
/* bad curve OID */
|
|
ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
pubKey.ecParams = *ecparams; // struct assignment
|
|
pubKey.publicValue.len = env->GetArrayLength(publicKey);
|
|
pubKey.publicValue.data =
|
|
(unsigned char *) env->GetByteArrayElements(publicKey, 0);
|
|
|
|
if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0)
|
|
!= SECSuccess) {
|
|
goto cleanup;
|
|
}
|
|
|
|
isValid = true;
|
|
|
|
cleanup:
|
|
{
|
|
if (params_item.data)
|
|
env->ReleaseByteArrayElements(encodedParams,
|
|
(jbyte *) params_item.data, JNI_ABORT);
|
|
|
|
if (pubKey.publicValue.data)
|
|
env->ReleaseByteArrayElements(publicKey,
|
|
(jbyte *) pubKey.publicValue.data, JNI_ABORT);
|
|
|
|
if (ecparams)
|
|
FreeECParams(ecparams, true);
|
|
|
|
if (pSignedDigestBuffer)
|
|
delete [] pSignedDigestBuffer;
|
|
|
|
if (pDigestBuffer)
|
|
delete [] pDigestBuffer;
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/*
|
|
* Class: sun_security_ec_ECDHKeyAgreement
|
|
* Method: deriveKey
|
|
* Signature: ([B[B[B)[B
|
|
*/
|
|
JNIEXPORT jbyteArray
|
|
JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
|
|
(JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
|
|
{
|
|
jbyteArray jSecret = NULL;
|
|
ECParams *ecparams = NULL;
|
|
SECItem privateValue_item;
|
|
privateValue_item.data = NULL;
|
|
SECItem publicValue_item;
|
|
publicValue_item.data = NULL;
|
|
SECKEYECParams params_item;
|
|
params_item.data = NULL;
|
|
|
|
// Extract private key value
|
|
privateValue_item.len = env->GetArrayLength(privateKey);
|
|
privateValue_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(privateKey, 0);
|
|
if (privateValue_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Extract public key value
|
|
publicValue_item.len = env->GetArrayLength(publicKey);
|
|
publicValue_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(publicKey, 0);
|
|
if (publicValue_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Initialize the ECParams struct
|
|
params_item.len = env->GetArrayLength(encodedParams);
|
|
params_item.data =
|
|
(unsigned char *) env->GetByteArrayElements(encodedParams, 0);
|
|
if (params_item.data == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Fill a new ECParams using the supplied OID
|
|
if (EC_DecodeParams(¶ms_item, &ecparams, 0) != SECSuccess) {
|
|
/* bad curve OID */
|
|
ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Prepare a buffer for the secret
|
|
SECItem secret_item;
|
|
secret_item.data = NULL;
|
|
secret_item.len = ecparams->order.len * 2;
|
|
|
|
if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE,
|
|
&secret_item, 0) != SECSuccess) {
|
|
ThrowException(env, ILLEGAL_STATE_EXCEPTION);
|
|
goto cleanup;
|
|
}
|
|
|
|
// Create new byte array
|
|
jSecret = env->NewByteArray(secret_item.len);
|
|
if (jSecret == NULL) {
|
|
goto cleanup;
|
|
}
|
|
|
|
// Copy bytes from the SECItem buffer to a Java byte array
|
|
env->SetByteArrayRegion(jSecret, 0, secret_item.len,
|
|
(jbyte *)secret_item.data);
|
|
|
|
// Free the SECItem data buffer
|
|
SECITEM_FreeItem(&secret_item, B_FALSE);
|
|
|
|
cleanup:
|
|
{
|
|
if (privateValue_item.data)
|
|
env->ReleaseByteArrayElements(privateKey,
|
|
(jbyte *) privateValue_item.data, JNI_ABORT);
|
|
|
|
if (publicValue_item.data)
|
|
env->ReleaseByteArrayElements(publicKey,
|
|
(jbyte *) publicValue_item.data, JNI_ABORT);
|
|
|
|
if (params_item.data)
|
|
env->ReleaseByteArrayElements(encodedParams,
|
|
(jbyte *) params_item.data, JNI_ABORT);
|
|
|
|
if (ecparams)
|
|
FreeECParams(ecparams, true);
|
|
}
|
|
|
|
return jSecret;
|
|
}
|
|
|
|
} /* extern "C" */
|