src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
changeset 47216 71c04702a3d5
parent 46041 d8e68e273172
child 50471 f0aeede1b855
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 #include <jni.h>
       
    27 #include "jni_util.h"
       
    28 #include "impl/ecc_impl.h"
       
    29 
       
    30 #define ILLEGAL_STATE_EXCEPTION "java/lang/IllegalStateException"
       
    31 #define INVALID_ALGORITHM_PARAMETER_EXCEPTION \
       
    32         "java/security/InvalidAlgorithmParameterException"
       
    33 #define INVALID_PARAMETER_EXCEPTION \
       
    34         "java/security/InvalidParameterException"
       
    35 #define KEY_EXCEPTION   "java/security/KeyException"
       
    36 
       
    37 extern "C" {
       
    38 
       
    39 /*
       
    40  * Declare library specific JNI_Onload entry if static build
       
    41  */
       
    42 DEF_STATIC_JNI_OnLoad
       
    43 
       
    44 /*
       
    45  * Throws an arbitrary Java exception.
       
    46  */
       
    47 void ThrowException(JNIEnv *env, const char *exceptionName)
       
    48 {
       
    49     jclass exceptionClazz = env->FindClass(exceptionName);
       
    50     if (exceptionClazz != NULL) {
       
    51         env->ThrowNew(exceptionClazz, NULL);
       
    52     }
       
    53 }
       
    54 
       
    55 /*
       
    56  * Deep free of the ECParams struct
       
    57  */
       
    58 void FreeECParams(ECParams *ecparams, jboolean freeStruct)
       
    59 {
       
    60     // Use B_FALSE to free the SECItem->data element, but not the SECItem itself
       
    61     // Use B_TRUE to free both
       
    62 
       
    63     SECITEM_FreeItem(&ecparams->fieldID.u.prime, B_FALSE);
       
    64     SECITEM_FreeItem(&ecparams->curve.a, B_FALSE);
       
    65     SECITEM_FreeItem(&ecparams->curve.b, B_FALSE);
       
    66     SECITEM_FreeItem(&ecparams->curve.seed, B_FALSE);
       
    67     SECITEM_FreeItem(&ecparams->base, B_FALSE);
       
    68     SECITEM_FreeItem(&ecparams->order, B_FALSE);
       
    69     SECITEM_FreeItem(&ecparams->DEREncoding, B_FALSE);
       
    70     SECITEM_FreeItem(&ecparams->curveOID, B_FALSE);
       
    71     if (freeStruct)
       
    72         free(ecparams);
       
    73 }
       
    74 
       
    75 jbyteArray getEncodedBytes(JNIEnv *env, SECItem *hSECItem)
       
    76 {
       
    77     SECItem *s = (SECItem *)hSECItem;
       
    78 
       
    79     jbyteArray jEncodedBytes = env->NewByteArray(s->len);
       
    80     if (jEncodedBytes == NULL) {
       
    81         return NULL;
       
    82     }
       
    83     // Copy bytes from a native SECItem buffer to Java byte array
       
    84     env->SetByteArrayRegion(jEncodedBytes, 0, s->len, (jbyte *)s->data);
       
    85     if (env->ExceptionCheck()) { // should never happen
       
    86         return NULL;
       
    87     }
       
    88     return jEncodedBytes;
       
    89 }
       
    90 
       
    91 /*
       
    92  * Class:     sun_security_ec_ECKeyPairGenerator
       
    93  * Method:    isCurveSupported
       
    94  * Signature: ([B)Z
       
    95  */
       
    96 JNIEXPORT jboolean
       
    97 JNICALL Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported
       
    98   (JNIEnv *env, jclass clazz, jbyteArray encodedParams)
       
    99 {
       
   100     SECKEYECParams params_item;
       
   101     ECParams *ecparams = NULL;
       
   102     jboolean result = JNI_FALSE;
       
   103 
       
   104     // The curve is supported if we can get parameters for it
       
   105     params_item.len = env->GetArrayLength(encodedParams);
       
   106     params_item.data =
       
   107         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   108     if (params_item.data == NULL) {
       
   109         goto cleanup;
       
   110     }
       
   111 
       
   112     // Fill a new ECParams using the supplied OID
       
   113     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   114         /* bad curve OID */
       
   115         goto cleanup;
       
   116     }
       
   117 
       
   118     // If we make it to here, then the curve is supported
       
   119     result = JNI_TRUE;
       
   120 
       
   121 cleanup:
       
   122     {
       
   123         if (params_item.data) {
       
   124             env->ReleaseByteArrayElements(encodedParams,
       
   125                 (jbyte *) params_item.data, JNI_ABORT);
       
   126         }
       
   127         if (ecparams) {
       
   128             FreeECParams(ecparams, true);
       
   129         }
       
   130     }
       
   131 
       
   132     return result;
       
   133 }
       
   134 
       
   135 /*
       
   136  * Class:     sun_security_ec_ECKeyPairGenerator
       
   137  * Method:    generateECKeyPair
       
   138  * Signature: (I[B[B)[[B
       
   139  */
       
   140 JNIEXPORT jobjectArray
       
   141 JNICALL Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair
       
   142   (JNIEnv *env, jclass clazz, jint keySize, jbyteArray encodedParams, jbyteArray seed)
       
   143 {
       
   144     ECPrivateKey *privKey = NULL; // contains both public and private values
       
   145     ECParams *ecparams = NULL;
       
   146     SECKEYECParams params_item;
       
   147     jint jSeedLength;
       
   148     jbyte* pSeedBuffer = NULL;
       
   149     jobjectArray result = NULL;
       
   150     jclass baCls = NULL;
       
   151     jbyteArray jba;
       
   152 
       
   153     // Initialize the ECParams struct
       
   154     params_item.len = env->GetArrayLength(encodedParams);
       
   155     params_item.data =
       
   156         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   157     if (params_item.data == NULL) {
       
   158         goto cleanup;
       
   159     }
       
   160 
       
   161     // Fill a new ECParams using the supplied OID
       
   162     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   163         /* bad curve OID */
       
   164         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   165         goto cleanup;
       
   166     }
       
   167 
       
   168     // Copy seed from Java to native buffer
       
   169     jSeedLength = env->GetArrayLength(seed);
       
   170     pSeedBuffer = new jbyte[jSeedLength];
       
   171     env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
       
   172 
       
   173     // Generate the new keypair (using the supplied seed)
       
   174     if (EC_NewKey(ecparams, &privKey, (unsigned char *) pSeedBuffer,
       
   175         jSeedLength, 0) != SECSuccess) {
       
   176         ThrowException(env, KEY_EXCEPTION);
       
   177         goto cleanup;
       
   178     }
       
   179 
       
   180     jboolean isCopy;
       
   181     baCls = env->FindClass("[B");
       
   182     if (baCls == NULL) {
       
   183         goto cleanup;
       
   184     }
       
   185     result = env->NewObjectArray(2, baCls, NULL);
       
   186     if (result == NULL) {
       
   187         goto cleanup;
       
   188     }
       
   189     jba = getEncodedBytes(env, &(privKey->privateValue));
       
   190     if (jba == NULL) {
       
   191         result = NULL;
       
   192         goto cleanup;
       
   193     }
       
   194     env->SetObjectArrayElement(result, 0, jba); // big integer
       
   195     if (env->ExceptionCheck()) { // should never happen
       
   196         result = NULL;
       
   197         goto cleanup;
       
   198     }
       
   199 
       
   200     jba = getEncodedBytes(env, &(privKey->publicValue));
       
   201     if (jba == NULL) {
       
   202         result = NULL;
       
   203         goto cleanup;
       
   204     }
       
   205     env->SetObjectArrayElement(result, 1, jba); // encoded ec point
       
   206     if (env->ExceptionCheck()) { // should never happen
       
   207         result = NULL;
       
   208         goto cleanup;
       
   209     }
       
   210 
       
   211 cleanup:
       
   212     {
       
   213         if (params_item.data) {
       
   214             env->ReleaseByteArrayElements(encodedParams,
       
   215                 (jbyte *) params_item.data, JNI_ABORT);
       
   216         }
       
   217         if (ecparams) {
       
   218             FreeECParams(ecparams, true);
       
   219         }
       
   220         if (privKey) {
       
   221             FreeECParams(&privKey->ecParams, false);
       
   222             SECITEM_FreeItem(&privKey->version, B_FALSE);
       
   223             SECITEM_FreeItem(&privKey->privateValue, B_FALSE);
       
   224             SECITEM_FreeItem(&privKey->publicValue, B_FALSE);
       
   225             free(privKey);
       
   226         }
       
   227 
       
   228         if (pSeedBuffer) {
       
   229             delete [] pSeedBuffer;
       
   230         }
       
   231     }
       
   232 
       
   233     return result;
       
   234 }
       
   235 
       
   236 /*
       
   237  * Class:     sun_security_ec_ECDSASignature
       
   238  * Method:    signDigest
       
   239  * Signature: ([B[B[B[B)[B
       
   240  */
       
   241 JNIEXPORT jbyteArray
       
   242 JNICALL Java_sun_security_ec_ECDSASignature_signDigest
       
   243   (JNIEnv *env, jclass clazz, jbyteArray digest, jbyteArray privateKey, jbyteArray encodedParams, jbyteArray seed, jint timing)
       
   244 {
       
   245     jbyte* pDigestBuffer = NULL;
       
   246     jint jDigestLength = env->GetArrayLength(digest);
       
   247     jbyteArray jSignedDigest = NULL;
       
   248 
       
   249     SECItem signature_item;
       
   250     jbyte* pSignedDigestBuffer = NULL;
       
   251     jbyteArray temp;
       
   252 
       
   253     jint jSeedLength = env->GetArrayLength(seed);
       
   254     jbyte* pSeedBuffer = NULL;
       
   255 
       
   256     // Copy digest from Java to native buffer
       
   257     pDigestBuffer = new jbyte[jDigestLength];
       
   258     env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
       
   259     SECItem digest_item;
       
   260     digest_item.data = (unsigned char *) pDigestBuffer;
       
   261     digest_item.len = jDigestLength;
       
   262 
       
   263     ECPrivateKey privKey;
       
   264     privKey.privateValue.data = NULL;
       
   265 
       
   266     // Initialize the ECParams struct
       
   267     ECParams *ecparams = NULL;
       
   268     SECKEYECParams params_item;
       
   269     params_item.len = env->GetArrayLength(encodedParams);
       
   270     params_item.data =
       
   271         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   272     if (params_item.data == NULL) {
       
   273         goto cleanup;
       
   274     }
       
   275 
       
   276     // Fill a new ECParams using the supplied OID
       
   277     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   278         /* bad curve OID */
       
   279         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   280         goto cleanup;
       
   281     }
       
   282 
       
   283     // Extract private key data
       
   284     privKey.ecParams = *ecparams; // struct assignment
       
   285     privKey.privateValue.len = env->GetArrayLength(privateKey);
       
   286     privKey.privateValue.data =
       
   287         (unsigned char *) env->GetByteArrayElements(privateKey, 0);
       
   288     if (privKey.privateValue.data == NULL) {
       
   289         goto cleanup;
       
   290     }
       
   291 
       
   292     // Prepare a buffer for the signature (twice the key length)
       
   293     pSignedDigestBuffer = new jbyte[ecparams->order.len * 2];
       
   294     signature_item.data = (unsigned char *) pSignedDigestBuffer;
       
   295     signature_item.len = ecparams->order.len * 2;
       
   296 
       
   297     // Copy seed from Java to native buffer
       
   298     pSeedBuffer = new jbyte[jSeedLength];
       
   299     env->GetByteArrayRegion(seed, 0, jSeedLength, pSeedBuffer);
       
   300 
       
   301     // Sign the digest (using the supplied seed)
       
   302     if (ECDSA_SignDigest(&privKey, &signature_item, &digest_item,
       
   303         (unsigned char *) pSeedBuffer, jSeedLength, 0, timing) != SECSuccess) {
       
   304         ThrowException(env, KEY_EXCEPTION);
       
   305         goto cleanup;
       
   306     }
       
   307 
       
   308     // Create new byte array
       
   309     temp = env->NewByteArray(signature_item.len);
       
   310     if (temp == NULL) {
       
   311         goto cleanup;
       
   312     }
       
   313 
       
   314     // Copy data from native buffer
       
   315     env->SetByteArrayRegion(temp, 0, signature_item.len, pSignedDigestBuffer);
       
   316     jSignedDigest = temp;
       
   317 
       
   318 cleanup:
       
   319     {
       
   320         if (params_item.data) {
       
   321             env->ReleaseByteArrayElements(encodedParams,
       
   322                 (jbyte *) params_item.data, JNI_ABORT);
       
   323         }
       
   324         if (privKey.privateValue.data) {
       
   325             env->ReleaseByteArrayElements(privateKey,
       
   326                 (jbyte *) privKey.privateValue.data, JNI_ABORT);
       
   327         }
       
   328         if (pDigestBuffer) {
       
   329             delete [] pDigestBuffer;
       
   330         }
       
   331         if (pSignedDigestBuffer) {
       
   332             delete [] pSignedDigestBuffer;
       
   333         }
       
   334         if (pSeedBuffer) {
       
   335             delete [] pSeedBuffer;
       
   336         }
       
   337         if (ecparams) {
       
   338             FreeECParams(ecparams, true);
       
   339         }
       
   340     }
       
   341 
       
   342     return jSignedDigest;
       
   343 }
       
   344 
       
   345 /*
       
   346  * Class:     sun_security_ec_ECDSASignature
       
   347  * Method:    verifySignedDigest
       
   348  * Signature: ([B[B[B[B)Z
       
   349  */
       
   350 JNIEXPORT jboolean
       
   351 JNICALL Java_sun_security_ec_ECDSASignature_verifySignedDigest
       
   352   (JNIEnv *env, jclass clazz, jbyteArray signedDigest, jbyteArray digest, jbyteArray publicKey, jbyteArray encodedParams)
       
   353 {
       
   354     jboolean isValid = false;
       
   355 
       
   356     // Copy signedDigest from Java to native buffer
       
   357     jbyte* pSignedDigestBuffer = NULL;
       
   358     jint jSignedDigestLength = env->GetArrayLength(signedDigest);
       
   359     pSignedDigestBuffer = new jbyte[jSignedDigestLength];
       
   360     env->GetByteArrayRegion(signedDigest, 0, jSignedDigestLength,
       
   361         pSignedDigestBuffer);
       
   362     SECItem signature_item;
       
   363     signature_item.data = (unsigned char *) pSignedDigestBuffer;
       
   364     signature_item.len = jSignedDigestLength;
       
   365 
       
   366     // Copy digest from Java to native buffer
       
   367     jbyte* pDigestBuffer = NULL;
       
   368     jint jDigestLength = env->GetArrayLength(digest);
       
   369     pDigestBuffer = new jbyte[jDigestLength];
       
   370     env->GetByteArrayRegion(digest, 0, jDigestLength, pDigestBuffer);
       
   371     SECItem digest_item;
       
   372     digest_item.data = (unsigned char *) pDigestBuffer;
       
   373     digest_item.len = jDigestLength;
       
   374 
       
   375     // Extract public key data
       
   376     ECPublicKey pubKey;
       
   377     pubKey.publicValue.data = NULL;
       
   378     ECParams *ecparams = NULL;
       
   379     SECKEYECParams params_item;
       
   380 
       
   381     // Initialize the ECParams struct
       
   382     params_item.len = env->GetArrayLength(encodedParams);
       
   383     params_item.data =
       
   384         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   385     if (params_item.data == NULL) {
       
   386         goto cleanup;
       
   387     }
       
   388 
       
   389     // Fill a new ECParams using the supplied OID
       
   390     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   391         /* bad curve OID */
       
   392         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   393         goto cleanup;
       
   394     }
       
   395     pubKey.ecParams = *ecparams; // struct assignment
       
   396     pubKey.publicValue.len = env->GetArrayLength(publicKey);
       
   397     pubKey.publicValue.data =
       
   398         (unsigned char *) env->GetByteArrayElements(publicKey, 0);
       
   399 
       
   400     if (ECDSA_VerifyDigest(&pubKey, &signature_item, &digest_item, 0)
       
   401             != SECSuccess) {
       
   402         goto cleanup;
       
   403     }
       
   404 
       
   405     isValid = true;
       
   406 
       
   407 cleanup:
       
   408     {
       
   409         if (params_item.data)
       
   410             env->ReleaseByteArrayElements(encodedParams,
       
   411                 (jbyte *) params_item.data, JNI_ABORT);
       
   412 
       
   413         if (pubKey.publicValue.data)
       
   414             env->ReleaseByteArrayElements(publicKey,
       
   415                 (jbyte *) pubKey.publicValue.data, JNI_ABORT);
       
   416 
       
   417         if (ecparams)
       
   418             FreeECParams(ecparams, true);
       
   419 
       
   420         if (pSignedDigestBuffer)
       
   421             delete [] pSignedDigestBuffer;
       
   422 
       
   423         if (pDigestBuffer)
       
   424             delete [] pDigestBuffer;
       
   425     }
       
   426 
       
   427     return isValid;
       
   428 }
       
   429 
       
   430 /*
       
   431  * Class:     sun_security_ec_ECDHKeyAgreement
       
   432  * Method:    deriveKey
       
   433  * Signature: ([B[B[B)[B
       
   434  */
       
   435 JNIEXPORT jbyteArray
       
   436 JNICALL Java_sun_security_ec_ECDHKeyAgreement_deriveKey
       
   437   (JNIEnv *env, jclass clazz, jbyteArray privateKey, jbyteArray publicKey, jbyteArray encodedParams)
       
   438 {
       
   439     jbyteArray jSecret = NULL;
       
   440     ECParams *ecparams = NULL;
       
   441     SECItem privateValue_item;
       
   442     privateValue_item.data = NULL;
       
   443     SECItem publicValue_item;
       
   444     publicValue_item.data = NULL;
       
   445     SECKEYECParams params_item;
       
   446     params_item.data = NULL;
       
   447 
       
   448     // Extract private key value
       
   449     privateValue_item.len = env->GetArrayLength(privateKey);
       
   450     privateValue_item.data =
       
   451             (unsigned char *) env->GetByteArrayElements(privateKey, 0);
       
   452     if (privateValue_item.data == NULL) {
       
   453         goto cleanup;
       
   454     }
       
   455 
       
   456     // Extract public key value
       
   457     publicValue_item.len = env->GetArrayLength(publicKey);
       
   458     publicValue_item.data =
       
   459         (unsigned char *) env->GetByteArrayElements(publicKey, 0);
       
   460     if (publicValue_item.data == NULL) {
       
   461         goto cleanup;
       
   462     }
       
   463 
       
   464     // Initialize the ECParams struct
       
   465     params_item.len = env->GetArrayLength(encodedParams);
       
   466     params_item.data =
       
   467         (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
       
   468     if (params_item.data == NULL) {
       
   469         goto cleanup;
       
   470     }
       
   471 
       
   472     // Fill a new ECParams using the supplied OID
       
   473     if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
       
   474         /* bad curve OID */
       
   475         ThrowException(env, INVALID_ALGORITHM_PARAMETER_EXCEPTION);
       
   476         goto cleanup;
       
   477     }
       
   478 
       
   479     // Prepare a buffer for the secret
       
   480     SECItem secret_item;
       
   481     secret_item.data = NULL;
       
   482     secret_item.len = ecparams->order.len * 2;
       
   483 
       
   484     if (ECDH_Derive(&publicValue_item, ecparams, &privateValue_item, B_FALSE,
       
   485         &secret_item, 0) != SECSuccess) {
       
   486         ThrowException(env, ILLEGAL_STATE_EXCEPTION);
       
   487         goto cleanup;
       
   488     }
       
   489 
       
   490     // Create new byte array
       
   491     jSecret = env->NewByteArray(secret_item.len);
       
   492     if (jSecret == NULL) {
       
   493         goto cleanup;
       
   494     }
       
   495 
       
   496     // Copy bytes from the SECItem buffer to a Java byte array
       
   497     env->SetByteArrayRegion(jSecret, 0, secret_item.len,
       
   498         (jbyte *)secret_item.data);
       
   499 
       
   500     // Free the SECItem data buffer
       
   501     SECITEM_FreeItem(&secret_item, B_FALSE);
       
   502 
       
   503 cleanup:
       
   504     {
       
   505         if (privateValue_item.data)
       
   506             env->ReleaseByteArrayElements(privateKey,
       
   507                 (jbyte *) privateValue_item.data, JNI_ABORT);
       
   508 
       
   509         if (publicValue_item.data)
       
   510             env->ReleaseByteArrayElements(publicKey,
       
   511                 (jbyte *) publicValue_item.data, JNI_ABORT);
       
   512 
       
   513         if (params_item.data)
       
   514             env->ReleaseByteArrayElements(encodedParams,
       
   515                 (jbyte *) params_item.data, JNI_ABORT);
       
   516 
       
   517         if (ecparams)
       
   518             FreeECParams(ecparams, true);
       
   519     }
       
   520 
       
   521     return jSecret;
       
   522 }
       
   523 
       
   524 } /* extern "C" */