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