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