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(¶ms_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(¶ms_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(¶ms_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(¶ms_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(¶ms_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" */