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