Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2007-2008 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | /** |
| 18 | * Native glue for Java class org.conscrypt.NativeCrypto |
| 19 | */ |
| 20 | |
| 21 | #define TO_STRING1(x) #x |
| 22 | #define TO_STRING(x) TO_STRING1(x) |
| 23 | #ifndef JNI_JARJAR_PREFIX |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 24 | #ifndef CONSCRYPT_NOT_UNBUNDLED |
| 25 | #define CONSCRYPT_UNBUNDLED |
| 26 | #endif |
| 27 | #define JNI_JARJAR_PREFIX |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 28 | #endif |
| 29 | |
| 30 | #define LOG_TAG "NativeCrypto" |
| 31 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 32 | #include <arpa/inet.h> |
| 33 | #include <fcntl.h> |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 34 | #include <pthread.h> |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 35 | #include <sys/socket.h> |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 36 | #include <sys/syscall.h> |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 37 | #include <unistd.h> |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 38 | |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 39 | #ifdef CONSCRYPT_UNBUNDLED |
| 40 | #include <dlfcn.h> |
| 41 | #endif |
| 42 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 43 | #include <jni.h> |
| 44 | |
| 45 | #include <openssl/asn1t.h> |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 46 | #include <openssl/engine.h> |
| 47 | #include <openssl/err.h> |
| 48 | #include <openssl/evp.h> |
| 49 | #include <openssl/rand.h> |
| 50 | #include <openssl/rsa.h> |
| 51 | #include <openssl/ssl.h> |
| 52 | #include <openssl/x509v3.h> |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 53 | #if defined(OPENSSL_IS_BORINGSSL) |
| 54 | #include <openssl/aead.h> |
| 55 | #endif |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 56 | |
| 57 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 58 | #include "crypto/ecdsa/ecs_locl.h" |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 59 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 60 | |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 61 | #ifndef CONSCRYPT_UNBUNDLED |
| 62 | /* If we're compiled unbundled from Android system image, we use the |
| 63 | * CompatibilityCloseMonitor |
| 64 | */ |
Neil Fuller | 798f944 | 2014-04-11 17:26:59 +0100 | [diff] [blame] | 65 | #include "AsynchronousCloseMonitor.h" |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 66 | #endif |
| 67 | |
| 68 | #ifndef CONSCRYPT_UNBUNDLED |
Ruben Brunk | 33bad17 | 2013-09-09 17:01:23 -0700 | [diff] [blame] | 69 | #include "cutils/log.h" |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 70 | #else |
Kenny Root | 6af242c | 2014-11-10 15:00:46 -0800 | [diff] [blame] | 71 | #include "log_compat.h" |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 72 | #endif |
| 73 | |
| 74 | #ifndef CONSCRYPT_UNBUNDLED |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 75 | #include "JNIHelp.h" |
| 76 | #include "JniConstants.h" |
| 77 | #include "JniException.h" |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 78 | #else |
| 79 | #define NATIVE_METHOD(className, functionName, signature) \ |
Kenny Root | c625fa9 | 2015-04-28 16:23:39 -0700 | [diff] [blame] | 80 | { (char*) #functionName, (char*) signature, reinterpret_cast<void*>(className ## _ ## functionName) } |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 81 | #define REGISTER_NATIVE_METHODS(jni_class_name) \ |
| 82 | RegisterNativeMethods(env, jni_class_name, gMethods, arraysize(gMethods)) |
| 83 | #endif |
| 84 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 85 | #include "ScopedLocalRef.h" |
| 86 | #include "ScopedPrimitiveArray.h" |
| 87 | #include "ScopedUtfChars.h" |
| 88 | #include "UniquePtr.h" |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 89 | #include "NetFd.h" |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 90 | |
Kenny Root | 8a9fc46 | 2015-04-02 17:06:30 -0700 | [diff] [blame] | 91 | #include "macros.h" |
| 92 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 93 | #undef WITH_JNI_TRACE |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 94 | #undef WITH_JNI_TRACE_MD |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 95 | #undef WITH_JNI_TRACE_DATA |
| 96 | |
Kenny Root | bcdb80d | 2013-05-28 14:51:51 -0700 | [diff] [blame] | 97 | /* |
| 98 | * How to use this for debugging with Wireshark: |
| 99 | * |
| 100 | * 1. Pull lines from logcat to a file that looks like (without quotes): |
| 101 | * "RSA Session-ID:... Master-Key:..." <CR> |
| 102 | * "RSA Session-ID:... Master-Key:..." <CR> |
| 103 | * <etc> |
| 104 | * 2. Start Wireshark |
| 105 | * 3. Go to Edit -> Preferences -> SSL -> (Pre-)Master-Key log and fill in |
| 106 | * the file you put the lines in above. |
| 107 | * 4. Follow the stream that corresponds to the desired "Session-ID" in |
| 108 | * the Server Hello. |
| 109 | */ |
| 110 | #undef WITH_JNI_TRACE_KEYS |
| 111 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 112 | #ifdef WITH_JNI_TRACE |
| 113 | #define JNI_TRACE(...) \ |
Kenny Root | 30550a8 | 2014-08-12 15:13:33 -0700 | [diff] [blame] | 114 | ((void)ALOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 115 | #else |
| 116 | #define JNI_TRACE(...) ((void)0) |
| 117 | #endif |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 118 | #ifdef WITH_JNI_TRACE_MD |
| 119 | #define JNI_TRACE_MD(...) \ |
| 120 | ((void)ALOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)); |
| 121 | #else |
| 122 | #define JNI_TRACE_MD(...) ((void)0) |
| 123 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 124 | // don't overwhelm logcat |
| 125 | #define WITH_JNI_TRACE_DATA_CHUNK_SIZE 512 |
| 126 | |
| 127 | static JavaVM* gJavaVM; |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 128 | static jclass cryptoUpcallsClass; |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 129 | static jclass openSslInputStreamClass; |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 130 | static jclass nativeRefClass; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 131 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 132 | static jclass byteArrayClass; |
| 133 | static jclass calendarClass; |
| 134 | static jclass objectClass; |
| 135 | static jclass objectArrayClass; |
| 136 | static jclass integerClass; |
| 137 | static jclass inputStreamClass; |
| 138 | static jclass outputStreamClass; |
| 139 | static jclass stringClass; |
| 140 | |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 141 | static jfieldID nativeRef_context; |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 142 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 143 | static jmethodID calendar_setMethod; |
| 144 | static jmethodID inputStream_readMethod; |
| 145 | static jmethodID integer_valueOfMethod; |
| 146 | static jmethodID openSslInputStream_readLineMethod; |
| 147 | static jmethodID outputStream_writeMethod; |
| 148 | static jmethodID outputStream_flushMethod; |
| 149 | |
| 150 | struct OPENSSL_Delete { |
| 151 | void operator()(void* p) const { |
| 152 | OPENSSL_free(p); |
| 153 | } |
| 154 | }; |
| 155 | typedef UniquePtr<unsigned char, OPENSSL_Delete> Unique_OPENSSL_str; |
| 156 | |
| 157 | struct BIO_Delete { |
| 158 | void operator()(BIO* p) const { |
Kenny Root | 19fdf1a | 2014-04-10 11:45:19 -0700 | [diff] [blame] | 159 | BIO_free_all(p); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 160 | } |
| 161 | }; |
| 162 | typedef UniquePtr<BIO, BIO_Delete> Unique_BIO; |
| 163 | |
| 164 | struct BIGNUM_Delete { |
| 165 | void operator()(BIGNUM* p) const { |
| 166 | BN_free(p); |
| 167 | } |
| 168 | }; |
| 169 | typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM; |
| 170 | |
Adam Langley | 05b8e50 | 2015-05-12 19:24:49 -0700 | [diff] [blame] | 171 | struct BN_CTX_Delete { |
| 172 | void operator()(BN_CTX* ctx) const { |
| 173 | BN_CTX_free(ctx); |
| 174 | } |
| 175 | }; |
| 176 | typedef UniquePtr<BN_CTX, BN_CTX_Delete> Unique_BN_CTX; |
| 177 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 178 | struct ASN1_INTEGER_Delete { |
| 179 | void operator()(ASN1_INTEGER* p) const { |
| 180 | ASN1_INTEGER_free(p); |
| 181 | } |
| 182 | }; |
| 183 | typedef UniquePtr<ASN1_INTEGER, ASN1_INTEGER_Delete> Unique_ASN1_INTEGER; |
| 184 | |
| 185 | struct DH_Delete { |
| 186 | void operator()(DH* p) const { |
| 187 | DH_free(p); |
| 188 | } |
| 189 | }; |
| 190 | typedef UniquePtr<DH, DH_Delete> Unique_DH; |
| 191 | |
| 192 | struct DSA_Delete { |
| 193 | void operator()(DSA* p) const { |
| 194 | DSA_free(p); |
| 195 | } |
| 196 | }; |
| 197 | typedef UniquePtr<DSA, DSA_Delete> Unique_DSA; |
| 198 | |
| 199 | struct EC_GROUP_Delete { |
| 200 | void operator()(EC_GROUP* p) const { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 201 | EC_GROUP_free(p); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 202 | } |
| 203 | }; |
| 204 | typedef UniquePtr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP; |
| 205 | |
| 206 | struct EC_POINT_Delete { |
| 207 | void operator()(EC_POINT* p) const { |
| 208 | EC_POINT_clear_free(p); |
| 209 | } |
| 210 | }; |
| 211 | typedef UniquePtr<EC_POINT, EC_POINT_Delete> Unique_EC_POINT; |
| 212 | |
| 213 | struct EC_KEY_Delete { |
| 214 | void operator()(EC_KEY* p) const { |
| 215 | EC_KEY_free(p); |
| 216 | } |
| 217 | }; |
| 218 | typedef UniquePtr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY; |
| 219 | |
| 220 | struct EVP_MD_CTX_Delete { |
| 221 | void operator()(EVP_MD_CTX* p) const { |
| 222 | EVP_MD_CTX_destroy(p); |
| 223 | } |
| 224 | }; |
| 225 | typedef UniquePtr<EVP_MD_CTX, EVP_MD_CTX_Delete> Unique_EVP_MD_CTX; |
| 226 | |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 227 | #if defined(OPENSSL_IS_BORINGSSL) |
| 228 | struct EVP_AEAD_CTX_Delete { |
| 229 | void operator()(EVP_AEAD_CTX* p) const { |
| 230 | EVP_AEAD_CTX_cleanup(p); |
| 231 | delete p; |
| 232 | } |
| 233 | }; |
| 234 | typedef UniquePtr<EVP_AEAD_CTX, EVP_AEAD_CTX_Delete> Unique_EVP_AEAD_CTX; |
| 235 | #endif |
| 236 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 237 | struct EVP_CIPHER_CTX_Delete { |
| 238 | void operator()(EVP_CIPHER_CTX* p) const { |
Kenny Root | 11ac10b | 2013-10-18 09:51:43 -0700 | [diff] [blame] | 239 | EVP_CIPHER_CTX_free(p); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 240 | } |
| 241 | }; |
| 242 | typedef UniquePtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_Delete> Unique_EVP_CIPHER_CTX; |
| 243 | |
| 244 | struct EVP_PKEY_Delete { |
| 245 | void operator()(EVP_PKEY* p) const { |
| 246 | EVP_PKEY_free(p); |
| 247 | } |
| 248 | }; |
| 249 | typedef UniquePtr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY; |
| 250 | |
| 251 | struct PKCS8_PRIV_KEY_INFO_Delete { |
| 252 | void operator()(PKCS8_PRIV_KEY_INFO* p) const { |
| 253 | PKCS8_PRIV_KEY_INFO_free(p); |
| 254 | } |
| 255 | }; |
| 256 | typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; |
| 257 | |
| 258 | struct RSA_Delete { |
| 259 | void operator()(RSA* p) const { |
| 260 | RSA_free(p); |
| 261 | } |
| 262 | }; |
| 263 | typedef UniquePtr<RSA, RSA_Delete> Unique_RSA; |
| 264 | |
| 265 | struct ASN1_BIT_STRING_Delete { |
| 266 | void operator()(ASN1_BIT_STRING* p) const { |
| 267 | ASN1_BIT_STRING_free(p); |
| 268 | } |
| 269 | }; |
| 270 | typedef UniquePtr<ASN1_BIT_STRING, ASN1_BIT_STRING_Delete> Unique_ASN1_BIT_STRING; |
| 271 | |
| 272 | struct ASN1_OBJECT_Delete { |
| 273 | void operator()(ASN1_OBJECT* p) const { |
| 274 | ASN1_OBJECT_free(p); |
| 275 | } |
| 276 | }; |
| 277 | typedef UniquePtr<ASN1_OBJECT, ASN1_OBJECT_Delete> Unique_ASN1_OBJECT; |
| 278 | |
| 279 | struct ASN1_GENERALIZEDTIME_Delete { |
| 280 | void operator()(ASN1_GENERALIZEDTIME* p) const { |
| 281 | ASN1_GENERALIZEDTIME_free(p); |
| 282 | } |
| 283 | }; |
| 284 | typedef UniquePtr<ASN1_GENERALIZEDTIME, ASN1_GENERALIZEDTIME_Delete> Unique_ASN1_GENERALIZEDTIME; |
| 285 | |
| 286 | struct SSL_Delete { |
| 287 | void operator()(SSL* p) const { |
| 288 | SSL_free(p); |
| 289 | } |
| 290 | }; |
| 291 | typedef UniquePtr<SSL, SSL_Delete> Unique_SSL; |
| 292 | |
| 293 | struct SSL_CTX_Delete { |
| 294 | void operator()(SSL_CTX* p) const { |
| 295 | SSL_CTX_free(p); |
| 296 | } |
| 297 | }; |
| 298 | typedef UniquePtr<SSL_CTX, SSL_CTX_Delete> Unique_SSL_CTX; |
| 299 | |
| 300 | struct X509_Delete { |
| 301 | void operator()(X509* p) const { |
| 302 | X509_free(p); |
| 303 | } |
| 304 | }; |
| 305 | typedef UniquePtr<X509, X509_Delete> Unique_X509; |
| 306 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 307 | struct X509_NAME_Delete { |
| 308 | void operator()(X509_NAME* p) const { |
| 309 | X509_NAME_free(p); |
| 310 | } |
| 311 | }; |
| 312 | typedef UniquePtr<X509_NAME, X509_NAME_Delete> Unique_X509_NAME; |
| 313 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 314 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 315 | struct PKCS7_Delete { |
| 316 | void operator()(PKCS7* p) const { |
| 317 | PKCS7_free(p); |
| 318 | } |
| 319 | }; |
| 320 | typedef UniquePtr<PKCS7, PKCS7_Delete> Unique_PKCS7; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 321 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 322 | |
| 323 | struct sk_SSL_CIPHER_Delete { |
| 324 | void operator()(STACK_OF(SSL_CIPHER)* p) const { |
Kenny Root | 8c51e39 | 2013-09-09 19:15:39 -0700 | [diff] [blame] | 325 | // We don't own SSL_CIPHER references, so no need for pop_free |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 326 | sk_SSL_CIPHER_free(p); |
| 327 | } |
| 328 | }; |
| 329 | typedef UniquePtr<STACK_OF(SSL_CIPHER), sk_SSL_CIPHER_Delete> Unique_sk_SSL_CIPHER; |
| 330 | |
| 331 | struct sk_X509_Delete { |
| 332 | void operator()(STACK_OF(X509)* p) const { |
Kenny Root | 8c51e39 | 2013-09-09 19:15:39 -0700 | [diff] [blame] | 333 | sk_X509_pop_free(p, X509_free); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 334 | } |
| 335 | }; |
| 336 | typedef UniquePtr<STACK_OF(X509), sk_X509_Delete> Unique_sk_X509; |
| 337 | |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 338 | #if defined(OPENSSL_IS_BORINGSSL) |
| 339 | struct sk_X509_CRL_Delete { |
| 340 | void operator()(STACK_OF(X509_CRL)* p) const { |
| 341 | sk_X509_CRL_pop_free(p, X509_CRL_free); |
| 342 | } |
| 343 | }; |
| 344 | typedef UniquePtr<STACK_OF(X509_CRL), sk_X509_CRL_Delete> Unique_sk_X509_CRL; |
| 345 | #endif |
| 346 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 347 | struct sk_X509_NAME_Delete { |
| 348 | void operator()(STACK_OF(X509_NAME)* p) const { |
Kenny Root | 8c51e39 | 2013-09-09 19:15:39 -0700 | [diff] [blame] | 349 | sk_X509_NAME_pop_free(p, X509_NAME_free); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 350 | } |
| 351 | }; |
| 352 | typedef UniquePtr<STACK_OF(X509_NAME), sk_X509_NAME_Delete> Unique_sk_X509_NAME; |
| 353 | |
| 354 | struct sk_ASN1_OBJECT_Delete { |
| 355 | void operator()(STACK_OF(ASN1_OBJECT)* p) const { |
Kenny Root | 8c51e39 | 2013-09-09 19:15:39 -0700 | [diff] [blame] | 356 | sk_ASN1_OBJECT_pop_free(p, ASN1_OBJECT_free); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 357 | } |
| 358 | }; |
| 359 | typedef UniquePtr<STACK_OF(ASN1_OBJECT), sk_ASN1_OBJECT_Delete> Unique_sk_ASN1_OBJECT; |
| 360 | |
| 361 | struct sk_GENERAL_NAME_Delete { |
| 362 | void operator()(STACK_OF(GENERAL_NAME)* p) const { |
Kenny Root | 8c51e39 | 2013-09-09 19:15:39 -0700 | [diff] [blame] | 363 | sk_GENERAL_NAME_pop_free(p, GENERAL_NAME_free); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 364 | } |
| 365 | }; |
| 366 | typedef UniquePtr<STACK_OF(GENERAL_NAME), sk_GENERAL_NAME_Delete> Unique_sk_GENERAL_NAME; |
| 367 | |
| 368 | /** |
| 369 | * Many OpenSSL APIs take ownership of an argument on success but don't free the argument |
| 370 | * on failure. This means we need to tell our scoped pointers when we've transferred ownership, |
| 371 | * without triggering a warning by not using the result of release(). |
| 372 | */ |
| 373 | #define OWNERSHIP_TRANSFERRED(obj) \ |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 374 | do { typeof (obj.release()) _dummy __attribute__((unused)) = obj.release(); } while(0) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 375 | |
| 376 | /** |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 377 | * UNUSED_ARGUMENT can be used to mark an, otherwise unused, argument as "used" |
| 378 | * for the purposes of -Werror=unused-parameter. This can be needed when an |
| 379 | * argument's use is based on an #ifdef. |
| 380 | */ |
| 381 | #define UNUSED_ARGUMENT(x) ((void)(x)); |
| 382 | |
| 383 | /** |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 384 | * Check array bounds for arguments when an array and offset are given. |
| 385 | */ |
| 386 | #define ARRAY_OFFSET_INVALID(array, offset) (offset < 0 || \ |
| 387 | offset > static_cast<ssize_t>(array.size())) |
| 388 | |
| 389 | /** |
| 390 | * Check array bounds for arguments when an array, offset, and length are given. |
| 391 | */ |
| 392 | #define ARRAY_OFFSET_LENGTH_INVALID(array, offset, len) (offset < 0 || \ |
| 393 | offset > static_cast<ssize_t>(array.size()) || len < 0 || \ |
| 394 | len > static_cast<ssize_t>(array.size()) - offset) |
| 395 | |
| 396 | /** |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 397 | * Frees the SSL error state. |
| 398 | * |
| 399 | * OpenSSL keeps an "error stack" per thread, and given that this code |
| 400 | * can be called from arbitrary threads that we don't keep track of, |
| 401 | * we err on the side of freeing the error state promptly (instead of, |
| 402 | * say, at thread death). |
| 403 | */ |
| 404 | static void freeOpenSslErrorState(void) { |
| 405 | ERR_clear_error(); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 406 | ERR_remove_thread_state(NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 407 | } |
| 408 | |
| 409 | /** |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 410 | * Manages the freeing of the OpenSSL error stack. This allows you to |
| 411 | * instantiate this object during an SSL call that may fail and not worry |
| 412 | * about manually calling freeOpenSslErrorState() later. |
| 413 | * |
| 414 | * As an optimization, you can also call .release() for passing as an |
| 415 | * argument to things that free the error stack state as a side-effect. |
| 416 | */ |
| 417 | class OpenSslError { |
| 418 | public: |
| 419 | OpenSslError() : sslError_(SSL_ERROR_NONE), released_(false) { |
| 420 | } |
| 421 | |
| 422 | OpenSslError(SSL* ssl, int returnCode) : sslError_(SSL_ERROR_NONE), released_(false) { |
| 423 | reset(ssl, returnCode); |
| 424 | } |
| 425 | |
| 426 | ~OpenSslError() { |
| 427 | if (!released_ && sslError_ != SSL_ERROR_NONE) { |
| 428 | freeOpenSslErrorState(); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | int get() const { |
| 433 | return sslError_; |
| 434 | } |
| 435 | |
| 436 | void reset(SSL* ssl, int returnCode) { |
| 437 | if (returnCode <= 0) { |
| 438 | sslError_ = SSL_get_error(ssl, returnCode); |
| 439 | } else { |
| 440 | sslError_ = SSL_ERROR_NONE; |
| 441 | } |
| 442 | } |
| 443 | |
| 444 | int release() { |
| 445 | released_ = true; |
| 446 | return sslError_; |
| 447 | } |
| 448 | |
| 449 | private: |
| 450 | int sslError_; |
| 451 | bool released_; |
| 452 | }; |
| 453 | |
| 454 | /** |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 455 | * Throws a OutOfMemoryError with the given string as a message. |
| 456 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 457 | static int jniThrowOutOfMemory(JNIEnv* env, const char* message) { |
| 458 | return jniThrowException(env, "java/lang/OutOfMemoryError", message); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 459 | } |
| 460 | |
| 461 | /** |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 462 | * Throws a BadPaddingException with the given string as a message. |
| 463 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 464 | static int throwBadPaddingException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 465 | JNI_TRACE("throwBadPaddingException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 466 | return jniThrowException(env, "javax/crypto/BadPaddingException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 467 | } |
| 468 | |
| 469 | /** |
| 470 | * Throws a SignatureException with the given string as a message. |
| 471 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 472 | static int throwSignatureException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 473 | JNI_TRACE("throwSignatureException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 474 | return jniThrowException(env, "java/security/SignatureException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 475 | } |
| 476 | |
| 477 | /** |
| 478 | * Throws a InvalidKeyException with the given string as a message. |
| 479 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 480 | static int throwInvalidKeyException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 481 | JNI_TRACE("throwInvalidKeyException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 482 | return jniThrowException(env, "java/security/InvalidKeyException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | /** |
| 486 | * Throws a SignatureException with the given string as a message. |
| 487 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 488 | static int throwIllegalBlockSizeException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 489 | JNI_TRACE("throwIllegalBlockSizeException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 490 | return jniThrowException(env, "javax/crypto/IllegalBlockSizeException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 491 | } |
| 492 | |
| 493 | /** |
| 494 | * Throws a NoSuchAlgorithmException with the given string as a message. |
| 495 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 496 | static int throwNoSuchAlgorithmException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 497 | JNI_TRACE("throwUnknownAlgorithmException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 498 | return jniThrowException(env, "java/security/NoSuchAlgorithmException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 499 | } |
| 500 | |
Kenny Root | 199a134 | 2015-06-11 13:54:18 -0700 | [diff] [blame] | 501 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 502 | /** |
| 503 | * Throws a ParsingException with the given string as a message. |
| 504 | */ |
| 505 | static int throwParsingException(JNIEnv* env, const char* message) { |
| 506 | return jniThrowException( |
| 507 | env, |
| 508 | TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLX509CertificateFactory$ParsingException", |
| 509 | message); |
| 510 | } |
Kenny Root | 199a134 | 2015-06-11 13:54:18 -0700 | [diff] [blame] | 511 | #endif |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 512 | |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 513 | static int throwForAsn1Error(JNIEnv* env, int reason, const char *message, |
| 514 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 515 | switch (reason) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 516 | case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE: |
Adam Langley | 09b021a | 2015-05-05 18:23:29 -0700 | [diff] [blame] | 517 | #if defined(ASN1_R_UNABLE_TO_DECODE_RSA_KEY) |
| 518 | case ASN1_R_UNABLE_TO_DECODE_RSA_KEY: |
| 519 | #endif |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 520 | #if defined(ASN1_R_WRONG_PUBLIC_KEY_TYPE) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 521 | case ASN1_R_WRONG_PUBLIC_KEY_TYPE: |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 522 | #endif |
Adam Langley | 09b021a | 2015-05-05 18:23:29 -0700 | [diff] [blame] | 523 | #if defined(ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY) |
| 524 | case ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY: |
| 525 | #endif |
| 526 | #if defined(ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE) |
| 527 | case ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE: |
| 528 | #endif |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 529 | return throwInvalidKeyException(env, message); |
| 530 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 531 | #if defined(ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 532 | case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 533 | return throwNoSuchAlgorithmException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 534 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 535 | #endif |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 536 | } |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 537 | return defaultThrow(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 538 | } |
| 539 | |
| 540 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 541 | static int throwForCipherError(JNIEnv* env, int reason, const char *message, |
| 542 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 543 | switch (reason) { |
| 544 | case CIPHER_R_BAD_DECRYPT: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 545 | return throwBadPaddingException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 546 | break; |
| 547 | case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: |
| 548 | case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 549 | return throwIllegalBlockSizeException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 550 | break; |
| 551 | case CIPHER_R_AES_KEY_SETUP_FAILED: |
| 552 | case CIPHER_R_BAD_KEY_LENGTH: |
| 553 | case CIPHER_R_UNSUPPORTED_KEY_SIZE: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 554 | return throwInvalidKeyException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 555 | break; |
| 556 | } |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 557 | return defaultThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 558 | } |
| 559 | |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 560 | static int throwForEvpError(JNIEnv* env, int reason, const char *message, |
| 561 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 562 | switch (reason) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 563 | case EVP_R_MISSING_PARAMETERS: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 564 | return throwInvalidKeyException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 565 | break; |
| 566 | case EVP_R_UNSUPPORTED_ALGORITHM: |
Adam Langley | 09b021a | 2015-05-05 18:23:29 -0700 | [diff] [blame] | 567 | #if defined(EVP_R_X931_UNSUPPORTED) |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 568 | case EVP_R_X931_UNSUPPORTED: |
Adam Langley | 09b021a | 2015-05-05 18:23:29 -0700 | [diff] [blame] | 569 | #endif |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 570 | return throwNoSuchAlgorithmException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 571 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 572 | #if defined(EVP_R_WRONG_PUBLIC_KEY_TYPE) |
| 573 | case EVP_R_WRONG_PUBLIC_KEY_TYPE: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 574 | return throwInvalidKeyException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 575 | break; |
| 576 | #endif |
| 577 | #if defined(EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM) |
| 578 | case EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 579 | return throwNoSuchAlgorithmException(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 580 | break; |
| 581 | #endif |
| 582 | default: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 583 | return defaultThrow(env, message); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 584 | break; |
| 585 | } |
| 586 | } |
| 587 | #else |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 588 | static int throwForEvpError(JNIEnv* env, int reason, const char *message, |
| 589 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 590 | switch (reason) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 591 | case EVP_R_BAD_DECRYPT: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 592 | return throwBadPaddingException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 593 | break; |
| 594 | case EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH: |
Kenny Root | 1d5c92f | 2013-09-12 10:48:37 -0700 | [diff] [blame] | 595 | case EVP_R_WRONG_FINAL_BLOCK_LENGTH: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 596 | return throwIllegalBlockSizeException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 597 | break; |
| 598 | case EVP_R_BAD_KEY_LENGTH: |
| 599 | case EVP_R_BN_DECODE_ERROR: |
| 600 | case EVP_R_BN_PUBKEY_ERROR: |
| 601 | case EVP_R_INVALID_KEY_LENGTH: |
| 602 | case EVP_R_MISSING_PARAMETERS: |
| 603 | case EVP_R_UNSUPPORTED_KEY_SIZE: |
| 604 | case EVP_R_UNSUPPORTED_KEYLENGTH: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 605 | return throwInvalidKeyException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 606 | break; |
| 607 | case EVP_R_WRONG_PUBLIC_KEY_TYPE: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 608 | return throwSignatureException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 609 | break; |
| 610 | case EVP_R_UNSUPPORTED_ALGORITHM: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 611 | return throwNoSuchAlgorithmException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 612 | break; |
| 613 | default: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 614 | return defaultThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 615 | break; |
| 616 | } |
| 617 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 618 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 619 | |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 620 | static int throwForRsaError(JNIEnv* env, int reason, const char *message, |
| 621 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 622 | switch (reason) { |
| 623 | case RSA_R_BLOCK_TYPE_IS_NOT_01: |
Kenny Root | 53497d0 | 2014-12-08 11:51:56 -0800 | [diff] [blame] | 624 | case RSA_R_PKCS_DECODING_ERROR: |
Adam Langley | 09b021a | 2015-05-05 18:23:29 -0700 | [diff] [blame] | 625 | #if defined(RSA_R_BLOCK_TYPE_IS_NOT_02) |
| 626 | case RSA_R_BLOCK_TYPE_IS_NOT_02: |
| 627 | #endif |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 628 | return throwBadPaddingException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 629 | break; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 630 | case RSA_R_BAD_SIGNATURE: |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 631 | case RSA_R_DATA_TOO_LARGE_FOR_MODULUS: |
| 632 | case RSA_R_INVALID_MESSAGE_LENGTH: |
| 633 | case RSA_R_WRONG_SIGNATURE_LENGTH: |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 634 | #if !defined(OPENSSL_IS_BORINGSSL) |
| 635 | case RSA_R_ALGORITHM_MISMATCH: |
| 636 | case RSA_R_DATA_GREATER_THAN_MOD_LEN: |
| 637 | #endif |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 638 | return throwSignatureException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 639 | break; |
| 640 | case RSA_R_UNKNOWN_ALGORITHM_TYPE: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 641 | return throwNoSuchAlgorithmException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 642 | break; |
| 643 | case RSA_R_MODULUS_TOO_LARGE: |
| 644 | case RSA_R_NO_PUBLIC_EXPONENT: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 645 | return throwInvalidKeyException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 646 | break; |
| 647 | } |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 648 | return defaultThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 649 | } |
| 650 | |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 651 | static int throwForX509Error(JNIEnv* env, int reason, const char *message, |
| 652 | int (*defaultThrow)(JNIEnv*, const char*)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 653 | switch (reason) { |
| 654 | case X509_R_UNSUPPORTED_ALGORITHM: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 655 | return throwNoSuchAlgorithmException(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 656 | break; |
| 657 | default: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 658 | return defaultThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 659 | break; |
| 660 | } |
| 661 | } |
| 662 | |
| 663 | /* |
| 664 | * Checks this thread's OpenSSL error queue and throws a RuntimeException if |
| 665 | * necessary. |
| 666 | * |
| 667 | * @return true if an exception was thrown, false if not. |
| 668 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 669 | static bool throwExceptionIfNecessary(JNIEnv* env, const char* location __attribute__ ((unused)), |
| 670 | int (*defaultThrow)(JNIEnv*, const char*) = jniThrowRuntimeException) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 671 | const char* file; |
| 672 | int line; |
| 673 | const char* data; |
| 674 | int flags; |
| 675 | unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags); |
| 676 | int result = false; |
| 677 | |
| 678 | if (error != 0) { |
| 679 | char message[256]; |
| 680 | ERR_error_string_n(error, message, sizeof(message)); |
| 681 | int library = ERR_GET_LIB(error); |
| 682 | int reason = ERR_GET_REASON(error); |
| 683 | JNI_TRACE("OpenSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s", |
| 684 | location, error, library, reason, file, line, message, |
| 685 | (flags & ERR_TXT_STRING) ? data : "(no data)"); |
| 686 | switch (library) { |
| 687 | case ERR_LIB_RSA: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 688 | throwForRsaError(env, reason, message, defaultThrow); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 689 | break; |
| 690 | case ERR_LIB_ASN1: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 691 | throwForAsn1Error(env, reason, message, defaultThrow); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 692 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 693 | #if defined(OPENSSL_IS_BORINGSSL) |
| 694 | case ERR_LIB_CIPHER: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 695 | throwForCipherError(env, reason, message, defaultThrow); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 696 | break; |
| 697 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 698 | case ERR_LIB_EVP: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 699 | throwForEvpError(env, reason, message, defaultThrow); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 700 | break; |
| 701 | case ERR_LIB_X509: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 702 | throwForX509Error(env, reason, message, defaultThrow); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 703 | break; |
| 704 | case ERR_LIB_DSA: |
| 705 | throwInvalidKeyException(env, message); |
| 706 | break; |
| 707 | default: |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 708 | defaultThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 709 | break; |
| 710 | } |
| 711 | result = true; |
| 712 | } |
| 713 | |
| 714 | freeOpenSslErrorState(); |
| 715 | return result; |
| 716 | } |
| 717 | |
| 718 | /** |
| 719 | * Throws an SocketTimeoutException with the given string as a message. |
| 720 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 721 | static int throwSocketTimeoutException(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 722 | JNI_TRACE("throwSocketTimeoutException %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 723 | return jniThrowException(env, "java/net/SocketTimeoutException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 724 | } |
| 725 | |
| 726 | /** |
| 727 | * Throws a javax.net.ssl.SSLException with the given string as a message. |
| 728 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 729 | static int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message) { |
Kenny Root | a0c196d | 2014-03-26 13:56:24 -0700 | [diff] [blame] | 730 | JNI_TRACE("throwSSLExceptionStr %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 731 | return jniThrowException(env, "javax/net/ssl/SSLHandshakeException", message); |
Kenny Root | a0c196d | 2014-03-26 13:56:24 -0700 | [diff] [blame] | 732 | } |
| 733 | |
| 734 | /** |
| 735 | * Throws a javax.net.ssl.SSLException with the given string as a message. |
| 736 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 737 | static int throwSSLExceptionStr(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 738 | JNI_TRACE("throwSSLExceptionStr %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 739 | return jniThrowException(env, "javax/net/ssl/SSLException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 740 | } |
| 741 | |
| 742 | /** |
| 743 | * Throws a javax.net.ssl.SSLProcotolException with the given string as a message. |
| 744 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 745 | static int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 746 | JNI_TRACE("throwSSLProtocolExceptionStr %s", message); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 747 | return jniThrowException(env, "javax/net/ssl/SSLProtocolException", message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 748 | } |
| 749 | |
| 750 | /** |
| 751 | * Throws an SSLException with a message constructed from the current |
| 752 | * SSL errors. This will also log the errors. |
| 753 | * |
| 754 | * @param env the JNI environment |
| 755 | * @param ssl the possibly NULL SSL |
| 756 | * @param sslErrorCode error code returned from SSL_get_error() or |
| 757 | * SSL_ERROR_NONE to probe with ERR_get_error |
| 758 | * @param message null-ok; general error message |
| 759 | */ |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 760 | static int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, |
| 761 | const char* message, int (*actualThrow)(JNIEnv*, const char*) = throwSSLExceptionStr) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 762 | |
| 763 | if (message == NULL) { |
| 764 | message = "SSL error"; |
| 765 | } |
| 766 | |
| 767 | // First consult the SSL error code for the general message. |
| 768 | const char* sslErrorStr = NULL; |
| 769 | switch (sslErrorCode) { |
| 770 | case SSL_ERROR_NONE: |
| 771 | if (ERR_peek_error() == 0) { |
| 772 | sslErrorStr = "OK"; |
| 773 | } else { |
| 774 | sslErrorStr = ""; |
| 775 | } |
| 776 | break; |
| 777 | case SSL_ERROR_SSL: |
| 778 | sslErrorStr = "Failure in SSL library, usually a protocol error"; |
| 779 | break; |
| 780 | case SSL_ERROR_WANT_READ: |
| 781 | sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this."; |
| 782 | break; |
| 783 | case SSL_ERROR_WANT_WRITE: |
| 784 | sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this."; |
| 785 | break; |
| 786 | case SSL_ERROR_WANT_X509_LOOKUP: |
| 787 | sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this."; |
| 788 | break; |
| 789 | case SSL_ERROR_SYSCALL: |
| 790 | sslErrorStr = "I/O error during system call"; |
| 791 | break; |
| 792 | case SSL_ERROR_ZERO_RETURN: |
| 793 | sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this."; |
| 794 | break; |
| 795 | case SSL_ERROR_WANT_CONNECT: |
| 796 | sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this."; |
| 797 | break; |
| 798 | case SSL_ERROR_WANT_ACCEPT: |
| 799 | sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this."; |
| 800 | break; |
| 801 | default: |
| 802 | sslErrorStr = "Unknown SSL error"; |
| 803 | } |
| 804 | |
| 805 | // Prepend either our explicit message or a default one. |
| 806 | char* str; |
| 807 | if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) { |
| 808 | // problem with asprintf, just throw argument message, log everything |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 809 | int ret = actualThrow(env, message); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 810 | ALOGV("%s: ssl=%p: %s", message, ssl, sslErrorStr); |
| 811 | freeOpenSslErrorState(); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 812 | return ret; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 813 | } |
| 814 | |
| 815 | char* allocStr = str; |
| 816 | |
| 817 | // For protocol errors, SSL might have more information. |
| 818 | if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) { |
| 819 | // Append each error as an additional line to the message. |
| 820 | for (;;) { |
| 821 | char errStr[256]; |
| 822 | const char* file; |
| 823 | int line; |
| 824 | const char* data; |
| 825 | int flags; |
| 826 | unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags); |
| 827 | if (err == 0) { |
| 828 | break; |
| 829 | } |
| 830 | |
| 831 | ERR_error_string_n(err, errStr, sizeof(errStr)); |
| 832 | |
| 833 | int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)", |
| 834 | (allocStr == NULL) ? "" : allocStr, |
| 835 | errStr, |
| 836 | file, |
| 837 | line, |
| 838 | (flags & ERR_TXT_STRING) ? data : "(no data)", |
| 839 | flags); |
| 840 | |
| 841 | if (ret < 0) { |
| 842 | break; |
| 843 | } |
| 844 | |
| 845 | free(allocStr); |
| 846 | allocStr = str; |
| 847 | } |
| 848 | // For errors during system calls, errno might be our friend. |
| 849 | } else if (sslErrorCode == SSL_ERROR_SYSCALL) { |
| 850 | if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) { |
| 851 | free(allocStr); |
| 852 | allocStr = str; |
| 853 | } |
| 854 | // If the error code is invalid, print it. |
| 855 | } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) { |
| 856 | if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) { |
| 857 | free(allocStr); |
| 858 | allocStr = str; |
| 859 | } |
| 860 | } |
| 861 | |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 862 | int ret; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 863 | if (sslErrorCode == SSL_ERROR_SSL) { |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 864 | ret = throwSSLProtocolExceptionStr(env, allocStr); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 865 | } else { |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 866 | ret = actualThrow(env, allocStr); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 867 | } |
| 868 | |
| 869 | ALOGV("%s", allocStr); |
| 870 | free(allocStr); |
| 871 | freeOpenSslErrorState(); |
Kenny Root | 48d7b0a | 2015-04-29 09:40:34 -0700 | [diff] [blame] | 872 | return ret; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 873 | } |
| 874 | |
| 875 | /** |
| 876 | * Helper function that grabs the casts an ssl pointer and then checks for nullness. |
| 877 | * If this function returns NULL and <code>throwIfNull</code> is |
| 878 | * passed as <code>true</code>, then this function will call |
| 879 | * <code>throwSSLExceptionStr</code> before returning, so in this case of |
| 880 | * NULL, a caller of this function should simply return and allow JNI |
| 881 | * to do its thing. |
| 882 | * |
| 883 | * @param env the JNI environment |
| 884 | * @param ssl_address; the ssl_address pointer as an integer |
| 885 | * @param throwIfNull whether to throw if the SSL pointer is NULL |
| 886 | * @returns the pointer, which may be NULL |
| 887 | */ |
| 888 | static SSL_CTX* to_SSL_CTX(JNIEnv* env, jlong ssl_ctx_address, bool throwIfNull) { |
| 889 | SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address)); |
| 890 | if ((ssl_ctx == NULL) && throwIfNull) { |
| 891 | JNI_TRACE("ssl_ctx == null"); |
| 892 | jniThrowNullPointerException(env, "ssl_ctx == null"); |
| 893 | } |
| 894 | return ssl_ctx; |
| 895 | } |
| 896 | |
| 897 | static SSL* to_SSL(JNIEnv* env, jlong ssl_address, bool throwIfNull) { |
| 898 | SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address)); |
| 899 | if ((ssl == NULL) && throwIfNull) { |
| 900 | JNI_TRACE("ssl == null"); |
| 901 | jniThrowNullPointerException(env, "ssl == null"); |
| 902 | } |
| 903 | return ssl; |
| 904 | } |
| 905 | |
| 906 | static SSL_SESSION* to_SSL_SESSION(JNIEnv* env, jlong ssl_session_address, bool throwIfNull) { |
| 907 | SSL_SESSION* ssl_session |
| 908 | = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address)); |
| 909 | if ((ssl_session == NULL) && throwIfNull) { |
| 910 | JNI_TRACE("ssl_session == null"); |
| 911 | jniThrowNullPointerException(env, "ssl_session == null"); |
| 912 | } |
| 913 | return ssl_session; |
| 914 | } |
| 915 | |
Alex Klyubin | 2d089e1 | 2013-11-21 10:28:08 -0800 | [diff] [blame] | 916 | static SSL_CIPHER* to_SSL_CIPHER(JNIEnv* env, jlong ssl_cipher_address, bool throwIfNull) { |
| 917 | SSL_CIPHER* ssl_cipher |
| 918 | = reinterpret_cast<SSL_CIPHER*>(static_cast<uintptr_t>(ssl_cipher_address)); |
| 919 | if ((ssl_cipher == NULL) && throwIfNull) { |
| 920 | JNI_TRACE("ssl_cipher == null"); |
| 921 | jniThrowNullPointerException(env, "ssl_cipher == null"); |
| 922 | } |
| 923 | return ssl_cipher; |
| 924 | } |
| 925 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 926 | template<typename T> |
| 927 | static T* fromContextObject(JNIEnv* env, jobject contextObject) { |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 928 | if (contextObject == NULL) { |
| 929 | JNI_TRACE("contextObject == null"); |
| 930 | jniThrowNullPointerException(env, "contextObject == null"); |
| 931 | return NULL; |
| 932 | } |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 933 | T* ref = reinterpret_cast<T*>(env->GetLongField(contextObject, nativeRef_context)); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 934 | if (ref == NULL) { |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 935 | JNI_TRACE("ref == null"); |
| 936 | jniThrowNullPointerException(env, "ref == null"); |
| 937 | return NULL; |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 938 | } |
| 939 | return ref; |
| 940 | } |
| 941 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 942 | /** |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 943 | * Converts a Java byte[] two's complement to an OpenSSL BIGNUM. This will |
| 944 | * allocate the BIGNUM if *dest == NULL. Returns true on success. If the |
| 945 | * return value is false, there is a pending exception. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 946 | */ |
| 947 | static bool arrayToBignum(JNIEnv* env, jbyteArray source, BIGNUM** dest) { |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 948 | JNI_TRACE("arrayToBignum(%p, %p)", source, dest); |
| 949 | if (dest == NULL) { |
| 950 | JNI_TRACE("arrayToBignum(%p, %p) => dest is null!", source, dest); |
| 951 | jniThrowNullPointerException(env, "dest == null"); |
| 952 | return false; |
| 953 | } |
| 954 | JNI_TRACE("arrayToBignum(%p, %p) *dest == %p", source, dest, *dest); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 955 | |
| 956 | ScopedByteArrayRO sourceBytes(env, source); |
| 957 | if (sourceBytes.get() == NULL) { |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 958 | JNI_TRACE("arrayToBignum(%p, %p) => NULL", source, dest); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 959 | return false; |
| 960 | } |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 961 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(sourceBytes.get()); |
| 962 | size_t tmpSize = sourceBytes.size(); |
Kenny Root | 5b1934c | 2014-01-31 15:35:13 -0800 | [diff] [blame] | 963 | |
| 964 | /* if the array is empty, it is zero. */ |
| 965 | if (tmpSize == 0) { |
| 966 | if (*dest == NULL) { |
| 967 | *dest = BN_new(); |
| 968 | } |
| 969 | BN_zero(*dest); |
| 970 | return true; |
| 971 | } |
| 972 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 973 | UniquePtr<unsigned char[]> twosComplement; |
| 974 | bool negative = (tmp[0] & 0x80) != 0; |
| 975 | if (negative) { |
| 976 | // Need to convert to two's complement. |
| 977 | twosComplement.reset(new unsigned char[tmpSize]); |
| 978 | unsigned char* twosBytes = reinterpret_cast<unsigned char*>(twosComplement.get()); |
| 979 | memcpy(twosBytes, tmp, tmpSize); |
| 980 | tmp = twosBytes; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 981 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 982 | bool carry = true; |
| 983 | for (ssize_t i = tmpSize - 1; i >= 0; i--) { |
| 984 | twosBytes[i] ^= 0xFF; |
| 985 | if (carry) { |
| 986 | carry = (++twosBytes[i]) == 0; |
| 987 | } |
| 988 | } |
| 989 | } |
| 990 | BIGNUM *ret = BN_bin2bn(tmp, tmpSize, *dest); |
| 991 | if (ret == NULL) { |
| 992 | jniThrowRuntimeException(env, "Conversion to BIGNUM failed"); |
| 993 | JNI_TRACE("arrayToBignum(%p, %p) => threw exception", source, dest); |
| 994 | return false; |
| 995 | } |
| 996 | BN_set_negative(ret, negative ? 1 : 0); |
| 997 | |
| 998 | *dest = ret; |
| 999 | JNI_TRACE("arrayToBignum(%p, %p) => *dest = %p", source, dest, ret); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1000 | return true; |
| 1001 | } |
| 1002 | |
Chih-Hung Hsieh | dbb6100 | 2014-11-21 17:21:30 -0800 | [diff] [blame] | 1003 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1004 | /** |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1005 | * arrayToBignumSize sets |*out_size| to the size of the big-endian number |
| 1006 | * contained in |source|. It returns true on success and sets an exception and |
| 1007 | * returns false otherwise. |
| 1008 | */ |
| 1009 | static bool arrayToBignumSize(JNIEnv* env, jbyteArray source, size_t* out_size) { |
| 1010 | JNI_TRACE("arrayToBignumSize(%p, %p)", source, out_size); |
| 1011 | |
| 1012 | ScopedByteArrayRO sourceBytes(env, source); |
| 1013 | if (sourceBytes.get() == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 1014 | JNI_TRACE("arrayToBignum(%p, %p) => NULL", source, out_size); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1015 | return false; |
| 1016 | } |
| 1017 | const uint8_t* tmp = reinterpret_cast<const uint8_t*>(sourceBytes.get()); |
| 1018 | size_t tmpSize = sourceBytes.size(); |
| 1019 | |
| 1020 | if (tmpSize == 0) { |
| 1021 | *out_size = 0; |
| 1022 | return true; |
| 1023 | } |
| 1024 | |
| 1025 | if ((tmp[0] & 0x80) != 0) { |
| 1026 | // Negative numbers are invalid. |
| 1027 | jniThrowRuntimeException(env, "Negative number"); |
| 1028 | return false; |
| 1029 | } |
| 1030 | |
| 1031 | while (tmpSize > 0 && tmp[0] == 0) { |
| 1032 | tmp++; |
| 1033 | tmpSize--; |
| 1034 | } |
| 1035 | |
| 1036 | *out_size = tmpSize; |
| 1037 | return true; |
| 1038 | } |
Chih-Hung Hsieh | dbb6100 | 2014-11-21 17:21:30 -0800 | [diff] [blame] | 1039 | #endif |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1040 | |
| 1041 | /** |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 1042 | * Converts an OpenSSL BIGNUM to a Java byte[] array in two's complement. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1043 | */ |
| 1044 | static jbyteArray bignumToArray(JNIEnv* env, const BIGNUM* source, const char* sourceName) { |
| 1045 | JNI_TRACE("bignumToArray(%p, %s)", source, sourceName); |
| 1046 | |
| 1047 | if (source == NULL) { |
| 1048 | jniThrowNullPointerException(env, sourceName); |
| 1049 | return NULL; |
| 1050 | } |
| 1051 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 1052 | size_t numBytes = BN_num_bytes(source) + 1; |
| 1053 | jbyteArray javaBytes = env->NewByteArray(numBytes); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1054 | ScopedByteArrayRW bytes(env, javaBytes); |
| 1055 | if (bytes.get() == NULL) { |
| 1056 | JNI_TRACE("bignumToArray(%p, %s) => NULL", source, sourceName); |
| 1057 | return NULL; |
| 1058 | } |
| 1059 | |
| 1060 | unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get()); |
Kenny Root | 38f3d46 | 2013-06-05 15:31:11 -0700 | [diff] [blame] | 1061 | if (BN_num_bytes(source) > 0 && BN_bn2bin(source, tmp + 1) <= 0) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1062 | throwExceptionIfNecessary(env, "bignumToArray"); |
| 1063 | return NULL; |
| 1064 | } |
| 1065 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 1066 | // Set the sign and convert to two's complement if necessary for the Java code. |
| 1067 | if (BN_is_negative(source)) { |
| 1068 | bool carry = true; |
| 1069 | for (ssize_t i = numBytes - 1; i >= 0; i--) { |
| 1070 | tmp[i] ^= 0xFF; |
| 1071 | if (carry) { |
| 1072 | carry = (++tmp[i]) == 0; |
| 1073 | } |
| 1074 | } |
| 1075 | *tmp |= 0x80; |
| 1076 | } else { |
| 1077 | *tmp = 0x00; |
| 1078 | } |
| 1079 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1080 | JNI_TRACE("bignumToArray(%p, %s) => %p", source, sourceName, javaBytes); |
| 1081 | return javaBytes; |
| 1082 | } |
| 1083 | |
| 1084 | /** |
| 1085 | * Converts various OpenSSL ASN.1 types to a jbyteArray with DER-encoded data |
| 1086 | * inside. The "i2d_func" function pointer is a function of the "i2d_<TYPE>" |
| 1087 | * from the OpenSSL ASN.1 API. |
| 1088 | */ |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1089 | template<typename T> |
| 1090 | jbyteArray ASN1ToByteArray(JNIEnv* env, T* obj, int (*i2d_func)(T*, unsigned char**)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1091 | if (obj == NULL) { |
| 1092 | jniThrowNullPointerException(env, "ASN1 input == null"); |
| 1093 | JNI_TRACE("ASN1ToByteArray(%p) => null input", obj); |
| 1094 | return NULL; |
| 1095 | } |
| 1096 | |
| 1097 | int derLen = i2d_func(obj, NULL); |
| 1098 | if (derLen < 0) { |
| 1099 | throwExceptionIfNecessary(env, "ASN1ToByteArray"); |
| 1100 | JNI_TRACE("ASN1ToByteArray(%p) => measurement failed", obj); |
| 1101 | return NULL; |
| 1102 | } |
| 1103 | |
| 1104 | ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(derLen)); |
| 1105 | if (byteArray.get() == NULL) { |
| 1106 | JNI_TRACE("ASN1ToByteArray(%p) => creating byte array failed", obj); |
| 1107 | return NULL; |
| 1108 | } |
| 1109 | |
| 1110 | ScopedByteArrayRW bytes(env, byteArray.get()); |
| 1111 | if (bytes.get() == NULL) { |
| 1112 | JNI_TRACE("ASN1ToByteArray(%p) => using byte array failed", obj); |
| 1113 | return NULL; |
| 1114 | } |
| 1115 | |
| 1116 | unsigned char* p = reinterpret_cast<unsigned char*>(bytes.get()); |
| 1117 | int ret = i2d_func(obj, &p); |
| 1118 | if (ret < 0) { |
| 1119 | throwExceptionIfNecessary(env, "ASN1ToByteArray"); |
| 1120 | JNI_TRACE("ASN1ToByteArray(%p) => final conversion failed", obj); |
| 1121 | return NULL; |
| 1122 | } |
| 1123 | |
| 1124 | JNI_TRACE("ASN1ToByteArray(%p) => success (%d bytes written)", obj, ret); |
| 1125 | return byteArray.release(); |
| 1126 | } |
| 1127 | |
| 1128 | template<typename T, T* (*d2i_func)(T**, const unsigned char**, long)> |
| 1129 | T* ByteArrayToASN1(JNIEnv* env, jbyteArray byteArray) { |
| 1130 | ScopedByteArrayRO bytes(env, byteArray); |
| 1131 | if (bytes.get() == NULL) { |
| 1132 | JNI_TRACE("ByteArrayToASN1(%p) => using byte array failed", byteArray); |
| 1133 | return 0; |
| 1134 | } |
| 1135 | |
| 1136 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); |
| 1137 | return d2i_func(NULL, &tmp, bytes.size()); |
| 1138 | } |
| 1139 | |
| 1140 | /** |
| 1141 | * Converts ASN.1 BIT STRING to a jbooleanArray. |
| 1142 | */ |
| 1143 | jbooleanArray ASN1BitStringToBooleanArray(JNIEnv* env, ASN1_BIT_STRING* bitStr) { |
| 1144 | int size = bitStr->length * 8; |
| 1145 | if (bitStr->flags & ASN1_STRING_FLAG_BITS_LEFT) { |
| 1146 | size -= bitStr->flags & 0x07; |
| 1147 | } |
| 1148 | |
| 1149 | ScopedLocalRef<jbooleanArray> bitsRef(env, env->NewBooleanArray(size)); |
| 1150 | if (bitsRef.get() == NULL) { |
| 1151 | return NULL; |
| 1152 | } |
| 1153 | |
| 1154 | ScopedBooleanArrayRW bitsArray(env, bitsRef.get()); |
| 1155 | for (int i = 0; i < static_cast<int>(bitsArray.size()); i++) { |
| 1156 | bitsArray[i] = ASN1_BIT_STRING_get_bit(bitStr, i); |
| 1157 | } |
| 1158 | |
| 1159 | return bitsRef.release(); |
| 1160 | } |
| 1161 | |
| 1162 | /** |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 1163 | * Safely clear SSL sessions and throw an error if there was something already |
| 1164 | * in the error stack. |
| 1165 | */ |
| 1166 | static void safeSslClear(SSL* ssl) { |
| 1167 | if (SSL_clear(ssl) != 1) { |
| 1168 | freeOpenSslErrorState(); |
| 1169 | } |
| 1170 | } |
| 1171 | |
| 1172 | /** |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 1173 | * To avoid the round-trip to ASN.1 and back in X509_dup, we just up the reference count. |
| 1174 | */ |
| 1175 | static X509* X509_dup_nocopy(X509* x509) { |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 1176 | if (x509 == NULL) { |
| 1177 | return NULL; |
| 1178 | } |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 1179 | #if defined(OPENSSL_IS_BORINGSSL) |
| 1180 | return X509_up_ref(x509); |
| 1181 | #else |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 1182 | CRYPTO_add(&x509->references, 1, CRYPTO_LOCK_X509); |
| 1183 | return x509; |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 1184 | #endif |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 1185 | } |
| 1186 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1187 | /* |
| 1188 | * Sets the read and write BIO for an SSL connection and removes it when it goes out of scope. |
| 1189 | * We hang on to BIO with a JNI GlobalRef and we want to remove them as soon as possible. |
| 1190 | */ |
| 1191 | class ScopedSslBio { |
| 1192 | public: |
| 1193 | ScopedSslBio(SSL *ssl, BIO* rbio, BIO* wbio) : ssl_(ssl) { |
| 1194 | SSL_set_bio(ssl_, rbio, wbio); |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 1195 | #if defined(OPENSSL_IS_BORINGSSL) |
| 1196 | BIO_up_ref(rbio); |
| 1197 | BIO_up_ref(wbio); |
| 1198 | #else |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1199 | CRYPTO_add(&rbio->references,1,CRYPTO_LOCK_BIO); |
| 1200 | CRYPTO_add(&wbio->references,1,CRYPTO_LOCK_BIO); |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 1201 | #endif |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1202 | } |
| 1203 | |
| 1204 | ~ScopedSslBio() { |
| 1205 | SSL_set_bio(ssl_, NULL, NULL); |
| 1206 | } |
| 1207 | |
| 1208 | private: |
| 1209 | SSL* const ssl_; |
| 1210 | }; |
| 1211 | |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 1212 | /** |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1213 | * Obtains the current thread's JNIEnv |
| 1214 | */ |
| 1215 | static JNIEnv* getJNIEnv() { |
| 1216 | JNIEnv* env; |
Kenny Root | e0e2a5b | 2015-04-28 16:43:59 -0700 | [diff] [blame] | 1217 | #ifdef ANDROID |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1218 | if (gJavaVM->AttachCurrentThread(&env, NULL) < 0) { |
Kenny Root | e0e2a5b | 2015-04-28 16:43:59 -0700 | [diff] [blame] | 1219 | #else |
| 1220 | if (gJavaVM->AttachCurrentThread(reinterpret_cast<void**>(&env), NULL) < 0) { |
| 1221 | #endif |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1222 | ALOGE("Could not attach JavaVM to find current JNIEnv"); |
| 1223 | return NULL; |
| 1224 | } |
| 1225 | return env; |
| 1226 | } |
| 1227 | |
| 1228 | /** |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1229 | * BIO for InputStream |
| 1230 | */ |
| 1231 | class BIO_Stream { |
| 1232 | public: |
| 1233 | BIO_Stream(jobject stream) : |
| 1234 | mEof(false) { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1235 | JNIEnv* env = getJNIEnv(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1236 | mStream = env->NewGlobalRef(stream); |
| 1237 | } |
| 1238 | |
| 1239 | ~BIO_Stream() { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1240 | JNIEnv* env = getJNIEnv(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1241 | |
| 1242 | env->DeleteGlobalRef(mStream); |
| 1243 | } |
| 1244 | |
| 1245 | bool isEof() const { |
| 1246 | JNI_TRACE("isEof? %s", mEof ? "yes" : "no"); |
| 1247 | return mEof; |
| 1248 | } |
| 1249 | |
| 1250 | int flush() { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1251 | JNIEnv* env = getJNIEnv(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1252 | if (env == NULL) { |
| 1253 | return -1; |
| 1254 | } |
| 1255 | |
Kenny Root | 64f361d | 2014-05-02 10:39:35 -0700 | [diff] [blame] | 1256 | if (env->ExceptionCheck()) { |
| 1257 | JNI_TRACE("BIO_Stream::flush called with pending exception"); |
| 1258 | return -1; |
| 1259 | } |
| 1260 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1261 | env->CallVoidMethod(mStream, outputStream_flushMethod); |
| 1262 | if (env->ExceptionCheck()) { |
| 1263 | return -1; |
| 1264 | } |
| 1265 | |
| 1266 | return 1; |
| 1267 | } |
| 1268 | |
| 1269 | protected: |
| 1270 | jobject getStream() { |
| 1271 | return mStream; |
| 1272 | } |
| 1273 | |
| 1274 | void setEof(bool eof) { |
| 1275 | mEof = eof; |
| 1276 | } |
| 1277 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1278 | private: |
| 1279 | jobject mStream; |
| 1280 | bool mEof; |
| 1281 | }; |
| 1282 | |
| 1283 | class BIO_InputStream : public BIO_Stream { |
| 1284 | public: |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 1285 | BIO_InputStream(jobject stream, bool isFinite) : |
| 1286 | BIO_Stream(stream), |
| 1287 | isFinite_(isFinite) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1288 | } |
| 1289 | |
| 1290 | int read(char *buf, int len) { |
| 1291 | return read_internal(buf, len, inputStream_readMethod); |
| 1292 | } |
| 1293 | |
| 1294 | int gets(char *buf, int len) { |
| 1295 | if (len > PEM_LINE_LENGTH) { |
| 1296 | len = PEM_LINE_LENGTH; |
| 1297 | } |
| 1298 | |
| 1299 | int read = read_internal(buf, len - 1, openSslInputStream_readLineMethod); |
| 1300 | buf[read] = '\0'; |
| 1301 | JNI_TRACE("BIO::gets \"%s\"", buf); |
| 1302 | return read; |
| 1303 | } |
| 1304 | |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 1305 | bool isFinite() const { |
| 1306 | return isFinite_; |
| 1307 | } |
| 1308 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1309 | private: |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 1310 | const bool isFinite_; |
| 1311 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1312 | int read_internal(char *buf, int len, jmethodID method) { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1313 | JNIEnv* env = getJNIEnv(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1314 | if (env == NULL) { |
| 1315 | JNI_TRACE("BIO_InputStream::read could not get JNIEnv"); |
| 1316 | return -1; |
| 1317 | } |
| 1318 | |
Kenny Root | 64f361d | 2014-05-02 10:39:35 -0700 | [diff] [blame] | 1319 | if (env->ExceptionCheck()) { |
| 1320 | JNI_TRACE("BIO_InputStream::read called with pending exception"); |
| 1321 | return -1; |
| 1322 | } |
| 1323 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1324 | ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len)); |
| 1325 | if (javaBytes.get() == NULL) { |
| 1326 | JNI_TRACE("BIO_InputStream::read failed call to NewByteArray"); |
| 1327 | return -1; |
| 1328 | } |
| 1329 | |
| 1330 | jint read = env->CallIntMethod(getStream(), method, javaBytes.get()); |
| 1331 | if (env->ExceptionCheck()) { |
| 1332 | JNI_TRACE("BIO_InputStream::read failed call to InputStream#read"); |
| 1333 | return -1; |
| 1334 | } |
| 1335 | |
| 1336 | /* Java uses -1 to indicate EOF condition. */ |
| 1337 | if (read == -1) { |
| 1338 | setEof(true); |
| 1339 | read = 0; |
| 1340 | } else if (read > 0) { |
| 1341 | env->GetByteArrayRegion(javaBytes.get(), 0, read, reinterpret_cast<jbyte*>(buf)); |
| 1342 | } |
| 1343 | |
| 1344 | return read; |
| 1345 | } |
| 1346 | |
| 1347 | public: |
| 1348 | /** Length of PEM-encoded line (64) plus CR plus NULL */ |
| 1349 | static const int PEM_LINE_LENGTH = 66; |
| 1350 | }; |
| 1351 | |
| 1352 | class BIO_OutputStream : public BIO_Stream { |
| 1353 | public: |
| 1354 | BIO_OutputStream(jobject stream) : |
| 1355 | BIO_Stream(stream) { |
| 1356 | } |
| 1357 | |
| 1358 | int write(const char *buf, int len) { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1359 | JNIEnv* env = getJNIEnv(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1360 | if (env == NULL) { |
| 1361 | JNI_TRACE("BIO_OutputStream::write => could not get JNIEnv"); |
| 1362 | return -1; |
| 1363 | } |
| 1364 | |
Kenny Root | 64f361d | 2014-05-02 10:39:35 -0700 | [diff] [blame] | 1365 | if (env->ExceptionCheck()) { |
| 1366 | JNI_TRACE("BIO_OutputStream::write => called with pending exception"); |
| 1367 | return -1; |
| 1368 | } |
| 1369 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1370 | ScopedLocalRef<jbyteArray> javaBytes(env, env->NewByteArray(len)); |
| 1371 | if (javaBytes.get() == NULL) { |
| 1372 | JNI_TRACE("BIO_OutputStream::write => failed call to NewByteArray"); |
| 1373 | return -1; |
| 1374 | } |
| 1375 | |
| 1376 | env->SetByteArrayRegion(javaBytes.get(), 0, len, reinterpret_cast<const jbyte*>(buf)); |
| 1377 | |
| 1378 | env->CallVoidMethod(getStream(), outputStream_writeMethod, javaBytes.get()); |
| 1379 | if (env->ExceptionCheck()) { |
| 1380 | JNI_TRACE("BIO_OutputStream::write => failed call to OutputStream#write"); |
| 1381 | return -1; |
| 1382 | } |
| 1383 | |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 1384 | return len; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1385 | } |
| 1386 | }; |
| 1387 | |
| 1388 | static int bio_stream_create(BIO *b) { |
| 1389 | b->init = 1; |
| 1390 | b->num = 0; |
| 1391 | b->ptr = NULL; |
| 1392 | b->flags = 0; |
| 1393 | return 1; |
| 1394 | } |
| 1395 | |
| 1396 | static int bio_stream_destroy(BIO *b) { |
| 1397 | if (b == NULL) { |
| 1398 | return 0; |
| 1399 | } |
| 1400 | |
| 1401 | if (b->ptr != NULL) { |
| 1402 | delete static_cast<BIO_Stream*>(b->ptr); |
| 1403 | b->ptr = NULL; |
| 1404 | } |
| 1405 | |
| 1406 | b->init = 0; |
| 1407 | b->flags = 0; |
| 1408 | return 1; |
| 1409 | } |
| 1410 | |
| 1411 | static int bio_stream_read(BIO *b, char *buf, int len) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1412 | BIO_clear_retry_flags(b); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1413 | BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1414 | int ret = stream->read(buf, len); |
| 1415 | if (ret == 0) { |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 1416 | if (stream->isFinite()) { |
| 1417 | return 0; |
| 1418 | } |
| 1419 | // If the BIO_InputStream is not finite then EOF doesn't mean that |
| 1420 | // there's nothing more coming. |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1421 | BIO_set_retry_read(b); |
| 1422 | return -1; |
| 1423 | } |
| 1424 | return ret; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1425 | } |
| 1426 | |
| 1427 | static int bio_stream_write(BIO *b, const char *buf, int len) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 1428 | BIO_clear_retry_flags(b); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 1429 | BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr); |
| 1430 | return stream->write(buf, len); |
| 1431 | } |
| 1432 | |
| 1433 | static int bio_stream_puts(BIO *b, const char *buf) { |
| 1434 | BIO_OutputStream* stream = static_cast<BIO_OutputStream*>(b->ptr); |
| 1435 | return stream->write(buf, strlen(buf)); |
| 1436 | } |
| 1437 | |
| 1438 | static int bio_stream_gets(BIO *b, char *buf, int len) { |
| 1439 | BIO_InputStream* stream = static_cast<BIO_InputStream*>(b->ptr); |
| 1440 | return stream->gets(buf, len); |
| 1441 | } |
| 1442 | |
| 1443 | static void bio_stream_assign(BIO *b, BIO_Stream* stream) { |
| 1444 | b->ptr = static_cast<void*>(stream); |
| 1445 | } |
| 1446 | |
| 1447 | static long bio_stream_ctrl(BIO *b, int cmd, long, void *) { |
| 1448 | BIO_Stream* stream = static_cast<BIO_Stream*>(b->ptr); |
| 1449 | |
| 1450 | switch (cmd) { |
| 1451 | case BIO_CTRL_EOF: |
| 1452 | return stream->isEof() ? 1 : 0; |
| 1453 | case BIO_CTRL_FLUSH: |
| 1454 | return stream->flush(); |
| 1455 | default: |
| 1456 | return 0; |
| 1457 | } |
| 1458 | } |
| 1459 | |
| 1460 | static BIO_METHOD stream_bio_method = { |
| 1461 | ( 100 | 0x0400 ), /* source/sink BIO */ |
| 1462 | "InputStream/OutputStream BIO", |
| 1463 | bio_stream_write, /* bio_write */ |
| 1464 | bio_stream_read, /* bio_read */ |
| 1465 | bio_stream_puts, /* bio_puts */ |
| 1466 | bio_stream_gets, /* bio_gets */ |
| 1467 | bio_stream_ctrl, /* bio_ctrl */ |
| 1468 | bio_stream_create, /* bio_create */ |
| 1469 | bio_stream_destroy, /* bio_free */ |
| 1470 | NULL, /* no bio_callback_ctrl */ |
| 1471 | }; |
| 1472 | |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1473 | static jbyteArray rawSignDigestWithPrivateKey(JNIEnv* env, jobject privateKey, |
| 1474 | const char* message, size_t message_len) { |
| 1475 | ScopedLocalRef<jbyteArray> messageArray(env, env->NewByteArray(message_len)); |
| 1476 | if (env->ExceptionCheck()) { |
| 1477 | JNI_TRACE("rawSignDigestWithPrivateKey(%p) => threw exception", privateKey); |
| 1478 | return NULL; |
| 1479 | } |
| 1480 | |
| 1481 | { |
| 1482 | ScopedByteArrayRW messageBytes(env, messageArray.get()); |
| 1483 | if (messageBytes.get() == NULL) { |
| 1484 | JNI_TRACE("rawSignDigestWithPrivateKey(%p) => using byte array failed", privateKey); |
| 1485 | return NULL; |
| 1486 | } |
| 1487 | |
| 1488 | memcpy(messageBytes.get(), message, message_len); |
| 1489 | } |
| 1490 | |
| 1491 | jmethodID rawSignMethod = env->GetStaticMethodID(cryptoUpcallsClass, |
| 1492 | "rawSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;[B)[B"); |
| 1493 | if (rawSignMethod == NULL) { |
| 1494 | ALOGE("Could not find rawSignDigestWithPrivateKey"); |
| 1495 | return NULL; |
| 1496 | } |
| 1497 | |
| 1498 | return reinterpret_cast<jbyteArray>(env->CallStaticObjectMethod( |
| 1499 | cryptoUpcallsClass, rawSignMethod, privateKey, messageArray.get())); |
| 1500 | } |
| 1501 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1502 | // rsaDecryptWithPrivateKey uses privateKey to decrypt |ciphertext_len| bytes |
| 1503 | // from |ciphertext|. The ciphertext is expected to be padded using the scheme |
| 1504 | // given in |padding|, which must be one of |RSA_*_PADDING| constants from |
| 1505 | // OpenSSL. |
| 1506 | static jbyteArray rsaDecryptWithPrivateKey(JNIEnv* env, jobject privateKey, jint padding, |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1507 | const char* ciphertext, size_t ciphertext_len) { |
| 1508 | ScopedLocalRef<jbyteArray> ciphertextArray(env, env->NewByteArray(ciphertext_len)); |
| 1509 | if (env->ExceptionCheck()) { |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1510 | JNI_TRACE("rsaDecryptWithPrivateKey(%p) => threw exception", privateKey); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1511 | return NULL; |
| 1512 | } |
| 1513 | |
| 1514 | { |
| 1515 | ScopedByteArrayRW ciphertextBytes(env, ciphertextArray.get()); |
| 1516 | if (ciphertextBytes.get() == NULL) { |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1517 | JNI_TRACE("rsaDecryptWithPrivateKey(%p) => using byte array failed", privateKey); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1518 | return NULL; |
| 1519 | } |
| 1520 | |
| 1521 | memcpy(ciphertextBytes.get(), ciphertext, ciphertext_len); |
| 1522 | } |
| 1523 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1524 | jmethodID rsaDecryptMethod = env->GetStaticMethodID(cryptoUpcallsClass, |
| 1525 | "rsaDecryptWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B"); |
| 1526 | if (rsaDecryptMethod == NULL) { |
| 1527 | ALOGE("Could not find rsaDecryptWithPrivateKey"); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1528 | return NULL; |
| 1529 | } |
| 1530 | |
| 1531 | return reinterpret_cast<jbyteArray>(env->CallStaticObjectMethod( |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1532 | cryptoUpcallsClass, |
| 1533 | rsaDecryptMethod, |
| 1534 | privateKey, |
| 1535 | padding, |
| 1536 | ciphertextArray.get())); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1537 | } |
| 1538 | |
| 1539 | // ********************************************* |
| 1540 | // From keystore_openssl.cpp in Chromium source. |
| 1541 | // ********************************************* |
| 1542 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1543 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1544 | // Custom RSA_METHOD that uses the platform APIs. |
| 1545 | // Note that for now, only signing through RSA_sign() is really supported. |
| 1546 | // all other method pointers are either stubs returning errors, or no-ops. |
| 1547 | // See <openssl/rsa.h> for exact declaration of RSA_METHOD. |
| 1548 | |
| 1549 | int RsaMethodPubEnc(int /* flen */, |
| 1550 | const unsigned char* /* from */, |
| 1551 | unsigned char* /* to */, |
| 1552 | RSA* /* rsa */, |
| 1553 | int /* padding */) { |
| 1554 | RSAerr(RSA_F_RSA_PUBLIC_ENCRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED); |
| 1555 | return -1; |
| 1556 | } |
| 1557 | |
Chih-Hung Hsieh | 04b3500 | 2014-08-26 11:16:49 -0700 | [diff] [blame] | 1558 | int RsaMethodPubDec(int /* flen */, |
| 1559 | const unsigned char* /* from */, |
| 1560 | unsigned char* /* to */, |
| 1561 | RSA* /* rsa */, |
| 1562 | int /* padding */) { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1563 | RSAerr(RSA_F_RSA_PUBLIC_DECRYPT, RSA_R_RSA_OPERATIONS_NOT_SUPPORTED); |
| 1564 | return -1; |
| 1565 | } |
| 1566 | |
| 1567 | // See RSA_eay_private_encrypt in |
| 1568 | // third_party/openssl/openssl/crypto/rsa/rsa_eay.c for the default |
| 1569 | // implementation of this function. |
| 1570 | int RsaMethodPrivEnc(int flen, |
| 1571 | const unsigned char *from, |
| 1572 | unsigned char *to, |
| 1573 | RSA *rsa, |
| 1574 | int padding) { |
| 1575 | if (padding != RSA_PKCS1_PADDING) { |
| 1576 | // TODO(davidben): If we need to, we can implement RSA_NO_PADDING |
| 1577 | // by using javax.crypto.Cipher and picking either the |
| 1578 | // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as |
| 1579 | // appropriate. I believe support for both of these was added in |
| 1580 | // the same Android version as the "NONEwithRSA" |
| 1581 | // java.security.Signature algorithm, so the same version checks |
| 1582 | // for GetRsaLegacyKey should work. |
| 1583 | RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); |
| 1584 | return -1; |
| 1585 | } |
| 1586 | |
| 1587 | // Retrieve private key JNI reference. |
| 1588 | jobject private_key = reinterpret_cast<jobject>(RSA_get_app_data(rsa)); |
| 1589 | if (!private_key) { |
| 1590 | ALOGE("Null JNI reference passed to RsaMethodPrivEnc!"); |
| 1591 | RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR); |
| 1592 | return -1; |
| 1593 | } |
| 1594 | |
| 1595 | JNIEnv* env = getJNIEnv(); |
| 1596 | if (env == NULL) { |
| 1597 | return -1; |
| 1598 | } |
| 1599 | |
| 1600 | // For RSA keys, this function behaves as RSA_private_encrypt with |
| 1601 | // PKCS#1 padding. |
| 1602 | ScopedLocalRef<jbyteArray> signature( |
| 1603 | env, rawSignDigestWithPrivateKey(env, private_key, |
| 1604 | reinterpret_cast<const char*>(from), flen)); |
| 1605 | if (signature.get() == NULL) { |
| 1606 | ALOGE("Could not sign message in RsaMethodPrivEnc!"); |
| 1607 | RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR); |
| 1608 | return -1; |
| 1609 | } |
| 1610 | |
| 1611 | ScopedByteArrayRO signatureBytes(env, signature.get()); |
| 1612 | size_t expected_size = static_cast<size_t>(RSA_size(rsa)); |
| 1613 | if (signatureBytes.size() > expected_size) { |
Ian Rogers | 1b60d4f | 2014-06-11 12:41:41 -0700 | [diff] [blame] | 1614 | ALOGE("RSA Signature size mismatch, actual: %zd, expected <= %zd", signatureBytes.size(), |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1615 | expected_size); |
| 1616 | RSAerr(RSA_F_RSA_PRIVATE_ENCRYPT, ERR_R_INTERNAL_ERROR); |
| 1617 | return -1; |
| 1618 | } |
| 1619 | |
| 1620 | // Copy result to OpenSSL-provided buffer. rawSignDigestWithPrivateKey |
| 1621 | // should pad with leading 0s, but if it doesn't, pad the result. |
| 1622 | size_t zero_pad = expected_size - signatureBytes.size(); |
| 1623 | memset(to, 0, zero_pad); |
| 1624 | memcpy(to + zero_pad, signatureBytes.get(), signatureBytes.size()); |
| 1625 | |
| 1626 | return expected_size; |
| 1627 | } |
| 1628 | |
| 1629 | int RsaMethodPrivDec(int flen, |
| 1630 | const unsigned char* from, |
| 1631 | unsigned char* to, |
| 1632 | RSA* rsa, |
| 1633 | int padding) { |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1634 | // Retrieve private key JNI reference. |
| 1635 | jobject private_key = reinterpret_cast<jobject>(RSA_get_app_data(rsa)); |
| 1636 | if (!private_key) { |
| 1637 | ALOGE("Null JNI reference passed to RsaMethodPrivDec!"); |
| 1638 | RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR); |
| 1639 | return -1; |
| 1640 | } |
| 1641 | |
| 1642 | JNIEnv* env = getJNIEnv(); |
| 1643 | if (env == NULL) { |
| 1644 | return -1; |
| 1645 | } |
| 1646 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1647 | // This function behaves as RSA_private_decrypt. |
| 1648 | ScopedLocalRef<jbyteArray> cleartext(env, rsaDecryptWithPrivateKey(env, private_key, |
| 1649 | padding, reinterpret_cast<const char*>(from), flen)); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1650 | if (cleartext.get() == NULL) { |
| 1651 | ALOGE("Could not decrypt message in RsaMethodPrivDec!"); |
| 1652 | RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR); |
| 1653 | return -1; |
| 1654 | } |
| 1655 | |
| 1656 | ScopedByteArrayRO cleartextBytes(env, cleartext.get()); |
| 1657 | size_t expected_size = static_cast<size_t>(RSA_size(rsa)); |
| 1658 | if (cleartextBytes.size() > expected_size) { |
Ian Rogers | 1b60d4f | 2014-06-11 12:41:41 -0700 | [diff] [blame] | 1659 | ALOGE("RSA ciphertext size mismatch, actual: %zd, expected <= %zd", cleartextBytes.size(), |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1660 | expected_size); |
| 1661 | RSAerr(RSA_F_RSA_PRIVATE_DECRYPT, ERR_R_INTERNAL_ERROR); |
| 1662 | return -1; |
| 1663 | } |
| 1664 | |
| 1665 | // Copy result to OpenSSL-provided buffer. |
| 1666 | memcpy(to, cleartextBytes.get(), cleartextBytes.size()); |
| 1667 | |
| 1668 | return cleartextBytes.size(); |
| 1669 | } |
| 1670 | |
| 1671 | int RsaMethodInit(RSA*) { |
| 1672 | return 0; |
| 1673 | } |
| 1674 | |
| 1675 | int RsaMethodFinish(RSA* rsa) { |
| 1676 | // Ensure the global JNI reference created with this wrapper is |
| 1677 | // properly destroyed with it. |
| 1678 | jobject key = reinterpret_cast<jobject>(RSA_get_app_data(rsa)); |
| 1679 | if (key != NULL) { |
| 1680 | RSA_set_app_data(rsa, NULL); |
| 1681 | JNIEnv* env = getJNIEnv(); |
| 1682 | env->DeleteGlobalRef(key); |
| 1683 | } |
| 1684 | // Actual return value is ignored by OpenSSL. There are no docs |
| 1685 | // explaining what this is supposed to be. |
| 1686 | return 0; |
| 1687 | } |
| 1688 | |
| 1689 | const RSA_METHOD android_rsa_method = { |
| 1690 | /* .name = */ "Android signing-only RSA method", |
| 1691 | /* .rsa_pub_enc = */ RsaMethodPubEnc, |
| 1692 | /* .rsa_pub_dec = */ RsaMethodPubDec, |
| 1693 | /* .rsa_priv_enc = */ RsaMethodPrivEnc, |
| 1694 | /* .rsa_priv_dec = */ RsaMethodPrivDec, |
| 1695 | /* .rsa_mod_exp = */ NULL, |
| 1696 | /* .bn_mod_exp = */ NULL, |
| 1697 | /* .init = */ RsaMethodInit, |
| 1698 | /* .finish = */ RsaMethodFinish, |
| 1699 | // This flag is necessary to tell OpenSSL to avoid checking the content |
| 1700 | // (i.e. internal fields) of the private key. Otherwise, it will complain |
| 1701 | // it's not valid for the certificate. |
| 1702 | /* .flags = */ RSA_METHOD_FLAG_NO_CHECK, |
| 1703 | /* .app_data = */ NULL, |
| 1704 | /* .rsa_sign = */ NULL, |
| 1705 | /* .rsa_verify = */ NULL, |
| 1706 | /* .rsa_keygen = */ NULL, |
| 1707 | }; |
| 1708 | |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1709 | // Used to ensure that the global JNI reference associated with a custom |
| 1710 | // EC_KEY + ECDSA_METHOD wrapper is released when its EX_DATA is destroyed |
| 1711 | // (this function is called when EVP_PKEY_free() is called on the wrapper). |
| 1712 | void ExDataFree(void* /* parent */, |
| 1713 | void* ptr, |
| 1714 | CRYPTO_EX_DATA* ad, |
| 1715 | int idx, |
| 1716 | long /* argl */, |
Kenny Root | cf9111e | 2015-04-29 10:08:33 -0700 | [diff] [blame] | 1717 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | a6a38cd | 2015-04-28 16:44:36 -0700 | [diff] [blame] | 1718 | const void* /* argp */) { |
Kenny Root | cf9111e | 2015-04-29 10:08:33 -0700 | [diff] [blame] | 1719 | #else /* defined(OPENSSL_IS_BORINGSSL) */ |
| 1720 | void* /* argp */) { |
| 1721 | #endif /* defined(OPENSSL_IS_BORINGSSL) */ |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1722 | jobject private_key = reinterpret_cast<jobject>(ptr); |
| 1723 | if (private_key == NULL) return; |
| 1724 | |
| 1725 | CRYPTO_set_ex_data(ad, idx, NULL); |
| 1726 | JNIEnv* env = getJNIEnv(); |
| 1727 | env->DeleteGlobalRef(private_key); |
| 1728 | } |
| 1729 | |
| 1730 | int ExDataDup(CRYPTO_EX_DATA* /* to */, |
| 1731 | CRYPTO_EX_DATA* /* from */, |
| 1732 | void* /* from_d */, |
| 1733 | int /* idx */, |
| 1734 | long /* argl */, |
Kenny Root | cf9111e | 2015-04-29 10:08:33 -0700 | [diff] [blame] | 1735 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | a6a38cd | 2015-04-28 16:44:36 -0700 | [diff] [blame] | 1736 | const void* /* argp */) { |
Kenny Root | cf9111e | 2015-04-29 10:08:33 -0700 | [diff] [blame] | 1737 | #else /* defined(OPENSSL_IS_BORINGSSL) */ |
| 1738 | void* /* argp */) { |
| 1739 | #endif /* defined(OPENSSL_IS_BORINGSSL) */ |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1740 | // This callback shall never be called with the current OpenSSL |
| 1741 | // implementation (the library only ever duplicates EX_DATA items |
| 1742 | // for SSL and BIO objects). But provide this to catch regressions |
| 1743 | // in the future. |
| 1744 | // Return value is currently ignored by OpenSSL. |
| 1745 | return 0; |
| 1746 | } |
| 1747 | |
| 1748 | class EcdsaExDataIndex { |
| 1749 | public: |
| 1750 | int ex_data_index() { return ex_data_index_; } |
| 1751 | |
| 1752 | static EcdsaExDataIndex& Instance() { |
| 1753 | static EcdsaExDataIndex singleton; |
| 1754 | return singleton; |
| 1755 | } |
| 1756 | |
| 1757 | private: |
| 1758 | EcdsaExDataIndex() { |
| 1759 | ex_data_index_ = ECDSA_get_ex_new_index(0, NULL, NULL, ExDataDup, ExDataFree); |
| 1760 | } |
| 1761 | EcdsaExDataIndex(EcdsaExDataIndex const&); |
| 1762 | ~EcdsaExDataIndex() {} |
| 1763 | EcdsaExDataIndex& operator=(EcdsaExDataIndex const&); |
| 1764 | |
| 1765 | int ex_data_index_; |
| 1766 | }; |
| 1767 | |
| 1768 | // Returns the index of the custom EX_DATA used to store the JNI reference. |
| 1769 | int EcdsaGetExDataIndex(void) { |
| 1770 | EcdsaExDataIndex& exData = EcdsaExDataIndex::Instance(); |
| 1771 | return exData.ex_data_index(); |
| 1772 | } |
| 1773 | |
| 1774 | ECDSA_SIG* EcdsaMethodDoSign(const unsigned char* dgst, int dgst_len, const BIGNUM* /* inv */, |
| 1775 | const BIGNUM* /* rp */, EC_KEY* eckey) { |
| 1776 | // Retrieve private key JNI reference. |
| 1777 | jobject private_key = |
| 1778 | reinterpret_cast<jobject>(ECDSA_get_ex_data(eckey, EcdsaGetExDataIndex())); |
| 1779 | if (!private_key) { |
| 1780 | ALOGE("Null JNI reference passed to EcdsaMethodDoSign!"); |
| 1781 | return NULL; |
| 1782 | } |
| 1783 | JNIEnv* env = getJNIEnv(); |
| 1784 | if (env == NULL) { |
| 1785 | return NULL; |
| 1786 | } |
| 1787 | |
| 1788 | // Sign message with it through JNI. |
| 1789 | ScopedLocalRef<jbyteArray> signature( |
| 1790 | env, rawSignDigestWithPrivateKey(env, private_key, reinterpret_cast<const char*>(dgst), |
| 1791 | dgst_len)); |
| 1792 | if (signature.get() == NULL) { |
| 1793 | ALOGE("Could not sign message in EcdsaMethodDoSign!"); |
| 1794 | return NULL; |
| 1795 | } |
| 1796 | |
| 1797 | ScopedByteArrayRO signatureBytes(env, signature.get()); |
| 1798 | // Note: With ECDSA, the actual signature may be smaller than |
| 1799 | // ECDSA_size(). |
| 1800 | size_t max_expected_size = static_cast<size_t>(ECDSA_size(eckey)); |
| 1801 | if (signatureBytes.size() > max_expected_size) { |
Ian Rogers | 1b60d4f | 2014-06-11 12:41:41 -0700 | [diff] [blame] | 1802 | ALOGE("ECDSA Signature size mismatch, actual: %zd, expected <= %zd", signatureBytes.size(), |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 1803 | max_expected_size); |
| 1804 | return NULL; |
| 1805 | } |
| 1806 | |
| 1807 | // Convert signature to ECDSA_SIG object |
| 1808 | const unsigned char* sigbuf = reinterpret_cast<const unsigned char*>(signatureBytes.get()); |
| 1809 | long siglen = static_cast<long>(signatureBytes.size()); |
| 1810 | return d2i_ECDSA_SIG(NULL, &sigbuf, siglen); |
| 1811 | } |
| 1812 | |
| 1813 | int EcdsaMethodSignSetup(EC_KEY* /* eckey */, |
| 1814 | BN_CTX* /* ctx */, |
| 1815 | BIGNUM** /* kinv */, |
| 1816 | BIGNUM** /* r */, |
| 1817 | const unsigned char*, |
| 1818 | int) { |
| 1819 | ECDSAerr(ECDSA_F_ECDSA_SIGN_SETUP, ECDSA_R_ERR_EC_LIB); |
| 1820 | return -1; |
| 1821 | } |
| 1822 | |
| 1823 | int EcdsaMethodDoVerify(const unsigned char* /* dgst */, |
| 1824 | int /* dgst_len */, |
| 1825 | const ECDSA_SIG* /* sig */, |
| 1826 | EC_KEY* /* eckey */) { |
| 1827 | ECDSAerr(ECDSA_F_ECDSA_DO_VERIFY, ECDSA_R_ERR_EC_LIB); |
| 1828 | return -1; |
| 1829 | } |
| 1830 | |
| 1831 | const ECDSA_METHOD android_ecdsa_method = { |
| 1832 | /* .name = */ "Android signing-only ECDSA method", |
| 1833 | /* .ecdsa_do_sign = */ EcdsaMethodDoSign, |
| 1834 | /* .ecdsa_sign_setup = */ EcdsaMethodSignSetup, |
| 1835 | /* .ecdsa_do_verify = */ EcdsaMethodDoVerify, |
| 1836 | /* .flags = */ 0, |
| 1837 | /* .app_data = */ NULL, |
| 1838 | }; |
| 1839 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1840 | #else /* OPENSSL_IS_BORINGSSL */ |
| 1841 | |
| 1842 | namespace { |
| 1843 | |
| 1844 | ENGINE *g_engine; |
| 1845 | int g_rsa_exdata_index; |
| 1846 | int g_ecdsa_exdata_index; |
| 1847 | pthread_once_t g_engine_once = PTHREAD_ONCE_INIT; |
| 1848 | |
| 1849 | void init_engine_globals(); |
| 1850 | |
| 1851 | void ensure_engine_globals() { |
| 1852 | pthread_once(&g_engine_once, init_engine_globals); |
| 1853 | } |
| 1854 | |
Kenny Root | e84805b | 2014-11-24 15:12:53 -0800 | [diff] [blame] | 1855 | // KeyExData contains the data that is contained in the EX_DATA of the RSA |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1856 | // and ECDSA objects that are created to wrap Android system keys. |
| 1857 | struct KeyExData { |
| 1858 | // private_key contains a reference to a Java, private-key object. |
| 1859 | jobject private_key; |
| 1860 | // cached_size contains the "size" of the key. This is the size of the |
Kenny Root | e84805b | 2014-11-24 15:12:53 -0800 | [diff] [blame] | 1861 | // modulus (in bytes) for RSA, or the group order size for ECDSA. This |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1862 | // avoids calling into Java to calculate the size. |
| 1863 | size_t cached_size; |
| 1864 | }; |
| 1865 | |
| 1866 | // ExDataDup is called when one of the RSA or EC_KEY objects is duplicated. We |
| 1867 | // don't support this and it should never happen. |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 1868 | int ExDataDup(CRYPTO_EX_DATA* /* to */, |
| 1869 | const CRYPTO_EX_DATA* /* from */, |
| 1870 | void** /* from_d */, |
| 1871 | int /* index */, |
| 1872 | long /* argl */, |
| 1873 | void* /* argp */) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1874 | return 0; |
| 1875 | } |
| 1876 | |
| 1877 | // ExDataFree is called when one of the RSA or EC_KEY objects is freed. |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 1878 | void ExDataFree(void* /* parent */, |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1879 | void* ptr, |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 1880 | CRYPTO_EX_DATA* /* ad */, |
| 1881 | int /* index */, |
| 1882 | long /* argl */, |
| 1883 | void* /* argp */) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1884 | // Ensure the global JNI reference created with this wrapper is |
| 1885 | // properly destroyed with it. |
| 1886 | KeyExData *ex_data = reinterpret_cast<KeyExData*>(ptr); |
| 1887 | if (ex_data != NULL) { |
| 1888 | JNIEnv* env = getJNIEnv(); |
| 1889 | env->DeleteGlobalRef(ex_data->private_key); |
| 1890 | delete ex_data; |
| 1891 | } |
| 1892 | } |
| 1893 | |
| 1894 | KeyExData* RsaGetExData(const RSA* rsa) { |
| 1895 | return reinterpret_cast<KeyExData*>(RSA_get_ex_data(rsa, g_rsa_exdata_index)); |
| 1896 | } |
| 1897 | |
| 1898 | size_t RsaMethodSize(const RSA *rsa) { |
| 1899 | const KeyExData *ex_data = RsaGetExData(rsa); |
| 1900 | return ex_data->cached_size; |
| 1901 | } |
| 1902 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 1903 | int RsaMethodEncrypt(RSA* /* rsa */, |
| 1904 | size_t* /* out_len */, |
| 1905 | uint8_t* /* out */, |
| 1906 | size_t /* max_out */, |
| 1907 | const uint8_t* /* in */, |
| 1908 | size_t /* in_len */, |
| 1909 | int /* padding */) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1910 | OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); |
| 1911 | return 0; |
| 1912 | } |
| 1913 | |
| 1914 | int RsaMethodSignRaw(RSA* rsa, |
| 1915 | size_t* out_len, |
| 1916 | uint8_t* out, |
| 1917 | size_t max_out, |
| 1918 | const uint8_t* in, |
| 1919 | size_t in_len, |
| 1920 | int padding) { |
| 1921 | if (padding != RSA_PKCS1_PADDING) { |
| 1922 | // TODO(davidben): If we need to, we can implement RSA_NO_PADDING |
| 1923 | // by using javax.crypto.Cipher and picking either the |
| 1924 | // "RSA/ECB/NoPadding" or "RSA/ECB/PKCS1Padding" transformation as |
| 1925 | // appropriate. I believe support for both of these was added in |
| 1926 | // the same Android version as the "NONEwithRSA" |
| 1927 | // java.security.Signature algorithm, so the same version checks |
| 1928 | // for GetRsaLegacyKey should work. |
| 1929 | OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE); |
| 1930 | return 0; |
| 1931 | } |
| 1932 | |
| 1933 | // Retrieve private key JNI reference. |
| 1934 | const KeyExData *ex_data = RsaGetExData(rsa); |
| 1935 | if (!ex_data || !ex_data->private_key) { |
| 1936 | OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 1937 | return 0; |
| 1938 | } |
| 1939 | |
| 1940 | JNIEnv* env = getJNIEnv(); |
| 1941 | if (env == NULL) { |
| 1942 | OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 1943 | return 0; |
| 1944 | } |
| 1945 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1946 | // For RSA keys, this function behaves as RSA_private_encrypt with |
| 1947 | // PKCS#1 padding. |
| 1948 | ScopedLocalRef<jbyteArray> signature( |
| 1949 | env, rawSignDigestWithPrivateKey( |
| 1950 | env, ex_data->private_key, |
| 1951 | reinterpret_cast<const char*>(in), in_len)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1952 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1953 | if (signature.get() == NULL) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1954 | OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 1955 | return 0; |
| 1956 | } |
| 1957 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1958 | ScopedByteArrayRO result(env, signature.get()); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 1959 | |
| 1960 | size_t expected_size = static_cast<size_t>(RSA_size(rsa)); |
| 1961 | if (result.size() > expected_size) { |
| 1962 | OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); |
| 1963 | return 0; |
| 1964 | } |
| 1965 | |
| 1966 | if (max_out < expected_size) { |
| 1967 | OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_DATA_TOO_LARGE); |
| 1968 | return 0; |
| 1969 | } |
| 1970 | |
| 1971 | // Copy result to OpenSSL-provided buffer. RawSignDigestWithPrivateKey |
| 1972 | // should pad with leading 0s, but if it doesn't, pad the result. |
| 1973 | size_t zero_pad = expected_size - result.size(); |
| 1974 | memset(out, 0, zero_pad); |
| 1975 | memcpy(out + zero_pad, &result[0], result.size()); |
| 1976 | *out_len = expected_size; |
| 1977 | |
| 1978 | return 1; |
| 1979 | } |
| 1980 | |
Alex Klyubin | d1b4488 | 2015-06-10 13:02:22 -0700 | [diff] [blame] | 1981 | int RsaMethodDecrypt(RSA* rsa, |
| 1982 | size_t* out_len, |
| 1983 | uint8_t* out, |
| 1984 | size_t max_out, |
| 1985 | const uint8_t* in, |
| 1986 | size_t in_len, |
| 1987 | int padding) { |
| 1988 | // Retrieve private key JNI reference. |
| 1989 | const KeyExData *ex_data = RsaGetExData(rsa); |
| 1990 | if (!ex_data || !ex_data->private_key) { |
| 1991 | OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_INTERNAL_ERROR); |
| 1992 | return 0; |
| 1993 | } |
| 1994 | |
| 1995 | JNIEnv* env = getJNIEnv(); |
| 1996 | if (env == NULL) { |
| 1997 | OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_INTERNAL_ERROR); |
| 1998 | return 0; |
| 1999 | } |
| 2000 | |
| 2001 | // This function behaves as RSA_private_decrypt. |
| 2002 | ScopedLocalRef<jbyteArray> cleartext( |
| 2003 | env, rsaDecryptWithPrivateKey( |
| 2004 | env, ex_data->private_key, padding, |
| 2005 | reinterpret_cast<const char*>(in), in_len)); |
| 2006 | if (cleartext.get() == NULL) { |
| 2007 | OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_INTERNAL_ERROR); |
| 2008 | return 0; |
| 2009 | } |
| 2010 | |
| 2011 | ScopedByteArrayRO cleartextBytes(env, cleartext.get()); |
| 2012 | |
| 2013 | if (max_out < cleartextBytes.size()) { |
| 2014 | OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_TOO_LARGE); |
| 2015 | return 0; |
| 2016 | } |
| 2017 | |
| 2018 | // Copy result to OpenSSL-provided buffer. |
| 2019 | memcpy(out, cleartextBytes.get(), cleartextBytes.size()); |
| 2020 | *out_len = cleartextBytes.size(); |
| 2021 | |
| 2022 | return 1; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2023 | } |
| 2024 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2025 | int RsaMethodVerifyRaw(RSA* /* rsa */, |
| 2026 | size_t* /* out_len */, |
| 2027 | uint8_t* /* out */, |
| 2028 | size_t /* max_out */, |
| 2029 | const uint8_t* /* in */, |
| 2030 | size_t /* in_len */, |
| 2031 | int /* padding */) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2032 | OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE); |
| 2033 | return 0; |
| 2034 | } |
| 2035 | |
| 2036 | const RSA_METHOD android_rsa_method = { |
| 2037 | { |
| 2038 | 0 /* references */, |
| 2039 | 1 /* is_static */ |
| 2040 | } /* common */, |
| 2041 | NULL /* app_data */, |
| 2042 | |
| 2043 | NULL /* init */, |
| 2044 | NULL /* finish */, |
| 2045 | RsaMethodSize, |
| 2046 | NULL /* sign */, |
| 2047 | NULL /* verify */, |
| 2048 | RsaMethodEncrypt, |
| 2049 | RsaMethodSignRaw, |
| 2050 | RsaMethodDecrypt, |
| 2051 | RsaMethodVerifyRaw, |
| 2052 | NULL /* mod_exp */, |
| 2053 | NULL /* bn_mod_exp */, |
| 2054 | NULL /* private_transform */, |
| 2055 | RSA_FLAG_OPAQUE, |
| 2056 | NULL /* keygen */, |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2057 | NULL /* supports_digest */, |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2058 | }; |
| 2059 | |
| 2060 | // Custom ECDSA_METHOD that uses the platform APIs. |
| 2061 | // Note that for now, only signing through ECDSA_sign() is really supported. |
| 2062 | // all other method pointers are either stubs returning errors, or no-ops. |
| 2063 | |
| 2064 | jobject EcKeyGetKey(const EC_KEY* ec_key) { |
| 2065 | KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( |
| 2066 | ec_key, g_ecdsa_exdata_index)); |
| 2067 | return ex_data->private_key; |
| 2068 | } |
| 2069 | |
| 2070 | size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { |
| 2071 | KeyExData* ex_data = reinterpret_cast<KeyExData*>(EC_KEY_get_ex_data( |
| 2072 | ec_key, g_ecdsa_exdata_index)); |
| 2073 | return ex_data->cached_size; |
| 2074 | } |
| 2075 | |
| 2076 | int EcdsaMethodSign(const uint8_t* digest, |
| 2077 | size_t digest_len, |
| 2078 | uint8_t* sig, |
| 2079 | unsigned int* sig_len, |
| 2080 | EC_KEY* ec_key) { |
| 2081 | // Retrieve private key JNI reference. |
| 2082 | jobject private_key = EcKeyGetKey(ec_key); |
| 2083 | if (!private_key) { |
| 2084 | ALOGE("Null JNI reference passed to EcdsaMethodSign!"); |
| 2085 | return 0; |
| 2086 | } |
| 2087 | |
| 2088 | JNIEnv* env = getJNIEnv(); |
| 2089 | if (env == NULL) { |
| 2090 | return 0; |
| 2091 | } |
| 2092 | |
| 2093 | // Sign message with it through JNI. |
| 2094 | ScopedLocalRef<jbyteArray> signature( |
| 2095 | env, rawSignDigestWithPrivateKey(env, private_key, |
| 2096 | reinterpret_cast<const char*>(digest), |
| 2097 | digest_len)); |
| 2098 | if (signature.get() == NULL) { |
| 2099 | ALOGE("Could not sign message in EcdsaMethodDoSign!"); |
| 2100 | return 0; |
| 2101 | } |
| 2102 | |
| 2103 | ScopedByteArrayRO signatureBytes(env, signature.get()); |
| 2104 | // Note: With ECDSA, the actual signature may be smaller than |
| 2105 | // ECDSA_size(). |
| 2106 | size_t max_expected_size = ECDSA_size(ec_key); |
| 2107 | if (signatureBytes.size() > max_expected_size) { |
| 2108 | ALOGE("ECDSA Signature size mismatch, actual: %zd, expected <= %zd", |
| 2109 | signatureBytes.size(), max_expected_size); |
| 2110 | return 0; |
| 2111 | } |
| 2112 | |
| 2113 | memcpy(sig, signatureBytes.get(), signatureBytes.size()); |
| 2114 | *sig_len = signatureBytes.size(); |
| 2115 | return 1; |
| 2116 | } |
| 2117 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2118 | int EcdsaMethodVerify(const uint8_t* /* digest */, |
| 2119 | size_t /* digest_len */, |
| 2120 | const uint8_t* /* sig */, |
| 2121 | size_t /* sig_len */, |
| 2122 | EC_KEY* /* ec_key */) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2123 | OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED); |
| 2124 | return 0; |
| 2125 | } |
| 2126 | |
| 2127 | const ECDSA_METHOD android_ecdsa_method = { |
| 2128 | { |
| 2129 | 0 /* references */, |
| 2130 | 1 /* is_static */ |
| 2131 | } /* common */, |
| 2132 | NULL /* app_data */, |
| 2133 | |
| 2134 | NULL /* init */, |
| 2135 | NULL /* finish */, |
| 2136 | EcdsaMethodGroupOrderSize, |
| 2137 | EcdsaMethodSign, |
| 2138 | EcdsaMethodVerify, |
| 2139 | ECDSA_FLAG_OPAQUE, |
| 2140 | }; |
| 2141 | |
| 2142 | |
| 2143 | void init_engine_globals() { |
| 2144 | g_rsa_exdata_index = |
| 2145 | RSA_get_ex_new_index(0 /* argl */, NULL /* argp */, NULL /* new_func */, |
| 2146 | ExDataDup, ExDataFree); |
| 2147 | g_ecdsa_exdata_index = |
| 2148 | EC_KEY_get_ex_new_index(0 /* argl */, NULL /* argp */, |
| 2149 | NULL /* new_func */, ExDataDup, ExDataFree); |
| 2150 | |
| 2151 | g_engine = ENGINE_new(); |
| 2152 | ENGINE_set_RSA_method(g_engine, &android_rsa_method, |
| 2153 | sizeof(android_rsa_method)); |
| 2154 | ENGINE_set_ECDSA_method(g_engine, &android_ecdsa_method, |
| 2155 | sizeof(android_ecdsa_method)); |
| 2156 | } |
| 2157 | |
| 2158 | } // anonymous namespace |
| 2159 | #endif |
| 2160 | |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 2161 | #ifdef CONSCRYPT_UNBUNDLED |
| 2162 | /* |
| 2163 | * This is a big hack; don't learn from this. Basically what happened is we do |
| 2164 | * not have an API way to insert ourselves into the AsynchronousCloseMonitor |
| 2165 | * that's compiled into the native libraries for libcore when we're unbundled. |
| 2166 | * So we try to look up the symbol from the main library to find it. |
| 2167 | */ |
| 2168 | typedef void (*acm_ctor_func)(void*, int); |
| 2169 | typedef void (*acm_dtor_func)(void*); |
| 2170 | static acm_ctor_func async_close_monitor_ctor = NULL; |
| 2171 | static acm_dtor_func async_close_monitor_dtor = NULL; |
| 2172 | |
| 2173 | class CompatibilityCloseMonitor { |
| 2174 | public: |
| 2175 | CompatibilityCloseMonitor(int fd) { |
| 2176 | if (async_close_monitor_ctor != NULL) { |
| 2177 | async_close_monitor_ctor(objBuffer, fd); |
| 2178 | } |
| 2179 | } |
| 2180 | |
| 2181 | ~CompatibilityCloseMonitor() { |
| 2182 | if (async_close_monitor_dtor != NULL) { |
| 2183 | async_close_monitor_dtor(objBuffer); |
| 2184 | } |
| 2185 | } |
| 2186 | private: |
| 2187 | char objBuffer[256]; |
| 2188 | #if 0 |
| 2189 | static_assert(sizeof(objBuffer) > 2*sizeof(AsynchronousCloseMonitor), |
| 2190 | "CompatibilityCloseMonitor must be larger than the actual object"); |
| 2191 | #endif |
| 2192 | }; |
| 2193 | |
| 2194 | static void findAsynchronousCloseMonitorFuncs() { |
| 2195 | void *lib = dlopen("libjavacore.so", RTLD_NOW); |
| 2196 | if (lib != NULL) { |
| 2197 | async_close_monitor_ctor = (acm_ctor_func) dlsym(lib, "_ZN24AsynchronousCloseMonitorC1Ei"); |
| 2198 | async_close_monitor_dtor = (acm_dtor_func) dlsym(lib, "_ZN24AsynchronousCloseMonitorD1Ev"); |
| 2199 | } |
| 2200 | } |
| 2201 | #endif |
| 2202 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2203 | /** |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 2204 | * Copied from libnativehelper NetworkUtilites.cpp |
| 2205 | */ |
| 2206 | static bool setBlocking(int fd, bool blocking) { |
| 2207 | int flags = fcntl(fd, F_GETFL); |
| 2208 | if (flags == -1) { |
| 2209 | return false; |
| 2210 | } |
| 2211 | |
| 2212 | if (!blocking) { |
| 2213 | flags |= O_NONBLOCK; |
| 2214 | } else { |
| 2215 | flags &= ~O_NONBLOCK; |
| 2216 | } |
| 2217 | |
| 2218 | int rc = fcntl(fd, F_SETFL, flags); |
| 2219 | return (rc != -1); |
| 2220 | } |
| 2221 | |
| 2222 | /** |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2223 | * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I |
| 2224 | * suppose there are not many other ways to do this on a Linux system (modulo |
| 2225 | * isomorphism). |
| 2226 | */ |
| 2227 | #define MUTEX_TYPE pthread_mutex_t |
| 2228 | #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) |
| 2229 | #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) |
| 2230 | #define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) |
| 2231 | #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) |
| 2232 | #define THREAD_ID pthread_self() |
| 2233 | #define THROW_SSLEXCEPTION (-2) |
| 2234 | #define THROW_SOCKETTIMEOUTEXCEPTION (-3) |
| 2235 | #define THROWN_EXCEPTION (-4) |
| 2236 | |
| 2237 | static MUTEX_TYPE* mutex_buf = NULL; |
| 2238 | |
| 2239 | static void locking_function(int mode, int n, const char*, int) { |
| 2240 | if (mode & CRYPTO_LOCK) { |
| 2241 | MUTEX_LOCK(mutex_buf[n]); |
| 2242 | } else { |
| 2243 | MUTEX_UNLOCK(mutex_buf[n]); |
| 2244 | } |
| 2245 | } |
| 2246 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2247 | static void threadid_callback(CRYPTO_THREADID *threadid) { |
Ian Rogers | a3a2eba | 2014-11-19 20:48:02 -0800 | [diff] [blame] | 2248 | #if defined(__APPLE__) |
Kenny Root | 0beef7d | 2014-11-20 09:01:08 -0800 | [diff] [blame] | 2249 | uint64_t owner; |
| 2250 | int rc = pthread_threadid_np(NULL, &owner); // Requires Mac OS 10.6 |
| 2251 | if (rc == 0) { |
| 2252 | CRYPTO_THREADID_set_numeric(threadid, owner); |
| 2253 | } else { |
| 2254 | ALOGE("Error calling pthread_threadid_np"); |
| 2255 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2256 | #else |
Kenny Root | 0beef7d | 2014-11-20 09:01:08 -0800 | [diff] [blame] | 2257 | // bionic exposes gettid(), but glibc doesn't |
| 2258 | CRYPTO_THREADID_set_numeric(threadid, syscall(__NR_gettid)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2259 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2260 | } |
| 2261 | |
| 2262 | int THREAD_setup(void) { |
| 2263 | mutex_buf = new MUTEX_TYPE[CRYPTO_num_locks()]; |
| 2264 | if (!mutex_buf) { |
| 2265 | return 0; |
| 2266 | } |
| 2267 | |
| 2268 | for (int i = 0; i < CRYPTO_num_locks(); ++i) { |
| 2269 | MUTEX_SETUP(mutex_buf[i]); |
| 2270 | } |
| 2271 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2272 | CRYPTO_THREADID_set_callback(threadid_callback); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2273 | CRYPTO_set_locking_callback(locking_function); |
| 2274 | |
| 2275 | return 1; |
| 2276 | } |
| 2277 | |
| 2278 | int THREAD_cleanup(void) { |
| 2279 | if (!mutex_buf) { |
| 2280 | return 0; |
| 2281 | } |
| 2282 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2283 | CRYPTO_THREADID_set_callback(NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2284 | CRYPTO_set_locking_callback(NULL); |
| 2285 | |
| 2286 | for (int i = 0; i < CRYPTO_num_locks( ); i++) { |
| 2287 | MUTEX_CLEANUP(mutex_buf[i]); |
| 2288 | } |
| 2289 | |
| 2290 | free(mutex_buf); |
| 2291 | mutex_buf = NULL; |
| 2292 | |
| 2293 | return 1; |
| 2294 | } |
| 2295 | |
| 2296 | /** |
| 2297 | * Initialization phase for every OpenSSL job: Loads the Error strings, the |
| 2298 | * crypto algorithms and reset the OpenSSL library |
| 2299 | */ |
Kenny Root | 4d7e1f9 | 2015-04-22 09:00:29 -0700 | [diff] [blame] | 2300 | static jboolean NativeCrypto_clinit(JNIEnv*, jclass) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2301 | { |
| 2302 | SSL_load_error_strings(); |
| 2303 | ERR_load_crypto_strings(); |
| 2304 | SSL_library_init(); |
| 2305 | OpenSSL_add_all_algorithms(); |
| 2306 | THREAD_setup(); |
Kenny Root | 4d7e1f9 | 2015-04-22 09:00:29 -0700 | [diff] [blame] | 2307 | #if !defined(OPENSSL_IS_BORINGSSL) |
| 2308 | return JNI_FALSE; |
| 2309 | #else |
| 2310 | return JNI_TRUE; |
| 2311 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2312 | } |
| 2313 | |
| 2314 | static void NativeCrypto_ENGINE_load_dynamic(JNIEnv*, jclass) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2315 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2316 | JNI_TRACE("ENGINE_load_dynamic()"); |
| 2317 | |
| 2318 | ENGINE_load_dynamic(); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2319 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2320 | } |
| 2321 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2322 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2323 | static jlong NativeCrypto_ENGINE_by_id(JNIEnv* env, jclass, jstring idJava) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2324 | JNI_TRACE("ENGINE_by_id(%p)", idJava); |
| 2325 | |
| 2326 | ScopedUtfChars id(env, idJava); |
| 2327 | if (id.c_str() == NULL) { |
| 2328 | JNI_TRACE("ENGINE_by_id(%p) => id == null", idJava); |
| 2329 | return 0; |
| 2330 | } |
| 2331 | JNI_TRACE("ENGINE_by_id(\"%s\")", id.c_str()); |
| 2332 | |
| 2333 | ENGINE* e = ENGINE_by_id(id.c_str()); |
| 2334 | if (e == NULL) { |
| 2335 | freeOpenSslErrorState(); |
| 2336 | } |
| 2337 | |
| 2338 | JNI_TRACE("ENGINE_by_id(\"%s\") => %p", id.c_str(), e); |
| 2339 | return reinterpret_cast<uintptr_t>(e); |
| 2340 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2341 | #else |
| 2342 | static jlong NativeCrypto_ENGINE_by_id(JNIEnv*, jclass, jstring) { |
| 2343 | return 0; |
| 2344 | } |
| 2345 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2346 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2347 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2348 | static jint NativeCrypto_ENGINE_add(JNIEnv* env, jclass, jlong engineRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2349 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2350 | JNI_TRACE("ENGINE_add(%p)", e); |
| 2351 | |
| 2352 | if (e == NULL) { |
| 2353 | jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); |
| 2354 | return 0; |
| 2355 | } |
| 2356 | |
| 2357 | int ret = ENGINE_add(e); |
| 2358 | |
| 2359 | /* |
| 2360 | * We tolerate errors, because the most likely error is that |
| 2361 | * the ENGINE is already in the list. |
| 2362 | */ |
| 2363 | freeOpenSslErrorState(); |
| 2364 | |
| 2365 | JNI_TRACE("ENGINE_add(%p) => %d", e, ret); |
| 2366 | return ret; |
| 2367 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2368 | #else |
| 2369 | static jint NativeCrypto_ENGINE_add(JNIEnv*, jclass, jlong) { |
| 2370 | return 0; |
| 2371 | } |
| 2372 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2373 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2374 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2375 | static jint NativeCrypto_ENGINE_init(JNIEnv* env, jclass, jlong engineRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2376 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2377 | JNI_TRACE("ENGINE_init(%p)", e); |
| 2378 | |
| 2379 | if (e == NULL) { |
| 2380 | jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); |
| 2381 | return 0; |
| 2382 | } |
| 2383 | |
| 2384 | int ret = ENGINE_init(e); |
| 2385 | JNI_TRACE("ENGINE_init(%p) => %d", e, ret); |
| 2386 | return ret; |
| 2387 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2388 | #else |
| 2389 | static jint NativeCrypto_ENGINE_init(JNIEnv*, jclass, jlong) { |
| 2390 | return 0; |
| 2391 | } |
| 2392 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2393 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2394 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2395 | static jint NativeCrypto_ENGINE_finish(JNIEnv* env, jclass, jlong engineRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2396 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2397 | JNI_TRACE("ENGINE_finish(%p)", e); |
| 2398 | |
| 2399 | if (e == NULL) { |
| 2400 | jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); |
| 2401 | return 0; |
| 2402 | } |
| 2403 | |
| 2404 | int ret = ENGINE_finish(e); |
| 2405 | JNI_TRACE("ENGINE_finish(%p) => %d", e, ret); |
| 2406 | return ret; |
| 2407 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2408 | #else |
| 2409 | static jint NativeCrypto_ENGINE_finish(JNIEnv*, jclass, jlong) { |
| 2410 | return 0; |
| 2411 | } |
| 2412 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2413 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2414 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2415 | static jint NativeCrypto_ENGINE_free(JNIEnv* env, jclass, jlong engineRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2416 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2417 | JNI_TRACE("ENGINE_free(%p)", e); |
| 2418 | |
| 2419 | if (e == NULL) { |
| 2420 | jniThrowException(env, "java/lang/IllegalArgumentException", "engineRef == 0"); |
| 2421 | return 0; |
| 2422 | } |
| 2423 | |
| 2424 | int ret = ENGINE_free(e); |
| 2425 | JNI_TRACE("ENGINE_free(%p) => %d", e, ret); |
| 2426 | return ret; |
| 2427 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2428 | #else |
| 2429 | static jint NativeCrypto_ENGINE_free(JNIEnv*, jclass, jlong) { |
| 2430 | return 0; |
| 2431 | } |
| 2432 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2433 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2434 | #if defined(OPENSSL_IS_BORINGSSL) |
| 2435 | extern "C" { |
| 2436 | /* EVP_PKEY_from_keystore is from system/security/keystore-engine. */ |
| 2437 | extern EVP_PKEY* EVP_PKEY_from_keystore(const char *key_id); |
| 2438 | } |
| 2439 | #endif |
| 2440 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2441 | static jlong NativeCrypto_ENGINE_load_private_key(JNIEnv* env, jclass, jlong engineRef, |
| 2442 | jstring idJava) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2443 | ScopedUtfChars id(env, idJava); |
| 2444 | if (id.c_str() == NULL) { |
| 2445 | jniThrowException(env, "java/lang/IllegalArgumentException", "id == NULL"); |
| 2446 | return 0; |
| 2447 | } |
| 2448 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2449 | #if !defined(OPENSSL_IS_BORINGSSL) |
| 2450 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2451 | JNI_TRACE("ENGINE_load_private_key(%p, %p)", e, idJava); |
| 2452 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2453 | Unique_EVP_PKEY pkey(ENGINE_load_private_key(e, id.c_str(), NULL, NULL)); |
| 2454 | if (pkey.get() == NULL) { |
Kenny Root | d12c567 | 2015-04-29 10:32:45 -0700 | [diff] [blame] | 2455 | throwExceptionIfNecessary(env, "ENGINE_load_private_key", throwInvalidKeyException); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2456 | return 0; |
| 2457 | } |
| 2458 | |
| 2459 | JNI_TRACE("ENGINE_load_private_key(%p, %p) => %p", e, idJava, pkey.get()); |
| 2460 | return reinterpret_cast<uintptr_t>(pkey.release()); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2461 | #else |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2462 | UNUSED_ARGUMENT(engineRef); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2463 | #if defined(NO_KEYSTORE_ENGINE) |
| 2464 | jniThrowRuntimeException(env, "No keystore ENGINE support compiled in"); |
| 2465 | return 0; |
| 2466 | #else |
| 2467 | Unique_EVP_PKEY pkey(EVP_PKEY_from_keystore(id.c_str())); |
| 2468 | if (pkey.get() == NULL) { |
Kenny Root | d12c567 | 2015-04-29 10:32:45 -0700 | [diff] [blame] | 2469 | throwExceptionIfNecessary(env, "ENGINE_load_private_key", throwInvalidKeyException); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2470 | return 0; |
| 2471 | } |
| 2472 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 2473 | #endif |
| 2474 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2475 | } |
| 2476 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2477 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2478 | static jstring NativeCrypto_ENGINE_get_id(JNIEnv* env, jclass, jlong engineRef) |
| 2479 | { |
| 2480 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2481 | JNI_TRACE("ENGINE_get_id(%p)", e); |
| 2482 | |
| 2483 | if (e == NULL) { |
| 2484 | jniThrowNullPointerException(env, "engine == null"); |
| 2485 | JNI_TRACE("ENGINE_get_id(%p) => engine == null", e); |
| 2486 | return NULL; |
| 2487 | } |
| 2488 | |
| 2489 | const char *id = ENGINE_get_id(e); |
| 2490 | ScopedLocalRef<jstring> idJava(env, env->NewStringUTF(id)); |
| 2491 | |
| 2492 | JNI_TRACE("ENGINE_get_id(%p) => \"%s\"", e, id); |
| 2493 | return idJava.release(); |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2494 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2495 | #else |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2496 | static jstring NativeCrypto_ENGINE_get_id(JNIEnv* env, jclass, jlong) |
| 2497 | { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2498 | ScopedLocalRef<jstring> idJava(env, env->NewStringUTF("keystore")); |
| 2499 | return idJava.release(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2500 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2501 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2502 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2503 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2504 | static jint NativeCrypto_ENGINE_ctrl_cmd_string(JNIEnv* env, jclass, jlong engineRef, |
| 2505 | jstring cmdJava, jstring argJava, jint cmd_optional) |
| 2506 | { |
| 2507 | ENGINE* e = reinterpret_cast<ENGINE*>(static_cast<uintptr_t>(engineRef)); |
| 2508 | JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d)", e, cmdJava, argJava, cmd_optional); |
| 2509 | |
| 2510 | if (e == NULL) { |
| 2511 | jniThrowNullPointerException(env, "engine == null"); |
| 2512 | JNI_TRACE("ENGINE_ctrl_cmd_string(%p, %p, %p, %d) => engine == null", e, cmdJava, argJava, |
| 2513 | cmd_optional); |
| 2514 | return 0; |
| 2515 | } |
| 2516 | |
| 2517 | ScopedUtfChars cmdChars(env, cmdJava); |
| 2518 | if (cmdChars.c_str() == NULL) { |
| 2519 | return 0; |
| 2520 | } |
| 2521 | |
| 2522 | UniquePtr<ScopedUtfChars> arg; |
| 2523 | const char* arg_c_str = NULL; |
| 2524 | if (argJava != NULL) { |
| 2525 | arg.reset(new ScopedUtfChars(env, argJava)); |
| 2526 | arg_c_str = arg->c_str(); |
| 2527 | if (arg_c_str == NULL) { |
| 2528 | return 0; |
| 2529 | } |
| 2530 | } |
| 2531 | JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d)", e, cmdChars.c_str(), arg_c_str, |
| 2532 | cmd_optional); |
| 2533 | |
| 2534 | int ret = ENGINE_ctrl_cmd_string(e, cmdChars.c_str(), arg_c_str, cmd_optional); |
| 2535 | if (ret != 1) { |
| 2536 | throwExceptionIfNecessary(env, "ENGINE_ctrl_cmd_string"); |
| 2537 | JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => threw error", e, |
| 2538 | cmdChars.c_str(), arg_c_str, cmd_optional); |
| 2539 | return 0; |
| 2540 | } |
| 2541 | |
| 2542 | JNI_TRACE("ENGINE_ctrl_cmd_string(%p, \"%s\", \"%s\", %d) => %d", e, cmdChars.c_str(), |
| 2543 | arg_c_str, cmd_optional, ret); |
| 2544 | return ret; |
| 2545 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 2546 | #else |
| 2547 | static jint NativeCrypto_ENGINE_ctrl_cmd_string(JNIEnv*, jclass, jlong, jstring, jstring, jint) |
| 2548 | { |
| 2549 | return 0; |
| 2550 | } |
| 2551 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2552 | |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 2553 | static jlong NativeCrypto_EVP_PKEY_new_DH(JNIEnv* env, jclass, |
| 2554 | jbyteArray p, jbyteArray g, |
| 2555 | jbyteArray pub_key, jbyteArray priv_key) { |
| 2556 | JNI_TRACE("EVP_PKEY_new_DH(p=%p, g=%p, pub_key=%p, priv_key=%p)", |
| 2557 | p, g, pub_key, priv_key); |
| 2558 | |
| 2559 | Unique_DH dh(DH_new()); |
| 2560 | if (dh.get() == NULL) { |
| 2561 | jniThrowRuntimeException(env, "DH_new failed"); |
| 2562 | return 0; |
| 2563 | } |
| 2564 | |
| 2565 | if (!arrayToBignum(env, p, &dh->p)) { |
| 2566 | return 0; |
| 2567 | } |
| 2568 | |
| 2569 | if (!arrayToBignum(env, g, &dh->g)) { |
| 2570 | return 0; |
| 2571 | } |
| 2572 | |
| 2573 | if (pub_key != NULL && !arrayToBignum(env, pub_key, &dh->pub_key)) { |
| 2574 | return 0; |
| 2575 | } |
| 2576 | |
| 2577 | if (priv_key != NULL && !arrayToBignum(env, priv_key, &dh->priv_key)) { |
| 2578 | return 0; |
| 2579 | } |
| 2580 | |
| 2581 | if (dh->p == NULL || dh->g == NULL |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 2582 | || (pub_key != NULL && dh->pub_key == NULL) |
| 2583 | || (priv_key != NULL && dh->priv_key == NULL)) { |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 2584 | jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); |
| 2585 | return 0; |
| 2586 | } |
| 2587 | |
Kenny Root | e526e75 | 2014-05-14 09:37:56 -0700 | [diff] [blame] | 2588 | /* The public key can be recovered if the private key is available. */ |
| 2589 | if (dh->pub_key == NULL && dh->priv_key != NULL) { |
| 2590 | if (!DH_generate_key(dh.get())) { |
| 2591 | jniThrowRuntimeException(env, "EVP_PKEY_new_DH failed during pub_key generation"); |
| 2592 | return 0; |
| 2593 | } |
| 2594 | } |
| 2595 | |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 2596 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 2597 | if (pkey.get() == NULL) { |
| 2598 | jniThrowRuntimeException(env, "EVP_PKEY_new failed"); |
| 2599 | return 0; |
| 2600 | } |
| 2601 | if (EVP_PKEY_assign_DH(pkey.get(), dh.get()) != 1) { |
| 2602 | jniThrowRuntimeException(env, "EVP_PKEY_assign_DH failed"); |
| 2603 | return 0; |
| 2604 | } |
| 2605 | OWNERSHIP_TRANSFERRED(dh); |
| 2606 | JNI_TRACE("EVP_PKEY_new_DH(p=%p, g=%p, pub_key=%p, priv_key=%p) => %p", |
| 2607 | p, g, pub_key, priv_key, pkey.get()); |
| 2608 | return reinterpret_cast<jlong>(pkey.release()); |
| 2609 | } |
| 2610 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2611 | /** |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2612 | * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q); |
| 2613 | */ |
| 2614 | static jlong NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass, |
| 2615 | jbyteArray n, jbyteArray e, jbyteArray d, |
| 2616 | jbyteArray p, jbyteArray q, |
| 2617 | jbyteArray dmp1, jbyteArray dmq1, |
| 2618 | jbyteArray iqmp) { |
| 2619 | JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p, dmp1=%p, dmq1=%p, iqmp=%p)", |
| 2620 | n, e, d, p, q, dmp1, dmq1, iqmp); |
| 2621 | |
| 2622 | Unique_RSA rsa(RSA_new()); |
| 2623 | if (rsa.get() == NULL) { |
| 2624 | jniThrowRuntimeException(env, "RSA_new failed"); |
| 2625 | return 0; |
| 2626 | } |
| 2627 | |
| 2628 | if (e == NULL && d == NULL) { |
| 2629 | jniThrowException(env, "java/lang/IllegalArgumentException", "e == NULL && d == NULL"); |
| 2630 | JNI_TRACE("NativeCrypto_EVP_PKEY_new_RSA => e == NULL && d == NULL"); |
| 2631 | return 0; |
| 2632 | } |
| 2633 | |
| 2634 | if (!arrayToBignum(env, n, &rsa->n)) { |
| 2635 | return 0; |
| 2636 | } |
| 2637 | |
| 2638 | if (e != NULL && !arrayToBignum(env, e, &rsa->e)) { |
| 2639 | return 0; |
| 2640 | } |
| 2641 | |
| 2642 | if (d != NULL && !arrayToBignum(env, d, &rsa->d)) { |
| 2643 | return 0; |
| 2644 | } |
| 2645 | |
| 2646 | if (p != NULL && !arrayToBignum(env, p, &rsa->p)) { |
| 2647 | return 0; |
| 2648 | } |
| 2649 | |
| 2650 | if (q != NULL && !arrayToBignum(env, q, &rsa->q)) { |
| 2651 | return 0; |
| 2652 | } |
| 2653 | |
| 2654 | if (dmp1 != NULL && !arrayToBignum(env, dmp1, &rsa->dmp1)) { |
| 2655 | return 0; |
| 2656 | } |
| 2657 | |
| 2658 | if (dmq1 != NULL && !arrayToBignum(env, dmq1, &rsa->dmq1)) { |
| 2659 | return 0; |
| 2660 | } |
| 2661 | |
| 2662 | if (iqmp != NULL && !arrayToBignum(env, iqmp, &rsa->iqmp)) { |
| 2663 | return 0; |
| 2664 | } |
| 2665 | |
| 2666 | #ifdef WITH_JNI_TRACE |
| 2667 | if (p != NULL && q != NULL) { |
| 2668 | int check = RSA_check_key(rsa.get()); |
| 2669 | JNI_TRACE("EVP_PKEY_new_RSA(...) RSA_check_key returns %d", check); |
| 2670 | } |
| 2671 | #endif |
| 2672 | |
| 2673 | if (rsa->n == NULL || (rsa->e == NULL && rsa->d == NULL)) { |
| 2674 | jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); |
| 2675 | return 0; |
| 2676 | } |
| 2677 | |
| 2678 | /* |
| 2679 | * If the private exponent is available, there is the potential to do signing |
Kenny Root | fbb754f | 2015-05-06 12:51:13 -0700 | [diff] [blame] | 2680 | * operations. However, we can only do blinding if the public exponent is also |
| 2681 | * available. Disable blinding if the public exponent isn't available. |
| 2682 | * |
| 2683 | * TODO[kroot]: We should try to recover the public exponent by trying |
| 2684 | * some common ones such 3, 17, or 65537. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2685 | */ |
Kenny Root | fbb754f | 2015-05-06 12:51:13 -0700 | [diff] [blame] | 2686 | if (rsa->d != NULL && rsa->e == NULL) { |
| 2687 | JNI_TRACE("EVP_PKEY_new_RSA(...) disabling RSA blinding => %p", rsa.get()); |
| 2688 | rsa->flags |= RSA_FLAG_NO_BLINDING; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2689 | } |
| 2690 | |
| 2691 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 2692 | if (pkey.get() == NULL) { |
| 2693 | jniThrowRuntimeException(env, "EVP_PKEY_new failed"); |
| 2694 | return 0; |
| 2695 | } |
| 2696 | if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { |
| 2697 | jniThrowRuntimeException(env, "EVP_PKEY_new failed"); |
| 2698 | return 0; |
| 2699 | } |
| 2700 | OWNERSHIP_TRANSFERRED(rsa); |
| 2701 | JNI_TRACE("EVP_PKEY_new_RSA(n=%p, e=%p, d=%p, p=%p, q=%p dmp1=%p, dmq1=%p, iqmp=%p) => %p", |
| 2702 | n, e, d, p, q, dmp1, dmq1, iqmp, pkey.get()); |
| 2703 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 2704 | } |
| 2705 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 2706 | static jlong NativeCrypto_EVP_PKEY_new_EC_KEY(JNIEnv* env, jclass, jobject groupRef, |
| 2707 | jobject pubkeyRef, jbyteArray keyJavaBytes) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2708 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p)", groupRef, pubkeyRef, keyJavaBytes); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 2709 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2710 | if (group == NULL) { |
| 2711 | return 0; |
| 2712 | } |
Kenny Root | 03b0898 | 2014-12-30 14:25:55 -0800 | [diff] [blame] | 2713 | const EC_POINT* pubkey = pubkeyRef == NULL ? NULL : |
| 2714 | fromContextObject<EC_POINT>(env, pubkeyRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2715 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) <- ptr", group, pubkey, keyJavaBytes); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2716 | |
| 2717 | Unique_BIGNUM key(NULL); |
| 2718 | if (keyJavaBytes != NULL) { |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 2719 | BIGNUM* keyRef = NULL; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2720 | if (!arrayToBignum(env, keyJavaBytes, &keyRef)) { |
| 2721 | return 0; |
| 2722 | } |
| 2723 | key.reset(keyRef); |
| 2724 | } |
| 2725 | |
| 2726 | Unique_EC_KEY eckey(EC_KEY_new()); |
| 2727 | if (eckey.get() == NULL) { |
| 2728 | jniThrowRuntimeException(env, "EC_KEY_new failed"); |
| 2729 | return 0; |
| 2730 | } |
| 2731 | |
| 2732 | if (EC_KEY_set_group(eckey.get(), group) != 1) { |
| 2733 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) > EC_KEY_set_group failed", group, pubkey, |
| 2734 | keyJavaBytes); |
| 2735 | throwExceptionIfNecessary(env, "EC_KEY_set_group"); |
| 2736 | return 0; |
| 2737 | } |
| 2738 | |
| 2739 | if (pubkey != NULL) { |
| 2740 | if (EC_KEY_set_public_key(eckey.get(), pubkey) != 1) { |
| 2741 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group, |
| 2742 | pubkey, keyJavaBytes); |
| 2743 | throwExceptionIfNecessary(env, "EC_KEY_set_public_key"); |
| 2744 | return 0; |
| 2745 | } |
| 2746 | } |
| 2747 | |
| 2748 | if (key.get() != NULL) { |
| 2749 | if (EC_KEY_set_private_key(eckey.get(), key.get()) != 1) { |
| 2750 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => EC_KEY_set_private_key failed", group, |
| 2751 | pubkey, keyJavaBytes); |
| 2752 | throwExceptionIfNecessary(env, "EC_KEY_set_private_key"); |
| 2753 | return 0; |
| 2754 | } |
| 2755 | if (pubkey == NULL) { |
| 2756 | Unique_EC_POINT calcPubkey(EC_POINT_new(group)); |
| 2757 | if (!EC_POINT_mul(group, calcPubkey.get(), key.get(), NULL, NULL, NULL)) { |
| 2758 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => can't calulate public key", group, |
| 2759 | pubkey, keyJavaBytes); |
| 2760 | throwExceptionIfNecessary(env, "EC_KEY_set_private_key"); |
| 2761 | return 0; |
| 2762 | } |
| 2763 | EC_KEY_set_public_key(eckey.get(), calcPubkey.get()); |
| 2764 | } |
| 2765 | } |
| 2766 | |
| 2767 | if (!EC_KEY_check_key(eckey.get())) { |
| 2768 | JNI_TRACE("EVP_KEY_new_EC_KEY(%p, %p, %p) => invalid key created", group, pubkey, keyJavaBytes); |
| 2769 | throwExceptionIfNecessary(env, "EC_KEY_check_key"); |
| 2770 | return 0; |
| 2771 | } |
| 2772 | |
| 2773 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 2774 | if (pkey.get() == NULL) { |
| 2775 | JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes); |
| 2776 | throwExceptionIfNecessary(env, "EVP_PKEY_new failed"); |
| 2777 | return 0; |
| 2778 | } |
| 2779 | if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) { |
| 2780 | JNI_TRACE("EVP_PKEY_new_EC(%p, %p, %p) => threw error", group, pubkey, keyJavaBytes); |
| 2781 | jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed"); |
| 2782 | return 0; |
| 2783 | } |
| 2784 | OWNERSHIP_TRANSFERRED(eckey); |
| 2785 | |
| 2786 | JNI_TRACE("EVP_PKEY_new_EC_KEY(%p, %p, %p) => %p", group, pubkey, keyJavaBytes, pkey.get()); |
| 2787 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 2788 | } |
| 2789 | |
| 2790 | static jlong NativeCrypto_EVP_PKEY_new_mac_key(JNIEnv* env, jclass, jint pkeyType, |
| 2791 | jbyteArray keyJavaBytes) |
| 2792 | { |
| 2793 | JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p)", pkeyType, keyJavaBytes); |
| 2794 | |
| 2795 | ScopedByteArrayRO key(env, keyJavaBytes); |
| 2796 | if (key.get() == NULL) { |
| 2797 | return 0; |
| 2798 | } |
| 2799 | |
| 2800 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(key.get()); |
| 2801 | Unique_EVP_PKEY pkey(EVP_PKEY_new_mac_key(pkeyType, (ENGINE *) NULL, tmp, key.size())); |
| 2802 | if (pkey.get() == NULL) { |
| 2803 | JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => threw error", pkeyType, keyJavaBytes); |
| 2804 | throwExceptionIfNecessary(env, "ENGINE_load_private_key"); |
| 2805 | return 0; |
| 2806 | } |
| 2807 | |
| 2808 | JNI_TRACE("EVP_PKEY_new_mac_key(%d, %p) => %p", pkeyType, keyJavaBytes, pkey.get()); |
| 2809 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 2810 | } |
| 2811 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2812 | static int NativeCrypto_EVP_PKEY_type(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2813 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2814 | JNI_TRACE("EVP_PKEY_type(%p)", pkey); |
| 2815 | |
| 2816 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2817 | return -1; |
| 2818 | } |
| 2819 | |
| 2820 | int result = EVP_PKEY_type(pkey->type); |
| 2821 | JNI_TRACE("EVP_PKEY_type(%p) => %d", pkey, result); |
| 2822 | return result; |
| 2823 | } |
| 2824 | |
| 2825 | /** |
| 2826 | * private static native int EVP_PKEY_size(int pkey); |
| 2827 | */ |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2828 | static int NativeCrypto_EVP_PKEY_size(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2829 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2830 | JNI_TRACE("EVP_PKEY_size(%p)", pkey); |
| 2831 | |
| 2832 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2833 | return -1; |
| 2834 | } |
| 2835 | |
| 2836 | int result = EVP_PKEY_size(pkey); |
| 2837 | JNI_TRACE("EVP_PKEY_size(%p) => %d", pkey, result); |
| 2838 | return result; |
| 2839 | } |
| 2840 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2841 | static jstring NativeCrypto_EVP_PKEY_print_public(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2842 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2843 | JNI_TRACE("EVP_PKEY_print_public(%p)", pkey); |
| 2844 | |
| 2845 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2846 | return NULL; |
| 2847 | } |
| 2848 | |
| 2849 | Unique_BIO buffer(BIO_new(BIO_s_mem())); |
| 2850 | if (buffer.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 2851 | jniThrowOutOfMemory(env, "Unable to allocate BIO"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2852 | return NULL; |
| 2853 | } |
| 2854 | |
| 2855 | if (EVP_PKEY_print_public(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) { |
| 2856 | throwExceptionIfNecessary(env, "EVP_PKEY_print_public"); |
| 2857 | return NULL; |
| 2858 | } |
| 2859 | // Null terminate this |
| 2860 | BIO_write(buffer.get(), "\0", 1); |
| 2861 | |
| 2862 | char *tmp; |
| 2863 | BIO_get_mem_data(buffer.get(), &tmp); |
| 2864 | jstring description = env->NewStringUTF(tmp); |
| 2865 | |
| 2866 | JNI_TRACE("EVP_PKEY_print_public(%p) => \"%s\"", pkey, tmp); |
| 2867 | return description; |
| 2868 | } |
| 2869 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2870 | static jstring NativeCrypto_EVP_PKEY_print_private(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2871 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2872 | JNI_TRACE("EVP_PKEY_print_private(%p)", pkey); |
| 2873 | |
| 2874 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2875 | return NULL; |
| 2876 | } |
| 2877 | |
| 2878 | Unique_BIO buffer(BIO_new(BIO_s_mem())); |
| 2879 | if (buffer.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 2880 | jniThrowOutOfMemory(env, "Unable to allocate BIO"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2881 | return NULL; |
| 2882 | } |
| 2883 | |
| 2884 | if (EVP_PKEY_print_private(buffer.get(), pkey, 0, (ASN1_PCTX*) NULL) != 1) { |
| 2885 | throwExceptionIfNecessary(env, "EVP_PKEY_print_private"); |
| 2886 | return NULL; |
| 2887 | } |
| 2888 | // Null terminate this |
| 2889 | BIO_write(buffer.get(), "\0", 1); |
| 2890 | |
| 2891 | char *tmp; |
| 2892 | BIO_get_mem_data(buffer.get(), &tmp); |
| 2893 | jstring description = env->NewStringUTF(tmp); |
| 2894 | |
| 2895 | JNI_TRACE("EVP_PKEY_print_private(%p) => \"%s\"", pkey, tmp); |
| 2896 | return description; |
| 2897 | } |
| 2898 | |
| 2899 | static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, jlong pkeyRef) { |
| 2900 | EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); |
| 2901 | JNI_TRACE("EVP_PKEY_free(%p)", pkey); |
| 2902 | |
| 2903 | if (pkey != NULL) { |
| 2904 | EVP_PKEY_free(pkey); |
| 2905 | } |
| 2906 | } |
| 2907 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2908 | static jint NativeCrypto_EVP_PKEY_cmp(JNIEnv* env, jclass, jobject pkey1Ref, jobject pkey2Ref) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2909 | JNI_TRACE("EVP_PKEY_cmp(%p, %p)", pkey1Ref, pkey2Ref); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2910 | EVP_PKEY* pkey1 = fromContextObject<EVP_PKEY>(env, pkey1Ref); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2911 | if (pkey1 == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2912 | JNI_TRACE("EVP_PKEY_cmp => pkey1 == NULL"); |
| 2913 | return 0; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2914 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2915 | EVP_PKEY* pkey2 = fromContextObject<EVP_PKEY>(env, pkey2Ref); |
| 2916 | if (pkey2 == NULL) { |
| 2917 | JNI_TRACE("EVP_PKEY_cmp => pkey2 == NULL"); |
| 2918 | return 0; |
| 2919 | } |
| 2920 | JNI_TRACE("EVP_PKEY_cmp(%p, %p) <- ptr", pkey1, pkey2); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2921 | |
| 2922 | int result = EVP_PKEY_cmp(pkey1, pkey2); |
| 2923 | JNI_TRACE("EVP_PKEY_cmp(%p, %p) => %d", pkey1, pkey2, result); |
| 2924 | return result; |
| 2925 | } |
| 2926 | |
| 2927 | /* |
| 2928 | * static native byte[] i2d_PKCS8_PRIV_KEY_INFO(int, byte[]) |
| 2929 | */ |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2930 | static jbyteArray NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2931 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2932 | JNI_TRACE("i2d_PKCS8_PRIV_KEY_INFO(%p)", pkey); |
| 2933 | |
| 2934 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2935 | return NULL; |
| 2936 | } |
| 2937 | |
| 2938 | Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey)); |
| 2939 | if (pkcs8.get() == NULL) { |
| 2940 | throwExceptionIfNecessary(env, "NativeCrypto_i2d_PKCS8_PRIV_KEY_INFO"); |
| 2941 | JNI_TRACE("key=%p i2d_PKCS8_PRIV_KEY_INFO => error from key to PKCS8", pkey); |
| 2942 | return NULL; |
| 2943 | } |
| 2944 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2945 | return ASN1ToByteArray<PKCS8_PRIV_KEY_INFO>(env, pkcs8.get(), i2d_PKCS8_PRIV_KEY_INFO); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2946 | } |
| 2947 | |
| 2948 | /* |
| 2949 | * static native int d2i_PKCS8_PRIV_KEY_INFO(byte[]) |
| 2950 | */ |
| 2951 | static jlong NativeCrypto_d2i_PKCS8_PRIV_KEY_INFO(JNIEnv* env, jclass, jbyteArray keyJavaBytes) { |
| 2952 | JNI_TRACE("d2i_PKCS8_PRIV_KEY_INFO(%p)", keyJavaBytes); |
| 2953 | |
| 2954 | ScopedByteArrayRO bytes(env, keyJavaBytes); |
| 2955 | if (bytes.get() == NULL) { |
| 2956 | JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => threw exception", keyJavaBytes); |
| 2957 | return 0; |
| 2958 | } |
| 2959 | |
| 2960 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); |
| 2961 | Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &tmp, bytes.size())); |
| 2962 | if (pkcs8.get() == NULL) { |
| 2963 | throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO"); |
| 2964 | JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from DER to PKCS8", keyJavaBytes); |
| 2965 | return 0; |
| 2966 | } |
| 2967 | |
| 2968 | Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); |
| 2969 | if (pkey.get() == NULL) { |
| 2970 | throwExceptionIfNecessary(env, "d2i_PKCS8_PRIV_KEY_INFO"); |
| 2971 | JNI_TRACE("ssl=%p d2i_PKCS8_PRIV_KEY_INFO => error from PKCS8 to key", keyJavaBytes); |
| 2972 | return 0; |
| 2973 | } |
| 2974 | |
| 2975 | JNI_TRACE("bytes=%p d2i_PKCS8_PRIV_KEY_INFO => %p", keyJavaBytes, pkey.get()); |
| 2976 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 2977 | } |
| 2978 | |
| 2979 | /* |
| 2980 | * static native byte[] i2d_PUBKEY(int) |
| 2981 | */ |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 2982 | static jbyteArray NativeCrypto_i2d_PUBKEY(JNIEnv* env, jclass, jobject pkeyRef) { |
| 2983 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2984 | JNI_TRACE("i2d_PUBKEY(%p)", pkey); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 2985 | if (pkey == NULL) { |
| 2986 | return NULL; |
| 2987 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 2988 | return ASN1ToByteArray<EVP_PKEY>(env, pkey, reinterpret_cast<int (*) (EVP_PKEY*, uint8_t **)>(i2d_PUBKEY)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 2989 | } |
| 2990 | |
| 2991 | /* |
| 2992 | * static native int d2i_PUBKEY(byte[]) |
| 2993 | */ |
| 2994 | static jlong NativeCrypto_d2i_PUBKEY(JNIEnv* env, jclass, jbyteArray javaBytes) { |
| 2995 | JNI_TRACE("d2i_PUBKEY(%p)", javaBytes); |
| 2996 | |
| 2997 | ScopedByteArrayRO bytes(env, javaBytes); |
| 2998 | if (bytes.get() == NULL) { |
| 2999 | JNI_TRACE("d2i_PUBKEY(%p) => threw error", javaBytes); |
| 3000 | return 0; |
| 3001 | } |
| 3002 | |
| 3003 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(bytes.get()); |
| 3004 | Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, bytes.size())); |
| 3005 | if (pkey.get() == NULL) { |
| 3006 | JNI_TRACE("bytes=%p d2i_PUBKEY => threw exception", javaBytes); |
| 3007 | throwExceptionIfNecessary(env, "d2i_PUBKEY"); |
| 3008 | return 0; |
| 3009 | } |
| 3010 | |
| 3011 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 3012 | } |
| 3013 | |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3014 | static jlong NativeCrypto_getRSAPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey, |
| 3015 | jbyteArray modulusBytes) { |
Kenny Root | 977f087 | 2014-08-04 12:15:04 -0700 | [diff] [blame] | 3016 | JNI_TRACE("getRSAPrivateKeyWrapper(%p, %p)", javaKey, modulusBytes); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3017 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3018 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3019 | Unique_RSA rsa(RSA_new()); |
| 3020 | if (rsa.get() == NULL) { |
| 3021 | jniThrowOutOfMemory(env, "Unable to allocate RSA key"); |
| 3022 | return 0; |
| 3023 | } |
| 3024 | |
| 3025 | RSA_set_method(rsa.get(), &android_rsa_method); |
| 3026 | |
| 3027 | if (!arrayToBignum(env, modulusBytes, &rsa->n)) { |
| 3028 | return 0; |
| 3029 | } |
| 3030 | |
| 3031 | RSA_set_app_data(rsa.get(), env->NewGlobalRef(javaKey)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3032 | #else |
| 3033 | size_t cached_size; |
| 3034 | if (!arrayToBignumSize(env, modulusBytes, &cached_size)) { |
| 3035 | JNI_TRACE("getRSAPrivateKeyWrapper failed"); |
| 3036 | return 0; |
| 3037 | } |
| 3038 | |
| 3039 | ensure_engine_globals(); |
| 3040 | |
| 3041 | Unique_RSA rsa(RSA_new_method(g_engine)); |
| 3042 | if (rsa.get() == NULL) { |
| 3043 | jniThrowOutOfMemory(env, "Unable to allocate RSA key"); |
| 3044 | return 0; |
| 3045 | } |
| 3046 | |
| 3047 | KeyExData* ex_data = new KeyExData; |
| 3048 | ex_data->private_key = env->NewGlobalRef(javaKey); |
| 3049 | ex_data->cached_size = cached_size; |
| 3050 | RSA_set_ex_data(rsa.get(), g_rsa_exdata_index, ex_data); |
| 3051 | #endif |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3052 | |
| 3053 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 3054 | if (pkey.get() == NULL) { |
| 3055 | JNI_TRACE("getRSAPrivateKeyWrapper failed"); |
| 3056 | jniThrowRuntimeException(env, "NativeCrypto_getRSAPrivateKeyWrapper failed"); |
| 3057 | freeOpenSslErrorState(); |
| 3058 | return 0; |
| 3059 | } |
| 3060 | |
| 3061 | if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { |
| 3062 | jniThrowRuntimeException(env, "getRSAPrivateKeyWrapper failed"); |
| 3063 | return 0; |
| 3064 | } |
| 3065 | OWNERSHIP_TRANSFERRED(rsa); |
| 3066 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 3067 | } |
| 3068 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3069 | static jlong NativeCrypto_getECPrivateKeyWrapper(JNIEnv* env, jclass, jobject javaKey, |
| 3070 | jobject groupRef) { |
| 3071 | EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 30550a8 | 2014-08-12 15:13:33 -0700 | [diff] [blame] | 3072 | JNI_TRACE("getECPrivateKeyWrapper(%p, %p)", javaKey, group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3073 | if (group == NULL) { |
| 3074 | return 0; |
| 3075 | } |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3076 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3077 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3078 | Unique_EC_KEY ecKey(EC_KEY_new()); |
| 3079 | if (ecKey.get() == NULL) { |
| 3080 | jniThrowOutOfMemory(env, "Unable to allocate EC key"); |
| 3081 | return 0; |
| 3082 | } |
| 3083 | |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3084 | JNI_TRACE("EC_GROUP_get_curve_name(%p)", group); |
| 3085 | |
| 3086 | if (group == NULL) { |
| 3087 | JNI_TRACE("EC_GROUP_get_curve_name => group == NULL"); |
| 3088 | jniThrowNullPointerException(env, "group == NULL"); |
| 3089 | return 0; |
| 3090 | } |
| 3091 | |
| 3092 | EC_KEY_set_group(ecKey.get(), group); |
| 3093 | |
| 3094 | ECDSA_set_method(ecKey.get(), &android_ecdsa_method); |
| 3095 | ECDSA_set_ex_data(ecKey.get(), EcdsaGetExDataIndex(), env->NewGlobalRef(javaKey)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3096 | #else |
| 3097 | ensure_engine_globals(); |
| 3098 | |
| 3099 | Unique_EC_KEY ecKey(EC_KEY_new_method(g_engine)); |
| 3100 | if (ecKey.get() == NULL) { |
| 3101 | jniThrowOutOfMemory(env, "Unable to allocate EC key"); |
| 3102 | return 0; |
| 3103 | } |
| 3104 | |
| 3105 | KeyExData* ex_data = new KeyExData; |
| 3106 | ex_data->private_key = env->NewGlobalRef(javaKey); |
| 3107 | |
Adam Langley | 9bca53c | 2015-06-10 13:25:47 -0700 | [diff] [blame] | 3108 | if (!EC_KEY_set_ex_data(ecKey.get(), g_ecdsa_exdata_index, ex_data)) { |
| 3109 | env->DeleteGlobalRef(ex_data->private_key); |
| 3110 | delete ex_data; |
| 3111 | jniThrowRuntimeException(env, "EC_KEY_set_ex_data"); |
| 3112 | return 0; |
| 3113 | } |
| 3114 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3115 | BIGNUM order; |
| 3116 | BN_init(&order); |
| 3117 | if (!EC_GROUP_get_order(group, &order, NULL)) { |
| 3118 | BN_free(&order); |
| 3119 | jniThrowRuntimeException(env, "EC_GROUP_get_order failed"); |
| 3120 | return 0; |
| 3121 | } |
| 3122 | ex_data->cached_size = BN_num_bytes(&order); |
| 3123 | BN_free(&order); |
| 3124 | #endif |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3125 | |
| 3126 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 3127 | if (pkey.get() == NULL) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3128 | JNI_TRACE("getECPrivateKeyWrapper failed"); |
| 3129 | jniThrowRuntimeException(env, "NativeCrypto_getECPrivateKeyWrapper failed"); |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 3130 | freeOpenSslErrorState(); |
| 3131 | return 0; |
| 3132 | } |
| 3133 | |
| 3134 | if (EVP_PKEY_assign_EC_KEY(pkey.get(), ecKey.get()) != 1) { |
| 3135 | jniThrowRuntimeException(env, "getECPrivateKeyWrapper failed"); |
| 3136 | return 0; |
| 3137 | } |
| 3138 | OWNERSHIP_TRANSFERRED(ecKey); |
| 3139 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 3140 | } |
| 3141 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3142 | /* |
| 3143 | * public static native int RSA_generate_key(int modulusBits, byte[] publicExponent); |
| 3144 | */ |
| 3145 | static jlong NativeCrypto_RSA_generate_key_ex(JNIEnv* env, jclass, jint modulusBits, |
| 3146 | jbyteArray publicExponent) { |
| 3147 | JNI_TRACE("RSA_generate_key_ex(%d, %p)", modulusBits, publicExponent); |
| 3148 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 3149 | BIGNUM* eRef = NULL; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3150 | if (!arrayToBignum(env, publicExponent, &eRef)) { |
| 3151 | return 0; |
| 3152 | } |
| 3153 | Unique_BIGNUM e(eRef); |
| 3154 | |
| 3155 | Unique_RSA rsa(RSA_new()); |
| 3156 | if (rsa.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3157 | jniThrowOutOfMemory(env, "Unable to allocate RSA key"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3158 | return 0; |
| 3159 | } |
| 3160 | |
| 3161 | if (RSA_generate_key_ex(rsa.get(), modulusBits, e.get(), NULL) < 0) { |
| 3162 | throwExceptionIfNecessary(env, "RSA_generate_key_ex"); |
| 3163 | return 0; |
| 3164 | } |
| 3165 | |
| 3166 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 3167 | if (pkey.get() == NULL) { |
| 3168 | jniThrowRuntimeException(env, "RSA_generate_key_ex failed"); |
| 3169 | return 0; |
| 3170 | } |
| 3171 | |
| 3172 | if (EVP_PKEY_assign_RSA(pkey.get(), rsa.get()) != 1) { |
| 3173 | jniThrowRuntimeException(env, "RSA_generate_key_ex failed"); |
| 3174 | return 0; |
| 3175 | } |
| 3176 | |
| 3177 | OWNERSHIP_TRANSFERRED(rsa); |
| 3178 | JNI_TRACE("RSA_generate_key_ex(n=%d, e=%p) => %p", modulusBits, publicExponent, pkey.get()); |
| 3179 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 3180 | } |
| 3181 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3182 | static jint NativeCrypto_RSA_size(JNIEnv* env, jclass, jobject pkeyRef) { |
| 3183 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3184 | JNI_TRACE("RSA_size(%p)", pkey); |
| 3185 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 3186 | if (pkey == NULL) { |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 3187 | return 0; |
| 3188 | } |
| 3189 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3190 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); |
| 3191 | if (rsa.get() == NULL) { |
| 3192 | jniThrowRuntimeException(env, "RSA_size failed"); |
| 3193 | return 0; |
| 3194 | } |
| 3195 | |
| 3196 | return static_cast<jint>(RSA_size(rsa.get())); |
| 3197 | } |
| 3198 | |
| 3199 | typedef int RSACryptOperation(int flen, const unsigned char* from, unsigned char* to, RSA* rsa, |
| 3200 | int padding); |
| 3201 | |
Kenny Root | d5d7063 | 2015-05-28 17:07:44 -0700 | [diff] [blame] | 3202 | static jint RSA_crypt_operation(RSACryptOperation operation, const char* caller, JNIEnv* env, |
| 3203 | jint flen, jbyteArray fromJavaBytes, jbyteArray toJavaBytes, |
| 3204 | jobject pkeyRef, jint padding) { |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3205 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3206 | JNI_TRACE("%s(%d, %p, %p, %p)", caller, flen, fromJavaBytes, toJavaBytes, pkey); |
| 3207 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 3208 | if (pkey == NULL) { |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 3209 | return -1; |
| 3210 | } |
| 3211 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3212 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); |
| 3213 | if (rsa.get() == NULL) { |
| 3214 | return -1; |
| 3215 | } |
| 3216 | |
| 3217 | ScopedByteArrayRO from(env, fromJavaBytes); |
| 3218 | if (from.get() == NULL) { |
| 3219 | return -1; |
| 3220 | } |
| 3221 | |
| 3222 | ScopedByteArrayRW to(env, toJavaBytes); |
| 3223 | if (to.get() == NULL) { |
| 3224 | return -1; |
| 3225 | } |
| 3226 | |
| 3227 | int resultSize = operation(static_cast<int>(flen), |
| 3228 | reinterpret_cast<const unsigned char*>(from.get()), |
| 3229 | reinterpret_cast<unsigned char*>(to.get()), rsa.get(), padding); |
| 3230 | if (resultSize == -1) { |
Kenny Root | d5d7063 | 2015-05-28 17:07:44 -0700 | [diff] [blame] | 3231 | if (throwExceptionIfNecessary(env, caller)) { |
| 3232 | JNI_TRACE("%s => threw error", caller); |
| 3233 | } else { |
| 3234 | throwBadPaddingException(env, caller); |
| 3235 | JNI_TRACE("%s => threw padding exception", caller); |
| 3236 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3237 | return -1; |
| 3238 | } |
| 3239 | |
| 3240 | JNI_TRACE("%s(%d, %p, %p, %p) => %d", caller, flen, fromJavaBytes, toJavaBytes, pkey, |
| 3241 | resultSize); |
| 3242 | return static_cast<jint>(resultSize); |
| 3243 | } |
| 3244 | |
| 3245 | static jint NativeCrypto_RSA_private_encrypt(JNIEnv* env, jclass, jint flen, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3246 | jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jobject pkeyRef, jint padding) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3247 | return RSA_crypt_operation(RSA_private_encrypt, __FUNCTION__, |
| 3248 | env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); |
| 3249 | } |
| 3250 | static jint NativeCrypto_RSA_public_decrypt(JNIEnv* env, jclass, jint flen, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3251 | jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jobject pkeyRef, jint padding) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3252 | return RSA_crypt_operation(RSA_public_decrypt, __FUNCTION__, |
| 3253 | env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); |
| 3254 | } |
| 3255 | static jint NativeCrypto_RSA_public_encrypt(JNIEnv* env, jclass, jint flen, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3256 | jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jobject pkeyRef, jint padding) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3257 | return RSA_crypt_operation(RSA_public_encrypt, __FUNCTION__, |
| 3258 | env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); |
| 3259 | } |
| 3260 | static jint NativeCrypto_RSA_private_decrypt(JNIEnv* env, jclass, jint flen, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3261 | jbyteArray fromJavaBytes, jbyteArray toJavaBytes, jobject pkeyRef, jint padding) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3262 | return RSA_crypt_operation(RSA_private_decrypt, __FUNCTION__, |
| 3263 | env, flen, fromJavaBytes, toJavaBytes, pkeyRef, padding); |
| 3264 | } |
| 3265 | |
| 3266 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 3267 | * public static native byte[][] get_RSA_public_params(long); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3268 | */ |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3269 | static jobjectArray NativeCrypto_get_RSA_public_params(JNIEnv* env, jclass, jobject pkeyRef) { |
| 3270 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3271 | JNI_TRACE("get_RSA_public_params(%p)", pkey); |
| 3272 | |
| 3273 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3274 | return 0; |
| 3275 | } |
| 3276 | |
| 3277 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); |
| 3278 | if (rsa.get() == NULL) { |
| 3279 | throwExceptionIfNecessary(env, "get_RSA_public_params failed"); |
| 3280 | return 0; |
| 3281 | } |
| 3282 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3283 | jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3284 | if (joa == NULL) { |
| 3285 | return NULL; |
| 3286 | } |
| 3287 | |
| 3288 | jbyteArray n = bignumToArray(env, rsa->n, "n"); |
| 3289 | if (env->ExceptionCheck()) { |
| 3290 | return NULL; |
| 3291 | } |
| 3292 | env->SetObjectArrayElement(joa, 0, n); |
| 3293 | |
| 3294 | jbyteArray e = bignumToArray(env, rsa->e, "e"); |
| 3295 | if (env->ExceptionCheck()) { |
| 3296 | return NULL; |
| 3297 | } |
| 3298 | env->SetObjectArrayElement(joa, 1, e); |
| 3299 | |
| 3300 | return joa; |
| 3301 | } |
| 3302 | |
| 3303 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 3304 | * public static native byte[][] get_RSA_private_params(long); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3305 | */ |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3306 | static jobjectArray NativeCrypto_get_RSA_private_params(JNIEnv* env, jclass, jobject pkeyRef) { |
| 3307 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3308 | JNI_TRACE("get_RSA_public_params(%p)", pkey); |
| 3309 | |
| 3310 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3311 | return 0; |
| 3312 | } |
| 3313 | |
| 3314 | Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); |
| 3315 | if (rsa.get() == NULL) { |
| 3316 | throwExceptionIfNecessary(env, "get_RSA_public_params failed"); |
| 3317 | return 0; |
| 3318 | } |
| 3319 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3320 | jobjectArray joa = env->NewObjectArray(8, byteArrayClass, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3321 | if (joa == NULL) { |
| 3322 | return NULL; |
| 3323 | } |
| 3324 | |
| 3325 | jbyteArray n = bignumToArray(env, rsa->n, "n"); |
| 3326 | if (env->ExceptionCheck()) { |
| 3327 | return NULL; |
| 3328 | } |
| 3329 | env->SetObjectArrayElement(joa, 0, n); |
| 3330 | |
| 3331 | if (rsa->e != NULL) { |
| 3332 | jbyteArray e = bignumToArray(env, rsa->e, "e"); |
| 3333 | if (env->ExceptionCheck()) { |
| 3334 | return NULL; |
| 3335 | } |
| 3336 | env->SetObjectArrayElement(joa, 1, e); |
| 3337 | } |
| 3338 | |
| 3339 | if (rsa->d != NULL) { |
| 3340 | jbyteArray d = bignumToArray(env, rsa->d, "d"); |
| 3341 | if (env->ExceptionCheck()) { |
| 3342 | return NULL; |
| 3343 | } |
| 3344 | env->SetObjectArrayElement(joa, 2, d); |
| 3345 | } |
| 3346 | |
| 3347 | if (rsa->p != NULL) { |
| 3348 | jbyteArray p = bignumToArray(env, rsa->p, "p"); |
| 3349 | if (env->ExceptionCheck()) { |
| 3350 | return NULL; |
| 3351 | } |
| 3352 | env->SetObjectArrayElement(joa, 3, p); |
| 3353 | } |
| 3354 | |
| 3355 | if (rsa->q != NULL) { |
| 3356 | jbyteArray q = bignumToArray(env, rsa->q, "q"); |
| 3357 | if (env->ExceptionCheck()) { |
| 3358 | return NULL; |
| 3359 | } |
| 3360 | env->SetObjectArrayElement(joa, 4, q); |
| 3361 | } |
| 3362 | |
| 3363 | if (rsa->dmp1 != NULL) { |
| 3364 | jbyteArray dmp1 = bignumToArray(env, rsa->dmp1, "dmp1"); |
| 3365 | if (env->ExceptionCheck()) { |
| 3366 | return NULL; |
| 3367 | } |
| 3368 | env->SetObjectArrayElement(joa, 5, dmp1); |
| 3369 | } |
| 3370 | |
| 3371 | if (rsa->dmq1 != NULL) { |
| 3372 | jbyteArray dmq1 = bignumToArray(env, rsa->dmq1, "dmq1"); |
| 3373 | if (env->ExceptionCheck()) { |
| 3374 | return NULL; |
| 3375 | } |
| 3376 | env->SetObjectArrayElement(joa, 6, dmq1); |
| 3377 | } |
| 3378 | |
| 3379 | if (rsa->iqmp != NULL) { |
| 3380 | jbyteArray iqmp = bignumToArray(env, rsa->iqmp, "iqmp"); |
| 3381 | if (env->ExceptionCheck()) { |
| 3382 | return NULL; |
| 3383 | } |
| 3384 | env->SetObjectArrayElement(joa, 7, iqmp); |
| 3385 | } |
| 3386 | |
| 3387 | return joa; |
| 3388 | } |
| 3389 | |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3390 | static jlong NativeCrypto_DH_generate_parameters_ex(JNIEnv* env, jclass, jint primeBits, jlong generator) { |
Kenny Root | 30550a8 | 2014-08-12 15:13:33 -0700 | [diff] [blame] | 3391 | JNI_TRACE("DH_generate_parameters_ex(%d, %lld)", primeBits, (long long) generator); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3392 | |
| 3393 | Unique_DH dh(DH_new()); |
| 3394 | if (dh.get() == NULL) { |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3395 | JNI_TRACE("DH_generate_parameters_ex failed"); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3396 | jniThrowOutOfMemory(env, "Unable to allocate DH key"); |
| 3397 | freeOpenSslErrorState(); |
| 3398 | return 0; |
| 3399 | } |
| 3400 | |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3401 | JNI_TRACE("DH_generate_parameters_ex generating parameters"); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3402 | |
| 3403 | if (!DH_generate_parameters_ex(dh.get(), primeBits, generator, NULL)) { |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3404 | JNI_TRACE("DH_generate_parameters_ex => param generation failed"); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3405 | throwExceptionIfNecessary(env, "NativeCrypto_DH_generate_parameters_ex failed"); |
| 3406 | return 0; |
| 3407 | } |
| 3408 | |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3409 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 3410 | if (pkey.get() == NULL) { |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3411 | JNI_TRACE("DH_generate_parameters_ex failed"); |
| 3412 | jniThrowRuntimeException(env, "NativeCrypto_DH_generate_parameters_ex failed"); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3413 | freeOpenSslErrorState(); |
| 3414 | return 0; |
| 3415 | } |
| 3416 | |
| 3417 | if (EVP_PKEY_assign_DH(pkey.get(), dh.get()) != 1) { |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3418 | JNI_TRACE("DH_generate_parameters_ex failed"); |
| 3419 | throwExceptionIfNecessary(env, "NativeCrypto_DH_generate_parameters_ex failed"); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3420 | return 0; |
| 3421 | } |
| 3422 | |
| 3423 | OWNERSHIP_TRANSFERRED(dh); |
Kenny Root | 30550a8 | 2014-08-12 15:13:33 -0700 | [diff] [blame] | 3424 | JNI_TRACE("DH_generate_parameters_ex(n=%d, g=%lld) => %p", primeBits, (long long) generator, |
| 3425 | pkey.get()); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3426 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 3427 | } |
| 3428 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3429 | static void NativeCrypto_DH_generate_key(JNIEnv* env, jclass, jobject pkeyRef) { |
| 3430 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 30550a8 | 2014-08-12 15:13:33 -0700 | [diff] [blame] | 3431 | JNI_TRACE("DH_generate_key(%p)", pkey); |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3432 | |
| 3433 | if (pkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3434 | return; |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 3435 | } |
| 3436 | |
| 3437 | Unique_DH dh(EVP_PKEY_get1_DH(pkey)); |
| 3438 | if (dh.get() == NULL) { |
| 3439 | JNI_TRACE("DH_generate_key failed"); |
| 3440 | throwExceptionIfNecessary(env, "Unable to get DH key"); |
| 3441 | freeOpenSslErrorState(); |
| 3442 | } |
| 3443 | |
| 3444 | if (!DH_generate_key(dh.get())) { |
| 3445 | JNI_TRACE("DH_generate_key failed"); |
| 3446 | throwExceptionIfNecessary(env, "NativeCrypto_DH_generate_key failed"); |
| 3447 | } |
| 3448 | } |
| 3449 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 3450 | static jobjectArray NativeCrypto_get_DH_params(JNIEnv* env, jclass, jobject pkeyRef) { |
| 3451 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3452 | JNI_TRACE("get_DH_params(%p)", pkey); |
| 3453 | |
| 3454 | if (pkey == NULL) { |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 3455 | return NULL; |
| 3456 | } |
| 3457 | |
| 3458 | Unique_DH dh(EVP_PKEY_get1_DH(pkey)); |
| 3459 | if (dh.get() == NULL) { |
| 3460 | throwExceptionIfNecessary(env, "get_DH_params failed"); |
| 3461 | return 0; |
| 3462 | } |
| 3463 | |
| 3464 | jobjectArray joa = env->NewObjectArray(4, byteArrayClass, NULL); |
| 3465 | if (joa == NULL) { |
| 3466 | return NULL; |
| 3467 | } |
| 3468 | |
| 3469 | if (dh->p != NULL) { |
| 3470 | jbyteArray p = bignumToArray(env, dh->p, "p"); |
| 3471 | if (env->ExceptionCheck()) { |
| 3472 | return NULL; |
| 3473 | } |
| 3474 | env->SetObjectArrayElement(joa, 0, p); |
| 3475 | } |
| 3476 | |
| 3477 | if (dh->g != NULL) { |
| 3478 | jbyteArray g = bignumToArray(env, dh->g, "g"); |
| 3479 | if (env->ExceptionCheck()) { |
| 3480 | return NULL; |
| 3481 | } |
| 3482 | env->SetObjectArrayElement(joa, 1, g); |
| 3483 | } |
| 3484 | |
| 3485 | if (dh->pub_key != NULL) { |
| 3486 | jbyteArray pub_key = bignumToArray(env, dh->pub_key, "pub_key"); |
| 3487 | if (env->ExceptionCheck()) { |
| 3488 | return NULL; |
| 3489 | } |
| 3490 | env->SetObjectArrayElement(joa, 2, pub_key); |
| 3491 | } |
| 3492 | |
| 3493 | if (dh->priv_key != NULL) { |
| 3494 | jbyteArray priv_key = bignumToArray(env, dh->priv_key, "priv_key"); |
| 3495 | if (env->ExceptionCheck()) { |
| 3496 | return NULL; |
| 3497 | } |
| 3498 | env->SetObjectArrayElement(joa, 3, priv_key); |
| 3499 | } |
| 3500 | |
| 3501 | return joa; |
| 3502 | } |
| 3503 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3504 | #define EC_CURVE_GFP 1 |
| 3505 | #define EC_CURVE_GF2M 2 |
| 3506 | |
| 3507 | /** |
| 3508 | * Return group type or 0 if unknown group. |
| 3509 | * EC_GROUP_GFP or EC_GROUP_GF2M |
| 3510 | */ |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3511 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3512 | static int get_EC_GROUP_type(const EC_GROUP* group) |
| 3513 | { |
Kenny Root | dc77a71 | 2015-05-03 17:15:59 -0700 | [diff] [blame] | 3514 | const int curve_nid = EC_METHOD_get_field_type(EC_GROUP_method_of(group)); |
| 3515 | if (curve_nid == NID_X9_62_prime_field) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3516 | return EC_CURVE_GFP; |
Kenny Root | dc77a71 | 2015-05-03 17:15:59 -0700 | [diff] [blame] | 3517 | } else if (curve_nid == NID_X9_62_characteristic_two_field) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3518 | return EC_CURVE_GF2M; |
| 3519 | } |
| 3520 | |
| 3521 | return 0; |
| 3522 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3523 | #else |
| 3524 | static int get_EC_GROUP_type(const EC_GROUP*) |
| 3525 | { |
| 3526 | return EC_CURVE_GFP; |
| 3527 | } |
| 3528 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3529 | |
| 3530 | static jlong NativeCrypto_EC_GROUP_new_by_curve_name(JNIEnv* env, jclass, jstring curveNameJava) |
| 3531 | { |
| 3532 | JNI_TRACE("EC_GROUP_new_by_curve_name(%p)", curveNameJava); |
| 3533 | |
| 3534 | ScopedUtfChars curveName(env, curveNameJava); |
| 3535 | if (curveName.c_str() == NULL) { |
| 3536 | return 0; |
| 3537 | } |
| 3538 | JNI_TRACE("EC_GROUP_new_by_curve_name(%s)", curveName.c_str()); |
| 3539 | |
| 3540 | int nid = OBJ_sn2nid(curveName.c_str()); |
| 3541 | if (nid == NID_undef) { |
| 3542 | JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID name", curveName.c_str()); |
| 3543 | return 0; |
| 3544 | } |
| 3545 | |
| 3546 | EC_GROUP* group = EC_GROUP_new_by_curve_name(nid); |
| 3547 | if (group == NULL) { |
| 3548 | JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => unknown NID %d", curveName.c_str(), nid); |
| 3549 | freeOpenSslErrorState(); |
| 3550 | return 0; |
| 3551 | } |
| 3552 | |
| 3553 | JNI_TRACE("EC_GROUP_new_by_curve_name(%s) => %p", curveName.c_str(), group); |
| 3554 | return reinterpret_cast<uintptr_t>(group); |
| 3555 | } |
| 3556 | |
Adam Langley | 05b8e50 | 2015-05-12 19:24:49 -0700 | [diff] [blame] | 3557 | static jlong NativeCrypto_EC_GROUP_new_arbitrary( |
| 3558 | JNIEnv* env, jclass, jbyteArray pBytes, jbyteArray aBytes, |
| 3559 | jbyteArray bBytes, jbyteArray xBytes, jbyteArray yBytes, |
| 3560 | jbyteArray orderBytes, jint cofactorInt) |
| 3561 | { |
| 3562 | BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL; |
| 3563 | BIGNUM *order = NULL, *cofactor = NULL; |
| 3564 | |
| 3565 | JNI_TRACE("EC_GROUP_new_arbitrary"); |
| 3566 | |
| 3567 | if (cofactorInt < 1) { |
| 3568 | jniThrowException(env, "java/lang/IllegalArgumentException", "cofactor < 1"); |
| 3569 | return 0; |
| 3570 | } |
| 3571 | |
| 3572 | cofactor = BN_new(); |
| 3573 | if (cofactor == NULL) { |
| 3574 | return 0; |
| 3575 | } |
| 3576 | |
| 3577 | int ok = 1; |
| 3578 | |
| 3579 | if (!arrayToBignum(env, pBytes, &p) || |
| 3580 | !arrayToBignum(env, aBytes, &a) || |
| 3581 | !arrayToBignum(env, bBytes, &b) || |
| 3582 | !arrayToBignum(env, xBytes, &x) || |
| 3583 | !arrayToBignum(env, yBytes, &y) || |
| 3584 | !arrayToBignum(env, orderBytes, &order) || |
| 3585 | !BN_set_word(cofactor, cofactorInt)) { |
| 3586 | ok = 0; |
| 3587 | } |
| 3588 | |
| 3589 | Unique_BIGNUM pStorage(p); |
| 3590 | Unique_BIGNUM aStorage(a); |
| 3591 | Unique_BIGNUM bStorage(b); |
| 3592 | Unique_BIGNUM xStorage(x); |
| 3593 | Unique_BIGNUM yStorage(y); |
| 3594 | Unique_BIGNUM orderStorage(order); |
| 3595 | Unique_BIGNUM cofactorStorage(cofactor); |
| 3596 | |
| 3597 | if (!ok) { |
| 3598 | return 0; |
| 3599 | } |
| 3600 | |
| 3601 | Unique_BN_CTX ctx(BN_CTX_new()); |
| 3602 | Unique_EC_GROUP group(EC_GROUP_new_curve_GFp(p, a, b, ctx.get())); |
| 3603 | if (group.get() == NULL) { |
| 3604 | JNI_TRACE("EC_GROUP_new_curve_GFp => NULL"); |
| 3605 | throwExceptionIfNecessary(env, "EC_GROUP_new_curve_GFp"); |
| 3606 | return 0; |
| 3607 | } |
| 3608 | |
| 3609 | Unique_EC_POINT generator(EC_POINT_new(group.get())); |
| 3610 | if (generator.get() == NULL) { |
| 3611 | JNI_TRACE("EC_POINT_new => NULL"); |
| 3612 | freeOpenSslErrorState(); |
| 3613 | return 0; |
| 3614 | } |
| 3615 | |
| 3616 | if (!EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(), x, y, ctx.get())) { |
| 3617 | JNI_TRACE("EC_POINT_set_affine_coordinates_GFp => error"); |
| 3618 | throwExceptionIfNecessary(env, "EC_POINT_set_affine_coordinates_GFp"); |
| 3619 | return 0; |
| 3620 | } |
| 3621 | |
| 3622 | if (!EC_GROUP_set_generator(group.get(), generator.get(), order, cofactor)) { |
| 3623 | JNI_TRACE("EC_GROUP_set_generator => error"); |
| 3624 | throwExceptionIfNecessary(env, "EC_GROUP_set_generator"); |
| 3625 | return 0; |
| 3626 | } |
| 3627 | |
| 3628 | JNI_TRACE("EC_GROUP_new_arbitrary => %p", group.get()); |
| 3629 | return reinterpret_cast<uintptr_t>(group.release()); |
| 3630 | } |
| 3631 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3632 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3633 | static void NativeCrypto_EC_GROUP_set_asn1_flag(JNIEnv* env, jclass, jobject groupRef, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3634 | jint flag) |
| 3635 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3636 | EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3637 | JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d)", group, flag); |
| 3638 | |
| 3639 | if (group == NULL) { |
| 3640 | JNI_TRACE("EC_GROUP_set_asn1_flag => group == NULL"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3641 | return; |
| 3642 | } |
| 3643 | |
| 3644 | EC_GROUP_set_asn1_flag(group, flag); |
| 3645 | JNI_TRACE("EC_GROUP_set_asn1_flag(%p, %d) => success", group, flag); |
| 3646 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3647 | #else |
| 3648 | static void NativeCrypto_EC_GROUP_set_asn1_flag(JNIEnv*, jclass, jobject, jint) |
| 3649 | { |
| 3650 | } |
| 3651 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3652 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3653 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3654 | static void NativeCrypto_EC_GROUP_set_point_conversion_form(JNIEnv* env, jclass, |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3655 | jobject groupRef, jint form) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3656 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3657 | EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3658 | JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d)", group, form); |
| 3659 | |
| 3660 | if (group == NULL) { |
| 3661 | JNI_TRACE("EC_GROUP_set_point_conversion_form => group == NULL"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3662 | return; |
| 3663 | } |
| 3664 | |
| 3665 | EC_GROUP_set_point_conversion_form(group, static_cast<point_conversion_form_t>(form)); |
| 3666 | JNI_TRACE("EC_GROUP_set_point_conversion_form(%p, %d) => success", group, form); |
| 3667 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 3668 | #else |
| 3669 | static void NativeCrypto_EC_GROUP_set_point_conversion_form(JNIEnv*, jclass, jobject, jint) |
| 3670 | { |
| 3671 | } |
| 3672 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3673 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3674 | static jstring NativeCrypto_EC_GROUP_get_curve_name(JNIEnv* env, jclass, jobject groupRef) { |
| 3675 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3676 | JNI_TRACE("EC_GROUP_get_curve_name(%p)", group); |
| 3677 | |
| 3678 | if (group == NULL) { |
| 3679 | JNI_TRACE("EC_GROUP_get_curve_name => group == NULL"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3680 | return 0; |
| 3681 | } |
| 3682 | |
| 3683 | int nid = EC_GROUP_get_curve_name(group); |
| 3684 | if (nid == NID_undef) { |
| 3685 | JNI_TRACE("EC_GROUP_get_curve_name(%p) => unnamed curve", group); |
| 3686 | return NULL; |
| 3687 | } |
| 3688 | |
| 3689 | const char* shortName = OBJ_nid2sn(nid); |
| 3690 | JNI_TRACE("EC_GROUP_get_curve_name(%p) => \"%s\"", group, shortName); |
| 3691 | return env->NewStringUTF(shortName); |
| 3692 | } |
| 3693 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3694 | static jobjectArray NativeCrypto_EC_GROUP_get_curve(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3695 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3696 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3697 | JNI_TRACE("EC_GROUP_get_curve(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3698 | if (group == NULL) { |
| 3699 | JNI_TRACE("EC_GROUP_get_curve => group == NULL"); |
| 3700 | return NULL; |
| 3701 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3702 | |
| 3703 | Unique_BIGNUM p(BN_new()); |
| 3704 | Unique_BIGNUM a(BN_new()); |
| 3705 | Unique_BIGNUM b(BN_new()); |
| 3706 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3707 | if (get_EC_GROUP_type(group) != EC_CURVE_GFP) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3708 | jniThrowRuntimeException(env, "invalid group"); |
| 3709 | return NULL; |
| 3710 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3711 | |
| 3712 | int ret = EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), (BN_CTX*) NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3713 | if (ret != 1) { |
| 3714 | throwExceptionIfNecessary(env, "EC_GROUP_get_curve"); |
| 3715 | return NULL; |
| 3716 | } |
| 3717 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3718 | jobjectArray joa = env->NewObjectArray(3, byteArrayClass, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3719 | if (joa == NULL) { |
| 3720 | return NULL; |
| 3721 | } |
| 3722 | |
| 3723 | jbyteArray pArray = bignumToArray(env, p.get(), "p"); |
| 3724 | if (env->ExceptionCheck()) { |
| 3725 | return NULL; |
| 3726 | } |
| 3727 | env->SetObjectArrayElement(joa, 0, pArray); |
| 3728 | |
| 3729 | jbyteArray aArray = bignumToArray(env, a.get(), "a"); |
| 3730 | if (env->ExceptionCheck()) { |
| 3731 | return NULL; |
| 3732 | } |
| 3733 | env->SetObjectArrayElement(joa, 1, aArray); |
| 3734 | |
| 3735 | jbyteArray bArray = bignumToArray(env, b.get(), "b"); |
| 3736 | if (env->ExceptionCheck()) { |
| 3737 | return NULL; |
| 3738 | } |
| 3739 | env->SetObjectArrayElement(joa, 2, bArray); |
| 3740 | |
| 3741 | JNI_TRACE("EC_GROUP_get_curve(%p) => %p", group, joa); |
| 3742 | return joa; |
| 3743 | } |
| 3744 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3745 | static jbyteArray NativeCrypto_EC_GROUP_get_order(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3746 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3747 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3748 | JNI_TRACE("EC_GROUP_get_order(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3749 | if (group == NULL) { |
| 3750 | return NULL; |
| 3751 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3752 | |
| 3753 | Unique_BIGNUM order(BN_new()); |
| 3754 | if (order.get() == NULL) { |
| 3755 | JNI_TRACE("EC_GROUP_get_order(%p) => can't create BN", group); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3756 | jniThrowOutOfMemory(env, "BN_new"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3757 | return NULL; |
| 3758 | } |
| 3759 | |
| 3760 | if (EC_GROUP_get_order(group, order.get(), NULL) != 1) { |
| 3761 | JNI_TRACE("EC_GROUP_get_order(%p) => threw error", group); |
| 3762 | throwExceptionIfNecessary(env, "EC_GROUP_get_order"); |
| 3763 | return NULL; |
| 3764 | } |
| 3765 | |
| 3766 | jbyteArray orderArray = bignumToArray(env, order.get(), "order"); |
| 3767 | if (env->ExceptionCheck()) { |
| 3768 | return NULL; |
| 3769 | } |
| 3770 | |
| 3771 | JNI_TRACE("EC_GROUP_get_order(%p) => %p", group, orderArray); |
| 3772 | return orderArray; |
| 3773 | } |
| 3774 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3775 | static jint NativeCrypto_EC_GROUP_get_degree(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3776 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3777 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3778 | JNI_TRACE("EC_GROUP_get_degree(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3779 | if (group == NULL) { |
| 3780 | return 0; |
| 3781 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3782 | |
| 3783 | jint degree = EC_GROUP_get_degree(group); |
| 3784 | if (degree == 0) { |
| 3785 | JNI_TRACE("EC_GROUP_get_degree(%p) => unsupported", group); |
| 3786 | jniThrowRuntimeException(env, "not supported"); |
| 3787 | return 0; |
| 3788 | } |
| 3789 | |
| 3790 | JNI_TRACE("EC_GROUP_get_degree(%p) => %d", group, degree); |
| 3791 | return degree; |
| 3792 | } |
| 3793 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3794 | static jbyteArray NativeCrypto_EC_GROUP_get_cofactor(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3795 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3796 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3797 | JNI_TRACE("EC_GROUP_get_cofactor(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3798 | if (group == NULL) { |
| 3799 | return NULL; |
| 3800 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3801 | |
| 3802 | Unique_BIGNUM cofactor(BN_new()); |
| 3803 | if (cofactor.get() == NULL) { |
| 3804 | JNI_TRACE("EC_GROUP_get_cofactor(%p) => can't create BN", group); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3805 | jniThrowOutOfMemory(env, "BN_new"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3806 | return NULL; |
| 3807 | } |
| 3808 | |
| 3809 | if (EC_GROUP_get_cofactor(group, cofactor.get(), NULL) != 1) { |
| 3810 | JNI_TRACE("EC_GROUP_get_cofactor(%p) => threw error", group); |
| 3811 | throwExceptionIfNecessary(env, "EC_GROUP_get_cofactor"); |
| 3812 | return NULL; |
| 3813 | } |
| 3814 | |
| 3815 | jbyteArray cofactorArray = bignumToArray(env, cofactor.get(), "cofactor"); |
| 3816 | if (env->ExceptionCheck()) { |
| 3817 | return NULL; |
| 3818 | } |
| 3819 | |
| 3820 | JNI_TRACE("EC_GROUP_get_cofactor(%p) => %p", group, cofactorArray); |
| 3821 | return cofactorArray; |
| 3822 | } |
| 3823 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3824 | static jint NativeCrypto_get_EC_GROUP_type(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3825 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3826 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3827 | JNI_TRACE("get_EC_GROUP_type(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3828 | if (group == NULL) { |
| 3829 | return 0; |
| 3830 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3831 | |
| 3832 | int type = get_EC_GROUP_type(group); |
| 3833 | if (type == 0) { |
| 3834 | JNI_TRACE("get_EC_GROUP_type(%p) => curve type", group); |
| 3835 | jniThrowRuntimeException(env, "unknown curve type"); |
| 3836 | } else { |
| 3837 | JNI_TRACE("get_EC_GROUP_type(%p) => %d", group, type); |
| 3838 | } |
| 3839 | return type; |
| 3840 | } |
| 3841 | |
| 3842 | static void NativeCrypto_EC_GROUP_clear_free(JNIEnv* env, jclass, jlong groupRef) |
| 3843 | { |
| 3844 | EC_GROUP* group = reinterpret_cast<EC_GROUP*>(groupRef); |
| 3845 | JNI_TRACE("EC_GROUP_clear_free(%p)", group); |
| 3846 | |
| 3847 | if (group == NULL) { |
| 3848 | JNI_TRACE("EC_GROUP_clear_free => group == NULL"); |
| 3849 | jniThrowNullPointerException(env, "group == NULL"); |
| 3850 | return; |
| 3851 | } |
| 3852 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3853 | EC_GROUP_free(group); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3854 | JNI_TRACE("EC_GROUP_clear_free(%p) => success", group); |
| 3855 | } |
| 3856 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3857 | static jboolean NativeCrypto_EC_GROUP_cmp(JNIEnv* env, jclass, jobject group1Ref, |
| 3858 | jobject group2Ref) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3859 | { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3860 | JNI_TRACE("EC_GROUP_cmp(%p, %p)", group1Ref, group2Ref); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3861 | const EC_GROUP* group1 = fromContextObject<EC_GROUP>(env, group1Ref); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3862 | if (group1 == NULL) { |
| 3863 | return JNI_FALSE; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3864 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3865 | const EC_GROUP* group2 = fromContextObject<EC_GROUP>(env, group2Ref); |
| 3866 | if (group2 == NULL) { |
| 3867 | return JNI_FALSE; |
| 3868 | } |
| 3869 | JNI_TRACE("EC_GROUP_cmp(%p, %p) <- ptr", group1, group2); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3870 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3871 | int ret = EC_GROUP_cmp(group1, group2, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3872 | |
| 3873 | JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", group1, group2, ret); |
| 3874 | return ret == 0; |
| 3875 | } |
| 3876 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3877 | static jlong NativeCrypto_EC_GROUP_get_generator(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3878 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3879 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3880 | JNI_TRACE("EC_GROUP_get_generator(%p)", group); |
| 3881 | |
| 3882 | if (group == NULL) { |
| 3883 | JNI_TRACE("EC_POINT_get_generator(%p) => group == null", group); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3884 | return 0; |
| 3885 | } |
| 3886 | |
| 3887 | const EC_POINT* generator = EC_GROUP_get0_generator(group); |
| 3888 | |
| 3889 | Unique_EC_POINT dup(EC_POINT_dup(generator, group)); |
| 3890 | if (dup.get() == NULL) { |
| 3891 | JNI_TRACE("EC_GROUP_get_generator(%p) => oom error", group); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3892 | jniThrowOutOfMemory(env, "unable to dupe generator"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3893 | return 0; |
| 3894 | } |
| 3895 | |
| 3896 | JNI_TRACE("EC_GROUP_get_generator(%p) => %p", group, dup.get()); |
| 3897 | return reinterpret_cast<uintptr_t>(dup.release()); |
| 3898 | } |
| 3899 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3900 | static jlong NativeCrypto_EC_POINT_new(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3901 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3902 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3903 | JNI_TRACE("EC_POINT_new(%p)", group); |
| 3904 | |
| 3905 | if (group == NULL) { |
| 3906 | JNI_TRACE("EC_POINT_new(%p) => group == null", group); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3907 | return 0; |
| 3908 | } |
| 3909 | |
| 3910 | EC_POINT* point = EC_POINT_new(group); |
| 3911 | if (point == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 3912 | jniThrowOutOfMemory(env, "Unable create an EC_POINT"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3913 | return 0; |
| 3914 | } |
| 3915 | |
| 3916 | return reinterpret_cast<uintptr_t>(point); |
| 3917 | } |
| 3918 | |
| 3919 | static void NativeCrypto_EC_POINT_clear_free(JNIEnv* env, jclass, jlong groupRef) { |
| 3920 | EC_POINT* group = reinterpret_cast<EC_POINT*>(groupRef); |
| 3921 | JNI_TRACE("EC_POINT_clear_free(%p)", group); |
| 3922 | |
| 3923 | if (group == NULL) { |
| 3924 | JNI_TRACE("EC_POINT_clear_free => group == NULL"); |
| 3925 | jniThrowNullPointerException(env, "group == NULL"); |
| 3926 | return; |
| 3927 | } |
| 3928 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3929 | EC_POINT_free(group); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3930 | JNI_TRACE("EC_POINT_clear_free(%p) => success", group); |
| 3931 | } |
| 3932 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3933 | static jboolean NativeCrypto_EC_POINT_cmp(JNIEnv* env, jclass, jobject groupRef, jobject point1Ref, |
| 3934 | jobject point2Ref) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3935 | { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3936 | JNI_TRACE("EC_POINT_cmp(%p, %p, %p)", groupRef, point1Ref, point2Ref); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3937 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3938 | if (group == NULL) { |
| 3939 | return JNI_FALSE; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3940 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3941 | const EC_POINT* point1 = fromContextObject<EC_POINT>(env, point1Ref); |
| 3942 | if (point1 == NULL) { |
| 3943 | return JNI_FALSE; |
| 3944 | } |
| 3945 | const EC_POINT* point2 = fromContextObject<EC_POINT>(env, point2Ref); |
| 3946 | if (point2 == NULL) { |
| 3947 | return JNI_FALSE; |
| 3948 | } |
| 3949 | JNI_TRACE("EC_POINT_cmp(%p, %p, %p) <- ptr", group, point1, point2); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3950 | |
| 3951 | int ret = EC_POINT_cmp(group, point1, point2, (BN_CTX*)NULL); |
| 3952 | |
| 3953 | JNI_TRACE("ECP_GROUP_cmp(%p, %p) => %d", point1, point2, ret); |
| 3954 | return ret == 0; |
| 3955 | } |
| 3956 | |
| 3957 | static void NativeCrypto_EC_POINT_set_affine_coordinates(JNIEnv* env, jclass, |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 3958 | jobject groupRef, jobject pointRef, jbyteArray xjavaBytes, jbyteArray yjavaBytes) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3959 | { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3960 | JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p)", groupRef, pointRef, xjavaBytes, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3961 | yjavaBytes); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3962 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
| 3963 | if (group == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3964 | return; |
| 3965 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 3966 | EC_POINT* point = fromContextObject<EC_POINT>(env, pointRef); |
| 3967 | if (point == NULL) { |
| 3968 | return; |
| 3969 | } |
| 3970 | JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) <- ptr", group, point, xjavaBytes, |
| 3971 | yjavaBytes); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3972 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 3973 | BIGNUM* xRef = NULL; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3974 | if (!arrayToBignum(env, xjavaBytes, &xRef)) { |
| 3975 | return; |
| 3976 | } |
| 3977 | Unique_BIGNUM x(xRef); |
| 3978 | |
Kenny Root | 1744cf2 | 2014-01-30 13:41:26 -0800 | [diff] [blame] | 3979 | BIGNUM* yRef = NULL; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3980 | if (!arrayToBignum(env, yjavaBytes, &yRef)) { |
| 3981 | return; |
| 3982 | } |
| 3983 | Unique_BIGNUM y(yRef); |
| 3984 | |
| 3985 | int ret; |
| 3986 | switch (get_EC_GROUP_type(group)) { |
| 3987 | case EC_CURVE_GFP: |
| 3988 | ret = EC_POINT_set_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL); |
| 3989 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3990 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3991 | case EC_CURVE_GF2M: |
| 3992 | ret = EC_POINT_set_affine_coordinates_GF2m(group, point, x.get(), y.get(), NULL); |
| 3993 | break; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 3994 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 3995 | default: |
| 3996 | jniThrowRuntimeException(env, "invalid curve type"); |
| 3997 | return; |
| 3998 | } |
| 3999 | |
| 4000 | if (ret != 1) { |
| 4001 | throwExceptionIfNecessary(env, "EC_POINT_set_affine_coordinates"); |
| 4002 | } |
| 4003 | |
| 4004 | JNI_TRACE("EC_POINT_set_affine_coordinates(%p, %p, %p, %p) => %d", group, point, |
| 4005 | xjavaBytes, yjavaBytes, ret); |
| 4006 | } |
| 4007 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4008 | static jobjectArray NativeCrypto_EC_POINT_get_affine_coordinates(JNIEnv* env, jclass, |
| 4009 | jobject groupRef, jobject pointRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4010 | { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4011 | JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", groupRef, pointRef); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4012 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4013 | if (group == NULL) { |
| 4014 | return NULL; |
| 4015 | } |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4016 | const EC_POINT* point = fromContextObject<EC_POINT>(env, pointRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4017 | if (point == NULL) { |
| 4018 | return NULL; |
| 4019 | } |
| 4020 | JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p) <- ptr", group, point); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4021 | |
| 4022 | Unique_BIGNUM x(BN_new()); |
| 4023 | Unique_BIGNUM y(BN_new()); |
| 4024 | |
| 4025 | int ret; |
| 4026 | switch (get_EC_GROUP_type(group)) { |
| 4027 | case EC_CURVE_GFP: |
| 4028 | ret = EC_POINT_get_affine_coordinates_GFp(group, point, x.get(), y.get(), NULL); |
| 4029 | break; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4030 | default: |
| 4031 | jniThrowRuntimeException(env, "invalid curve type"); |
| 4032 | return NULL; |
| 4033 | } |
| 4034 | if (ret != 1) { |
| 4035 | JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p)", group, point); |
| 4036 | throwExceptionIfNecessary(env, "EC_POINT_get_affine_coordinates"); |
| 4037 | return NULL; |
| 4038 | } |
| 4039 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 4040 | jobjectArray joa = env->NewObjectArray(2, byteArrayClass, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4041 | if (joa == NULL) { |
| 4042 | return NULL; |
| 4043 | } |
| 4044 | |
| 4045 | jbyteArray xBytes = bignumToArray(env, x.get(), "x"); |
| 4046 | if (env->ExceptionCheck()) { |
| 4047 | return NULL; |
| 4048 | } |
| 4049 | env->SetObjectArrayElement(joa, 0, xBytes); |
| 4050 | |
| 4051 | jbyteArray yBytes = bignumToArray(env, y.get(), "y"); |
| 4052 | if (env->ExceptionCheck()) { |
| 4053 | return NULL; |
| 4054 | } |
| 4055 | env->SetObjectArrayElement(joa, 1, yBytes); |
| 4056 | |
| 4057 | JNI_TRACE("EC_POINT_get_affine_coordinates(%p, %p) => %p", group, point, joa); |
| 4058 | return joa; |
| 4059 | } |
| 4060 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4061 | static jlong NativeCrypto_EC_KEY_generate_key(JNIEnv* env, jclass, jobject groupRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4062 | { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4063 | const EC_GROUP* group = fromContextObject<EC_GROUP>(env, groupRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4064 | JNI_TRACE("EC_KEY_generate_key(%p)", group); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4065 | if (group == NULL) { |
| 4066 | return 0; |
| 4067 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4068 | |
| 4069 | Unique_EC_KEY eckey(EC_KEY_new()); |
| 4070 | if (eckey.get() == NULL) { |
| 4071 | JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_new() oom", group); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 4072 | jniThrowOutOfMemory(env, "Unable to create an EC_KEY"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4073 | return 0; |
| 4074 | } |
| 4075 | |
| 4076 | if (EC_KEY_set_group(eckey.get(), group) != 1) { |
| 4077 | JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_set_group error", group); |
| 4078 | throwExceptionIfNecessary(env, "EC_KEY_set_group"); |
| 4079 | return 0; |
| 4080 | } |
| 4081 | |
| 4082 | if (EC_KEY_generate_key(eckey.get()) != 1) { |
| 4083 | JNI_TRACE("EC_KEY_generate_key(%p) => EC_KEY_generate_key error", group); |
| 4084 | throwExceptionIfNecessary(env, "EC_KEY_set_group"); |
| 4085 | return 0; |
| 4086 | } |
| 4087 | |
| 4088 | Unique_EVP_PKEY pkey(EVP_PKEY_new()); |
| 4089 | if (pkey.get() == NULL) { |
| 4090 | JNI_TRACE("EC_KEY_generate_key(%p) => threw error", group); |
| 4091 | throwExceptionIfNecessary(env, "EC_KEY_generate_key"); |
| 4092 | return 0; |
| 4093 | } |
| 4094 | if (EVP_PKEY_assign_EC_KEY(pkey.get(), eckey.get()) != 1) { |
| 4095 | jniThrowRuntimeException(env, "EVP_PKEY_assign_EC_KEY failed"); |
| 4096 | return 0; |
| 4097 | } |
| 4098 | OWNERSHIP_TRANSFERRED(eckey); |
| 4099 | |
| 4100 | JNI_TRACE("EC_KEY_generate_key(%p) => %p", group, pkey.get()); |
| 4101 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 4102 | } |
| 4103 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4104 | static jlong NativeCrypto_EC_KEY_get1_group(JNIEnv* env, jclass, jobject pkeyRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4105 | { |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4106 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4107 | JNI_TRACE("EC_KEY_get1_group(%p)", pkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4108 | |
| 4109 | if (pkey == NULL) { |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4110 | JNI_TRACE("EC_KEY_get1_group(%p) => pkey == null", pkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4111 | return 0; |
| 4112 | } |
| 4113 | |
| 4114 | if (EVP_PKEY_type(pkey->type) != EVP_PKEY_EC) { |
| 4115 | jniThrowRuntimeException(env, "not EC key"); |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4116 | JNI_TRACE("EC_KEY_get1_group(%p) => not EC key (type == %d)", pkey, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4117 | EVP_PKEY_type(pkey->type)); |
| 4118 | return 0; |
| 4119 | } |
| 4120 | |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 4121 | EC_GROUP* group = EC_GROUP_dup(EC_KEY_get0_group(pkey->pkey.ec)); |
| 4122 | JNI_TRACE("EC_KEY_get1_group(%p) => %p", pkey, group); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4123 | return reinterpret_cast<uintptr_t>(group); |
| 4124 | } |
| 4125 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4126 | static jbyteArray NativeCrypto_EC_KEY_get_private_key(JNIEnv* env, jclass, jobject pkeyRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4127 | { |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4128 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4129 | JNI_TRACE("EC_KEY_get_private_key(%p)", pkey); |
| 4130 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4131 | if (pkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4132 | JNI_TRACE("EC_KEY_get_private_key => pkey == NULL"); |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4133 | return NULL; |
| 4134 | } |
| 4135 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4136 | Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); |
| 4137 | if (eckey.get() == NULL) { |
| 4138 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY"); |
| 4139 | return NULL; |
| 4140 | } |
| 4141 | |
| 4142 | const BIGNUM *privkey = EC_KEY_get0_private_key(eckey.get()); |
| 4143 | |
| 4144 | jbyteArray privBytes = bignumToArray(env, privkey, "privkey"); |
| 4145 | if (env->ExceptionCheck()) { |
| 4146 | JNI_TRACE("EC_KEY_get_private_key(%p) => threw error", pkey); |
| 4147 | return NULL; |
| 4148 | } |
| 4149 | |
| 4150 | JNI_TRACE("EC_KEY_get_private_key(%p) => %p", pkey, privBytes); |
| 4151 | return privBytes; |
| 4152 | } |
| 4153 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4154 | static jlong NativeCrypto_EC_KEY_get_public_key(JNIEnv* env, jclass, jobject pkeyRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4155 | { |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4156 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4157 | JNI_TRACE("EC_KEY_get_public_key(%p)", pkey); |
| 4158 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4159 | if (pkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4160 | JNI_TRACE("EC_KEY_get_public_key => pkey == NULL"); |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4161 | return 0; |
| 4162 | } |
| 4163 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4164 | Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); |
| 4165 | if (eckey.get() == NULL) { |
| 4166 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY"); |
| 4167 | return 0; |
| 4168 | } |
| 4169 | |
| 4170 | Unique_EC_POINT dup(EC_POINT_dup(EC_KEY_get0_public_key(eckey.get()), |
| 4171 | EC_KEY_get0_group(eckey.get()))); |
| 4172 | if (dup.get() == NULL) { |
| 4173 | JNI_TRACE("EC_KEY_get_public_key(%p) => can't dup public key", pkey); |
| 4174 | jniThrowRuntimeException(env, "EC_POINT_dup"); |
| 4175 | return 0; |
| 4176 | } |
| 4177 | |
| 4178 | JNI_TRACE("EC_KEY_get_public_key(%p) => %p", pkey, dup.get()); |
| 4179 | return reinterpret_cast<uintptr_t>(dup.release()); |
| 4180 | } |
| 4181 | |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 4182 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4183 | static void NativeCrypto_EC_KEY_set_nonce_from_hash(JNIEnv* env, jclass, jobject pkeyRef, |
Alex Klyubin | 60f8380 | 2014-02-03 15:21:56 -0800 | [diff] [blame] | 4184 | jboolean enabled) |
| 4185 | { |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4186 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Alex Klyubin | 60f8380 | 2014-02-03 15:21:56 -0800 | [diff] [blame] | 4187 | JNI_TRACE("EC_KEY_set_nonce_from_hash(%p, %d)", pkey, enabled ? 1 : 0); |
| 4188 | |
| 4189 | if (pkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4190 | JNI_TRACE("EC_KEY_set_nonce_from_hash => pkey == NULL"); |
Alex Klyubin | 60f8380 | 2014-02-03 15:21:56 -0800 | [diff] [blame] | 4191 | return; |
| 4192 | } |
| 4193 | |
| 4194 | Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); |
| 4195 | if (eckey.get() == NULL) { |
| 4196 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY"); |
| 4197 | return; |
| 4198 | } |
| 4199 | |
| 4200 | EC_KEY_set_nonce_from_hash(eckey.get(), enabled ? 1 : 0); |
| 4201 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 4202 | #else |
| 4203 | static void NativeCrypto_EC_KEY_set_nonce_from_hash(JNIEnv*, jclass, jobject, jboolean) |
| 4204 | { |
| 4205 | } |
| 4206 | #endif |
Alex Klyubin | 60f8380 | 2014-02-03 15:21:56 -0800 | [diff] [blame] | 4207 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4208 | static jint NativeCrypto_ECDH_compute_key(JNIEnv* env, jclass, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4209 | jbyteArray outArray, jint outOffset, jobject pubkeyRef, jobject privkeyRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4210 | { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4211 | JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p)", outArray, outOffset, pubkeyRef, privkeyRef); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4212 | EVP_PKEY* pubPkey = fromContextObject<EVP_PKEY>(env, pubkeyRef); |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 4213 | if (pubPkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4214 | JNI_TRACE("ECDH_compute_key => pubPkey == NULL"); |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 4215 | return -1; |
| 4216 | } |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4217 | EVP_PKEY* privPkey = fromContextObject<EVP_PKEY>(env, privkeyRef); |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 4218 | if (privPkey == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4219 | JNI_TRACE("ECDH_compute_key => privPkey == NULL"); |
Sergio Giro | 796ed06 | 2015-03-18 17:01:28 +0000 | [diff] [blame] | 4220 | return -1; |
| 4221 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4222 | JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p) <- ptr", outArray, outOffset, pubPkey, privPkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4223 | |
| 4224 | ScopedByteArrayRW out(env, outArray); |
| 4225 | if (out.get() == NULL) { |
| 4226 | JNI_TRACE("ECDH_compute_key(%p, %d, %p, %p) can't get output buffer", |
| 4227 | outArray, outOffset, pubPkey, privPkey); |
| 4228 | return -1; |
| 4229 | } |
| 4230 | |
| 4231 | if ((outOffset < 0) || ((size_t) outOffset >= out.size())) { |
| 4232 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); |
| 4233 | return -1; |
| 4234 | } |
| 4235 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4236 | if (pubPkey == NULL) { |
| 4237 | jniThrowNullPointerException(env, "pubPkey == null"); |
| 4238 | return -1; |
| 4239 | } |
| 4240 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4241 | Unique_EC_KEY pubkey(EVP_PKEY_get1_EC_KEY(pubPkey)); |
| 4242 | if (pubkey.get() == NULL) { |
| 4243 | JNI_TRACE("ECDH_compute_key(%p) => can't get public key", pubPkey); |
| 4244 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public"); |
| 4245 | return -1; |
| 4246 | } |
| 4247 | |
| 4248 | const EC_POINT* pubkeyPoint = EC_KEY_get0_public_key(pubkey.get()); |
| 4249 | if (pubkeyPoint == NULL) { |
| 4250 | JNI_TRACE("ECDH_compute_key(%p) => can't get public key point", pubPkey); |
| 4251 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY public"); |
| 4252 | return -1; |
| 4253 | } |
| 4254 | |
Alex Klyubin | 7c2b4ae | 2014-02-12 16:36:59 -0800 | [diff] [blame] | 4255 | if (privPkey == NULL) { |
| 4256 | jniThrowNullPointerException(env, "privPkey == null"); |
| 4257 | return -1; |
| 4258 | } |
| 4259 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4260 | Unique_EC_KEY privkey(EVP_PKEY_get1_EC_KEY(privPkey)); |
| 4261 | if (privkey.get() == NULL) { |
| 4262 | throwExceptionIfNecessary(env, "EVP_PKEY_get1_EC_KEY private"); |
| 4263 | return -1; |
| 4264 | } |
| 4265 | |
| 4266 | int outputLength = ECDH_compute_key( |
| 4267 | &out[outOffset], |
| 4268 | out.size() - outOffset, |
| 4269 | pubkeyPoint, |
| 4270 | privkey.get(), |
| 4271 | NULL // No KDF |
| 4272 | ); |
| 4273 | if (outputLength == -1) { |
| 4274 | throwExceptionIfNecessary(env, "ECDH_compute_key"); |
| 4275 | return -1; |
| 4276 | } |
| 4277 | |
| 4278 | return outputLength; |
| 4279 | } |
| 4280 | |
| 4281 | static jlong NativeCrypto_EVP_MD_CTX_create(JNIEnv* env, jclass) { |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4282 | JNI_TRACE_MD("EVP_MD_CTX_create()"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4283 | |
| 4284 | Unique_EVP_MD_CTX ctx(EVP_MD_CTX_create()); |
| 4285 | if (ctx.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 4286 | jniThrowOutOfMemory(env, "Unable create a EVP_MD_CTX"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4287 | return 0; |
| 4288 | } |
| 4289 | |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4290 | JNI_TRACE_MD("EVP_MD_CTX_create() => %p", ctx.get()); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4291 | return reinterpret_cast<uintptr_t>(ctx.release()); |
| 4292 | } |
| 4293 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4294 | static void NativeCrypto_EVP_MD_CTX_init(JNIEnv* env, jclass, jobject ctxRef) { |
| 4295 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef); |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4296 | JNI_TRACE_MD("EVP_MD_CTX_init(%p)", ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4297 | |
| 4298 | if (ctx != NULL) { |
| 4299 | EVP_MD_CTX_init(ctx); |
| 4300 | } |
| 4301 | } |
| 4302 | |
Kenny Root | 4ccb72f | 2014-05-30 11:27:32 -0700 | [diff] [blame] | 4303 | static void NativeCrypto_EVP_MD_CTX_destroy(JNIEnv*, jclass, jlong ctxRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4304 | EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef); |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4305 | JNI_TRACE_MD("EVP_MD_CTX_destroy(%p)", ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4306 | |
| 4307 | if (ctx != NULL) { |
| 4308 | EVP_MD_CTX_destroy(ctx); |
| 4309 | } |
| 4310 | } |
| 4311 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4312 | static jint NativeCrypto_EVP_MD_CTX_copy(JNIEnv* env, jclass, jobject dstCtxRef, jobject srcCtxRef) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4313 | JNI_TRACE_MD("EVP_MD_CTX_copy(%p. %p)", dstCtxRef, srcCtxRef); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4314 | EVP_MD_CTX* dst_ctx = fromContextObject<EVP_MD_CTX>(env, dstCtxRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4315 | if (dst_ctx == NULL) { |
| 4316 | JNI_TRACE_MD("EVP_MD_CTX_copy => dst_ctx == NULL"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4317 | return 0; |
| 4318 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4319 | const EVP_MD_CTX* src_ctx = fromContextObject<EVP_MD_CTX>(env, srcCtxRef); |
| 4320 | if (src_ctx == NULL) { |
| 4321 | JNI_TRACE_MD("EVP_MD_CTX_copy => src_ctx == NULL"); |
| 4322 | return 0; |
| 4323 | } |
| 4324 | JNI_TRACE_MD("EVP_MD_CTX_copy(%p. %p) <- ptr", dst_ctx, src_ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4325 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4326 | int result = EVP_MD_CTX_copy_ex(dst_ctx, src_ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4327 | if (result == 0) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4328 | jniThrowRuntimeException(env, "Unable to copy EVP_MD_CTX"); |
| 4329 | freeOpenSslErrorState(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4330 | } |
| 4331 | |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4332 | JNI_TRACE_MD("EVP_MD_CTX_copy(%p, %p) => %d", dst_ctx, src_ctx, result); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4333 | return result; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4334 | } |
| 4335 | |
| 4336 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4337 | * public static native int EVP_DigestFinal(long, byte[], int) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4338 | */ |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4339 | static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray hash, |
| 4340 | jint offset) { |
| 4341 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef); |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4342 | JNI_TRACE_MD("EVP_DigestFinal(%p, %p, %d)", ctx, hash, offset); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4343 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4344 | if (ctx == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4345 | JNI_TRACE("EVP_DigestFinal => ctx == NULL"); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4346 | return -1; |
| 4347 | } else if (hash == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4348 | jniThrowNullPointerException(env, "hash == null"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4349 | return -1; |
| 4350 | } |
| 4351 | |
| 4352 | ScopedByteArrayRW hashBytes(env, hash); |
| 4353 | if (hashBytes.get() == NULL) { |
| 4354 | return -1; |
| 4355 | } |
| 4356 | unsigned int bytesWritten = -1; |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4357 | int ok = EVP_DigestFinal_ex(ctx, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4358 | reinterpret_cast<unsigned char*>(hashBytes.get() + offset), |
| 4359 | &bytesWritten); |
| 4360 | if (ok == 0) { |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4361 | throwExceptionIfNecessary(env, "EVP_DigestFinal"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4362 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4363 | |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4364 | JNI_TRACE_MD("EVP_DigestFinal(%p, %p, %d) => %d (%d)", ctx, hash, offset, bytesWritten, ok); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4365 | return bytesWritten; |
| 4366 | } |
| 4367 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4368 | static jint evpInit(JNIEnv* env, jobject evpMdCtxRef, jlong evpMdRef, const char* jniName, |
| 4369 | int (*init_func)(EVP_MD_CTX*, const EVP_MD*, ENGINE*)) { |
| 4370 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef); |
Kenny Root | caceea7 | 2013-12-06 13:45:03 -0800 | [diff] [blame] | 4371 | const EVP_MD* evp_md = reinterpret_cast<const EVP_MD*>(evpMdRef); |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4372 | JNI_TRACE_MD("%s(%p, %p)", jniName, ctx, evp_md); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4373 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4374 | if (ctx == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4375 | JNI_TRACE("%s(%p) => ctx == NULL", jniName, evp_md); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4376 | return 0; |
| 4377 | } else if (evp_md == NULL) { |
| 4378 | jniThrowNullPointerException(env, "evp_md == null"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4379 | return 0; |
| 4380 | } |
| 4381 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4382 | int ok = init_func(ctx, evp_md, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4383 | if (ok == 0) { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4384 | bool exception = throwExceptionIfNecessary(env, jniName); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4385 | if (exception) { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4386 | JNI_TRACE("%s(%p) => threw exception", jniName, evp_md); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4387 | return 0; |
| 4388 | } |
| 4389 | } |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4390 | JNI_TRACE_MD("%s(%p, %p) => %d", jniName, ctx, evp_md, ok); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4391 | return ok; |
| 4392 | } |
| 4393 | |
| 4394 | static jint NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, jobject evpMdCtxRef, jlong evpMdRef) { |
| 4395 | return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_DigestInit", EVP_DigestInit_ex); |
| 4396 | } |
| 4397 | |
| 4398 | static jint NativeCrypto_EVP_SignInit(JNIEnv* env, jclass, jobject evpMdCtxRef, jlong evpMdRef) { |
| 4399 | return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_SignInit", EVP_DigestInit_ex); |
| 4400 | } |
| 4401 | |
| 4402 | static jint NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, jobject evpMdCtxRef, jlong evpMdRef) { |
| 4403 | return evpInit(env, evpMdCtxRef, evpMdRef, "EVP_VerifyInit", EVP_DigestInit_ex); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4404 | } |
| 4405 | |
| 4406 | /* |
| 4407 | * public static native int EVP_get_digestbyname(java.lang.String) |
| 4408 | */ |
| 4409 | static jlong NativeCrypto_EVP_get_digestbyname(JNIEnv* env, jclass, jstring algorithm) { |
| 4410 | JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%p)", algorithm); |
| 4411 | |
| 4412 | if (algorithm == NULL) { |
| 4413 | jniThrowNullPointerException(env, NULL); |
| 4414 | return -1; |
| 4415 | } |
| 4416 | |
| 4417 | ScopedUtfChars algorithmChars(env, algorithm); |
| 4418 | if (algorithmChars.c_str() == NULL) { |
| 4419 | return 0; |
| 4420 | } |
| 4421 | JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s)", algorithmChars.c_str()); |
| 4422 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4423 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4424 | const EVP_MD* evp_md = EVP_get_digestbyname(algorithmChars.c_str()); |
| 4425 | if (evp_md == NULL) { |
| 4426 | jniThrowRuntimeException(env, "Hash algorithm not found"); |
| 4427 | return 0; |
| 4428 | } |
| 4429 | |
| 4430 | JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => %p", algorithmChars.c_str(), evp_md); |
| 4431 | return reinterpret_cast<uintptr_t>(evp_md); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4432 | #else |
| 4433 | const char *alg = algorithmChars.c_str(); |
| 4434 | const EVP_MD *md; |
| 4435 | |
| 4436 | if (strcasecmp(alg, "md4") == 0) { |
| 4437 | md = EVP_md4(); |
| 4438 | } else if (strcasecmp(alg, "md5") == 0) { |
| 4439 | md = EVP_md5(); |
| 4440 | } else if (strcasecmp(alg, "sha1") == 0) { |
| 4441 | md = EVP_sha1(); |
| 4442 | } else if (strcasecmp(alg, "sha224") == 0) { |
| 4443 | md = EVP_sha224(); |
| 4444 | } else if (strcasecmp(alg, "sha256") == 0) { |
| 4445 | md = EVP_sha256(); |
| 4446 | } else if (strcasecmp(alg, "sha384") == 0) { |
| 4447 | md = EVP_sha384(); |
| 4448 | } else if (strcasecmp(alg, "sha512") == 0) { |
| 4449 | md = EVP_sha512(); |
| 4450 | } else { |
| 4451 | JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => error", alg); |
| 4452 | jniThrowRuntimeException(env, "Hash algorithm not found"); |
| 4453 | return 0; |
| 4454 | } |
| 4455 | |
| 4456 | return reinterpret_cast<uintptr_t>(md); |
| 4457 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4458 | } |
| 4459 | |
| 4460 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4461 | * public static native int EVP_MD_size(long) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4462 | */ |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4463 | static jint NativeCrypto_EVP_MD_size(JNIEnv* env, jclass, jlong evpMdRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4464 | EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef); |
| 4465 | JNI_TRACE("NativeCrypto_EVP_MD_size(%p)", evp_md); |
| 4466 | |
| 4467 | if (evp_md == NULL) { |
| 4468 | jniThrowNullPointerException(env, NULL); |
| 4469 | return -1; |
| 4470 | } |
| 4471 | |
| 4472 | int result = EVP_MD_size(evp_md); |
| 4473 | JNI_TRACE("NativeCrypto_EVP_MD_size(%p) => %d", evp_md, result); |
| 4474 | return result; |
| 4475 | } |
| 4476 | |
| 4477 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4478 | * public static int void EVP_MD_block_size(long) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4479 | */ |
| 4480 | static jint NativeCrypto_EVP_MD_block_size(JNIEnv* env, jclass, jlong evpMdRef) { |
| 4481 | EVP_MD* evp_md = reinterpret_cast<EVP_MD*>(evpMdRef); |
| 4482 | JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p)", evp_md); |
| 4483 | |
| 4484 | if (evp_md == NULL) { |
| 4485 | jniThrowNullPointerException(env, NULL); |
| 4486 | return -1; |
| 4487 | } |
| 4488 | |
| 4489 | int result = EVP_MD_block_size(evp_md); |
| 4490 | JNI_TRACE("NativeCrypto_EVP_MD_block_size(%p) => %d", evp_md, result); |
| 4491 | return result; |
| 4492 | } |
| 4493 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4494 | static void NativeCrypto_EVP_DigestSignInit(JNIEnv* env, jclass, jobject evpMdCtxRef, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4495 | const jlong evpMdRef, jobject pkeyRef) { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4496 | EVP_MD_CTX* mdCtx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4497 | if (mdCtx == NULL) { |
| 4498 | JNI_TRACE("EVP_DigestSignInit => mdCtx == NULL"); |
| 4499 | return; |
| 4500 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4501 | const EVP_MD* md = reinterpret_cast<const EVP_MD*>(evpMdRef); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4502 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4503 | if (pkey == NULL) { |
| 4504 | JNI_TRACE("ctx=%p EVP_DigestSignInit => pkey == NULL", mdCtx); |
| 4505 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4506 | } |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4507 | JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) <- ptr", mdCtx, md, pkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4508 | |
| 4509 | if (md == NULL) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4510 | JNI_TRACE("ctx=%p EVP_DigestSignInit => md == NULL", mdCtx); |
| 4511 | jniThrowNullPointerException(env, "md == null"); |
| 4512 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4513 | } |
| 4514 | |
| 4515 | if (EVP_DigestSignInit(mdCtx, (EVP_PKEY_CTX **) NULL, md, (ENGINE *) NULL, pkey) <= 0) { |
| 4516 | JNI_TRACE("ctx=%p EVP_DigestSignInit => threw exception", mdCtx); |
| 4517 | throwExceptionIfNecessary(env, "EVP_DigestSignInit"); |
| 4518 | return; |
| 4519 | } |
| 4520 | |
| 4521 | JNI_TRACE("EVP_DigestSignInit(%p, %p, %p) => success", mdCtx, md, pkey); |
| 4522 | } |
| 4523 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4524 | static void evpUpdate(JNIEnv* env, jobject evpMdCtxRef, jbyteArray inJavaBytes, jint inOffset, |
| 4525 | jint inLength, const char *jniName, int (*update_func)(EVP_MD_CTX*, const void *, |
Kévin PETIT | 88758d4 | 2014-02-27 11:26:45 +0000 | [diff] [blame] | 4526 | size_t)) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4527 | { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4528 | EVP_MD_CTX* mdCtx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef); |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4529 | JNI_TRACE_MD("%s(%p, %p, %d, %d)", jniName, mdCtx, inJavaBytes, inOffset, inLength); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4530 | |
| 4531 | if (mdCtx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4532 | return; |
| 4533 | } |
| 4534 | |
| 4535 | ScopedByteArrayRO inBytes(env, inJavaBytes); |
| 4536 | if (inBytes.get() == NULL) { |
| 4537 | return; |
| 4538 | } |
| 4539 | |
| 4540 | if (inOffset < 0 || size_t(inOffset) > inBytes.size()) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 4541 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "inOffset"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4542 | return; |
| 4543 | } |
| 4544 | |
| 4545 | const ssize_t inEnd = inOffset + inLength; |
Marcus Oakland | 3f8d640 | 2014-05-14 13:32:50 +0100 | [diff] [blame] | 4546 | if (inLength < 0 || inEnd < 0 || size_t(inEnd) > inBytes.size()) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 4547 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "inLength"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4548 | return; |
| 4549 | } |
| 4550 | |
| 4551 | const unsigned char *tmp = reinterpret_cast<const unsigned char *>(inBytes.get()); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4552 | if (!update_func(mdCtx, tmp + inOffset, inLength)) { |
| 4553 | JNI_TRACE("ctx=%p %s => threw exception", mdCtx, jniName); |
| 4554 | throwExceptionIfNecessary(env, jniName); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4555 | } |
| 4556 | |
Kenny Root | acc950a | 2014-03-26 13:55:26 -0700 | [diff] [blame] | 4557 | JNI_TRACE_MD("%s(%p, %p, %d, %d) => success", jniName, mdCtx, inJavaBytes, inOffset, inLength); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4558 | } |
| 4559 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4560 | static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef, |
| 4561 | jbyteArray inJavaBytes, jint inOffset, jint inLength) { |
| 4562 | evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_DigestUpdate", |
| 4563 | EVP_DigestUpdate); |
| 4564 | } |
| 4565 | |
| 4566 | static void NativeCrypto_EVP_DigestSignUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef, |
| 4567 | jbyteArray inJavaBytes, jint inOffset, jint inLength) { |
| 4568 | evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_DigestSignUpdate", |
| 4569 | EVP_DigestUpdate); |
| 4570 | } |
| 4571 | |
| 4572 | static void NativeCrypto_EVP_SignUpdate(JNIEnv* env, jclass, jobject evpMdCtxRef, |
| 4573 | jbyteArray inJavaBytes, jint inOffset, jint inLength) { |
| 4574 | evpUpdate(env, evpMdCtxRef, inJavaBytes, inOffset, inLength, "EVP_SignUpdate", |
| 4575 | EVP_DigestUpdate); |
| 4576 | } |
| 4577 | |
| 4578 | static jbyteArray NativeCrypto_EVP_DigestSignFinal(JNIEnv* env, jclass, jobject evpMdCtxRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4579 | { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4580 | EVP_MD_CTX* mdCtx = fromContextObject<EVP_MD_CTX>(env, evpMdCtxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4581 | JNI_TRACE("EVP_DigestSignFinal(%p)", mdCtx); |
| 4582 | |
| 4583 | if (mdCtx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4584 | return NULL; |
| 4585 | } |
| 4586 | |
David Benjamin | bca895f | 2014-07-10 18:12:08 -0400 | [diff] [blame] | 4587 | size_t len; |
| 4588 | if (EVP_DigestSignFinal(mdCtx, NULL, &len) != 1) { |
| 4589 | JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx); |
| 4590 | throwExceptionIfNecessary(env, "EVP_DigestSignFinal"); |
| 4591 | return 0; |
| 4592 | } |
| 4593 | ScopedLocalRef<jbyteArray> outJavaBytes(env, env->NewByteArray(len)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4594 | if (outJavaBytes.get() == NULL) { |
| 4595 | return NULL; |
| 4596 | } |
| 4597 | ScopedByteArrayRW outBytes(env, outJavaBytes.get()); |
| 4598 | if (outBytes.get() == NULL) { |
| 4599 | return NULL; |
| 4600 | } |
| 4601 | unsigned char *tmp = reinterpret_cast<unsigned char*>(outBytes.get()); |
David Benjamin | bca895f | 2014-07-10 18:12:08 -0400 | [diff] [blame] | 4602 | if (EVP_DigestSignFinal(mdCtx, tmp, &len) != 1) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4603 | JNI_TRACE("ctx=%p EVP_DigestSignFinal => threw exception", mdCtx); |
| 4604 | throwExceptionIfNecessary(env, "EVP_DigestSignFinal"); |
| 4605 | return 0; |
| 4606 | } |
| 4607 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4608 | JNI_TRACE("EVP_DigestSignFinal(%p) => %p", mdCtx, outJavaBytes.get()); |
| 4609 | return outJavaBytes.release(); |
| 4610 | } |
| 4611 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4612 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4613 | * public static native int EVP_SignFinal(long, byte[], int, long) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4614 | */ |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4615 | static jint NativeCrypto_EVP_SignFinal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray signature, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4616 | jint offset, jobject pkeyRef) { |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4617 | JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p)", ctxRef, signature, offset, pkeyRef); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4618 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4619 | if (ctx == NULL) { |
| 4620 | return -1; |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4621 | } |
| 4622 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
| 4623 | JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) <- ptr", ctx, signature, offset, pkey); |
| 4624 | |
| 4625 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4626 | return -1; |
| 4627 | } |
| 4628 | |
| 4629 | ScopedByteArrayRW signatureBytes(env, signature); |
| 4630 | if (signatureBytes.get() == NULL) { |
| 4631 | return -1; |
| 4632 | } |
| 4633 | unsigned int bytesWritten = -1; |
| 4634 | int ok = EVP_SignFinal(ctx, |
| 4635 | reinterpret_cast<unsigned char*>(signatureBytes.get() + offset), |
| 4636 | &bytesWritten, |
| 4637 | pkey); |
Kenny Root | 1305c13 | 2015-05-29 19:33:40 -0700 | [diff] [blame] | 4638 | if (ok != 1) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4639 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_SignFinal"); |
| 4640 | } |
| 4641 | JNI_TRACE("NativeCrypto_EVP_SignFinal(%p, %p, %d, %p) => %u", |
| 4642 | ctx, signature, offset, pkey, bytesWritten); |
| 4643 | |
| 4644 | return bytesWritten; |
| 4645 | } |
| 4646 | |
| 4647 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4648 | * public static native void EVP_VerifyUpdate(long, byte[], int, int) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4649 | */ |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4650 | static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, jobject ctxRef, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4651 | jbyteArray buffer, jint offset, jint length) { |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4652 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4653 | JNI_TRACE("NativeCrypto_EVP_VerifyUpdate(%p, %p, %d, %d)", ctx, buffer, offset, length); |
| 4654 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4655 | if (ctx == NULL) { |
| 4656 | return; |
| 4657 | } else if (buffer == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4658 | jniThrowNullPointerException(env, NULL); |
| 4659 | return; |
| 4660 | } |
| 4661 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4662 | if (offset < 0 || length < 0) { |
| 4663 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); |
| 4664 | return; |
| 4665 | } |
| 4666 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4667 | ScopedByteArrayRO bufferBytes(env, buffer); |
| 4668 | if (bufferBytes.get() == NULL) { |
| 4669 | return; |
| 4670 | } |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4671 | if (bufferBytes.size() < static_cast<size_t>(offset + length)) { |
| 4672 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); |
| 4673 | return; |
| 4674 | } |
| 4675 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4676 | int ok = EVP_VerifyUpdate(ctx, |
| 4677 | reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset), |
| 4678 | length); |
| 4679 | if (ok == 0) { |
| 4680 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate"); |
| 4681 | } |
| 4682 | } |
| 4683 | |
| 4684 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4685 | * public static native int EVP_VerifyFinal(long, byte[], int, int, long) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4686 | */ |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4687 | static jint NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray buffer, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 4688 | jint offset, jint length, jobject pkeyRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4689 | JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p)", |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4690 | ctxRef, buffer, offset, length, pkeyRef); |
| 4691 | EVP_MD_CTX* ctx = fromContextObject<EVP_MD_CTX>(env, ctxRef); |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 4692 | if (ctx == NULL) { |
| 4693 | return -1; |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 4694 | } |
| 4695 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
| 4696 | if (pkey == NULL) { |
| 4697 | return -1; |
| 4698 | } |
| 4699 | JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) <- ptr", |
| 4700 | ctx, buffer, offset, length, pkey); |
| 4701 | |
| 4702 | if (buffer == NULL) { |
| 4703 | jniThrowNullPointerException(env, "buffer == null"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4704 | return -1; |
| 4705 | } |
| 4706 | |
| 4707 | ScopedByteArrayRO bufferBytes(env, buffer); |
| 4708 | if (bufferBytes.get() == NULL) { |
| 4709 | return -1; |
| 4710 | } |
Kenny Root | cecb4da | 2015-06-04 12:02:05 -0700 | [diff] [blame] | 4711 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4712 | int ok = EVP_VerifyFinal(ctx, |
| 4713 | reinterpret_cast<const unsigned char*>(bufferBytes.get() + offset), |
| 4714 | length, |
| 4715 | pkey); |
Kenny Root | cecb4da | 2015-06-04 12:02:05 -0700 | [diff] [blame] | 4716 | // The upper (Java language) layer should take care of throwing the |
| 4717 | // expected exceptions before calling to this, so we just clear |
| 4718 | // the OpenSSL/BoringSSL error stack here. |
| 4719 | freeOpenSslErrorState(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4720 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4721 | JNI_TRACE("NativeCrypto_EVP_VerifyFinal(%p, %p, %d, %d, %p) => %d", |
| 4722 | ctx, buffer, offset, length, pkey, ok); |
| 4723 | |
| 4724 | return ok; |
| 4725 | } |
| 4726 | |
| 4727 | static jlong NativeCrypto_EVP_get_cipherbyname(JNIEnv* env, jclass, jstring algorithm) { |
| 4728 | JNI_TRACE("EVP_get_cipherbyname(%p)", algorithm); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4729 | |
| 4730 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4731 | if (algorithm == NULL) { |
| 4732 | JNI_TRACE("EVP_get_cipherbyname(%p) => threw exception algorithm == null", algorithm); |
| 4733 | jniThrowNullPointerException(env, NULL); |
| 4734 | return -1; |
| 4735 | } |
| 4736 | |
| 4737 | ScopedUtfChars algorithmChars(env, algorithm); |
| 4738 | if (algorithmChars.c_str() == NULL) { |
| 4739 | return 0; |
| 4740 | } |
| 4741 | JNI_TRACE("EVP_get_cipherbyname(%p) => algorithm = %s", algorithm, algorithmChars.c_str()); |
| 4742 | |
| 4743 | const EVP_CIPHER* evp_cipher = EVP_get_cipherbyname(algorithmChars.c_str()); |
| 4744 | if (evp_cipher == NULL) { |
| 4745 | freeOpenSslErrorState(); |
| 4746 | } |
| 4747 | |
| 4748 | JNI_TRACE("EVP_get_cipherbyname(%s) => %p", algorithmChars.c_str(), evp_cipher); |
| 4749 | return reinterpret_cast<uintptr_t>(evp_cipher); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4750 | #else |
| 4751 | ScopedUtfChars scoped_alg(env, algorithm); |
| 4752 | const char *alg = scoped_alg.c_str(); |
| 4753 | const EVP_CIPHER *cipher; |
| 4754 | |
| 4755 | if (strcasecmp(alg, "rc4") == 0) { |
| 4756 | cipher = EVP_rc4(); |
| 4757 | } else if (strcasecmp(alg, "des-cbc") == 0) { |
| 4758 | cipher = EVP_des_cbc(); |
Adam Langley | 6ae71b6 | 2015-04-23 14:29:23 -0700 | [diff] [blame] | 4759 | } else if (strcasecmp(alg, "des-ede-cbc") == 0) { |
Kenny Root | b839f31 | 2016-08-25 12:08:18 -0700 | [diff] [blame] | 4760 | cipher = EVP_des_ede_cbc(); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4761 | } else if (strcasecmp(alg, "des-ede3-cbc") == 0) { |
| 4762 | cipher = EVP_des_ede3_cbc(); |
| 4763 | } else if (strcasecmp(alg, "aes-128-ecb") == 0) { |
| 4764 | cipher = EVP_aes_128_ecb(); |
| 4765 | } else if (strcasecmp(alg, "aes-128-cbc") == 0) { |
| 4766 | cipher = EVP_aes_128_cbc(); |
| 4767 | } else if (strcasecmp(alg, "aes-128-ctr") == 0) { |
| 4768 | cipher = EVP_aes_128_ctr(); |
| 4769 | } else if (strcasecmp(alg, "aes-128-gcm") == 0) { |
| 4770 | cipher = EVP_aes_128_gcm(); |
Adam Langley | 34160c5 | 2015-04-21 17:25:00 -0700 | [diff] [blame] | 4771 | } else if (strcasecmp(alg, "aes-192-ecb") == 0) { |
| 4772 | cipher = EVP_aes_192_ecb(); |
| 4773 | } else if (strcasecmp(alg, "aes-192-cbc") == 0) { |
| 4774 | cipher = EVP_aes_192_cbc(); |
| 4775 | } else if (strcasecmp(alg, "aes-192-ctr") == 0) { |
| 4776 | cipher = EVP_aes_192_ctr(); |
| 4777 | } else if (strcasecmp(alg, "aes-192-gcm") == 0) { |
| 4778 | cipher = EVP_aes_192_gcm(); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4779 | } else if (strcasecmp(alg, "aes-256-ecb") == 0) { |
| 4780 | cipher = EVP_aes_256_ecb(); |
| 4781 | } else if (strcasecmp(alg, "aes-256-cbc") == 0) { |
| 4782 | cipher = EVP_aes_256_cbc(); |
| 4783 | } else if (strcasecmp(alg, "aes-256-ctr") == 0) { |
| 4784 | cipher = EVP_aes_256_ctr(); |
| 4785 | } else if (strcasecmp(alg, "aes-256-gcm") == 0) { |
| 4786 | cipher = EVP_aes_256_gcm(); |
| 4787 | } else { |
| 4788 | JNI_TRACE("NativeCrypto_EVP_get_digestbyname(%s) => error", alg); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 4789 | return 0; |
| 4790 | } |
| 4791 | |
| 4792 | return reinterpret_cast<uintptr_t>(cipher); |
| 4793 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4794 | } |
| 4795 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4796 | static void NativeCrypto_EVP_CipherInit_ex(JNIEnv* env, jclass, jobject ctxRef, jlong evpCipherRef, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4797 | jbyteArray keyArray, jbyteArray ivArray, jboolean encrypting) { |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4798 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4799 | const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef); |
| 4800 | JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d)", ctx, evpCipher, keyArray, ivArray, |
| 4801 | encrypting ? 1 : 0); |
| 4802 | |
| 4803 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4804 | JNI_TRACE("EVP_CipherUpdate => ctx == null"); |
| 4805 | return; |
| 4806 | } |
| 4807 | |
| 4808 | // The key can be null if we need to set extra parameters. |
| 4809 | UniquePtr<unsigned char[]> keyPtr; |
| 4810 | if (keyArray != NULL) { |
| 4811 | ScopedByteArrayRO keyBytes(env, keyArray); |
| 4812 | if (keyBytes.get() == NULL) { |
| 4813 | return; |
| 4814 | } |
| 4815 | |
| 4816 | keyPtr.reset(new unsigned char[keyBytes.size()]); |
| 4817 | memcpy(keyPtr.get(), keyBytes.get(), keyBytes.size()); |
| 4818 | } |
| 4819 | |
| 4820 | // The IV can be null if we're using ECB. |
| 4821 | UniquePtr<unsigned char[]> ivPtr; |
| 4822 | if (ivArray != NULL) { |
| 4823 | ScopedByteArrayRO ivBytes(env, ivArray); |
| 4824 | if (ivBytes.get() == NULL) { |
| 4825 | return; |
| 4826 | } |
| 4827 | |
| 4828 | ivPtr.reset(new unsigned char[ivBytes.size()]); |
| 4829 | memcpy(ivPtr.get(), ivBytes.get(), ivBytes.size()); |
| 4830 | } |
| 4831 | |
| 4832 | if (!EVP_CipherInit_ex(ctx, evpCipher, NULL, keyPtr.get(), ivPtr.get(), encrypting ? 1 : 0)) { |
| 4833 | throwExceptionIfNecessary(env, "EVP_CipherInit_ex"); |
| 4834 | JNI_TRACE("EVP_CipherInit_ex => error initializing cipher"); |
| 4835 | return; |
| 4836 | } |
| 4837 | |
| 4838 | JNI_TRACE("EVP_CipherInit_ex(%p, %p, %p, %p, %d) => success", ctx, evpCipher, keyArray, ivArray, |
| 4839 | encrypting ? 1 : 0); |
| 4840 | } |
| 4841 | |
| 4842 | /* |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 4843 | * public static native int EVP_CipherUpdate(long ctx, byte[] out, int outOffset, byte[] in, |
| 4844 | * int inOffset, int inLength); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4845 | */ |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4846 | static jint NativeCrypto_EVP_CipherUpdate(JNIEnv* env, jclass, jobject ctxRef, jbyteArray outArray, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4847 | jint outOffset, jbyteArray inArray, jint inOffset, jint inLength) { |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4848 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4849 | JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d)", ctx, outArray, outOffset, inArray, inOffset); |
| 4850 | |
| 4851 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4852 | JNI_TRACE("ctx=%p EVP_CipherUpdate => ctx == null", ctx); |
| 4853 | return 0; |
| 4854 | } |
| 4855 | |
| 4856 | ScopedByteArrayRO inBytes(env, inArray); |
| 4857 | if (inBytes.get() == NULL) { |
| 4858 | return 0; |
| 4859 | } |
| 4860 | const size_t inSize = inBytes.size(); |
| 4861 | if (size_t(inOffset + inLength) > inSize) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 4862 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4863 | "in.length < (inSize + inOffset)"); |
| 4864 | return 0; |
| 4865 | } |
| 4866 | |
| 4867 | ScopedByteArrayRW outBytes(env, outArray); |
| 4868 | if (outBytes.get() == NULL) { |
| 4869 | return 0; |
| 4870 | } |
| 4871 | const size_t outSize = outBytes.size(); |
| 4872 | if (size_t(outOffset + inLength) > outSize) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 4873 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4874 | "out.length < inSize + outOffset + blockSize - 1"); |
| 4875 | return 0; |
| 4876 | } |
| 4877 | |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 4878 | JNI_TRACE("ctx=%p EVP_CipherUpdate in=%p in.length=%zd inOffset=%zd inLength=%zd out=%p out.length=%zd outOffset=%zd", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4879 | ctx, inBytes.get(), inBytes.size(), inOffset, inLength, outBytes.get(), outBytes.size(), outOffset); |
| 4880 | |
| 4881 | unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get()); |
| 4882 | const unsigned char* in = reinterpret_cast<const unsigned char*>(inBytes.get()); |
| 4883 | |
| 4884 | int outl; |
| 4885 | if (!EVP_CipherUpdate(ctx, out + outOffset, &outl, in + inOffset, inLength)) { |
| 4886 | throwExceptionIfNecessary(env, "EVP_CipherUpdate"); |
| 4887 | JNI_TRACE("ctx=%p EVP_CipherUpdate => threw error", ctx); |
| 4888 | return 0; |
| 4889 | } |
| 4890 | |
| 4891 | JNI_TRACE("EVP_CipherUpdate(%p, %p, %d, %p, %d) => %d", ctx, outArray, outOffset, inArray, |
| 4892 | inOffset, outl); |
| 4893 | return outl; |
| 4894 | } |
| 4895 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4896 | static jint NativeCrypto_EVP_CipherFinal_ex(JNIEnv* env, jclass, jobject ctxRef, |
| 4897 | jbyteArray outArray, jint outOffset) { |
| 4898 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4899 | JNI_TRACE("EVP_CipherFinal_ex(%p, %p, %d)", ctx, outArray, outOffset); |
| 4900 | |
| 4901 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4902 | JNI_TRACE("ctx=%p EVP_CipherFinal_ex => ctx == null", ctx); |
| 4903 | return 0; |
| 4904 | } |
| 4905 | |
| 4906 | ScopedByteArrayRW outBytes(env, outArray); |
| 4907 | if (outBytes.get() == NULL) { |
| 4908 | return 0; |
| 4909 | } |
| 4910 | |
| 4911 | unsigned char* out = reinterpret_cast<unsigned char*>(outBytes.get()); |
| 4912 | |
| 4913 | int outl; |
| 4914 | if (!EVP_CipherFinal_ex(ctx, out + outOffset, &outl)) { |
Kenny Root | 058faf1 | 2014-12-08 14:12:20 -0800 | [diff] [blame] | 4915 | if (throwExceptionIfNecessary(env, "EVP_CipherFinal_ex")) { |
| 4916 | JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw error", ctx); |
| 4917 | } else { |
| 4918 | throwBadPaddingException(env, "EVP_CipherFinal_ex"); |
| 4919 | JNI_TRACE("ctx=%p EVP_CipherFinal_ex => threw padding exception", ctx); |
| 4920 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4921 | return 0; |
| 4922 | } |
| 4923 | |
| 4924 | JNI_TRACE("EVP_CipherFinal(%p, %p, %d) => %d", ctx, outArray, outOffset, outl); |
| 4925 | return outl; |
| 4926 | } |
| 4927 | |
| 4928 | static jint NativeCrypto_EVP_CIPHER_iv_length(JNIEnv* env, jclass, jlong evpCipherRef) { |
| 4929 | const EVP_CIPHER* evpCipher = reinterpret_cast<const EVP_CIPHER*>(evpCipherRef); |
| 4930 | JNI_TRACE("EVP_CIPHER_iv_length(%p)", evpCipher); |
| 4931 | |
| 4932 | if (evpCipher == NULL) { |
| 4933 | jniThrowNullPointerException(env, "evpCipher == null"); |
| 4934 | JNI_TRACE("EVP_CIPHER_iv_length => evpCipher == null"); |
| 4935 | return 0; |
| 4936 | } |
| 4937 | |
| 4938 | const int ivLength = EVP_CIPHER_iv_length(evpCipher); |
| 4939 | JNI_TRACE("EVP_CIPHER_iv_length(%p) => %d", evpCipher, ivLength); |
| 4940 | return ivLength; |
| 4941 | } |
| 4942 | |
| 4943 | static jlong NativeCrypto_EVP_CIPHER_CTX_new(JNIEnv* env, jclass) { |
| 4944 | JNI_TRACE("EVP_CIPHER_CTX_new()"); |
| 4945 | |
| 4946 | Unique_EVP_CIPHER_CTX ctx(EVP_CIPHER_CTX_new()); |
| 4947 | if (ctx.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 4948 | jniThrowOutOfMemory(env, "Unable to allocate cipher context"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4949 | JNI_TRACE("EVP_CipherInit_ex => context allocation error"); |
| 4950 | return 0; |
| 4951 | } |
| 4952 | |
| 4953 | JNI_TRACE("EVP_CIPHER_CTX_new() => %p", ctx.get()); |
| 4954 | return reinterpret_cast<uintptr_t>(ctx.release()); |
| 4955 | } |
| 4956 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4957 | static jint NativeCrypto_EVP_CIPHER_CTX_block_size(JNIEnv* env, jclass, jobject ctxRef) { |
| 4958 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4959 | JNI_TRACE("EVP_CIPHER_CTX_block_size(%p)", ctx); |
| 4960 | |
| 4961 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4962 | JNI_TRACE("ctx=%p EVP_CIPHER_CTX_block_size => ctx == null", ctx); |
| 4963 | return 0; |
| 4964 | } |
| 4965 | |
| 4966 | int blockSize = EVP_CIPHER_CTX_block_size(ctx); |
| 4967 | JNI_TRACE("EVP_CIPHER_CTX_block_size(%p) => %d", ctx, blockSize); |
| 4968 | return blockSize; |
| 4969 | } |
| 4970 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4971 | static jint NativeCrypto_get_EVP_CIPHER_CTX_buf_len(JNIEnv* env, jclass, jobject ctxRef) { |
| 4972 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4973 | JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p)", ctx); |
| 4974 | |
| 4975 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 4976 | JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_buf_len => ctx == null", ctx); |
| 4977 | return 0; |
| 4978 | } |
| 4979 | |
| 4980 | int buf_len = ctx->buf_len; |
| 4981 | JNI_TRACE("get_EVP_CIPHER_CTX_buf_len(%p) => %d", ctx, buf_len); |
| 4982 | return buf_len; |
| 4983 | } |
| 4984 | |
Sergio Giro | 1127c19 | 2015-06-08 11:36:14 +0100 | [diff] [blame] | 4985 | static jboolean NativeCrypto_get_EVP_CIPHER_CTX_final_used(JNIEnv* env, jclass, jobject ctxRef) { |
| 4986 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
| 4987 | JNI_TRACE("get_EVP_CIPHER_CTX_final_used(%p)", ctx); |
| 4988 | |
| 4989 | if (ctx == NULL) { |
| 4990 | JNI_TRACE("ctx=%p get_EVP_CIPHER_CTX_final_used => ctx == null", ctx); |
| 4991 | return 0; |
| 4992 | } |
| 4993 | |
| 4994 | bool final_used = ctx->final_used != 0; |
| 4995 | JNI_TRACE("get_EVP_CIPHER_CTX_final_used(%p) => %d", ctx, final_used); |
| 4996 | return final_used; |
| 4997 | } |
| 4998 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 4999 | static void NativeCrypto_EVP_CIPHER_CTX_set_padding(JNIEnv* env, jclass, jobject ctxRef, |
| 5000 | jboolean enablePaddingBool) { |
| 5001 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5002 | jint enablePadding = enablePaddingBool ? 1 : 0; |
| 5003 | JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d)", ctx, enablePadding); |
| 5004 | |
| 5005 | if (ctx == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5006 | JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_padding => ctx == null", ctx); |
| 5007 | return; |
| 5008 | } |
| 5009 | |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 5010 | EVP_CIPHER_CTX_set_padding(ctx, enablePadding); // Not void, but always returns 1. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5011 | JNI_TRACE("EVP_CIPHER_CTX_set_padding(%p, %d) => success", ctx, enablePadding); |
| 5012 | } |
| 5013 | |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 5014 | static void NativeCrypto_EVP_CIPHER_CTX_set_key_length(JNIEnv* env, jclass, jobject ctxRef, |
Kenny Root | 153fd44 | 2014-11-26 08:03:42 -0800 | [diff] [blame] | 5015 | jint keySizeBits) { |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 5016 | EVP_CIPHER_CTX* ctx = fromContextObject<EVP_CIPHER_CTX>(env, ctxRef); |
Kenny Root | 153fd44 | 2014-11-26 08:03:42 -0800 | [diff] [blame] | 5017 | JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d)", ctx, keySizeBits); |
| 5018 | |
| 5019 | if (ctx == NULL) { |
Kenny Root | 153fd44 | 2014-11-26 08:03:42 -0800 | [diff] [blame] | 5020 | JNI_TRACE("ctx=%p EVP_CIPHER_CTX_set_key_length => ctx == null", ctx); |
| 5021 | return; |
| 5022 | } |
| 5023 | |
| 5024 | if (!EVP_CIPHER_CTX_set_key_length(ctx, keySizeBits)) { |
| 5025 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_CIPHER_CTX_set_key_length"); |
| 5026 | JNI_TRACE("NativeCrypto_EVP_CIPHER_CTX_set_key_length => threw error"); |
| 5027 | return; |
| 5028 | } |
| 5029 | JNI_TRACE("EVP_CIPHER_CTX_set_key_length(%p, %d) => success", ctx, keySizeBits); |
| 5030 | } |
| 5031 | |
Narayan Kamath | b578b39 | 2014-12-10 14:58:44 +0000 | [diff] [blame] | 5032 | static void NativeCrypto_EVP_CIPHER_CTX_free(JNIEnv*, jclass, jlong ctxRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5033 | EVP_CIPHER_CTX* ctx = reinterpret_cast<EVP_CIPHER_CTX*>(ctxRef); |
Narayan Kamath | b578b39 | 2014-12-10 14:58:44 +0000 | [diff] [blame] | 5034 | JNI_TRACE("EVP_CIPHER_CTX_free(%p)", ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5035 | |
Narayan Kamath | b578b39 | 2014-12-10 14:58:44 +0000 | [diff] [blame] | 5036 | EVP_CIPHER_CTX_free(ctx); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5037 | } |
| 5038 | |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5039 | static jlong NativeCrypto_EVP_aead_aes_128_gcm(JNIEnv* env, jclass) { |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5040 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5041 | UNUSED_ARGUMENT(env); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5042 | const EVP_AEAD* ctx = EVP_aead_aes_128_gcm(); |
| 5043 | JNI_TRACE("EVP_aead_aes_128_gcm => ctx=%p", ctx); |
| 5044 | return reinterpret_cast<jlong>(ctx); |
| 5045 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5046 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5047 | return 0; |
| 5048 | #endif |
| 5049 | } |
| 5050 | |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5051 | static jlong NativeCrypto_EVP_aead_aes_256_gcm(JNIEnv* env, jclass) { |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5052 | #if defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5053 | UNUSED_ARGUMENT(env); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5054 | const EVP_AEAD* ctx = EVP_aead_aes_256_gcm(); |
| 5055 | JNI_TRACE("EVP_aead_aes_256_gcm => ctx=%p", ctx); |
| 5056 | return reinterpret_cast<jlong>(ctx); |
| 5057 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5058 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
| 5059 | return 0; |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5060 | #endif |
| 5061 | } |
| 5062 | |
| 5063 | static jlong NativeCrypto_EVP_AEAD_CTX_init(JNIEnv* env, jclass, jlong evpAeadRef, |
| 5064 | jbyteArray keyArray, jint tagLen) { |
| 5065 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5066 | const EVP_AEAD* evpAead = reinterpret_cast<const EVP_AEAD*>(evpAeadRef); |
| 5067 | JNI_TRACE("EVP_AEAD_CTX_init(%p, %p, %d)", evpAead, keyArray, tagLen); |
| 5068 | |
| 5069 | ScopedByteArrayRO keyBytes(env, keyArray); |
| 5070 | if (keyBytes.get() == NULL) { |
| 5071 | return 0; |
| 5072 | } |
| 5073 | |
| 5074 | Unique_EVP_AEAD_CTX aeadCtx(reinterpret_cast<EVP_AEAD_CTX*>( |
| 5075 | OPENSSL_malloc(sizeof(EVP_AEAD_CTX)))); |
| 5076 | memset(aeadCtx.get(), 0, sizeof(EVP_AEAD_CTX)); |
| 5077 | |
| 5078 | const uint8_t* tmp = reinterpret_cast<const uint8_t*>(keyBytes.get()); |
| 5079 | int ret = EVP_AEAD_CTX_init(aeadCtx.get(), evpAead, tmp, keyBytes.size(), tagLen, NULL); |
| 5080 | if (ret != 1) { |
| 5081 | throwExceptionIfNecessary(env, "EVP_AEAD_CTX_init"); |
| 5082 | JNI_TRACE("EVP_AEAD_CTX_init(%p, %p, %d) => fail EVP_AEAD_CTX_init", evpAead, |
| 5083 | keyArray, tagLen); |
| 5084 | return 0; |
| 5085 | } |
| 5086 | |
| 5087 | JNI_TRACE("EVP_AEAD_CTX_init(%p, %p, %d) => %p", evpAead, keyArray, tagLen, aeadCtx.get()); |
| 5088 | return reinterpret_cast<jlong>(aeadCtx.release()); |
| 5089 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5090 | UNUSED_ARGUMENT(env); |
| 5091 | UNUSED_ARGUMENT(evpAeadRef); |
| 5092 | UNUSED_ARGUMENT(keyArray); |
| 5093 | UNUSED_ARGUMENT(tagLen); |
| 5094 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5095 | return 0; |
| 5096 | #endif |
| 5097 | } |
| 5098 | |
| 5099 | static void NativeCrypto_EVP_AEAD_CTX_cleanup(JNIEnv* env, jclass, jlong evpAeadCtxRef) { |
| 5100 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5101 | EVP_AEAD_CTX* evpAeadCtx = reinterpret_cast<EVP_AEAD_CTX*>(evpAeadCtxRef); |
| 5102 | JNI_TRACE("EVP_AEAD_CTX_cleanup(%p)", evpAeadCtx); |
| 5103 | if (evpAeadCtx == NULL) { |
| 5104 | jniThrowNullPointerException(env, "evpAead == null"); |
| 5105 | return; |
| 5106 | } |
| 5107 | |
| 5108 | EVP_AEAD_CTX_cleanup(evpAeadCtx); |
| 5109 | OPENSSL_free(evpAeadCtx); |
| 5110 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5111 | UNUSED_ARGUMENT(env); |
| 5112 | UNUSED_ARGUMENT(evpAeadCtxRef); |
| 5113 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5114 | #endif |
| 5115 | } |
| 5116 | |
| 5117 | static jint NativeCrypto_EVP_AEAD_max_overhead(JNIEnv* env, jclass, jlong evpAeadRef) { |
| 5118 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5119 | const EVP_AEAD* evpAead = reinterpret_cast<const EVP_AEAD*>(evpAeadRef); |
| 5120 | JNI_TRACE("EVP_AEAD_max_overhead(%p)", evpAead); |
| 5121 | if (evpAead == NULL) { |
| 5122 | jniThrowNullPointerException(env, "evpAead == null"); |
| 5123 | return 0; |
| 5124 | } |
| 5125 | int maxOverhead = EVP_AEAD_max_overhead(evpAead); |
| 5126 | JNI_TRACE("EVP_AEAD_max_overhead(%p) => %d", evpAead, maxOverhead); |
| 5127 | return maxOverhead; |
| 5128 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5129 | UNUSED_ARGUMENT(env); |
| 5130 | UNUSED_ARGUMENT(evpAeadRef); |
| 5131 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5132 | return 0; |
| 5133 | #endif |
| 5134 | } |
| 5135 | |
| 5136 | static jint NativeCrypto_EVP_AEAD_nonce_length(JNIEnv* env, jclass, jlong evpAeadRef) { |
| 5137 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5138 | const EVP_AEAD* evpAead = reinterpret_cast<const EVP_AEAD*>(evpAeadRef); |
| 5139 | JNI_TRACE("EVP_AEAD_nonce_length(%p)", evpAead); |
| 5140 | if (evpAead == NULL) { |
| 5141 | jniThrowNullPointerException(env, "evpAead == null"); |
| 5142 | return 0; |
| 5143 | } |
| 5144 | int nonceLength = EVP_AEAD_nonce_length(evpAead); |
| 5145 | JNI_TRACE("EVP_AEAD_nonce_length(%p) => %d", evpAead, nonceLength); |
| 5146 | return nonceLength; |
| 5147 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5148 | UNUSED_ARGUMENT(env); |
| 5149 | UNUSED_ARGUMENT(evpAeadRef); |
| 5150 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5151 | return 0; |
| 5152 | #endif |
| 5153 | } |
| 5154 | |
| 5155 | static jint NativeCrypto_EVP_AEAD_max_tag_len(JNIEnv* env, jclass, jlong evpAeadRef) { |
| 5156 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5157 | const EVP_AEAD* evpAead = reinterpret_cast<const EVP_AEAD*>(evpAeadRef); |
| 5158 | JNI_TRACE("EVP_AEAD_max_tag_len(%p)", evpAead); |
| 5159 | if (evpAead == NULL) { |
| 5160 | jniThrowNullPointerException(env, "evpAead == null"); |
| 5161 | return 0; |
| 5162 | } |
| 5163 | int maxTagLen = EVP_AEAD_max_tag_len(evpAead); |
| 5164 | JNI_TRACE("EVP_AEAD_max_tag_len(%p) => %d", evpAead, maxTagLen); |
| 5165 | return maxTagLen; |
| 5166 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5167 | UNUSED_ARGUMENT(env); |
| 5168 | UNUSED_ARGUMENT(evpAeadRef); |
| 5169 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5170 | return 0; |
| 5171 | #endif |
| 5172 | } |
| 5173 | |
| 5174 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5175 | typedef int (*evp_aead_ctx_op_func)(const EVP_AEAD_CTX *ctx, uint8_t *out, |
| 5176 | size_t *out_len, size_t max_out_len, |
| 5177 | const uint8_t *nonce, size_t nonce_len, |
| 5178 | const uint8_t *in, size_t in_len, |
| 5179 | const uint8_t *ad, size_t ad_len); |
| 5180 | |
| 5181 | static jint evp_aead_ctx_op(JNIEnv* env, jobject ctxRef, jbyteArray outArray, jint outOffset, |
| 5182 | jbyteArray nonceArray, jbyteArray inArray, jint inOffset, jint inLength, |
| 5183 | jbyteArray aadArray, evp_aead_ctx_op_func realFunc) { |
| 5184 | EVP_AEAD_CTX* ctx = fromContextObject<EVP_AEAD_CTX>(env, ctxRef); |
| 5185 | JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %d, %d, %p)", ctx, outArray, outOffset, |
| 5186 | nonceArray, inArray, inOffset, inLength, aadArray); |
| 5187 | |
| 5188 | ScopedByteArrayRW outBytes(env, outArray); |
| 5189 | if (outBytes.get() == NULL) { |
| 5190 | return 0; |
| 5191 | } |
| 5192 | |
| 5193 | if (ARRAY_OFFSET_INVALID(outBytes, outOffset)) { |
Kenny Root | 203afd8 | 2015-05-18 16:36:23 -0700 | [diff] [blame] | 5194 | JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %d, %d, %p)", ctx, outArray, outOffset, |
| 5195 | nonceArray, inArray, inOffset, inLength, aadArray); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5196 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "out"); |
| 5197 | return 0; |
| 5198 | } |
| 5199 | |
| 5200 | ScopedByteArrayRO inBytes(env, inArray); |
| 5201 | if (inBytes.get() == NULL) { |
| 5202 | return 0; |
| 5203 | } |
| 5204 | |
| 5205 | if (ARRAY_OFFSET_LENGTH_INVALID(inBytes, inOffset, inLength)) { |
Kenny Root | 203afd8 | 2015-05-18 16:36:23 -0700 | [diff] [blame] | 5206 | JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %d, %d, %p)", ctx, outArray, outOffset, |
| 5207 | nonceArray, inArray, inOffset, inLength, aadArray); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5208 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "in"); |
| 5209 | return 0; |
| 5210 | } |
| 5211 | |
| 5212 | UniquePtr<ScopedByteArrayRO> aad; |
| 5213 | const uint8_t* aad_chars = NULL; |
| 5214 | size_t aad_chars_size = 0; |
| 5215 | if (aadArray != NULL) { |
| 5216 | aad.reset(new ScopedByteArrayRO(env, aadArray)); |
| 5217 | aad_chars = reinterpret_cast<const uint8_t*>(aad->get()); |
| 5218 | if (aad_chars == NULL) { |
| 5219 | return 0; |
| 5220 | } |
| 5221 | aad_chars_size = aad->size(); |
| 5222 | } |
| 5223 | |
| 5224 | ScopedByteArrayRO nonceBytes(env, nonceArray); |
| 5225 | if (nonceBytes.get() == NULL) { |
| 5226 | return 0; |
| 5227 | } |
| 5228 | |
| 5229 | uint8_t* outTmp = reinterpret_cast<uint8_t*>(outBytes.get()); |
| 5230 | const uint8_t* inTmp = reinterpret_cast<const uint8_t*>(inBytes.get()); |
| 5231 | const uint8_t* nonceTmp = reinterpret_cast<const uint8_t*>(nonceBytes.get()); |
| 5232 | size_t actualOutLength; |
| 5233 | int ret = realFunc(ctx, outTmp + outOffset, &actualOutLength, outBytes.size() - outOffset, |
| 5234 | nonceTmp, nonceBytes.size(), inTmp + inOffset, inLength, aad_chars, aad_chars_size); |
| 5235 | if (ret != 1) { |
| 5236 | throwExceptionIfNecessary(env, "evp_aead_ctx_op"); |
| 5237 | } |
| 5238 | |
| 5239 | JNI_TRACE("evp_aead_ctx_op(%p, %p, %d, %p, %p, %d, %d, %p) => ret=%d, outLength=%zd", |
| 5240 | ctx, outArray, outOffset, nonceArray, inArray, inOffset, inLength, aadArray, ret, |
| 5241 | actualOutLength); |
| 5242 | return static_cast<jlong>(actualOutLength); |
| 5243 | } |
| 5244 | #endif |
| 5245 | |
| 5246 | static jint NativeCrypto_EVP_AEAD_CTX_seal(JNIEnv* env, jclass, jobject ctxRef, jbyteArray outArray, |
| 5247 | jint outOffset, jbyteArray nonceArray, jbyteArray inArray, jint inOffset, jint inLength, |
| 5248 | jbyteArray aadArray) { |
| 5249 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5250 | return evp_aead_ctx_op(env, ctxRef, outArray, outOffset, nonceArray, inArray, inOffset, |
| 5251 | inLength, aadArray, EVP_AEAD_CTX_seal); |
| 5252 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5253 | UNUSED_ARGUMENT(env); |
| 5254 | UNUSED_ARGUMENT(ctxRef); |
| 5255 | UNUSED_ARGUMENT(outArray); |
| 5256 | UNUSED_ARGUMENT(outOffset); |
| 5257 | UNUSED_ARGUMENT(nonceArray); |
| 5258 | UNUSED_ARGUMENT(inArray); |
| 5259 | UNUSED_ARGUMENT(inOffset); |
| 5260 | UNUSED_ARGUMENT(inLength); |
| 5261 | UNUSED_ARGUMENT(aadArray); |
| 5262 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5263 | return 0; |
| 5264 | #endif |
| 5265 | } |
| 5266 | |
| 5267 | static jint NativeCrypto_EVP_AEAD_CTX_open(JNIEnv* env, jclass, jobject ctxRef, jbyteArray outArray, |
| 5268 | jint outOffset, jbyteArray nonceArray, jbyteArray inArray, jint inOffset, jint inLength, |
| 5269 | jbyteArray aadArray) { |
| 5270 | #if defined(OPENSSL_IS_BORINGSSL) |
| 5271 | return evp_aead_ctx_op(env, ctxRef, outArray, outOffset, nonceArray, inArray, inOffset, |
| 5272 | inLength, aadArray, EVP_AEAD_CTX_open); |
| 5273 | #else |
Kenny Root | 7c0a4c8 | 2015-05-12 16:50:19 -0700 | [diff] [blame] | 5274 | UNUSED_ARGUMENT(env); |
| 5275 | UNUSED_ARGUMENT(ctxRef); |
| 5276 | UNUSED_ARGUMENT(outArray); |
| 5277 | UNUSED_ARGUMENT(outOffset); |
| 5278 | UNUSED_ARGUMENT(nonceArray); |
| 5279 | UNUSED_ARGUMENT(inArray); |
| 5280 | UNUSED_ARGUMENT(inOffset); |
| 5281 | UNUSED_ARGUMENT(inLength); |
| 5282 | UNUSED_ARGUMENT(aadArray); |
| 5283 | jniThrowRuntimeException(env, "Not supported for OpenSSL"); |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 5284 | return 0; |
| 5285 | #endif |
| 5286 | } |
| 5287 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5288 | /** |
| 5289 | * public static native void RAND_seed(byte[]); |
| 5290 | */ |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 5291 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5292 | static void NativeCrypto_RAND_seed(JNIEnv* env, jclass, jbyteArray seed) { |
Kenny Root | 4f81d31 | 2014-11-19 13:02:24 -0800 | [diff] [blame] | 5293 | JNI_TRACE("NativeCrypto_RAND_seed seed=%p", seed); |
Kenny Root | 4f81d31 | 2014-11-19 13:02:24 -0800 | [diff] [blame] | 5294 | ScopedByteArrayRO randseed(env, seed); |
| 5295 | if (randseed.get() == NULL) { |
| 5296 | return; |
| 5297 | } |
| 5298 | RAND_seed(randseed.get(), randseed.size()); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5299 | } |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 5300 | #else |
| 5301 | static void NativeCrypto_RAND_seed(JNIEnv*, jclass, jbyteArray) { |
| 5302 | } |
| 5303 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5304 | |
| 5305 | static jint NativeCrypto_RAND_load_file(JNIEnv* env, jclass, jstring filename, jlong max_bytes) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 5306 | JNI_TRACE("NativeCrypto_RAND_load_file filename=%p max_bytes=%lld", filename, (long long) max_bytes); |
Kenny Root | 4f81d31 | 2014-11-19 13:02:24 -0800 | [diff] [blame] | 5307 | #if !defined(OPENSSL_IS_BORINGSSL) |
| 5308 | ScopedUtfChars file(env, filename); |
| 5309 | if (file.c_str() == NULL) { |
| 5310 | return -1; |
| 5311 | } |
| 5312 | int result = RAND_load_file(file.c_str(), max_bytes); |
| 5313 | JNI_TRACE("NativeCrypto_RAND_load_file file=%s => %d", file.c_str(), result); |
| 5314 | return result; |
| 5315 | #else |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 5316 | UNUSED_ARGUMENT(env); |
| 5317 | UNUSED_ARGUMENT(filename); |
Kenny Root | 4f81d31 | 2014-11-19 13:02:24 -0800 | [diff] [blame] | 5318 | // OpenSSLRandom calls this and checks the return value. |
| 5319 | return static_cast<jint>(max_bytes); |
| 5320 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5321 | } |
| 5322 | |
| 5323 | static void NativeCrypto_RAND_bytes(JNIEnv* env, jclass, jbyteArray output) { |
| 5324 | JNI_TRACE("NativeCrypto_RAND_bytes(%p)", output); |
| 5325 | |
| 5326 | ScopedByteArrayRW outputBytes(env, output); |
| 5327 | if (outputBytes.get() == NULL) { |
| 5328 | return; |
| 5329 | } |
| 5330 | |
| 5331 | unsigned char* tmp = reinterpret_cast<unsigned char*>(outputBytes.get()); |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 5332 | if (RAND_bytes(tmp, outputBytes.size()) <= 0) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5333 | throwExceptionIfNecessary(env, "NativeCrypto_RAND_bytes"); |
| 5334 | JNI_TRACE("tmp=%p NativeCrypto_RAND_bytes => threw error", tmp); |
| 5335 | return; |
| 5336 | } |
| 5337 | |
| 5338 | JNI_TRACE("NativeCrypto_RAND_bytes(%p) => success", output); |
| 5339 | } |
| 5340 | |
| 5341 | static jint NativeCrypto_OBJ_txt2nid(JNIEnv* env, jclass, jstring oidStr) { |
| 5342 | JNI_TRACE("OBJ_txt2nid(%p)", oidStr); |
| 5343 | |
| 5344 | ScopedUtfChars oid(env, oidStr); |
| 5345 | if (oid.c_str() == NULL) { |
| 5346 | return 0; |
| 5347 | } |
| 5348 | |
| 5349 | int nid = OBJ_txt2nid(oid.c_str()); |
| 5350 | JNI_TRACE("OBJ_txt2nid(%s) => %d", oid.c_str(), nid); |
| 5351 | return nid; |
| 5352 | } |
| 5353 | |
| 5354 | static jstring NativeCrypto_OBJ_txt2nid_longName(JNIEnv* env, jclass, jstring oidStr) { |
| 5355 | JNI_TRACE("OBJ_txt2nid_longName(%p)", oidStr); |
| 5356 | |
| 5357 | ScopedUtfChars oid(env, oidStr); |
| 5358 | if (oid.c_str() == NULL) { |
| 5359 | return NULL; |
| 5360 | } |
| 5361 | |
| 5362 | JNI_TRACE("OBJ_txt2nid_longName(%s)", oid.c_str()); |
| 5363 | |
| 5364 | int nid = OBJ_txt2nid(oid.c_str()); |
| 5365 | if (nid == NID_undef) { |
| 5366 | JNI_TRACE("OBJ_txt2nid_longName(%s) => NID_undef", oid.c_str()); |
| 5367 | freeOpenSslErrorState(); |
| 5368 | return NULL; |
| 5369 | } |
| 5370 | |
| 5371 | const char* longName = OBJ_nid2ln(nid); |
| 5372 | JNI_TRACE("OBJ_txt2nid_longName(%s) => %s", oid.c_str(), longName); |
| 5373 | return env->NewStringUTF(longName); |
| 5374 | } |
| 5375 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 5376 | static jstring ASN1_OBJECT_to_OID_string(JNIEnv* env, const ASN1_OBJECT* obj) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5377 | /* |
| 5378 | * The OBJ_obj2txt API doesn't "measure" if you pass in NULL as the buffer. |
| 5379 | * Just make a buffer that's large enough here. The documentation recommends |
| 5380 | * 80 characters. |
| 5381 | */ |
| 5382 | char output[128]; |
| 5383 | int ret = OBJ_obj2txt(output, sizeof(output), obj, 1); |
| 5384 | if (ret < 0) { |
| 5385 | throwExceptionIfNecessary(env, "ASN1_OBJECT_to_OID_string"); |
| 5386 | return NULL; |
| 5387 | } else if (size_t(ret) >= sizeof(output)) { |
| 5388 | jniThrowRuntimeException(env, "ASN1_OBJECT_to_OID_string buffer too small"); |
| 5389 | return NULL; |
| 5390 | } |
| 5391 | |
| 5392 | JNI_TRACE("ASN1_OBJECT_to_OID_string(%p) => %s", obj, output); |
| 5393 | return env->NewStringUTF(output); |
| 5394 | } |
| 5395 | |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 5396 | static jlong NativeCrypto_create_BIO_InputStream(JNIEnv* env, jclass, |
| 5397 | jobject streamObj, |
| 5398 | jboolean isFinite) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5399 | JNI_TRACE("create_BIO_InputStream(%p)", streamObj); |
| 5400 | |
| 5401 | if (streamObj == NULL) { |
| 5402 | jniThrowNullPointerException(env, "stream == null"); |
| 5403 | return 0; |
| 5404 | } |
| 5405 | |
| 5406 | Unique_BIO bio(BIO_new(&stream_bio_method)); |
| 5407 | if (bio.get() == NULL) { |
| 5408 | return 0; |
| 5409 | } |
| 5410 | |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 5411 | bio_stream_assign(bio.get(), new BIO_InputStream(streamObj, isFinite)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5412 | |
| 5413 | JNI_TRACE("create_BIO_InputStream(%p) => %p", streamObj, bio.get()); |
| 5414 | return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release())); |
| 5415 | } |
| 5416 | |
| 5417 | static jlong NativeCrypto_create_BIO_OutputStream(JNIEnv* env, jclass, jobject streamObj) { |
| 5418 | JNI_TRACE("create_BIO_OutputStream(%p)", streamObj); |
| 5419 | |
| 5420 | if (streamObj == NULL) { |
| 5421 | jniThrowNullPointerException(env, "stream == null"); |
| 5422 | return 0; |
| 5423 | } |
| 5424 | |
| 5425 | Unique_BIO bio(BIO_new(&stream_bio_method)); |
| 5426 | if (bio.get() == NULL) { |
| 5427 | return 0; |
| 5428 | } |
| 5429 | |
| 5430 | bio_stream_assign(bio.get(), new BIO_OutputStream(streamObj)); |
| 5431 | |
| 5432 | JNI_TRACE("create_BIO_OutputStream(%p) => %p", streamObj, bio.get()); |
| 5433 | return static_cast<jlong>(reinterpret_cast<uintptr_t>(bio.release())); |
| 5434 | } |
| 5435 | |
| 5436 | static int NativeCrypto_BIO_read(JNIEnv* env, jclass, jlong bioRef, jbyteArray outputJavaBytes) { |
| 5437 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 5438 | JNI_TRACE("BIO_read(%p, %p)", bio, outputJavaBytes); |
| 5439 | |
| 5440 | if (outputJavaBytes == NULL) { |
| 5441 | jniThrowNullPointerException(env, "output == null"); |
| 5442 | JNI_TRACE("BIO_read(%p, %p) => output == null", bio, outputJavaBytes); |
| 5443 | return 0; |
| 5444 | } |
| 5445 | |
| 5446 | int outputSize = env->GetArrayLength(outputJavaBytes); |
| 5447 | |
| 5448 | UniquePtr<unsigned char[]> buffer(new unsigned char[outputSize]); |
| 5449 | if (buffer.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5450 | jniThrowOutOfMemory(env, "Unable to allocate buffer for read"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5451 | return 0; |
| 5452 | } |
| 5453 | |
| 5454 | int read = BIO_read(bio, buffer.get(), outputSize); |
| 5455 | if (read <= 0) { |
| 5456 | jniThrowException(env, "java/io/IOException", "BIO_read"); |
| 5457 | JNI_TRACE("BIO_read(%p, %p) => threw IO exception", bio, outputJavaBytes); |
| 5458 | return 0; |
| 5459 | } |
| 5460 | |
| 5461 | env->SetByteArrayRegion(outputJavaBytes, 0, read, reinterpret_cast<jbyte*>(buffer.get())); |
| 5462 | JNI_TRACE("BIO_read(%p, %p) => %d", bio, outputJavaBytes, read); |
| 5463 | return read; |
| 5464 | } |
| 5465 | |
| 5466 | static void NativeCrypto_BIO_write(JNIEnv* env, jclass, jlong bioRef, jbyteArray inputJavaBytes, |
| 5467 | jint offset, jint length) { |
| 5468 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 5469 | JNI_TRACE("BIO_write(%p, %p, %d, %d)", bio, inputJavaBytes, offset, length); |
| 5470 | |
| 5471 | if (inputJavaBytes == NULL) { |
| 5472 | jniThrowNullPointerException(env, "input == null"); |
| 5473 | return; |
| 5474 | } |
| 5475 | |
| 5476 | if (offset < 0 || length < 0) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 5477 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", "offset < 0 || length < 0"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5478 | JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length); |
| 5479 | return; |
| 5480 | } |
| 5481 | |
| 5482 | int inputSize = env->GetArrayLength(inputJavaBytes); |
| 5483 | if (inputSize < offset + length) { |
Kenny Root | ca85213 | 2014-02-24 14:13:32 -0800 | [diff] [blame] | 5484 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5485 | "input.length < offset + length"); |
| 5486 | JNI_TRACE("BIO_write(%p, %p, %d, %d) => IOOB", bio, inputJavaBytes, offset, length); |
| 5487 | return; |
| 5488 | } |
| 5489 | |
| 5490 | UniquePtr<unsigned char[]> buffer(new unsigned char[length]); |
| 5491 | if (buffer.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5492 | jniThrowOutOfMemory(env, "Unable to allocate buffer for write"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5493 | return; |
| 5494 | } |
| 5495 | |
| 5496 | env->GetByteArrayRegion(inputJavaBytes, offset, length, reinterpret_cast<jbyte*>(buffer.get())); |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 5497 | if (BIO_write(bio, buffer.get(), length) != length) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5498 | freeOpenSslErrorState(); |
| 5499 | jniThrowException(env, "java/io/IOException", "BIO_write"); |
| 5500 | JNI_TRACE("BIO_write(%p, %p, %d, %d) => IO error", bio, inputJavaBytes, offset, length); |
| 5501 | return; |
| 5502 | } |
| 5503 | |
| 5504 | JNI_TRACE("BIO_write(%p, %p, %d, %d) => success", bio, inputJavaBytes, offset, length); |
| 5505 | } |
| 5506 | |
Kenny Root | 19fdf1a | 2014-04-10 11:45:19 -0700 | [diff] [blame] | 5507 | static void NativeCrypto_BIO_free_all(JNIEnv* env, jclass, jlong bioRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5508 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
Kenny Root | 19fdf1a | 2014-04-10 11:45:19 -0700 | [diff] [blame] | 5509 | JNI_TRACE("BIO_free_all(%p)", bio); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5510 | |
| 5511 | if (bio == NULL) { |
| 5512 | jniThrowNullPointerException(env, "bio == null"); |
| 5513 | return; |
| 5514 | } |
| 5515 | |
Kenny Root | 19fdf1a | 2014-04-10 11:45:19 -0700 | [diff] [blame] | 5516 | BIO_free_all(bio); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5517 | } |
| 5518 | |
| 5519 | static jstring X509_NAME_to_jstring(JNIEnv* env, X509_NAME* name, unsigned long flags) { |
| 5520 | JNI_TRACE("X509_NAME_to_jstring(%p)", name); |
| 5521 | |
| 5522 | Unique_BIO buffer(BIO_new(BIO_s_mem())); |
| 5523 | if (buffer.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5524 | jniThrowOutOfMemory(env, "Unable to allocate BIO"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5525 | JNI_TRACE("X509_NAME_to_jstring(%p) => threw error", name); |
| 5526 | return NULL; |
| 5527 | } |
| 5528 | |
| 5529 | /* Don't interpret the string. */ |
| 5530 | flags &= ~(ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_MSB); |
| 5531 | |
| 5532 | /* Write in given format and null terminate. */ |
| 5533 | X509_NAME_print_ex(buffer.get(), name, 0, flags); |
| 5534 | BIO_write(buffer.get(), "\0", 1); |
| 5535 | |
| 5536 | char *tmp; |
| 5537 | BIO_get_mem_data(buffer.get(), &tmp); |
| 5538 | JNI_TRACE("X509_NAME_to_jstring(%p) => \"%s\"", name, tmp); |
| 5539 | return env->NewStringUTF(tmp); |
| 5540 | } |
| 5541 | |
| 5542 | |
| 5543 | /** |
| 5544 | * Converts GENERAL_NAME items to the output format expected in |
| 5545 | * X509Certificate#getSubjectAlternativeNames and |
| 5546 | * X509Certificate#getIssuerAlternativeNames return. |
| 5547 | */ |
| 5548 | static jobject GENERAL_NAME_to_jobject(JNIEnv* env, GENERAL_NAME* gen) { |
| 5549 | switch (gen->type) { |
| 5550 | case GEN_EMAIL: |
| 5551 | case GEN_DNS: |
| 5552 | case GEN_URI: { |
| 5553 | // This must not be a T61String and must not contain NULLs. |
| 5554 | const char* data = reinterpret_cast<const char*>(ASN1_STRING_data(gen->d.ia5)); |
| 5555 | ssize_t len = ASN1_STRING_length(gen->d.ia5); |
| 5556 | if ((len == static_cast<ssize_t>(strlen(data))) |
| 5557 | && (ASN1_PRINTABLE_type(ASN1_STRING_data(gen->d.ia5), len) != V_ASN1_T61STRING)) { |
| 5558 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI \"%s\"", gen, data); |
| 5559 | return env->NewStringUTF(data); |
| 5560 | } else { |
| 5561 | jniThrowException(env, "java/security/cert/CertificateParsingException", |
| 5562 | "Invalid dNSName encoding"); |
| 5563 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => Email/DNS/URI invalid", gen); |
| 5564 | return NULL; |
| 5565 | } |
| 5566 | } |
| 5567 | case GEN_DIRNAME: |
| 5568 | /* Write in RFC 2253 format */ |
| 5569 | return X509_NAME_to_jstring(env, gen->d.directoryName, XN_FLAG_RFC2253); |
| 5570 | case GEN_IPADD: { |
| 5571 | const void *ip = reinterpret_cast<const void *>(gen->d.ip->data); |
| 5572 | if (gen->d.ip->length == 4) { |
| 5573 | // IPv4 |
| 5574 | UniquePtr<char[]> buffer(new char[INET_ADDRSTRLEN]); |
| 5575 | if (inet_ntop(AF_INET, ip, buffer.get(), INET_ADDRSTRLEN) != NULL) { |
| 5576 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 %s", gen, buffer.get()); |
| 5577 | return env->NewStringUTF(buffer.get()); |
| 5578 | } else { |
| 5579 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv4 failed %s", gen, strerror(errno)); |
| 5580 | } |
| 5581 | } else if (gen->d.ip->length == 16) { |
| 5582 | // IPv6 |
| 5583 | UniquePtr<char[]> buffer(new char[INET6_ADDRSTRLEN]); |
| 5584 | if (inet_ntop(AF_INET6, ip, buffer.get(), INET6_ADDRSTRLEN) != NULL) { |
| 5585 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 %s", gen, buffer.get()); |
| 5586 | return env->NewStringUTF(buffer.get()); |
| 5587 | } else { |
| 5588 | JNI_TRACE("GENERAL_NAME_to_jobject(%p) => IPv6 failed %s", gen, strerror(errno)); |
| 5589 | } |
| 5590 | } |
| 5591 | |
| 5592 | /* Invalid IP encodings are pruned out without throwing an exception. */ |
| 5593 | return NULL; |
| 5594 | } |
| 5595 | case GEN_RID: |
| 5596 | return ASN1_OBJECT_to_OID_string(env, gen->d.registeredID); |
| 5597 | case GEN_OTHERNAME: |
| 5598 | case GEN_X400: |
| 5599 | default: |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 5600 | return ASN1ToByteArray<GENERAL_NAME>(env, gen, i2d_GENERAL_NAME); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5601 | } |
| 5602 | |
| 5603 | return NULL; |
| 5604 | } |
| 5605 | |
| 5606 | #define GN_STACK_SUBJECT_ALT_NAME 1 |
| 5607 | #define GN_STACK_ISSUER_ALT_NAME 2 |
| 5608 | |
| 5609 | static jobjectArray NativeCrypto_get_X509_GENERAL_NAME_stack(JNIEnv* env, jclass, jlong x509Ref, |
| 5610 | jint type) { |
| 5611 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5612 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d)", x509, type); |
| 5613 | |
| 5614 | if (x509 == NULL) { |
| 5615 | jniThrowNullPointerException(env, "x509 == null"); |
| 5616 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => x509 == null", x509, type); |
| 5617 | return NULL; |
| 5618 | } |
| 5619 | |
| 5620 | X509_check_ca(x509); |
| 5621 | |
| 5622 | STACK_OF(GENERAL_NAME)* gn_stack; |
| 5623 | Unique_sk_GENERAL_NAME stackHolder; |
| 5624 | if (type == GN_STACK_SUBJECT_ALT_NAME) { |
| 5625 | gn_stack = x509->altname; |
| 5626 | } else if (type == GN_STACK_ISSUER_ALT_NAME) { |
| 5627 | stackHolder.reset( |
| 5628 | static_cast<STACK_OF(GENERAL_NAME)*>(X509_get_ext_d2i(x509, NID_issuer_alt_name, |
| 5629 | NULL, NULL))); |
| 5630 | gn_stack = stackHolder.get(); |
| 5631 | } else { |
| 5632 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => unknown type", x509, type); |
| 5633 | return NULL; |
| 5634 | } |
| 5635 | |
| 5636 | int count = sk_GENERAL_NAME_num(gn_stack); |
| 5637 | if (count <= 0) { |
| 5638 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => null (no entries)", x509, type); |
| 5639 | return NULL; |
| 5640 | } |
| 5641 | |
| 5642 | /* |
| 5643 | * Keep track of how many originally so we can ignore any invalid |
| 5644 | * values later. |
| 5645 | */ |
| 5646 | const int origCount = count; |
| 5647 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5648 | ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, objectArrayClass, NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5649 | for (int i = 0, j = 0; i < origCount; i++, j++) { |
| 5650 | GENERAL_NAME* gen = sk_GENERAL_NAME_value(gn_stack, i); |
| 5651 | ScopedLocalRef<jobject> val(env, GENERAL_NAME_to_jobject(env, gen)); |
| 5652 | if (env->ExceptionCheck()) { |
| 5653 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => threw exception parsing gen name", |
| 5654 | x509, type); |
| 5655 | return NULL; |
| 5656 | } |
| 5657 | |
| 5658 | /* |
| 5659 | * If it's NULL, we'll have to skip this, reduce the number of total |
| 5660 | * entries, and fix up the array later. |
| 5661 | */ |
| 5662 | if (val.get() == NULL) { |
| 5663 | j--; |
| 5664 | count--; |
| 5665 | continue; |
| 5666 | } |
| 5667 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5668 | ScopedLocalRef<jobjectArray> item(env, env->NewObjectArray(2, objectClass, NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5669 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5670 | ScopedLocalRef<jobject> type(env, env->CallStaticObjectMethod(integerClass, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5671 | integer_valueOfMethod, gen->type)); |
| 5672 | env->SetObjectArrayElement(item.get(), 0, type.get()); |
| 5673 | env->SetObjectArrayElement(item.get(), 1, val.get()); |
| 5674 | |
| 5675 | env->SetObjectArrayElement(joa.get(), j, item.get()); |
| 5676 | } |
| 5677 | |
| 5678 | if (count == 0) { |
| 5679 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to 0; returning NULL", |
| 5680 | x509, type, origCount); |
| 5681 | joa.reset(NULL); |
| 5682 | } else if (origCount != count) { |
| 5683 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) shrunk from %d to %d", x509, type, |
| 5684 | origCount, count); |
| 5685 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 5686 | ScopedLocalRef<jobjectArray> joa_copy(env, env->NewObjectArray(count, objectArrayClass, |
| 5687 | NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5688 | |
| 5689 | for (int i = 0; i < count; i++) { |
| 5690 | ScopedLocalRef<jobject> item(env, env->GetObjectArrayElement(joa.get(), i)); |
| 5691 | env->SetObjectArrayElement(joa_copy.get(), i, item.get()); |
| 5692 | } |
| 5693 | |
| 5694 | joa.reset(joa_copy.release()); |
| 5695 | } |
| 5696 | |
| 5697 | JNI_TRACE("get_X509_GENERAL_NAME_stack(%p, %d) => %d entries", x509, type, count); |
| 5698 | return joa.release(); |
| 5699 | } |
| 5700 | |
| 5701 | static jlong NativeCrypto_X509_get_notBefore(JNIEnv* env, jclass, jlong x509Ref) { |
| 5702 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5703 | JNI_TRACE("X509_get_notBefore(%p)", x509); |
| 5704 | |
| 5705 | if (x509 == NULL) { |
| 5706 | jniThrowNullPointerException(env, "x509 == null"); |
| 5707 | JNI_TRACE("X509_get_notBefore(%p) => x509 == null", x509); |
| 5708 | return 0; |
| 5709 | } |
| 5710 | |
| 5711 | ASN1_TIME* notBefore = X509_get_notBefore(x509); |
| 5712 | JNI_TRACE("X509_get_notBefore(%p) => %p", x509, notBefore); |
| 5713 | return reinterpret_cast<uintptr_t>(notBefore); |
| 5714 | } |
| 5715 | |
| 5716 | static jlong NativeCrypto_X509_get_notAfter(JNIEnv* env, jclass, jlong x509Ref) { |
| 5717 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5718 | JNI_TRACE("X509_get_notAfter(%p)", x509); |
| 5719 | |
| 5720 | if (x509 == NULL) { |
| 5721 | jniThrowNullPointerException(env, "x509 == null"); |
| 5722 | JNI_TRACE("X509_get_notAfter(%p) => x509 == null", x509); |
| 5723 | return 0; |
| 5724 | } |
| 5725 | |
| 5726 | ASN1_TIME* notAfter = X509_get_notAfter(x509); |
| 5727 | JNI_TRACE("X509_get_notAfter(%p) => %p", x509, notAfter); |
| 5728 | return reinterpret_cast<uintptr_t>(notAfter); |
| 5729 | } |
| 5730 | |
| 5731 | static long NativeCrypto_X509_get_version(JNIEnv*, jclass, jlong x509Ref) { |
| 5732 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5733 | JNI_TRACE("X509_get_version(%p)", x509); |
| 5734 | |
| 5735 | long version = X509_get_version(x509); |
| 5736 | JNI_TRACE("X509_get_version(%p) => %ld", x509, version); |
| 5737 | return version; |
| 5738 | } |
| 5739 | |
| 5740 | template<typename T> |
| 5741 | static jbyteArray get_X509Type_serialNumber(JNIEnv* env, T* x509Type, ASN1_INTEGER* (*get_serial_func)(T*)) { |
| 5742 | JNI_TRACE("get_X509Type_serialNumber(%p)", x509Type); |
| 5743 | |
| 5744 | if (x509Type == NULL) { |
| 5745 | jniThrowNullPointerException(env, "x509Type == null"); |
| 5746 | JNI_TRACE("get_X509Type_serialNumber(%p) => x509Type == null", x509Type); |
| 5747 | return NULL; |
| 5748 | } |
| 5749 | |
| 5750 | ASN1_INTEGER* serialNumber = get_serial_func(x509Type); |
| 5751 | Unique_BIGNUM serialBn(ASN1_INTEGER_to_BN(serialNumber, NULL)); |
| 5752 | if (serialBn.get() == NULL) { |
| 5753 | JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type); |
| 5754 | return NULL; |
| 5755 | } |
| 5756 | |
| 5757 | ScopedLocalRef<jbyteArray> serialArray(env, bignumToArray(env, serialBn.get(), "serialBn")); |
| 5758 | if (env->ExceptionCheck()) { |
| 5759 | JNI_TRACE("X509_get_serialNumber(%p) => threw exception", x509Type); |
| 5760 | return NULL; |
| 5761 | } |
| 5762 | |
| 5763 | JNI_TRACE("X509_get_serialNumber(%p) => %p", x509Type, serialArray.get()); |
| 5764 | return serialArray.release(); |
| 5765 | } |
| 5766 | |
| 5767 | /* OpenSSL includes set_serialNumber but not get. */ |
| 5768 | #if !defined(X509_REVOKED_get_serialNumber) |
| 5769 | static ASN1_INTEGER* X509_REVOKED_get_serialNumber(X509_REVOKED* x) { |
| 5770 | return x->serialNumber; |
| 5771 | } |
| 5772 | #endif |
| 5773 | |
| 5774 | static jbyteArray NativeCrypto_X509_get_serialNumber(JNIEnv* env, jclass, jlong x509Ref) { |
| 5775 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5776 | JNI_TRACE("X509_get_serialNumber(%p)", x509); |
| 5777 | return get_X509Type_serialNumber<X509>(env, x509, X509_get_serialNumber); |
| 5778 | } |
| 5779 | |
| 5780 | static jbyteArray NativeCrypto_X509_REVOKED_get_serialNumber(JNIEnv* env, jclass, jlong x509RevokedRef) { |
| 5781 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 5782 | JNI_TRACE("X509_REVOKED_get_serialNumber(%p)", revoked); |
| 5783 | return get_X509Type_serialNumber<X509_REVOKED>(env, revoked, X509_REVOKED_get_serialNumber); |
| 5784 | } |
| 5785 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 5786 | static void NativeCrypto_X509_verify(JNIEnv* env, jclass, jlong x509Ref, jobject pkeyRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5787 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 5788 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5789 | JNI_TRACE("X509_verify(%p, %p)", x509, pkey); |
| 5790 | |
| 5791 | if (x509 == NULL) { |
| 5792 | jniThrowNullPointerException(env, "x509 == null"); |
| 5793 | JNI_TRACE("X509_verify(%p, %p) => x509 == null", x509, pkey); |
| 5794 | return; |
| 5795 | } |
| 5796 | |
| 5797 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5798 | JNI_TRACE("X509_verify(%p, %p) => pkey == null", x509, pkey); |
| 5799 | return; |
| 5800 | } |
| 5801 | |
| 5802 | if (X509_verify(x509, pkey) != 1) { |
| 5803 | throwExceptionIfNecessary(env, "X509_verify"); |
| 5804 | JNI_TRACE("X509_verify(%p, %p) => verify failure", x509, pkey); |
| 5805 | } else { |
| 5806 | JNI_TRACE("X509_verify(%p, %p) => verify success", x509, pkey); |
| 5807 | } |
| 5808 | } |
| 5809 | |
| 5810 | static jbyteArray NativeCrypto_get_X509_cert_info_enc(JNIEnv* env, jclass, jlong x509Ref) { |
| 5811 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5812 | JNI_TRACE("get_X509_cert_info_enc(%p)", x509); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 5813 | return ASN1ToByteArray<X509_CINF>(env, x509->cert_info, i2d_X509_CINF); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5814 | } |
| 5815 | |
| 5816 | static jint NativeCrypto_get_X509_ex_flags(JNIEnv* env, jclass, jlong x509Ref) { |
| 5817 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5818 | JNI_TRACE("get_X509_ex_flags(%p)", x509); |
| 5819 | |
| 5820 | if (x509 == NULL) { |
| 5821 | jniThrowNullPointerException(env, "x509 == null"); |
| 5822 | JNI_TRACE("get_X509_ex_flags(%p) => x509 == null", x509); |
| 5823 | return 0; |
| 5824 | } |
| 5825 | |
| 5826 | X509_check_ca(x509); |
| 5827 | |
| 5828 | return x509->ex_flags; |
| 5829 | } |
| 5830 | |
Elliott Hughes | ab3c653 | 2013-07-30 15:42:28 -0700 | [diff] [blame] | 5831 | static jboolean NativeCrypto_X509_check_issued(JNIEnv*, jclass, jlong x509Ref1, jlong x509Ref2) { |
Kenny Root | 35beb30 | 2013-05-06 11:49:28 -0700 | [diff] [blame] | 5832 | X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1)); |
| 5833 | X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2)); |
| 5834 | JNI_TRACE("X509_check_issued(%p, %p)", x509_1, x509_2); |
| 5835 | |
| 5836 | int ret = X509_check_issued(x509_1, x509_2); |
| 5837 | JNI_TRACE("X509_check_issued(%p, %p) => %d", x509_1, x509_2, ret); |
| 5838 | return ret; |
| 5839 | } |
| 5840 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5841 | static void get_X509_signature(X509 *x509, ASN1_BIT_STRING** signature) { |
| 5842 | *signature = x509->signature; |
| 5843 | } |
| 5844 | |
| 5845 | static void get_X509_CRL_signature(X509_CRL *crl, ASN1_BIT_STRING** signature) { |
| 5846 | *signature = crl->signature; |
| 5847 | } |
| 5848 | |
| 5849 | template<typename T> |
| 5850 | static jbyteArray get_X509Type_signature(JNIEnv* env, T* x509Type, void (*get_signature_func)(T*, ASN1_BIT_STRING**)) { |
| 5851 | JNI_TRACE("get_X509Type_signature(%p)", x509Type); |
| 5852 | |
| 5853 | if (x509Type == NULL) { |
| 5854 | jniThrowNullPointerException(env, "x509Type == null"); |
| 5855 | JNI_TRACE("get_X509Type_signature(%p) => x509Type == null", x509Type); |
| 5856 | return NULL; |
| 5857 | } |
| 5858 | |
| 5859 | ASN1_BIT_STRING* signature; |
| 5860 | get_signature_func(x509Type, &signature); |
| 5861 | |
| 5862 | ScopedLocalRef<jbyteArray> signatureArray(env, env->NewByteArray(signature->length)); |
| 5863 | if (env->ExceptionCheck()) { |
| 5864 | JNI_TRACE("get_X509Type_signature(%p) => threw exception", x509Type); |
| 5865 | return NULL; |
| 5866 | } |
| 5867 | |
| 5868 | ScopedByteArrayRW signatureBytes(env, signatureArray.get()); |
| 5869 | if (signatureBytes.get() == NULL) { |
| 5870 | JNI_TRACE("get_X509Type_signature(%p) => using byte array failed", x509Type); |
| 5871 | return NULL; |
| 5872 | } |
| 5873 | |
| 5874 | memcpy(signatureBytes.get(), signature->data, signature->length); |
| 5875 | |
| 5876 | JNI_TRACE("get_X509Type_signature(%p) => %p (%d bytes)", x509Type, signatureArray.get(), |
| 5877 | signature->length); |
| 5878 | return signatureArray.release(); |
| 5879 | } |
| 5880 | |
| 5881 | static jbyteArray NativeCrypto_get_X509_signature(JNIEnv* env, jclass, jlong x509Ref) { |
| 5882 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5883 | JNI_TRACE("get_X509_signature(%p)", x509); |
| 5884 | return get_X509Type_signature<X509>(env, x509, get_X509_signature); |
| 5885 | } |
| 5886 | |
| 5887 | static jbyteArray NativeCrypto_get_X509_CRL_signature(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 5888 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 5889 | JNI_TRACE("get_X509_CRL_signature(%p)", crl); |
| 5890 | return get_X509Type_signature<X509_CRL>(env, crl, get_X509_CRL_signature); |
| 5891 | } |
| 5892 | |
| 5893 | static jlong NativeCrypto_X509_CRL_get0_by_cert(JNIEnv* env, jclass, jlong x509crlRef, jlong x509Ref) { |
| 5894 | X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef)); |
| 5895 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 5896 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p)", x509crl, x509); |
| 5897 | |
| 5898 | if (x509crl == NULL) { |
| 5899 | jniThrowNullPointerException(env, "x509crl == null"); |
| 5900 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509crl == null", x509crl, x509); |
| 5901 | return 0; |
| 5902 | } else if (x509 == NULL) { |
| 5903 | jniThrowNullPointerException(env, "x509 == null"); |
| 5904 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => x509 == null", x509crl, x509); |
| 5905 | return 0; |
| 5906 | } |
| 5907 | |
| 5908 | X509_REVOKED* revoked = NULL; |
| 5909 | int ret = X509_CRL_get0_by_cert(x509crl, &revoked, x509); |
| 5910 | if (ret == 0) { |
| 5911 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => none", x509crl, x509); |
| 5912 | return 0; |
| 5913 | } |
| 5914 | |
| 5915 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, x509, revoked); |
| 5916 | return reinterpret_cast<uintptr_t>(revoked); |
| 5917 | } |
| 5918 | |
| 5919 | static jlong NativeCrypto_X509_CRL_get0_by_serial(JNIEnv* env, jclass, jlong x509crlRef, jbyteArray serialArray) { |
| 5920 | X509_CRL* x509crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509crlRef)); |
| 5921 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p)", x509crl, serialArray); |
| 5922 | |
| 5923 | if (x509crl == NULL) { |
| 5924 | jniThrowNullPointerException(env, "x509crl == null"); |
| 5925 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => crl == null", x509crl, serialArray); |
| 5926 | return 0; |
| 5927 | } |
| 5928 | |
| 5929 | Unique_BIGNUM serialBn(BN_new()); |
| 5930 | if (serialBn.get() == NULL) { |
| 5931 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN allocation failed", x509crl, serialArray); |
| 5932 | return 0; |
| 5933 | } |
| 5934 | |
| 5935 | BIGNUM* serialBare = serialBn.get(); |
| 5936 | if (!arrayToBignum(env, serialArray, &serialBare)) { |
| 5937 | if (!env->ExceptionCheck()) { |
| 5938 | jniThrowNullPointerException(env, "serial == null"); |
| 5939 | } |
| 5940 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray); |
| 5941 | return 0; |
| 5942 | } |
| 5943 | |
| 5944 | Unique_ASN1_INTEGER serialInteger(BN_to_ASN1_INTEGER(serialBn.get(), NULL)); |
| 5945 | if (serialInteger.get() == NULL) { |
| 5946 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => BN conversion failed", x509crl, serialArray); |
| 5947 | return 0; |
| 5948 | } |
| 5949 | |
| 5950 | X509_REVOKED* revoked = NULL; |
| 5951 | int ret = X509_CRL_get0_by_serial(x509crl, &revoked, serialInteger.get()); |
| 5952 | if (ret == 0) { |
| 5953 | JNI_TRACE("X509_CRL_get0_by_serial(%p, %p) => none", x509crl, serialArray); |
| 5954 | return 0; |
| 5955 | } |
| 5956 | |
| 5957 | JNI_TRACE("X509_CRL_get0_by_cert(%p, %p) => %p", x509crl, serialArray, revoked); |
| 5958 | return reinterpret_cast<uintptr_t>(revoked); |
| 5959 | } |
| 5960 | |
| 5961 | |
| 5962 | /* This appears to be missing from OpenSSL. */ |
Adam Langley | 0ccc17a | 2015-02-25 11:37:23 -0800 | [diff] [blame] | 5963 | #if !defined(X509_REVOKED_dup) && !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5964 | X509_REVOKED* X509_REVOKED_dup(X509_REVOKED* x) { |
| 5965 | return reinterpret_cast<X509_REVOKED*>(ASN1_item_dup(ASN1_ITEM_rptr(X509_REVOKED), x)); |
| 5966 | } |
| 5967 | #endif |
| 5968 | |
| 5969 | static jlongArray NativeCrypto_X509_CRL_get_REVOKED(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 5970 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 5971 | JNI_TRACE("X509_CRL_get_REVOKED(%p)", crl); |
| 5972 | |
| 5973 | if (crl == NULL) { |
| 5974 | jniThrowNullPointerException(env, "crl == null"); |
| 5975 | return NULL; |
| 5976 | } |
| 5977 | |
| 5978 | STACK_OF(X509_REVOKED)* stack = X509_CRL_get_REVOKED(crl); |
| 5979 | if (stack == NULL) { |
| 5980 | JNI_TRACE("X509_CRL_get_REVOKED(%p) => stack is null", crl); |
| 5981 | return NULL; |
| 5982 | } |
| 5983 | |
| 5984 | size_t size = sk_X509_REVOKED_num(stack); |
| 5985 | |
| 5986 | ScopedLocalRef<jlongArray> revokedArray(env, env->NewLongArray(size)); |
| 5987 | ScopedLongArrayRW revoked(env, revokedArray.get()); |
| 5988 | for (size_t i = 0; i < size; i++) { |
| 5989 | X509_REVOKED* item = reinterpret_cast<X509_REVOKED*>(sk_X509_REVOKED_value(stack, i)); |
| 5990 | revoked[i] = reinterpret_cast<uintptr_t>(X509_REVOKED_dup(item)); |
| 5991 | } |
| 5992 | |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 5993 | JNI_TRACE("X509_CRL_get_REVOKED(%p) => %p [size=%zd]", stack, revokedArray.get(), size); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 5994 | return revokedArray.release(); |
| 5995 | } |
| 5996 | |
| 5997 | static jbyteArray NativeCrypto_i2d_X509_CRL(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 5998 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 5999 | JNI_TRACE("i2d_X509_CRL(%p)", crl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6000 | return ASN1ToByteArray<X509_CRL>(env, crl, i2d_X509_CRL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6001 | } |
| 6002 | |
| 6003 | static void NativeCrypto_X509_CRL_free(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6004 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6005 | JNI_TRACE("X509_CRL_free(%p)", crl); |
| 6006 | |
| 6007 | if (crl == NULL) { |
| 6008 | jniThrowNullPointerException(env, "crl == null"); |
| 6009 | JNI_TRACE("X509_CRL_free(%p) => crl == null", crl); |
| 6010 | return; |
| 6011 | } |
| 6012 | |
| 6013 | X509_CRL_free(crl); |
| 6014 | } |
| 6015 | |
| 6016 | static void NativeCrypto_X509_CRL_print(JNIEnv* env, jclass, jlong bioRef, jlong x509CrlRef) { |
| 6017 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6018 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6019 | JNI_TRACE("X509_CRL_print(%p, %p)", bio, crl); |
| 6020 | |
| 6021 | if (bio == NULL) { |
| 6022 | jniThrowNullPointerException(env, "bio == null"); |
| 6023 | JNI_TRACE("X509_CRL_print(%p, %p) => bio == null", bio, crl); |
| 6024 | return; |
| 6025 | } |
| 6026 | |
| 6027 | if (crl == NULL) { |
| 6028 | jniThrowNullPointerException(env, "crl == null"); |
| 6029 | JNI_TRACE("X509_CRL_print(%p, %p) => crl == null", bio, crl); |
| 6030 | return; |
| 6031 | } |
| 6032 | |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 6033 | if (!X509_CRL_print(bio, crl)) { |
| 6034 | throwExceptionIfNecessary(env, "X509_CRL_print"); |
| 6035 | JNI_TRACE("X509_CRL_print(%p, %p) => threw error", bio, crl); |
| 6036 | } else { |
| 6037 | JNI_TRACE("X509_CRL_print(%p, %p) => success", bio, crl); |
| 6038 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6039 | } |
| 6040 | |
| 6041 | static jstring NativeCrypto_get_X509_CRL_sig_alg_oid(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6042 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6043 | JNI_TRACE("get_X509_CRL_sig_alg_oid(%p)", crl); |
| 6044 | |
| 6045 | if (crl == NULL || crl->sig_alg == NULL) { |
| 6046 | jniThrowNullPointerException(env, "crl == NULL || crl->sig_alg == NULL"); |
| 6047 | JNI_TRACE("get_X509_CRL_sig_alg_oid(%p) => crl == NULL", crl); |
| 6048 | return NULL; |
| 6049 | } |
| 6050 | |
| 6051 | return ASN1_OBJECT_to_OID_string(env, crl->sig_alg->algorithm); |
| 6052 | } |
| 6053 | |
| 6054 | static jbyteArray NativeCrypto_get_X509_CRL_sig_alg_parameter(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6055 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6056 | JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p)", crl); |
| 6057 | |
| 6058 | if (crl == NULL) { |
| 6059 | jniThrowNullPointerException(env, "crl == null"); |
| 6060 | JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => crl == null", crl); |
| 6061 | return NULL; |
| 6062 | } |
| 6063 | |
| 6064 | if (crl->sig_alg->parameter == NULL) { |
| 6065 | JNI_TRACE("get_X509_CRL_sig_alg_parameter(%p) => null", crl); |
| 6066 | return NULL; |
| 6067 | } |
| 6068 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6069 | return ASN1ToByteArray<ASN1_TYPE>(env, crl->sig_alg->parameter, i2d_ASN1_TYPE); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6070 | } |
| 6071 | |
| 6072 | static jbyteArray NativeCrypto_X509_CRL_get_issuer_name(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6073 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6074 | JNI_TRACE("X509_CRL_get_issuer_name(%p)", crl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6075 | return ASN1ToByteArray<X509_NAME>(env, X509_CRL_get_issuer(crl), i2d_X509_NAME); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6076 | } |
| 6077 | |
| 6078 | static long NativeCrypto_X509_CRL_get_version(JNIEnv*, jclass, jlong x509CrlRef) { |
| 6079 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6080 | JNI_TRACE("X509_CRL_get_version(%p)", crl); |
| 6081 | |
| 6082 | long version = X509_CRL_get_version(crl); |
| 6083 | JNI_TRACE("X509_CRL_get_version(%p) => %ld", crl, version); |
| 6084 | return version; |
| 6085 | } |
| 6086 | |
| 6087 | template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int), |
| 6088 | X509_EXTENSION* (*get_ext_func)(T*, int)> |
| 6089 | static X509_EXTENSION *X509Type_get_ext(JNIEnv* env, T* x509Type, jstring oidString) { |
| 6090 | JNI_TRACE("X509Type_get_ext(%p)", x509Type); |
| 6091 | |
| 6092 | if (x509Type == NULL) { |
| 6093 | jniThrowNullPointerException(env, "x509 == null"); |
| 6094 | return NULL; |
| 6095 | } |
| 6096 | |
| 6097 | ScopedUtfChars oid(env, oidString); |
| 6098 | if (oid.c_str() == NULL) { |
| 6099 | return NULL; |
| 6100 | } |
| 6101 | |
| 6102 | Unique_ASN1_OBJECT asn1(OBJ_txt2obj(oid.c_str(), 1)); |
| 6103 | if (asn1.get() == NULL) { |
| 6104 | JNI_TRACE("X509Type_get_ext(%p, %s) => oid conversion failed", x509Type, oid.c_str()); |
| 6105 | freeOpenSslErrorState(); |
| 6106 | return NULL; |
| 6107 | } |
| 6108 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6109 | int extIndex = get_ext_by_OBJ_func(x509Type, (ASN1_OBJECT*) asn1.get(), -1); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6110 | if (extIndex == -1) { |
| 6111 | JNI_TRACE("X509Type_get_ext(%p, %s) => ext not found", x509Type, oid.c_str()); |
| 6112 | return NULL; |
| 6113 | } |
| 6114 | |
| 6115 | X509_EXTENSION* ext = get_ext_func(x509Type, extIndex); |
| 6116 | JNI_TRACE("X509Type_get_ext(%p, %s) => %p", x509Type, oid.c_str(), ext); |
| 6117 | return ext; |
| 6118 | } |
| 6119 | |
| 6120 | template<typename T, int (*get_ext_by_OBJ_func)(T*, ASN1_OBJECT*, int), |
| 6121 | X509_EXTENSION* (*get_ext_func)(T*, int)> |
| 6122 | static jbyteArray X509Type_get_ext_oid(JNIEnv* env, T* x509Type, jstring oidString) { |
| 6123 | X509_EXTENSION* ext = X509Type_get_ext<T, get_ext_by_OBJ_func, get_ext_func>(env, x509Type, |
| 6124 | oidString); |
| 6125 | if (ext == NULL) { |
| 6126 | JNI_TRACE("X509Type_get_ext_oid(%p, %p) => fetching extension failed", x509Type, oidString); |
| 6127 | return NULL; |
| 6128 | } |
| 6129 | |
| 6130 | JNI_TRACE("X509Type_get_ext_oid(%p, %p) => %p", x509Type, oidString, ext->value); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6131 | return ASN1ToByteArray<ASN1_OCTET_STRING>(env, ext->value, i2d_ASN1_OCTET_STRING); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6132 | } |
| 6133 | |
Bowen Zhao | a770db2 | 2015-01-28 17:01:40 +0800 | [diff] [blame] | 6134 | static jlong NativeCrypto_X509_CRL_get_ext(JNIEnv* env, jclass, jlong x509CrlRef, jstring oid) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6135 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6136 | JNI_TRACE("X509_CRL_get_ext(%p, %p)", crl, oid); |
| 6137 | X509_EXTENSION* ext = X509Type_get_ext<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>( |
| 6138 | env, crl, oid); |
| 6139 | JNI_TRACE("X509_CRL_get_ext(%p, %p) => %p", crl, oid, ext); |
| 6140 | return reinterpret_cast<uintptr_t>(ext); |
| 6141 | } |
| 6142 | |
Bowen Zhao | a770db2 | 2015-01-28 17:01:40 +0800 | [diff] [blame] | 6143 | static jlong NativeCrypto_X509_REVOKED_get_ext(JNIEnv* env, jclass, jlong x509RevokedRef, |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6144 | jstring oid) { |
| 6145 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 6146 | JNI_TRACE("X509_REVOKED_get_ext(%p, %p)", revoked, oid); |
| 6147 | X509_EXTENSION* ext = X509Type_get_ext<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, |
| 6148 | X509_REVOKED_get_ext>(env, revoked, oid); |
| 6149 | JNI_TRACE("X509_REVOKED_get_ext(%p, %p) => %p", revoked, oid, ext); |
| 6150 | return reinterpret_cast<uintptr_t>(ext); |
| 6151 | } |
| 6152 | |
| 6153 | static jlong NativeCrypto_X509_REVOKED_dup(JNIEnv* env, jclass, jlong x509RevokedRef) { |
| 6154 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 6155 | JNI_TRACE("X509_REVOKED_dup(%p)", revoked); |
| 6156 | |
| 6157 | if (revoked == NULL) { |
| 6158 | jniThrowNullPointerException(env, "revoked == null"); |
| 6159 | JNI_TRACE("X509_REVOKED_dup(%p) => revoked == null", revoked); |
| 6160 | return 0; |
| 6161 | } |
| 6162 | |
| 6163 | X509_REVOKED* dup = X509_REVOKED_dup(revoked); |
| 6164 | JNI_TRACE("X509_REVOKED_dup(%p) => %p", revoked, dup); |
| 6165 | return reinterpret_cast<uintptr_t>(dup); |
| 6166 | } |
| 6167 | |
| 6168 | static jlong NativeCrypto_get_X509_REVOKED_revocationDate(JNIEnv* env, jclass, jlong x509RevokedRef) { |
| 6169 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 6170 | JNI_TRACE("get_X509_REVOKED_revocationDate(%p)", revoked); |
| 6171 | |
| 6172 | if (revoked == NULL) { |
| 6173 | jniThrowNullPointerException(env, "revoked == null"); |
| 6174 | JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => revoked == null", revoked); |
| 6175 | return 0; |
| 6176 | } |
| 6177 | |
| 6178 | JNI_TRACE("get_X509_REVOKED_revocationDate(%p) => %p", revoked, revoked->revocationDate); |
| 6179 | return reinterpret_cast<uintptr_t>(revoked->revocationDate); |
| 6180 | } |
| 6181 | |
Anwar Ghuloum | e75878c | 2013-05-24 09:11:52 -0700 | [diff] [blame] | 6182 | #pragma GCC diagnostic push |
| 6183 | #pragma GCC diagnostic ignored "-Wwrite-strings" |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6184 | static void NativeCrypto_X509_REVOKED_print(JNIEnv* env, jclass, jlong bioRef, jlong x509RevokedRef) { |
| 6185 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6186 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 6187 | JNI_TRACE("X509_REVOKED_print(%p, %p)", bio, revoked); |
| 6188 | |
| 6189 | if (bio == NULL) { |
| 6190 | jniThrowNullPointerException(env, "bio == null"); |
| 6191 | JNI_TRACE("X509_REVOKED_print(%p, %p) => bio == null", bio, revoked); |
| 6192 | return; |
| 6193 | } |
| 6194 | |
| 6195 | if (revoked == NULL) { |
| 6196 | jniThrowNullPointerException(env, "revoked == null"); |
| 6197 | JNI_TRACE("X509_REVOKED_print(%p, %p) => revoked == null", bio, revoked); |
| 6198 | return; |
| 6199 | } |
| 6200 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6201 | BIO_printf(bio, "Serial Number: "); |
| 6202 | i2a_ASN1_INTEGER(bio, revoked->serialNumber); |
| 6203 | BIO_printf(bio, "\nRevocation Date: "); |
| 6204 | ASN1_TIME_print(bio, revoked->revocationDate); |
| 6205 | BIO_printf(bio, "\n"); |
| 6206 | X509V3_extensions_print(bio, "CRL entry extensions", revoked->extensions, 0, 0); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6207 | } |
Anwar Ghuloum | e75878c | 2013-05-24 09:11:52 -0700 | [diff] [blame] | 6208 | #pragma GCC diagnostic pop |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6209 | |
| 6210 | static jbyteArray NativeCrypto_get_X509_CRL_crl_enc(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6211 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6212 | JNI_TRACE("get_X509_CRL_crl_enc(%p)", crl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6213 | return ASN1ToByteArray<X509_CRL_INFO>(env, crl->crl, i2d_X509_CRL_INFO); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6214 | } |
| 6215 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 6216 | static void NativeCrypto_X509_CRL_verify(JNIEnv* env, jclass, jlong x509CrlRef, jobject pkeyRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6217 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 6218 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6219 | JNI_TRACE("X509_CRL_verify(%p, %p)", crl, pkey); |
| 6220 | |
| 6221 | if (crl == NULL) { |
| 6222 | jniThrowNullPointerException(env, "crl == null"); |
| 6223 | JNI_TRACE("X509_CRL_verify(%p, %p) => crl == null", crl, pkey); |
| 6224 | return; |
| 6225 | } |
| 6226 | |
| 6227 | if (pkey == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6228 | JNI_TRACE("X509_CRL_verify(%p, %p) => pkey == null", crl, pkey); |
| 6229 | return; |
| 6230 | } |
| 6231 | |
| 6232 | if (X509_CRL_verify(crl, pkey) != 1) { |
| 6233 | throwExceptionIfNecessary(env, "X509_CRL_verify"); |
| 6234 | JNI_TRACE("X509_CRL_verify(%p, %p) => verify failure", crl, pkey); |
| 6235 | } else { |
| 6236 | JNI_TRACE("X509_CRL_verify(%p, %p) => verify success", crl, pkey); |
| 6237 | } |
| 6238 | } |
| 6239 | |
| 6240 | static jlong NativeCrypto_X509_CRL_get_lastUpdate(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6241 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6242 | JNI_TRACE("X509_CRL_get_lastUpdate(%p)", crl); |
| 6243 | |
| 6244 | if (crl == NULL) { |
| 6245 | jniThrowNullPointerException(env, "crl == null"); |
| 6246 | JNI_TRACE("X509_CRL_get_lastUpdate(%p) => crl == null", crl); |
| 6247 | return 0; |
| 6248 | } |
| 6249 | |
| 6250 | ASN1_TIME* lastUpdate = X509_CRL_get_lastUpdate(crl); |
| 6251 | JNI_TRACE("X509_CRL_get_lastUpdate(%p) => %p", crl, lastUpdate); |
| 6252 | return reinterpret_cast<uintptr_t>(lastUpdate); |
| 6253 | } |
| 6254 | |
| 6255 | static jlong NativeCrypto_X509_CRL_get_nextUpdate(JNIEnv* env, jclass, jlong x509CrlRef) { |
| 6256 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 6257 | JNI_TRACE("X509_CRL_get_nextUpdate(%p)", crl); |
| 6258 | |
| 6259 | if (crl == NULL) { |
| 6260 | jniThrowNullPointerException(env, "crl == null"); |
| 6261 | JNI_TRACE("X509_CRL_get_nextUpdate(%p) => crl == null", crl); |
| 6262 | return 0; |
| 6263 | } |
| 6264 | |
| 6265 | ASN1_TIME* nextUpdate = X509_CRL_get_nextUpdate(crl); |
| 6266 | JNI_TRACE("X509_CRL_get_nextUpdate(%p) => %p", crl, nextUpdate); |
| 6267 | return reinterpret_cast<uintptr_t>(nextUpdate); |
| 6268 | } |
| 6269 | |
| 6270 | static jbyteArray NativeCrypto_i2d_X509_REVOKED(JNIEnv* env, jclass, jlong x509RevokedRef) { |
| 6271 | X509_REVOKED* x509Revoked = |
| 6272 | reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 6273 | JNI_TRACE("i2d_X509_REVOKED(%p)", x509Revoked); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6274 | return ASN1ToByteArray<X509_REVOKED>(env, x509Revoked, i2d_X509_REVOKED); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6275 | } |
| 6276 | |
| 6277 | static jint NativeCrypto_X509_supported_extension(JNIEnv* env, jclass, jlong x509ExtensionRef) { |
| 6278 | X509_EXTENSION* ext = reinterpret_cast<X509_EXTENSION*>(static_cast<uintptr_t>(x509ExtensionRef)); |
| 6279 | |
| 6280 | if (ext == NULL) { |
| 6281 | jniThrowNullPointerException(env, "ext == NULL"); |
| 6282 | return 0; |
| 6283 | } |
| 6284 | |
| 6285 | return X509_supported_extension(ext); |
| 6286 | } |
| 6287 | |
| 6288 | static inline void get_ASN1_TIME_data(char **data, int* output, size_t len) { |
| 6289 | char c = **data; |
| 6290 | **data = '\0'; |
| 6291 | *data -= len; |
| 6292 | *output = atoi(*data); |
| 6293 | *(*data + len) = c; |
| 6294 | } |
| 6295 | |
| 6296 | static void NativeCrypto_ASN1_TIME_to_Calendar(JNIEnv* env, jclass, jlong asn1TimeRef, jobject calendar) { |
| 6297 | ASN1_TIME* asn1Time = reinterpret_cast<ASN1_TIME*>(static_cast<uintptr_t>(asn1TimeRef)); |
| 6298 | JNI_TRACE("ASN1_TIME_to_Calendar(%p, %p)", asn1Time, calendar); |
| 6299 | |
| 6300 | if (asn1Time == NULL) { |
| 6301 | jniThrowNullPointerException(env, "asn1Time == null"); |
| 6302 | return; |
| 6303 | } |
| 6304 | |
| 6305 | Unique_ASN1_GENERALIZEDTIME gen(ASN1_TIME_to_generalizedtime(asn1Time, NULL)); |
| 6306 | if (gen.get() == NULL) { |
| 6307 | jniThrowNullPointerException(env, "asn1Time == null"); |
| 6308 | return; |
| 6309 | } |
| 6310 | |
| 6311 | if (gen->length < 14 || gen->data == NULL) { |
| 6312 | jniThrowNullPointerException(env, "gen->length < 14 || gen->data == NULL"); |
| 6313 | return; |
| 6314 | } |
| 6315 | |
| 6316 | int sec, min, hour, mday, mon, year; |
| 6317 | |
| 6318 | char *p = (char*) &gen->data[14]; |
| 6319 | |
| 6320 | get_ASN1_TIME_data(&p, &sec, 2); |
| 6321 | get_ASN1_TIME_data(&p, &min, 2); |
| 6322 | get_ASN1_TIME_data(&p, &hour, 2); |
| 6323 | get_ASN1_TIME_data(&p, &mday, 2); |
| 6324 | get_ASN1_TIME_data(&p, &mon, 2); |
| 6325 | get_ASN1_TIME_data(&p, &year, 4); |
| 6326 | |
| 6327 | env->CallVoidMethod(calendar, calendar_setMethod, year, mon - 1, mday, hour, min, sec); |
| 6328 | } |
| 6329 | |
| 6330 | static jstring NativeCrypto_OBJ_txt2nid_oid(JNIEnv* env, jclass, jstring oidStr) { |
| 6331 | JNI_TRACE("OBJ_txt2nid_oid(%p)", oidStr); |
| 6332 | |
| 6333 | ScopedUtfChars oid(env, oidStr); |
| 6334 | if (oid.c_str() == NULL) { |
| 6335 | return NULL; |
| 6336 | } |
| 6337 | |
| 6338 | JNI_TRACE("OBJ_txt2nid_oid(%s)", oid.c_str()); |
| 6339 | |
| 6340 | int nid = OBJ_txt2nid(oid.c_str()); |
| 6341 | if (nid == NID_undef) { |
| 6342 | JNI_TRACE("OBJ_txt2nid_oid(%s) => NID_undef", oid.c_str()); |
| 6343 | freeOpenSslErrorState(); |
| 6344 | return NULL; |
| 6345 | } |
| 6346 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6347 | const ASN1_OBJECT* obj = OBJ_nid2obj(nid); |
| 6348 | if (obj == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6349 | throwExceptionIfNecessary(env, "OBJ_nid2obj"); |
| 6350 | return NULL; |
| 6351 | } |
| 6352 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6353 | ScopedLocalRef<jstring> ouputStr(env, ASN1_OBJECT_to_OID_string(env, obj)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6354 | JNI_TRACE("OBJ_txt2nid_oid(%s) => %p", oid.c_str(), ouputStr.get()); |
| 6355 | return ouputStr.release(); |
| 6356 | } |
| 6357 | |
| 6358 | static jstring NativeCrypto_X509_NAME_print_ex(JNIEnv* env, jclass, jlong x509NameRef, jlong jflags) { |
| 6359 | X509_NAME* x509name = reinterpret_cast<X509_NAME*>(static_cast<uintptr_t>(x509NameRef)); |
| 6360 | unsigned long flags = static_cast<unsigned long>(jflags); |
| 6361 | JNI_TRACE("X509_NAME_print_ex(%p, %ld)", x509name, flags); |
| 6362 | |
| 6363 | if (x509name == NULL) { |
| 6364 | jniThrowNullPointerException(env, "x509name == null"); |
| 6365 | JNI_TRACE("X509_NAME_print_ex(%p, %ld) => x509name == null", x509name, flags); |
| 6366 | return NULL; |
| 6367 | } |
| 6368 | |
| 6369 | return X509_NAME_to_jstring(env, x509name, flags); |
| 6370 | } |
| 6371 | |
| 6372 | template <typename T, T* (*d2i_func)(BIO*, T**)> |
| 6373 | static jlong d2i_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) { |
| 6374 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6375 | JNI_TRACE("d2i_ASN1Object_to_jlong(%p)", bio); |
| 6376 | |
| 6377 | if (bio == NULL) { |
| 6378 | jniThrowNullPointerException(env, "bio == null"); |
| 6379 | return 0; |
| 6380 | } |
| 6381 | |
| 6382 | T* x = d2i_func(bio, NULL); |
| 6383 | if (x == NULL) { |
| 6384 | throwExceptionIfNecessary(env, "d2i_ASN1Object_to_jlong"); |
| 6385 | return 0; |
| 6386 | } |
| 6387 | |
| 6388 | return reinterpret_cast<uintptr_t>(x); |
| 6389 | } |
| 6390 | |
| 6391 | static jlong NativeCrypto_d2i_X509_CRL_bio(JNIEnv* env, jclass, jlong bioRef) { |
| 6392 | return d2i_ASN1Object_to_jlong<X509_CRL, d2i_X509_CRL_bio>(env, bioRef); |
| 6393 | } |
| 6394 | |
| 6395 | static jlong NativeCrypto_d2i_X509_bio(JNIEnv* env, jclass, jlong bioRef) { |
| 6396 | return d2i_ASN1Object_to_jlong<X509, d2i_X509_bio>(env, bioRef); |
| 6397 | } |
| 6398 | |
| 6399 | static jlong NativeCrypto_d2i_X509(JNIEnv* env, jclass, jbyteArray certBytes) { |
| 6400 | X509* x = ByteArrayToASN1<X509, d2i_X509>(env, certBytes); |
| 6401 | return reinterpret_cast<uintptr_t>(x); |
| 6402 | } |
| 6403 | |
| 6404 | static jbyteArray NativeCrypto_i2d_X509(JNIEnv* env, jclass, jlong x509Ref) { |
| 6405 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6406 | JNI_TRACE("i2d_X509(%p)", x509); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6407 | return ASN1ToByteArray<X509>(env, x509, i2d_X509); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6408 | } |
| 6409 | |
| 6410 | static jbyteArray NativeCrypto_i2d_X509_PUBKEY(JNIEnv* env, jclass, jlong x509Ref) { |
| 6411 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6412 | JNI_TRACE("i2d_X509_PUBKEY(%p)", x509); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6413 | return ASN1ToByteArray<X509_PUBKEY>(env, X509_get_X509_PUBKEY(x509), i2d_X509_PUBKEY); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6414 | } |
| 6415 | |
| 6416 | |
| 6417 | template<typename T, T* (*PEM_read_func)(BIO*, T**, pem_password_cb*, void*)> |
| 6418 | static jlong PEM_ASN1Object_to_jlong(JNIEnv* env, jlong bioRef) { |
| 6419 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6420 | JNI_TRACE("PEM_ASN1Object_to_jlong(%p)", bio); |
| 6421 | |
| 6422 | if (bio == NULL) { |
| 6423 | jniThrowNullPointerException(env, "bio == null"); |
| 6424 | JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => bio == null", bio); |
| 6425 | return 0; |
| 6426 | } |
| 6427 | |
| 6428 | T* x = PEM_read_func(bio, NULL, NULL, NULL); |
| 6429 | if (x == NULL) { |
| 6430 | throwExceptionIfNecessary(env, "PEM_ASN1Object_to_jlong"); |
| 6431 | // Sometimes the PEM functions fail without pushing an error |
| 6432 | if (!env->ExceptionCheck()) { |
| 6433 | jniThrowRuntimeException(env, "Failure parsing PEM"); |
| 6434 | } |
| 6435 | JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => threw exception", bio); |
| 6436 | return 0; |
| 6437 | } |
| 6438 | |
| 6439 | JNI_TRACE("PEM_ASN1Object_to_jlong(%p) => %p", bio, x); |
| 6440 | return reinterpret_cast<uintptr_t>(x); |
| 6441 | } |
| 6442 | |
| 6443 | static jlong NativeCrypto_PEM_read_bio_X509(JNIEnv* env, jclass, jlong bioRef) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 6444 | JNI_TRACE("PEM_read_bio_X509(0x%llx)", (long long) bioRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6445 | return PEM_ASN1Object_to_jlong<X509, PEM_read_bio_X509>(env, bioRef); |
| 6446 | } |
| 6447 | |
| 6448 | static jlong NativeCrypto_PEM_read_bio_X509_CRL(JNIEnv* env, jclass, jlong bioRef) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 6449 | JNI_TRACE("PEM_read_bio_X509_CRL(0x%llx)", (long long) bioRef); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6450 | return PEM_ASN1Object_to_jlong<X509_CRL, PEM_read_bio_X509_CRL>(env, bioRef); |
| 6451 | } |
| 6452 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6453 | template <typename T, typename T_stack> |
| 6454 | static jlongArray PKCS7_to_ItemArray(JNIEnv* env, T_stack* stack, T* (*dup_func)(T*)) |
| 6455 | { |
| 6456 | if (stack == NULL) { |
| 6457 | return NULL; |
| 6458 | } |
| 6459 | |
| 6460 | ScopedLocalRef<jlongArray> ref_array(env, NULL); |
| 6461 | size_t size = sk_num(reinterpret_cast<_STACK*>(stack)); |
| 6462 | ref_array.reset(env->NewLongArray(size)); |
| 6463 | ScopedLongArrayRW items(env, ref_array.get()); |
| 6464 | for (size_t i = 0; i < size; i++) { |
| 6465 | T* item = reinterpret_cast<T*>(sk_value(reinterpret_cast<_STACK*>(stack), i)); |
| 6466 | items[i] = reinterpret_cast<uintptr_t>(dup_func(item)); |
| 6467 | } |
| 6468 | |
Kenny Root | 8a77c20 | 2015-04-24 10:37:11 -0700 | [diff] [blame] | 6469 | JNI_TRACE("PKCS7_to_ItemArray(%p) => %p [size=%zd]", stack, ref_array.get(), size); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6470 | return ref_array.release(); |
| 6471 | } |
| 6472 | |
| 6473 | #define PKCS7_CERTS 1 |
| 6474 | #define PKCS7_CRLS 2 |
| 6475 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6476 | static jbyteArray NativeCrypto_i2d_PKCS7(JNIEnv* env, jclass, jlongArray certsArray) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6477 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6478 | JNI_TRACE("i2d_PKCS7(%p)", certsArray); |
| 6479 | |
| 6480 | Unique_PKCS7 pkcs7(PKCS7_new()); |
| 6481 | if (pkcs7.get() == NULL) { |
| 6482 | jniThrowNullPointerException(env, "pkcs7 == null"); |
| 6483 | JNI_TRACE("i2d_PKCS7(%p) => pkcs7 == null", certsArray); |
| 6484 | return NULL; |
| 6485 | } |
| 6486 | |
| 6487 | if (PKCS7_set_type(pkcs7.get(), NID_pkcs7_signed) != 1) { |
| 6488 | throwExceptionIfNecessary(env, "PKCS7_set_type"); |
| 6489 | return NULL; |
| 6490 | } |
| 6491 | |
Kenny Root | 525df9b | 2014-12-09 13:46:03 -0800 | [diff] [blame] | 6492 | // The EncapsulatedContentInfo must be present in the output, but OpenSSL |
| 6493 | // will fill in a zero-length OID if you don't call PKCS7_set_content on the |
| 6494 | // outer PKCS7 container. So we construct an empty PKCS7 data container and |
| 6495 | // set it as the content. |
| 6496 | Unique_PKCS7 pkcs7Data(PKCS7_new()); |
| 6497 | if (PKCS7_set_type(pkcs7Data.get(), NID_pkcs7_data) != 1) { |
| 6498 | throwExceptionIfNecessary(env, "PKCS7_set_type data"); |
| 6499 | return NULL; |
| 6500 | } |
| 6501 | |
| 6502 | if (PKCS7_set_content(pkcs7.get(), pkcs7Data.get()) != 1) { |
| 6503 | throwExceptionIfNecessary(env, "PKCS7_set_content"); |
| 6504 | return NULL; |
| 6505 | } |
| 6506 | OWNERSHIP_TRANSFERRED(pkcs7Data); |
| 6507 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6508 | ScopedLongArrayRO certs(env, certsArray); |
| 6509 | for (size_t i = 0; i < certs.size(); i++) { |
| 6510 | X509* item = reinterpret_cast<X509*>(certs[i]); |
| 6511 | if (PKCS7_add_certificate(pkcs7.get(), item) != 1) { |
| 6512 | throwExceptionIfNecessary(env, "i2d_PKCS7"); |
| 6513 | return NULL; |
| 6514 | } |
| 6515 | } |
| 6516 | |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 6517 | JNI_TRACE("i2d_PKCS7(%p) => %zd certs", certsArray, certs.size()); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6518 | return ASN1ToByteArray<PKCS7>(env, pkcs7.get(), i2d_PKCS7); |
| 6519 | #else // OPENSSL_IS_BORINGSSL |
| 6520 | STACK_OF(X509) *stack = sk_X509_new_null(); |
| 6521 | |
| 6522 | ScopedLongArrayRO certs(env, certsArray); |
| 6523 | for (size_t i = 0; i < certs.size(); i++) { |
| 6524 | X509* item = reinterpret_cast<X509*>(certs[i]); |
| 6525 | if (sk_X509_push(stack, item) == 0) { |
| 6526 | sk_X509_free(stack); |
| 6527 | throwExceptionIfNecessary(env, "sk_X509_push"); |
| 6528 | return NULL; |
| 6529 | } |
| 6530 | } |
| 6531 | |
| 6532 | CBB out; |
| 6533 | CBB_init(&out, 1024 * certs.size()); |
| 6534 | if (!PKCS7_bundle_certificates(&out, stack)) { |
| 6535 | CBB_cleanup(&out); |
| 6536 | sk_X509_free(stack); |
| 6537 | throwExceptionIfNecessary(env, "PKCS7_bundle_certificates"); |
| 6538 | return NULL; |
| 6539 | } |
| 6540 | |
| 6541 | sk_X509_free(stack); |
| 6542 | |
| 6543 | uint8_t *derBytes; |
| 6544 | size_t derLen; |
| 6545 | if (!CBB_finish(&out, &derBytes, &derLen)) { |
| 6546 | CBB_cleanup(&out); |
| 6547 | throwExceptionIfNecessary(env, "CBB_finish"); |
| 6548 | return NULL; |
| 6549 | } |
| 6550 | |
| 6551 | ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(derLen)); |
| 6552 | if (byteArray.get() == NULL) { |
| 6553 | JNI_TRACE("creating byte array failed"); |
| 6554 | return NULL; |
| 6555 | } |
| 6556 | |
| 6557 | ScopedByteArrayRW bytes(env, byteArray.get()); |
| 6558 | if (bytes.get() == NULL) { |
| 6559 | JNI_TRACE("using byte array failed"); |
| 6560 | return NULL; |
| 6561 | } |
| 6562 | |
| 6563 | uint8_t* p = reinterpret_cast<unsigned char*>(bytes.get()); |
| 6564 | memcpy(p, derBytes, derLen); |
| 6565 | |
| 6566 | return byteArray.release(); |
| 6567 | #endif // OPENSSL_IS_BORINGSSL |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6568 | } |
| 6569 | |
Adam Langley | 8673398 | 2015-05-18 17:33:35 -0700 | [diff] [blame] | 6570 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6571 | |
| 6572 | static STACK_OF(X509)* PKCS7_get_certs(PKCS7* pkcs7) { |
| 6573 | if (PKCS7_type_is_signed(pkcs7)) { |
| 6574 | return pkcs7->d.sign->cert; |
| 6575 | } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) { |
| 6576 | return pkcs7->d.signed_and_enveloped->cert; |
| 6577 | } else { |
| 6578 | JNI_TRACE("PKCS7_get_certs(%p) => unknown PKCS7 type", pkcs7); |
| 6579 | return NULL; |
| 6580 | } |
| 6581 | } |
| 6582 | |
| 6583 | static STACK_OF(X509_CRL)* PKCS7_get_CRLs(PKCS7* pkcs7) { |
| 6584 | if (PKCS7_type_is_signed(pkcs7)) { |
| 6585 | return pkcs7->d.sign->crl; |
| 6586 | } else if (PKCS7_type_is_signedAndEnveloped(pkcs7)) { |
| 6587 | return pkcs7->d.signed_and_enveloped->crl; |
| 6588 | } else { |
| 6589 | JNI_TRACE("PKCS7_get_CRLs(%p) => unknown PKCS7 type", pkcs7); |
| 6590 | return NULL; |
| 6591 | } |
| 6592 | } |
| 6593 | |
| 6594 | #endif |
| 6595 | |
| 6596 | static jlongArray NativeCrypto_PEM_read_bio_PKCS7(JNIEnv* env, jclass, jlong bioRef, jint which) { |
| 6597 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6598 | JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p)", bio); |
| 6599 | |
| 6600 | if (bio == NULL) { |
| 6601 | jniThrowNullPointerException(env, "bio == null"); |
| 6602 | JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => bio == null", bio); |
| 6603 | return 0; |
| 6604 | } |
| 6605 | |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6606 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6607 | Unique_PKCS7 pkcs7(PEM_read_bio_PKCS7(bio, NULL, NULL, NULL)); |
| 6608 | if (pkcs7.get() == NULL) { |
| 6609 | throwExceptionIfNecessary(env, "PEM_read_bio_PKCS7_CRLs"); |
| 6610 | JNI_TRACE("PEM_read_bio_PKCS7_CRLs(%p) => threw exception", bio); |
| 6611 | return 0; |
| 6612 | } |
| 6613 | |
| 6614 | switch (which) { |
| 6615 | case PKCS7_CERTS: |
| 6616 | return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup); |
| 6617 | case PKCS7_CRLS: |
| 6618 | return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()), |
| 6619 | X509_CRL_dup); |
| 6620 | default: |
| 6621 | jniThrowRuntimeException(env, "unknown PKCS7 field"); |
| 6622 | return NULL; |
| 6623 | } |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6624 | #else |
| 6625 | if (which == PKCS7_CERTS) { |
| 6626 | Unique_sk_X509 outCerts(sk_X509_new_null()); |
| 6627 | if (!PKCS7_get_PEM_certificates(outCerts.get(), bio)) { |
| 6628 | throwExceptionIfNecessary(env, "PKCS7_get_PEM_certificates"); |
| 6629 | return 0; |
| 6630 | } |
| 6631 | return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, outCerts.get(), X509_dup); |
| 6632 | } else if (which == PKCS7_CRLS) { |
| 6633 | Unique_sk_X509_CRL outCRLs(sk_X509_CRL_new_null()); |
| 6634 | if (!PKCS7_get_PEM_CRLs(outCRLs.get(), bio)) { |
| 6635 | throwExceptionIfNecessary(env, "PKCS7_get_PEM_CRLs"); |
| 6636 | return 0; |
| 6637 | } |
| 6638 | return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>( |
| 6639 | env, outCRLs.get(), X509_CRL_dup); |
| 6640 | } else { |
| 6641 | jniThrowRuntimeException(env, "unknown PKCS7 field"); |
| 6642 | return 0; |
| 6643 | } |
| 6644 | #endif |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6645 | } |
| 6646 | |
| 6647 | static jlongArray NativeCrypto_d2i_PKCS7_bio(JNIEnv* env, jclass, jlong bioRef, jint which) { |
| 6648 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6649 | JNI_TRACE("d2i_PKCS7_bio(%p, %d)", bio, which); |
| 6650 | |
| 6651 | if (bio == NULL) { |
| 6652 | jniThrowNullPointerException(env, "bio == null"); |
| 6653 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => bio == null", bio, which); |
| 6654 | return 0; |
| 6655 | } |
| 6656 | |
| 6657 | #if !defined(OPENSSL_IS_BORINGSSL) |
| 6658 | Unique_PKCS7 pkcs7(d2i_PKCS7_bio(bio, NULL)); |
| 6659 | if (pkcs7.get() == NULL) { |
| 6660 | throwExceptionIfNecessary(env, "d2i_PKCS7_bio"); |
| 6661 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => threw exception", bio, which); |
| 6662 | return 0; |
| 6663 | } |
| 6664 | |
| 6665 | switch (which) { |
| 6666 | case PKCS7_CERTS: |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6667 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => returned", bio, which); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6668 | return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, PKCS7_get_certs(pkcs7.get()), X509_dup); |
| 6669 | case PKCS7_CRLS: |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6670 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => returned", bio, which); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6671 | return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>(env, PKCS7_get_CRLs(pkcs7.get()), |
| 6672 | X509_CRL_dup); |
| 6673 | default: |
| 6674 | jniThrowRuntimeException(env, "unknown PKCS7 field"); |
| 6675 | return NULL; |
| 6676 | } |
| 6677 | #else |
Adam Langley | 8673398 | 2015-05-18 17:33:35 -0700 | [diff] [blame] | 6678 | uint8_t *data; |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6679 | size_t len; |
Adam Langley | 8673398 | 2015-05-18 17:33:35 -0700 | [diff] [blame] | 6680 | if (!BIO_read_asn1(bio, &data, &len, 256 * 1024 * 1024 /* max length, 256MB for sanity */)) { |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6681 | if (!throwExceptionIfNecessary(env, "Error reading PKCS#7 data")) { |
| 6682 | throwParsingException(env, "Error reading PKCS#7 data"); |
| 6683 | } |
| 6684 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading BIO", bio, which); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6685 | return 0; |
| 6686 | } |
Adam Langley | 8673398 | 2015-05-18 17:33:35 -0700 | [diff] [blame] | 6687 | Unique_OPENSSL_str data_storage(data); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6688 | |
| 6689 | CBS cbs; |
Adam Langley | 8673398 | 2015-05-18 17:33:35 -0700 | [diff] [blame] | 6690 | CBS_init(&cbs, data, len); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6691 | |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6692 | if (which == PKCS7_CERTS) { |
| 6693 | Unique_sk_X509 outCerts(sk_X509_new_null()); |
| 6694 | if (!PKCS7_get_certificates(outCerts.get(), &cbs)) { |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6695 | if (!throwExceptionIfNecessary(env, "PKCS7_get_certificates")) { |
| 6696 | throwParsingException(env, "Error parsing PKCS#7 certificate data"); |
| 6697 | } |
| 6698 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading certs", bio, which); |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6699 | return 0; |
| 6700 | } |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6701 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => success certs", bio, which); |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6702 | return PKCS7_to_ItemArray<X509, STACK_OF(X509)>(env, outCerts.get(), X509_dup); |
| 6703 | } else if (which == PKCS7_CRLS) { |
| 6704 | Unique_sk_X509_CRL outCRLs(sk_X509_CRL_new_null()); |
| 6705 | if (!PKCS7_get_CRLs(outCRLs.get(), &cbs)) { |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6706 | if (!throwExceptionIfNecessary(env, "PKCS7_get_CRLs")) { |
| 6707 | throwParsingException(env, "Error parsing PKCS#7 CRL data"); |
| 6708 | } |
| 6709 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => error reading CRLs", bio, which); |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6710 | return 0; |
| 6711 | } |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6712 | JNI_TRACE("d2i_PKCS7_bio(%p, %d) => success CRLs", bio, which); |
Adam Langley | 811e7ae | 2015-02-27 13:20:02 -0800 | [diff] [blame] | 6713 | return PKCS7_to_ItemArray<X509_CRL, STACK_OF(X509_CRL)>( |
| 6714 | env, outCRLs.get(), X509_CRL_dup); |
| 6715 | } else { |
| 6716 | jniThrowRuntimeException(env, "unknown PKCS7 field"); |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6717 | return 0; |
| 6718 | } |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 6719 | #endif |
| 6720 | } |
| 6721 | |
| 6722 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6723 | typedef STACK_OF(X509) PKIPATH; |
| 6724 | |
| 6725 | ASN1_ITEM_TEMPLATE(PKIPATH) = |
| 6726 | ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, PkiPath, X509) |
| 6727 | ASN1_ITEM_TEMPLATE_END(PKIPATH) |
| 6728 | |
| 6729 | static jlongArray NativeCrypto_ASN1_seq_unpack_X509_bio(JNIEnv* env, jclass, jlong bioRef) { |
| 6730 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6731 | JNI_TRACE("ASN1_seq_unpack_X509_bio(%p)", bio); |
| 6732 | |
| 6733 | Unique_sk_X509 path((PKIPATH*) ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKIPATH), bio, NULL)); |
| 6734 | if (path.get() == NULL) { |
| 6735 | throwExceptionIfNecessary(env, "ASN1_seq_unpack_X509_bio"); |
Kenny Root | ccb8225 | 2015-06-11 12:58:31 -0700 | [diff] [blame] | 6736 | JNI_TRACE("ASN1_seq_unpack_X509_bio(%p) => threw error", bio); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6737 | return NULL; |
| 6738 | } |
| 6739 | |
| 6740 | size_t size = sk_X509_num(path.get()); |
| 6741 | |
| 6742 | ScopedLocalRef<jlongArray> certArray(env, env->NewLongArray(size)); |
| 6743 | ScopedLongArrayRW certs(env, certArray.get()); |
| 6744 | for (size_t i = 0; i < size; i++) { |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 6745 | X509* item = reinterpret_cast<X509*>(sk_X509_shift(path.get())); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6746 | certs[i] = reinterpret_cast<uintptr_t>(item); |
| 6747 | } |
| 6748 | |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 6749 | JNI_TRACE("ASN1_seq_unpack_X509_bio(%p) => returns %zd items", bio, size); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6750 | return certArray.release(); |
| 6751 | } |
| 6752 | |
| 6753 | static jbyteArray NativeCrypto_ASN1_seq_pack_X509(JNIEnv* env, jclass, jlongArray certs) { |
| 6754 | JNI_TRACE("ASN1_seq_pack_X509(%p)", certs); |
| 6755 | ScopedLongArrayRO certsArray(env, certs); |
| 6756 | if (certsArray.get() == NULL) { |
| 6757 | JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to get certs array", certs); |
| 6758 | return NULL; |
| 6759 | } |
| 6760 | |
| 6761 | Unique_sk_X509 certStack(sk_X509_new_null()); |
| 6762 | if (certStack.get() == NULL) { |
| 6763 | JNI_TRACE("ASN1_seq_pack_X509(%p) => failed to make cert stack", certs); |
| 6764 | return NULL; |
| 6765 | } |
| 6766 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6767 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6768 | for (size_t i = 0; i < certsArray.size(); i++) { |
| 6769 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(certsArray[i])); |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 6770 | sk_X509_push(certStack.get(), X509_dup_nocopy(x509)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6771 | } |
| 6772 | |
| 6773 | int len; |
| 6774 | Unique_OPENSSL_str encoded(ASN1_seq_pack( |
| 6775 | reinterpret_cast<STACK_OF(OPENSSL_BLOCK)*>( |
| 6776 | reinterpret_cast<uintptr_t>(certStack.get())), |
| 6777 | reinterpret_cast<int (*)(void*, unsigned char**)>(i2d_X509), NULL, &len)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6778 | if (encoded.get() == NULL || len < 0) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6779 | JNI_TRACE("ASN1_seq_pack_X509(%p) => trouble encoding", certs); |
| 6780 | return NULL; |
| 6781 | } |
| 6782 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6783 | uint8_t *out = encoded.get(); |
| 6784 | size_t out_len = len; |
| 6785 | #else |
| 6786 | CBB result, seq_contents; |
| 6787 | if (!CBB_init(&result, 2048 * certsArray.size())) { |
| 6788 | JNI_TRACE("ASN1_seq_pack_X509(%p) => CBB_init failed", certs); |
| 6789 | return NULL; |
| 6790 | } |
| 6791 | if (!CBB_add_asn1(&result, &seq_contents, CBS_ASN1_SEQUENCE)) { |
| 6792 | CBB_cleanup(&result); |
| 6793 | return NULL; |
| 6794 | } |
| 6795 | |
| 6796 | for (size_t i = 0; i < certsArray.size(); i++) { |
| 6797 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(certsArray[i])); |
| 6798 | uint8_t *buf; |
| 6799 | int len = i2d_X509(x509, NULL); |
| 6800 | |
| 6801 | if (len < 0 || |
| 6802 | !CBB_add_space(&seq_contents, &buf, len) || |
| 6803 | i2d_X509(x509, &buf) < 0) { |
| 6804 | CBB_cleanup(&result); |
| 6805 | return NULL; |
| 6806 | } |
| 6807 | } |
| 6808 | |
| 6809 | uint8_t *out; |
| 6810 | size_t out_len; |
| 6811 | if (!CBB_finish(&result, &out, &out_len)) { |
| 6812 | CBB_cleanup(&result); |
| 6813 | return NULL; |
| 6814 | } |
| 6815 | UniquePtr<uint8_t> out_storage(out); |
| 6816 | #endif |
| 6817 | |
| 6818 | ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(out_len)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6819 | if (byteArray.get() == NULL) { |
| 6820 | JNI_TRACE("ASN1_seq_pack_X509(%p) => creating byte array failed", certs); |
| 6821 | return NULL; |
| 6822 | } |
| 6823 | |
| 6824 | ScopedByteArrayRW bytes(env, byteArray.get()); |
| 6825 | if (bytes.get() == NULL) { |
| 6826 | JNI_TRACE("ASN1_seq_pack_X509(%p) => using byte array failed", certs); |
| 6827 | return NULL; |
| 6828 | } |
| 6829 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6830 | uint8_t *p = reinterpret_cast<uint8_t*>(bytes.get()); |
| 6831 | memcpy(p, out, out_len); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6832 | |
| 6833 | return byteArray.release(); |
| 6834 | } |
| 6835 | |
| 6836 | static void NativeCrypto_X509_free(JNIEnv* env, jclass, jlong x509Ref) { |
| 6837 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6838 | JNI_TRACE("X509_free(%p)", x509); |
| 6839 | |
| 6840 | if (x509 == NULL) { |
| 6841 | jniThrowNullPointerException(env, "x509 == null"); |
| 6842 | JNI_TRACE("X509_free(%p) => x509 == null", x509); |
| 6843 | return; |
| 6844 | } |
| 6845 | |
| 6846 | X509_free(x509); |
| 6847 | } |
| 6848 | |
| 6849 | static jint NativeCrypto_X509_cmp(JNIEnv* env, jclass, jlong x509Ref1, jlong x509Ref2) { |
| 6850 | X509* x509_1 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref1)); |
| 6851 | X509* x509_2 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref2)); |
| 6852 | JNI_TRACE("X509_cmp(%p, %p)", x509_1, x509_2); |
| 6853 | |
| 6854 | if (x509_1 == NULL) { |
| 6855 | jniThrowNullPointerException(env, "x509_1 == null"); |
| 6856 | JNI_TRACE("X509_cmp(%p, %p) => x509_1 == null", x509_1, x509_2); |
| 6857 | return -1; |
| 6858 | } |
| 6859 | |
| 6860 | if (x509_2 == NULL) { |
| 6861 | jniThrowNullPointerException(env, "x509_2 == null"); |
| 6862 | JNI_TRACE("X509_cmp(%p, %p) => x509_2 == null", x509_1, x509_2); |
| 6863 | return -1; |
| 6864 | } |
| 6865 | |
| 6866 | int ret = X509_cmp(x509_1, x509_2); |
| 6867 | JNI_TRACE("X509_cmp(%p, %p) => %d", x509_1, x509_2, ret); |
| 6868 | return ret; |
| 6869 | } |
| 6870 | |
| 6871 | static jint NativeCrypto_get_X509_hashCode(JNIEnv* env, jclass, jlong x509Ref) { |
| 6872 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6873 | |
| 6874 | if (x509 == NULL) { |
| 6875 | jniThrowNullPointerException(env, "x509 == null"); |
| 6876 | JNI_TRACE("get_X509_hashCode(%p) => x509 == null", x509); |
| 6877 | return 0; |
| 6878 | } |
| 6879 | |
| 6880 | // Force caching extensions. |
| 6881 | X509_check_ca(x509); |
| 6882 | |
| 6883 | jint hashCode = 0L; |
| 6884 | for (int i = 0; i < SHA_DIGEST_LENGTH; i++) { |
| 6885 | hashCode = 31 * hashCode + x509->sha1_hash[i]; |
| 6886 | } |
| 6887 | return hashCode; |
| 6888 | } |
| 6889 | |
| 6890 | static void NativeCrypto_X509_print_ex(JNIEnv* env, jclass, jlong bioRef, jlong x509Ref, |
| 6891 | jlong nmflagJava, jlong certflagJava) { |
| 6892 | BIO* bio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(bioRef)); |
| 6893 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6894 | long nmflag = static_cast<long>(nmflagJava); |
| 6895 | long certflag = static_cast<long>(certflagJava); |
| 6896 | JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld)", bio, x509, nmflag, certflag); |
| 6897 | |
| 6898 | if (bio == NULL) { |
| 6899 | jniThrowNullPointerException(env, "bio == null"); |
| 6900 | JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => bio == null", bio, x509, nmflag, certflag); |
| 6901 | return; |
| 6902 | } |
| 6903 | |
| 6904 | if (x509 == NULL) { |
| 6905 | jniThrowNullPointerException(env, "x509 == null"); |
| 6906 | JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => x509 == null", bio, x509, nmflag, certflag); |
| 6907 | return; |
| 6908 | } |
| 6909 | |
Elliott Hughes | fb822ae | 2013-08-19 15:45:20 -0700 | [diff] [blame] | 6910 | if (!X509_print_ex(bio, x509, nmflag, certflag)) { |
| 6911 | throwExceptionIfNecessary(env, "X509_print_ex"); |
| 6912 | JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => threw error", bio, x509, nmflag, certflag); |
| 6913 | } else { |
| 6914 | JNI_TRACE("X509_print_ex(%p, %p, %ld, %ld) => success", bio, x509, nmflag, certflag); |
| 6915 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6916 | } |
| 6917 | |
| 6918 | static jlong NativeCrypto_X509_get_pubkey(JNIEnv* env, jclass, jlong x509Ref) { |
| 6919 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6920 | JNI_TRACE("X509_get_pubkey(%p)", x509); |
| 6921 | |
| 6922 | if (x509 == NULL) { |
| 6923 | jniThrowNullPointerException(env, "x509 == null"); |
| 6924 | JNI_TRACE("X509_get_pubkey(%p) => x509 == null", x509); |
| 6925 | return 0; |
| 6926 | } |
| 6927 | |
| 6928 | Unique_EVP_PKEY pkey(X509_get_pubkey(x509)); |
| 6929 | if (pkey.get() == NULL) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6930 | #if defined(OPENSSL_IS_BORINGSSL) |
| 6931 | const uint32_t last_error = ERR_peek_last_error(); |
| 6932 | const uint32_t first_error = ERR_peek_error(); |
| 6933 | if ((ERR_GET_LIB(last_error) == ERR_LIB_EVP && |
| 6934 | ERR_GET_REASON(last_error) == EVP_R_UNKNOWN_PUBLIC_KEY_TYPE) || |
| 6935 | (ERR_GET_LIB(first_error) == ERR_LIB_EC && |
| 6936 | ERR_GET_REASON(first_error) == EC_R_UNKNOWN_GROUP)) { |
| 6937 | freeOpenSslErrorState(); |
| 6938 | throwNoSuchAlgorithmException(env, "X509_get_pubkey"); |
| 6939 | return 0; |
| 6940 | } |
| 6941 | #endif |
| 6942 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6943 | throwExceptionIfNecessary(env, "X509_get_pubkey"); |
| 6944 | return 0; |
| 6945 | } |
| 6946 | |
Kenny Root | 3bcae05 | 2014-02-05 11:25:54 -0800 | [diff] [blame] | 6947 | JNI_TRACE("X509_get_pubkey(%p) => %p", x509, pkey.get()); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6948 | return reinterpret_cast<uintptr_t>(pkey.release()); |
| 6949 | } |
| 6950 | |
| 6951 | static jbyteArray NativeCrypto_X509_get_issuer_name(JNIEnv* env, jclass, jlong x509Ref) { |
| 6952 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6953 | JNI_TRACE("X509_get_issuer_name(%p)", x509); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6954 | return ASN1ToByteArray<X509_NAME>(env, X509_get_issuer_name(x509), i2d_X509_NAME); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6955 | } |
| 6956 | |
| 6957 | static jbyteArray NativeCrypto_X509_get_subject_name(JNIEnv* env, jclass, jlong x509Ref) { |
| 6958 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6959 | JNI_TRACE("X509_get_subject_name(%p)", x509); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 6960 | return ASN1ToByteArray<X509_NAME>(env, X509_get_subject_name(x509), i2d_X509_NAME); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 6961 | } |
| 6962 | |
| 6963 | static jstring NativeCrypto_get_X509_pubkey_oid(JNIEnv* env, jclass, jlong x509Ref) { |
| 6964 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6965 | JNI_TRACE("get_X509_pubkey_oid(%p)", x509); |
| 6966 | |
| 6967 | if (x509 == NULL) { |
| 6968 | jniThrowNullPointerException(env, "x509 == null"); |
| 6969 | JNI_TRACE("get_X509_pubkey_oid(%p) => x509 == null", x509); |
| 6970 | return NULL; |
| 6971 | } |
| 6972 | |
| 6973 | X509_PUBKEY* pubkey = X509_get_X509_PUBKEY(x509); |
| 6974 | return ASN1_OBJECT_to_OID_string(env, pubkey->algor->algorithm); |
| 6975 | } |
| 6976 | |
| 6977 | static jstring NativeCrypto_get_X509_sig_alg_oid(JNIEnv* env, jclass, jlong x509Ref) { |
| 6978 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6979 | JNI_TRACE("get_X509_sig_alg_oid(%p)", x509); |
| 6980 | |
| 6981 | if (x509 == NULL || x509->sig_alg == NULL) { |
| 6982 | jniThrowNullPointerException(env, "x509 == NULL || x509->sig_alg == NULL"); |
| 6983 | JNI_TRACE("get_X509_sig_alg_oid(%p) => x509 == NULL", x509); |
| 6984 | return NULL; |
| 6985 | } |
| 6986 | |
| 6987 | return ASN1_OBJECT_to_OID_string(env, x509->sig_alg->algorithm); |
| 6988 | } |
| 6989 | |
| 6990 | static jbyteArray NativeCrypto_get_X509_sig_alg_parameter(JNIEnv* env, jclass, jlong x509Ref) { |
| 6991 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 6992 | JNI_TRACE("get_X509_sig_alg_parameter(%p)", x509); |
| 6993 | |
| 6994 | if (x509 == NULL) { |
| 6995 | jniThrowNullPointerException(env, "x509 == null"); |
| 6996 | JNI_TRACE("get_X509_sig_alg_parameter(%p) => x509 == null", x509); |
| 6997 | return NULL; |
| 6998 | } |
| 6999 | |
| 7000 | if (x509->sig_alg->parameter == NULL) { |
| 7001 | JNI_TRACE("get_X509_sig_alg_parameter(%p) => null", x509); |
| 7002 | return NULL; |
| 7003 | } |
| 7004 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7005 | return ASN1ToByteArray<ASN1_TYPE>(env, x509->sig_alg->parameter, i2d_ASN1_TYPE); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7006 | } |
| 7007 | |
| 7008 | static jbooleanArray NativeCrypto_get_X509_issuerUID(JNIEnv* env, jclass, jlong x509Ref) { |
| 7009 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7010 | JNI_TRACE("get_X509_issuerUID(%p)", x509); |
| 7011 | |
| 7012 | if (x509 == NULL) { |
| 7013 | jniThrowNullPointerException(env, "x509 == null"); |
| 7014 | JNI_TRACE("get_X509_issuerUID(%p) => x509 == null", x509); |
| 7015 | return NULL; |
| 7016 | } |
| 7017 | |
| 7018 | if (x509->cert_info->issuerUID == NULL) { |
| 7019 | JNI_TRACE("get_X509_issuerUID(%p) => null", x509); |
| 7020 | return NULL; |
| 7021 | } |
| 7022 | |
| 7023 | return ASN1BitStringToBooleanArray(env, x509->cert_info->issuerUID); |
| 7024 | } |
| 7025 | static jbooleanArray NativeCrypto_get_X509_subjectUID(JNIEnv* env, jclass, jlong x509Ref) { |
| 7026 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7027 | JNI_TRACE("get_X509_subjectUID(%p)", x509); |
| 7028 | |
| 7029 | if (x509 == NULL) { |
| 7030 | jniThrowNullPointerException(env, "x509 == null"); |
| 7031 | JNI_TRACE("get_X509_subjectUID(%p) => x509 == null", x509); |
| 7032 | return NULL; |
| 7033 | } |
| 7034 | |
| 7035 | if (x509->cert_info->subjectUID == NULL) { |
| 7036 | JNI_TRACE("get_X509_subjectUID(%p) => null", x509); |
| 7037 | return NULL; |
| 7038 | } |
| 7039 | |
| 7040 | return ASN1BitStringToBooleanArray(env, x509->cert_info->subjectUID); |
| 7041 | } |
| 7042 | |
| 7043 | static jbooleanArray NativeCrypto_get_X509_ex_kusage(JNIEnv* env, jclass, jlong x509Ref) { |
| 7044 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7045 | JNI_TRACE("get_X509_ex_kusage(%p)", x509); |
| 7046 | |
| 7047 | if (x509 == NULL) { |
| 7048 | jniThrowNullPointerException(env, "x509 == null"); |
| 7049 | JNI_TRACE("get_X509_ex_kusage(%p) => x509 == null", x509); |
| 7050 | return NULL; |
| 7051 | } |
| 7052 | |
| 7053 | Unique_ASN1_BIT_STRING bitStr(static_cast<ASN1_BIT_STRING*>( |
| 7054 | X509_get_ext_d2i(x509, NID_key_usage, NULL, NULL))); |
| 7055 | if (bitStr.get() == NULL) { |
| 7056 | JNI_TRACE("get_X509_ex_kusage(%p) => null", x509); |
| 7057 | return NULL; |
| 7058 | } |
| 7059 | |
| 7060 | return ASN1BitStringToBooleanArray(env, bitStr.get()); |
| 7061 | } |
| 7062 | |
| 7063 | static jobjectArray NativeCrypto_get_X509_ex_xkusage(JNIEnv* env, jclass, jlong x509Ref) { |
| 7064 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7065 | JNI_TRACE("get_X509_ex_xkusage(%p)", x509); |
| 7066 | |
| 7067 | if (x509 == NULL) { |
| 7068 | jniThrowNullPointerException(env, "x509 == null"); |
| 7069 | JNI_TRACE("get_X509_ex_xkusage(%p) => x509 == null", x509); |
| 7070 | return NULL; |
| 7071 | } |
| 7072 | |
| 7073 | Unique_sk_ASN1_OBJECT objArray(static_cast<STACK_OF(ASN1_OBJECT)*>( |
| 7074 | X509_get_ext_d2i(x509, NID_ext_key_usage, NULL, NULL))); |
| 7075 | if (objArray.get() == NULL) { |
| 7076 | JNI_TRACE("get_X509_ex_xkusage(%p) => null", x509); |
| 7077 | return NULL; |
| 7078 | } |
| 7079 | |
| 7080 | size_t size = sk_ASN1_OBJECT_num(objArray.get()); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 7081 | ScopedLocalRef<jobjectArray> exKeyUsage(env, env->NewObjectArray(size, stringClass, NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7082 | if (exKeyUsage.get() == NULL) { |
| 7083 | return NULL; |
| 7084 | } |
| 7085 | |
| 7086 | for (size_t i = 0; i < size; i++) { |
| 7087 | ScopedLocalRef<jstring> oidStr(env, ASN1_OBJECT_to_OID_string(env, |
| 7088 | sk_ASN1_OBJECT_value(objArray.get(), i))); |
| 7089 | env->SetObjectArrayElement(exKeyUsage.get(), i, oidStr.get()); |
| 7090 | } |
| 7091 | |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 7092 | JNI_TRACE("get_X509_ex_xkusage(%p) => success (%zd entries)", x509, size); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7093 | return exKeyUsage.release(); |
| 7094 | } |
| 7095 | |
| 7096 | static jint NativeCrypto_get_X509_ex_pathlen(JNIEnv* env, jclass, jlong x509Ref) { |
| 7097 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7098 | JNI_TRACE("get_X509_ex_pathlen(%p)", x509); |
| 7099 | |
| 7100 | if (x509 == NULL) { |
| 7101 | jniThrowNullPointerException(env, "x509 == null"); |
| 7102 | JNI_TRACE("get_X509_ex_pathlen(%p) => x509 == null", x509); |
| 7103 | return 0; |
| 7104 | } |
| 7105 | |
| 7106 | /* Just need to do this to cache the ex_* values. */ |
| 7107 | X509_check_ca(x509); |
| 7108 | |
| 7109 | JNI_TRACE("get_X509_ex_pathlen(%p) => %ld", x509, x509->ex_pathlen); |
| 7110 | return x509->ex_pathlen; |
| 7111 | } |
| 7112 | |
| 7113 | static jbyteArray NativeCrypto_X509_get_ext_oid(JNIEnv* env, jclass, jlong x509Ref, |
| 7114 | jstring oidString) { |
| 7115 | X509* x509 = reinterpret_cast<X509*>(static_cast<uintptr_t>(x509Ref)); |
| 7116 | JNI_TRACE("X509_get_ext_oid(%p, %p)", x509, oidString); |
| 7117 | return X509Type_get_ext_oid<X509, X509_get_ext_by_OBJ, X509_get_ext>(env, x509, oidString); |
| 7118 | } |
| 7119 | |
| 7120 | static jbyteArray NativeCrypto_X509_CRL_get_ext_oid(JNIEnv* env, jclass, jlong x509CrlRef, |
| 7121 | jstring oidString) { |
| 7122 | X509_CRL* crl = reinterpret_cast<X509_CRL*>(static_cast<uintptr_t>(x509CrlRef)); |
| 7123 | JNI_TRACE("X509_CRL_get_ext_oid(%p, %p)", crl, oidString); |
| 7124 | return X509Type_get_ext_oid<X509_CRL, X509_CRL_get_ext_by_OBJ, X509_CRL_get_ext>(env, crl, |
| 7125 | oidString); |
| 7126 | } |
| 7127 | |
| 7128 | static jbyteArray NativeCrypto_X509_REVOKED_get_ext_oid(JNIEnv* env, jclass, jlong x509RevokedRef, |
| 7129 | jstring oidString) { |
| 7130 | X509_REVOKED* revoked = reinterpret_cast<X509_REVOKED*>(static_cast<uintptr_t>(x509RevokedRef)); |
| 7131 | JNI_TRACE("X509_REVOKED_get_ext_oid(%p, %p)", revoked, oidString); |
| 7132 | return X509Type_get_ext_oid<X509_REVOKED, X509_REVOKED_get_ext_by_OBJ, X509_REVOKED_get_ext>( |
| 7133 | env, revoked, oidString); |
| 7134 | } |
| 7135 | |
| 7136 | template<typename T, int (*get_ext_by_critical_func)(T*, int, int), X509_EXTENSION* (*get_ext_func)(T*, int)> |
| 7137 | static jobjectArray get_X509Type_ext_oids(JNIEnv* env, jlong x509Ref, jint critical) { |
| 7138 | T* x509 = reinterpret_cast<T*>(static_cast<uintptr_t>(x509Ref)); |
| 7139 | JNI_TRACE("get_X509Type_ext_oids(%p, %d)", x509, critical); |
| 7140 | |
| 7141 | if (x509 == NULL) { |
| 7142 | jniThrowNullPointerException(env, "x509 == null"); |
| 7143 | JNI_TRACE("get_X509Type_ext_oids(%p, %d) => x509 == null", x509, critical); |
| 7144 | return NULL; |
| 7145 | } |
| 7146 | |
| 7147 | int lastPos = -1; |
| 7148 | int count = 0; |
| 7149 | while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) { |
| 7150 | count++; |
| 7151 | } |
| 7152 | |
| 7153 | JNI_TRACE("get_X509Type_ext_oids(%p, %d) has %d entries", x509, critical, count); |
| 7154 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 7155 | ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, stringClass, NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7156 | if (joa.get() == NULL) { |
| 7157 | JNI_TRACE("get_X509Type_ext_oids(%p, %d) => fail to allocate result array", x509, critical); |
| 7158 | return NULL; |
| 7159 | } |
| 7160 | |
| 7161 | lastPos = -1; |
| 7162 | count = 0; |
| 7163 | while ((lastPos = get_ext_by_critical_func(x509, critical, lastPos)) != -1) { |
| 7164 | X509_EXTENSION* ext = get_ext_func(x509, lastPos); |
| 7165 | |
| 7166 | ScopedLocalRef<jstring> extOid(env, ASN1_OBJECT_to_OID_string(env, ext->object)); |
| 7167 | if (extOid.get() == NULL) { |
| 7168 | JNI_TRACE("get_X509Type_ext_oids(%p) => couldn't get OID", x509); |
| 7169 | return NULL; |
| 7170 | } |
| 7171 | |
| 7172 | env->SetObjectArrayElement(joa.get(), count++, extOid.get()); |
| 7173 | } |
| 7174 | |
| 7175 | JNI_TRACE("get_X509Type_ext_oids(%p, %d) => success", x509, critical); |
| 7176 | return joa.release(); |
| 7177 | } |
| 7178 | |
| 7179 | static jobjectArray NativeCrypto_get_X509_ext_oids(JNIEnv* env, jclass, jlong x509Ref, |
| 7180 | jint critical) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 7181 | JNI_TRACE("get_X509_ext_oids(0x%llx, %d)", (long long) x509Ref, critical); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7182 | return get_X509Type_ext_oids<X509, X509_get_ext_by_critical, X509_get_ext>(env, x509Ref, |
| 7183 | critical); |
| 7184 | } |
| 7185 | |
| 7186 | static jobjectArray NativeCrypto_get_X509_CRL_ext_oids(JNIEnv* env, jclass, jlong x509CrlRef, |
| 7187 | jint critical) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 7188 | JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", (long long) x509CrlRef, critical); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7189 | return get_X509Type_ext_oids<X509_CRL, X509_CRL_get_ext_by_critical, X509_CRL_get_ext>(env, |
| 7190 | x509CrlRef, critical); |
| 7191 | } |
| 7192 | |
| 7193 | static jobjectArray NativeCrypto_get_X509_REVOKED_ext_oids(JNIEnv* env, jclass, jlong x509RevokedRef, |
| 7194 | jint critical) { |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 7195 | JNI_TRACE("get_X509_CRL_ext_oids(0x%llx, %d)", (long long) x509RevokedRef, critical); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7196 | return get_X509Type_ext_oids<X509_REVOKED, X509_REVOKED_get_ext_by_critical, |
| 7197 | X509_REVOKED_get_ext>(env, x509RevokedRef, critical); |
| 7198 | } |
| 7199 | |
| 7200 | #ifdef WITH_JNI_TRACE |
| 7201 | /** |
| 7202 | * Based on example logging call back from SSL_CTX_set_info_callback man page |
| 7203 | */ |
| 7204 | static void info_callback_LOG(const SSL* s __attribute__ ((unused)), int where, int ret) |
| 7205 | { |
| 7206 | int w = where & ~SSL_ST_MASK; |
| 7207 | const char* str; |
| 7208 | if (w & SSL_ST_CONNECT) { |
| 7209 | str = "SSL_connect"; |
| 7210 | } else if (w & SSL_ST_ACCEPT) { |
| 7211 | str = "SSL_accept"; |
| 7212 | } else { |
| 7213 | str = "undefined"; |
| 7214 | } |
| 7215 | |
| 7216 | if (where & SSL_CB_LOOP) { |
| 7217 | JNI_TRACE("ssl=%p %s:%s %s", s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 7218 | } else if (where & SSL_CB_ALERT) { |
| 7219 | str = (where & SSL_CB_READ) ? "read" : "write"; |
| 7220 | JNI_TRACE("ssl=%p SSL3 alert %s:%s:%s %s %s", |
| 7221 | s, |
| 7222 | str, |
| 7223 | SSL_alert_type_string(ret), |
| 7224 | SSL_alert_desc_string(ret), |
| 7225 | SSL_alert_type_string_long(ret), |
| 7226 | SSL_alert_desc_string_long(ret)); |
| 7227 | } else if (where & SSL_CB_EXIT) { |
| 7228 | if (ret == 0) { |
| 7229 | JNI_TRACE("ssl=%p %s:failed exit in %s %s", |
| 7230 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 7231 | } else if (ret < 0) { |
| 7232 | JNI_TRACE("ssl=%p %s:error exit in %s %s", |
| 7233 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 7234 | } else if (ret == 1) { |
| 7235 | JNI_TRACE("ssl=%p %s:ok exit in %s %s", |
| 7236 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 7237 | } else { |
| 7238 | JNI_TRACE("ssl=%p %s:unknown exit %d in %s %s", |
| 7239 | s, str, ret, SSL_state_string(s), SSL_state_string_long(s)); |
| 7240 | } |
| 7241 | } else if (where & SSL_CB_HANDSHAKE_START) { |
| 7242 | JNI_TRACE("ssl=%p handshake start in %s %s", |
| 7243 | s, SSL_state_string(s), SSL_state_string_long(s)); |
| 7244 | } else if (where & SSL_CB_HANDSHAKE_DONE) { |
| 7245 | JNI_TRACE("ssl=%p handshake done in %s %s", |
| 7246 | s, SSL_state_string(s), SSL_state_string_long(s)); |
| 7247 | } else { |
| 7248 | JNI_TRACE("ssl=%p %s:unknown where %d in %s %s", |
| 7249 | s, str, where, SSL_state_string(s), SSL_state_string_long(s)); |
| 7250 | } |
| 7251 | } |
| 7252 | #endif |
| 7253 | |
| 7254 | /** |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7255 | * Returns an array containing all the X509 certificate references |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7256 | */ |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7257 | static jlongArray getCertificateRefs(JNIEnv* env, const STACK_OF(X509)* chain) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7258 | { |
| 7259 | if (chain == NULL) { |
| 7260 | // Chain can be NULL if the associated cipher doesn't do certs. |
| 7261 | return NULL; |
| 7262 | } |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7263 | ssize_t count = sk_X509_num(chain); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7264 | if (count <= 0) { |
| 7265 | return NULL; |
| 7266 | } |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7267 | ScopedLocalRef<jlongArray> refArray(env, env->NewLongArray(count)); |
| 7268 | ScopedLongArrayRW refs(env, refArray.get()); |
| 7269 | if (refs.get() == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7270 | return NULL; |
| 7271 | } |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7272 | for (ssize_t i = 0; i < count; i++) { |
| 7273 | refs[i] = reinterpret_cast<uintptr_t>(X509_dup_nocopy(sk_X509_value(chain, i))); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7274 | } |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7275 | return refArray.release(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7276 | } |
| 7277 | |
| 7278 | /** |
| 7279 | * Returns an array containing all the X500 principal's bytes. |
| 7280 | */ |
| 7281 | static jobjectArray getPrincipalBytes(JNIEnv* env, const STACK_OF(X509_NAME)* names) |
| 7282 | { |
| 7283 | if (names == NULL) { |
| 7284 | return NULL; |
| 7285 | } |
| 7286 | |
| 7287 | int count = sk_X509_NAME_num(names); |
| 7288 | if (count <= 0) { |
| 7289 | return NULL; |
| 7290 | } |
| 7291 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 7292 | ScopedLocalRef<jobjectArray> joa(env, env->NewObjectArray(count, byteArrayClass, NULL)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7293 | if (joa.get() == NULL) { |
| 7294 | return NULL; |
| 7295 | } |
| 7296 | |
| 7297 | for (int i = 0; i < count; i++) { |
| 7298 | X509_NAME* principal = sk_X509_NAME_value(names, i); |
| 7299 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7300 | ScopedLocalRef<jbyteArray> byteArray(env, ASN1ToByteArray<X509_NAME>(env, |
| 7301 | principal, i2d_X509_NAME)); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7302 | if (byteArray.get() == NULL) { |
| 7303 | return NULL; |
| 7304 | } |
| 7305 | env->SetObjectArrayElement(joa.get(), i, byteArray.get()); |
| 7306 | } |
| 7307 | |
| 7308 | return joa.release(); |
| 7309 | } |
| 7310 | |
| 7311 | /** |
| 7312 | * Our additional application data needed for getting synchronization right. |
| 7313 | * This maybe warrants a bit of lengthy prose: |
| 7314 | * |
| 7315 | * (1) We use a flag to reflect whether we consider the SSL connection alive. |
| 7316 | * Any read or write attempt loops will be cancelled once this flag becomes 0. |
| 7317 | * |
| 7318 | * (2) We use an int to count the number of threads that are blocked by the |
| 7319 | * underlying socket. This may be at most two (one reader and one writer), since |
| 7320 | * the Java layer ensures that no more threads will enter the native code at the |
| 7321 | * same time. |
| 7322 | * |
| 7323 | * (3) The pipe is used primarily as a means of cancelling a blocking select() |
| 7324 | * when we want to close the connection (aka "emergency button"). It is also |
| 7325 | * necessary for dealing with a possible race condition situation: There might |
| 7326 | * be cases where both threads see an SSL_ERROR_WANT_READ or |
| 7327 | * SSL_ERROR_WANT_WRITE. Both will enter a select() with the proper argument. |
| 7328 | * If one leaves the select() successfully before the other enters it, the |
| 7329 | * "success" event is already consumed and the second thread will be blocked, |
| 7330 | * possibly forever (depending on network conditions). |
| 7331 | * |
| 7332 | * The idea for solving the problem looks like this: Whenever a thread is |
| 7333 | * successful in moving around data on the network, and it knows there is |
| 7334 | * another thread stuck in a select(), it will write a byte to the pipe, waking |
| 7335 | * up the other thread. A thread that returned from select(), on the other hand, |
| 7336 | * knows whether it's been woken up by the pipe. If so, it will consume the |
| 7337 | * byte, and the original state of affairs has been restored. |
| 7338 | * |
| 7339 | * The pipe may seem like a bit of overhead, but it fits in nicely with the |
| 7340 | * other file descriptors of the select(), so there's only one condition to wait |
| 7341 | * for. |
| 7342 | * |
| 7343 | * (4) Finally, a mutex is needed to make sure that at most one thread is in |
| 7344 | * either SSL_read() or SSL_write() at any given time. This is an OpenSSL |
| 7345 | * requirement. We use the same mutex to guard the field for counting the |
| 7346 | * waiting threads. |
| 7347 | * |
| 7348 | * Note: The current implementation assumes that we don't have to deal with |
| 7349 | * problems induced by multiple cores or processors and their respective |
| 7350 | * memory caches. One possible problem is that of inconsistent views on the |
| 7351 | * "aliveAndKicking" field. This could be worked around by also enclosing all |
| 7352 | * accesses to that field inside a lock/unlock sequence of our mutex, but |
| 7353 | * currently this seems a bit like overkill. Marking volatile at the very least. |
| 7354 | * |
| 7355 | * During handshaking, additional fields are used to up-call into |
| 7356 | * Java to perform certificate verification and handshake |
| 7357 | * completion. These are also used in any renegotiation. |
| 7358 | * |
| 7359 | * (5) the JNIEnv so we can invoke the Java callback |
| 7360 | * |
| 7361 | * (6) a NativeCrypto.SSLHandshakeCallbacks instance for callbacks from native to Java |
| 7362 | * |
| 7363 | * (7) a java.io.FileDescriptor wrapper to check for socket close |
| 7364 | * |
| 7365 | * We store the NPN protocols list so we can either send it (from the server) or |
| 7366 | * select a protocol (on the client). We eagerly acquire a pointer to the array |
| 7367 | * data so the callback doesn't need to acquire resources that it cannot |
| 7368 | * release. |
| 7369 | * |
| 7370 | * Because renegotiation can be requested by the peer at any time, |
| 7371 | * care should be taken to maintain an appropriate JNIEnv on any |
| 7372 | * downcall to openssl since it could result in an upcall to Java. The |
| 7373 | * current code does try to cover these cases by conditionally setting |
| 7374 | * the JNIEnv on calls that can read and write to the SSL such as |
| 7375 | * SSL_do_handshake, SSL_read, SSL_write, and SSL_shutdown. |
| 7376 | * |
| 7377 | * Finally, we have two emphemeral keys setup by OpenSSL callbacks: |
| 7378 | * |
| 7379 | * (8) a set of ephemeral RSA keys that is lazily generated if a peer |
| 7380 | * wants to use an exportable RSA cipher suite. |
| 7381 | * |
| 7382 | * (9) a set of ephemeral EC keys that is lazily generated if a peer |
| 7383 | * wants to use an TLS_ECDHE_* cipher suite. |
| 7384 | * |
| 7385 | */ |
| 7386 | class AppData { |
| 7387 | public: |
| 7388 | volatile int aliveAndKicking; |
| 7389 | int waitingThreads; |
| 7390 | int fdsEmergency[2]; |
| 7391 | MUTEX_TYPE mutex; |
| 7392 | JNIEnv* env; |
| 7393 | jobject sslHandshakeCallbacks; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7394 | jbyteArray npnProtocolsArray; |
| 7395 | jbyte* npnProtocolsData; |
| 7396 | size_t npnProtocolsLength; |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7397 | jbyteArray alpnProtocolsArray; |
| 7398 | jbyte* alpnProtocolsData; |
| 7399 | size_t alpnProtocolsLength; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7400 | Unique_RSA ephemeralRsa; |
| 7401 | Unique_EC_KEY ephemeralEc; |
| 7402 | |
| 7403 | /** |
| 7404 | * Creates the application data context for the SSL*. |
| 7405 | */ |
| 7406 | public: |
| 7407 | static AppData* create() { |
| 7408 | UniquePtr<AppData> appData(new AppData()); |
| 7409 | if (pipe(appData.get()->fdsEmergency) == -1) { |
| 7410 | ALOGE("AppData::create pipe(2) failed: %s", strerror(errno)); |
| 7411 | return NULL; |
| 7412 | } |
| 7413 | if (!setBlocking(appData.get()->fdsEmergency[0], false)) { |
| 7414 | ALOGE("AppData::create fcntl(2) failed: %s", strerror(errno)); |
| 7415 | return NULL; |
| 7416 | } |
| 7417 | if (MUTEX_SETUP(appData.get()->mutex) == -1) { |
| 7418 | ALOGE("pthread_mutex_init(3) failed: %s", strerror(errno)); |
| 7419 | return NULL; |
| 7420 | } |
| 7421 | return appData.release(); |
| 7422 | } |
| 7423 | |
| 7424 | ~AppData() { |
| 7425 | aliveAndKicking = 0; |
| 7426 | if (fdsEmergency[0] != -1) { |
| 7427 | close(fdsEmergency[0]); |
| 7428 | } |
| 7429 | if (fdsEmergency[1] != -1) { |
| 7430 | close(fdsEmergency[1]); |
| 7431 | } |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 7432 | clearCallbackState(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7433 | MUTEX_CLEANUP(mutex); |
| 7434 | } |
| 7435 | |
| 7436 | private: |
| 7437 | AppData() : |
| 7438 | aliveAndKicking(1), |
| 7439 | waitingThreads(0), |
| 7440 | env(NULL), |
| 7441 | sslHandshakeCallbacks(NULL), |
| 7442 | npnProtocolsArray(NULL), |
| 7443 | npnProtocolsData(NULL), |
| 7444 | npnProtocolsLength(-1), |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7445 | alpnProtocolsArray(NULL), |
| 7446 | alpnProtocolsData(NULL), |
| 7447 | alpnProtocolsLength(-1), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7448 | ephemeralRsa(NULL), |
| 7449 | ephemeralEc(NULL) { |
| 7450 | fdsEmergency[0] = -1; |
| 7451 | fdsEmergency[1] = -1; |
| 7452 | } |
| 7453 | |
| 7454 | public: |
| 7455 | /** |
| 7456 | * Used to set the SSL-to-Java callback state before each SSL_* |
| 7457 | * call that may result in a callback. It should be cleared after |
| 7458 | * the operation returns with clearCallbackState. |
| 7459 | * |
| 7460 | * @param env The JNIEnv |
| 7461 | * @param shc The SSLHandshakeCallbacks |
| 7462 | * @param fd The FileDescriptor |
| 7463 | * @param npnProtocols NPN protocols so that they may be advertised (by the |
| 7464 | * server) or selected (by the client). Has no effect |
| 7465 | * unless NPN is enabled. |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7466 | * @param alpnProtocols ALPN protocols so that they may be advertised (by the |
| 7467 | * server) or selected (by the client). Passing non-NULL |
| 7468 | * enables ALPN. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7469 | */ |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7470 | bool setCallbackState(JNIEnv* e, jobject shc, jobject fd, jbyteArray npnProtocols, |
| 7471 | jbyteArray alpnProtocols) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7472 | UniquePtr<NetFd> netFd; |
| 7473 | if (fd != NULL) { |
| 7474 | netFd.reset(new NetFd(e, fd)); |
| 7475 | if (netFd->isClosed()) { |
Kenny Root | 81c6667 | 2014-05-19 12:26:16 -0700 | [diff] [blame] | 7476 | JNI_TRACE("appData=%p setCallbackState => netFd->isClosed() == true", this); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7477 | return false; |
| 7478 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7479 | } |
| 7480 | env = e; |
| 7481 | sslHandshakeCallbacks = shc; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7482 | if (npnProtocols != NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7483 | npnProtocolsData = e->GetByteArrayElements(npnProtocols, NULL); |
| 7484 | if (npnProtocolsData == NULL) { |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 7485 | clearCallbackState(); |
Kenny Root | 81c6667 | 2014-05-19 12:26:16 -0700 | [diff] [blame] | 7486 | JNI_TRACE("appData=%p setCallbackState => npnProtocolsData == NULL", this); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7487 | return false; |
| 7488 | } |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 7489 | npnProtocolsArray = npnProtocols; |
| 7490 | npnProtocolsLength = e->GetArrayLength(npnProtocols); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7491 | } |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7492 | if (alpnProtocols != NULL) { |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7493 | alpnProtocolsData = e->GetByteArrayElements(alpnProtocols, NULL); |
| 7494 | if (alpnProtocolsData == NULL) { |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 7495 | clearCallbackState(); |
Kenny Root | 81c6667 | 2014-05-19 12:26:16 -0700 | [diff] [blame] | 7496 | JNI_TRACE("appData=%p setCallbackState => alpnProtocolsData == NULL", this); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7497 | return false; |
| 7498 | } |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 7499 | alpnProtocolsArray = alpnProtocols; |
| 7500 | alpnProtocolsLength = e->GetArrayLength(alpnProtocols); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7501 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7502 | return true; |
| 7503 | } |
| 7504 | |
| 7505 | void clearCallbackState() { |
| 7506 | sslHandshakeCallbacks = NULL; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7507 | if (npnProtocolsArray != NULL) { |
| 7508 | env->ReleaseByteArrayElements(npnProtocolsArray, npnProtocolsData, JNI_ABORT); |
| 7509 | npnProtocolsArray = NULL; |
| 7510 | npnProtocolsData = NULL; |
| 7511 | npnProtocolsLength = -1; |
| 7512 | } |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 7513 | if (alpnProtocolsArray != NULL) { |
| 7514 | env->ReleaseByteArrayElements(alpnProtocolsArray, alpnProtocolsData, JNI_ABORT); |
| 7515 | alpnProtocolsArray = NULL; |
| 7516 | alpnProtocolsData = NULL; |
| 7517 | alpnProtocolsLength = -1; |
| 7518 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7519 | env = NULL; |
| 7520 | } |
| 7521 | |
| 7522 | }; |
| 7523 | |
| 7524 | /** |
| 7525 | * Dark magic helper function that checks, for a given SSL session, whether it |
| 7526 | * can SSL_read() or SSL_write() without blocking. Takes into account any |
| 7527 | * concurrent attempts to close the SSLSocket from the Java side. This is |
| 7528 | * needed to get rid of the hangs that occur when thread #1 closes the SSLSocket |
| 7529 | * while thread #2 is sitting in a blocking read or write. The type argument |
| 7530 | * specifies whether we are waiting for readability or writability. It expects |
| 7531 | * to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we |
| 7532 | * only need to wait in case one of these problems occurs. |
| 7533 | * |
| 7534 | * @param env |
| 7535 | * @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE |
| 7536 | * @param fdObject The FileDescriptor, since appData->fileDescriptor should be NULL |
| 7537 | * @param appData The application data structure with mutex info etc. |
| 7538 | * @param timeout_millis The timeout value for select call, with the special value |
| 7539 | * 0 meaning no timeout at all (wait indefinitely). Note: This is |
| 7540 | * the Java semantics of the timeout value, not the usual |
| 7541 | * select() semantics. |
| 7542 | * @return The result of the inner select() call, |
| 7543 | * THROW_SOCKETEXCEPTION if a SocketException was thrown, -1 on |
| 7544 | * additional errors |
| 7545 | */ |
| 7546 | static int sslSelect(JNIEnv* env, int type, jobject fdObject, AppData* appData, int timeout_millis) { |
| 7547 | // This loop is an expanded version of the NET_FAILURE_RETRY |
| 7548 | // macro. It cannot simply be used in this case because select |
| 7549 | // cannot be restarted without recreating the fd_sets and timeout |
| 7550 | // structure. |
| 7551 | int result; |
| 7552 | fd_set rfds; |
| 7553 | fd_set wfds; |
| 7554 | do { |
| 7555 | NetFd fd(env, fdObject); |
| 7556 | if (fd.isClosed()) { |
| 7557 | result = THROWN_EXCEPTION; |
| 7558 | break; |
| 7559 | } |
| 7560 | int intFd = fd.get(); |
| 7561 | JNI_TRACE("sslSelect type=%s fd=%d appData=%p timeout_millis=%d", |
| 7562 | (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", intFd, appData, timeout_millis); |
| 7563 | |
| 7564 | FD_ZERO(&rfds); |
| 7565 | FD_ZERO(&wfds); |
| 7566 | |
| 7567 | if (type == SSL_ERROR_WANT_READ) { |
| 7568 | FD_SET(intFd, &rfds); |
| 7569 | } else { |
| 7570 | FD_SET(intFd, &wfds); |
| 7571 | } |
| 7572 | |
| 7573 | FD_SET(appData->fdsEmergency[0], &rfds); |
| 7574 | |
| 7575 | int maxFd = (intFd > appData->fdsEmergency[0]) ? intFd : appData->fdsEmergency[0]; |
| 7576 | |
| 7577 | // Build a struct for the timeout data if we actually want a timeout. |
| 7578 | timeval tv; |
| 7579 | timeval* ptv; |
| 7580 | if (timeout_millis > 0) { |
| 7581 | tv.tv_sec = timeout_millis / 1000; |
| 7582 | tv.tv_usec = (timeout_millis % 1000) * 1000; |
| 7583 | ptv = &tv; |
| 7584 | } else { |
| 7585 | ptv = NULL; |
| 7586 | } |
| 7587 | |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 7588 | #ifndef CONSCRYPT_UNBUNDLED |
Neil Fuller | 798f944 | 2014-04-11 17:26:59 +0100 | [diff] [blame] | 7589 | AsynchronousCloseMonitor monitor(intFd); |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 7590 | #else |
| 7591 | CompatibilityCloseMonitor monitor(intFd); |
| 7592 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7593 | result = select(maxFd + 1, &rfds, &wfds, NULL, ptv); |
| 7594 | JNI_TRACE("sslSelect %s fd=%d appData=%p timeout_millis=%d => %d", |
| 7595 | (type == SSL_ERROR_WANT_READ) ? "READ" : "WRITE", |
| 7596 | fd.get(), appData, timeout_millis, result); |
| 7597 | if (result == -1) { |
| 7598 | if (fd.isClosed()) { |
| 7599 | result = THROWN_EXCEPTION; |
| 7600 | break; |
| 7601 | } |
| 7602 | if (errno != EINTR) { |
| 7603 | break; |
| 7604 | } |
| 7605 | } |
| 7606 | } while (result == -1); |
| 7607 | |
| 7608 | if (MUTEX_LOCK(appData->mutex) == -1) { |
| 7609 | return -1; |
| 7610 | } |
| 7611 | |
| 7612 | if (result > 0) { |
| 7613 | // We have been woken up by a token in the emergency pipe. We |
| 7614 | // can't be sure the token is still in the pipe at this point |
| 7615 | // because it could have already been read by the thread that |
| 7616 | // originally wrote it if it entered sslSelect and acquired |
| 7617 | // the mutex before we did. Thus we cannot safely read from |
| 7618 | // the pipe in a blocking way (so we make the pipe |
| 7619 | // non-blocking at creation). |
| 7620 | if (FD_ISSET(appData->fdsEmergency[0], &rfds)) { |
| 7621 | char token; |
| 7622 | do { |
Elliott Hughes | 57ad13f | 2015-05-12 21:16:12 -0700 | [diff] [blame] | 7623 | (void) read(appData->fdsEmergency[0], &token, 1); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7624 | } while (errno == EINTR); |
| 7625 | } |
| 7626 | } |
| 7627 | |
| 7628 | // Tell the world that there is now one thread less waiting for the |
| 7629 | // underlying network. |
| 7630 | appData->waitingThreads--; |
| 7631 | |
| 7632 | MUTEX_UNLOCK(appData->mutex); |
| 7633 | |
| 7634 | return result; |
| 7635 | } |
| 7636 | |
| 7637 | /** |
| 7638 | * Helper function that wakes up a thread blocked in select(), in case there is |
| 7639 | * one. Is being called by sslRead() and sslWrite() as well as by JNI glue |
| 7640 | * before closing the connection. |
| 7641 | * |
| 7642 | * @param data The application data structure with mutex info etc. |
| 7643 | */ |
| 7644 | static void sslNotify(AppData* appData) { |
| 7645 | // Write a byte to the emergency pipe, so a concurrent select() can return. |
| 7646 | // Note we have to restore the errno of the original system call, since the |
| 7647 | // caller relies on it for generating error messages. |
| 7648 | int errnoBackup = errno; |
| 7649 | char token = '*'; |
| 7650 | do { |
| 7651 | errno = 0; |
Elliott Hughes | 57ad13f | 2015-05-12 21:16:12 -0700 | [diff] [blame] | 7652 | (void) write(appData->fdsEmergency[1], &token, 1); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7653 | } while (errno == EINTR); |
| 7654 | errno = errnoBackup; |
| 7655 | } |
| 7656 | |
| 7657 | static AppData* toAppData(const SSL* ssl) { |
| 7658 | return reinterpret_cast<AppData*>(SSL_get_app_data(ssl)); |
| 7659 | } |
| 7660 | |
| 7661 | /** |
| 7662 | * Verify the X509 certificate via SSL_CTX_set_cert_verify_callback |
| 7663 | */ |
| 7664 | static int cert_verify_callback(X509_STORE_CTX* x509_store_ctx, void* arg __attribute__ ((unused))) |
| 7665 | { |
| 7666 | /* Get the correct index to the SSLobject stored into X509_STORE_CTX. */ |
| 7667 | SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(x509_store_ctx, |
| 7668 | SSL_get_ex_data_X509_STORE_CTX_idx())); |
| 7669 | JNI_TRACE("ssl=%p cert_verify_callback x509_store_ctx=%p arg=%p", ssl, x509_store_ctx, arg); |
| 7670 | |
| 7671 | AppData* appData = toAppData(ssl); |
| 7672 | JNIEnv* env = appData->env; |
| 7673 | if (env == NULL) { |
| 7674 | ALOGE("AppData->env missing in cert_verify_callback"); |
| 7675 | JNI_TRACE("ssl=%p cert_verify_callback => 0", ssl); |
| 7676 | return 0; |
| 7677 | } |
| 7678 | jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; |
| 7679 | |
| 7680 | jclass cls = env->GetObjectClass(sslHandshakeCallbacks); |
| 7681 | jmethodID methodID |
Kenny Root | d2cced8 | 2014-03-20 15:03:28 -0700 | [diff] [blame] | 7682 | = env->GetMethodID(cls, "verifyCertificateChain", "(J[JLjava/lang/String;)V"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7683 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 7684 | jlongArray refArray = getCertificateRefs(env, x509_store_ctx->untrusted); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7685 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7686 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7687 | const char* authMethod = SSL_authentication_method(ssl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7688 | #else |
| 7689 | const SSL_CIPHER *cipher = ssl->s3->tmp.new_cipher; |
| 7690 | const char *authMethod = SSL_CIPHER_get_kx_name(cipher); |
| 7691 | #endif |
| 7692 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7693 | JNI_TRACE("ssl=%p cert_verify_callback calling verifyCertificateChain authMethod=%s", |
| 7694 | ssl, authMethod); |
| 7695 | jstring authMethodString = env->NewStringUTF(authMethod); |
Kenny Root | d2cced8 | 2014-03-20 15:03:28 -0700 | [diff] [blame] | 7696 | env->CallVoidMethod(sslHandshakeCallbacks, methodID, |
| 7697 | static_cast<jlong>(reinterpret_cast<uintptr_t>(SSL_get1_session(ssl))), refArray, |
| 7698 | authMethodString); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7699 | |
| 7700 | int result = (env->ExceptionCheck()) ? 0 : 1; |
| 7701 | JNI_TRACE("ssl=%p cert_verify_callback => %d", ssl, result); |
| 7702 | return result; |
| 7703 | } |
| 7704 | |
| 7705 | /** |
| 7706 | * Call back to watch for handshake to be completed. This is necessary |
| 7707 | * for SSL_MODE_HANDSHAKE_CUTTHROUGH support, since SSL_do_handshake |
| 7708 | * returns before the handshake is completed in this case. |
| 7709 | */ |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7710 | static void info_callback(const SSL* ssl, int where, int ret) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7711 | JNI_TRACE("ssl=%p info_callback where=0x%x ret=%d", ssl, where, ret); |
| 7712 | #ifdef WITH_JNI_TRACE |
| 7713 | info_callback_LOG(ssl, where, ret); |
| 7714 | #endif |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7715 | if (!(where & SSL_CB_HANDSHAKE_DONE) && !(where & SSL_CB_HANDSHAKE_START)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7716 | JNI_TRACE("ssl=%p info_callback ignored", ssl); |
| 7717 | return; |
| 7718 | } |
| 7719 | |
| 7720 | AppData* appData = toAppData(ssl); |
| 7721 | JNIEnv* env = appData->env; |
| 7722 | if (env == NULL) { |
| 7723 | ALOGE("AppData->env missing in info_callback"); |
| 7724 | JNI_TRACE("ssl=%p info_callback env error", ssl); |
| 7725 | return; |
| 7726 | } |
| 7727 | if (env->ExceptionCheck()) { |
| 7728 | JNI_TRACE("ssl=%p info_callback already pending exception", ssl); |
| 7729 | return; |
| 7730 | } |
| 7731 | |
| 7732 | jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; |
| 7733 | |
| 7734 | jclass cls = env->GetObjectClass(sslHandshakeCallbacks); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7735 | jmethodID methodID = env->GetMethodID(cls, "onSSLStateChange", "(JII)V"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7736 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 7737 | JNI_TRACE("ssl=%p info_callback calling onSSLStateChange", ssl); |
| 7738 | env->CallVoidMethod(sslHandshakeCallbacks, methodID, reinterpret_cast<jlong>(ssl), where, ret); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7739 | |
| 7740 | if (env->ExceptionCheck()) { |
| 7741 | JNI_TRACE("ssl=%p info_callback exception", ssl); |
| 7742 | } |
| 7743 | JNI_TRACE("ssl=%p info_callback completed", ssl); |
| 7744 | } |
| 7745 | |
| 7746 | /** |
| 7747 | * Call back to ask for a client certificate. There are three possible exit codes: |
| 7748 | * |
| 7749 | * 1 is success. x509Out and pkeyOut should point to the correct private key and certificate. |
| 7750 | * 0 is unable to find key. x509Out and pkeyOut should be NULL. |
| 7751 | * -1 is error and it doesn't matter what x509Out and pkeyOut are. |
| 7752 | */ |
| 7753 | static int client_cert_cb(SSL* ssl, X509** x509Out, EVP_PKEY** pkeyOut) { |
| 7754 | JNI_TRACE("ssl=%p client_cert_cb x509Out=%p pkeyOut=%p", ssl, x509Out, pkeyOut); |
| 7755 | |
| 7756 | /* Clear output of key and certificate in case of early exit due to error. */ |
| 7757 | *x509Out = NULL; |
| 7758 | *pkeyOut = NULL; |
| 7759 | |
| 7760 | AppData* appData = toAppData(ssl); |
| 7761 | JNIEnv* env = appData->env; |
| 7762 | if (env == NULL) { |
| 7763 | ALOGE("AppData->env missing in client_cert_cb"); |
| 7764 | JNI_TRACE("ssl=%p client_cert_cb env error => 0", ssl); |
| 7765 | return 0; |
| 7766 | } |
| 7767 | if (env->ExceptionCheck()) { |
| 7768 | JNI_TRACE("ssl=%p client_cert_cb already pending exception => 0", ssl); |
| 7769 | return -1; |
| 7770 | } |
| 7771 | jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; |
| 7772 | |
| 7773 | jclass cls = env->GetObjectClass(sslHandshakeCallbacks); |
| 7774 | jmethodID methodID |
| 7775 | = env->GetMethodID(cls, "clientCertificateRequested", "([B[[B)V"); |
| 7776 | |
| 7777 | // Call Java callback which can use SSL_use_certificate and SSL_use_PrivateKey to set values |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7778 | const char* ctype = NULL; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7779 | #if !defined(OPENSSL_IS_BORINGSSL) |
Adam Langley | ca34114 | 2014-12-11 17:26:18 -0800 | [diff] [blame] | 7780 | char ssl2_ctype = SSL3_CT_RSA_SIGN; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7781 | int ctype_num = 0; |
| 7782 | jobjectArray issuers = NULL; |
| 7783 | switch (ssl->version) { |
| 7784 | case SSL2_VERSION: |
| 7785 | ctype = &ssl2_ctype; |
| 7786 | ctype_num = 1; |
| 7787 | break; |
| 7788 | case SSL3_VERSION: |
| 7789 | case TLS1_VERSION: |
| 7790 | case TLS1_1_VERSION: |
| 7791 | case TLS1_2_VERSION: |
| 7792 | case DTLS1_VERSION: |
| 7793 | ctype = ssl->s3->tmp.ctype; |
| 7794 | ctype_num = ssl->s3->tmp.ctype_num; |
| 7795 | issuers = getPrincipalBytes(env, ssl->s3->tmp.ca_names); |
| 7796 | break; |
| 7797 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 7798 | #else |
| 7799 | int ctype_num = SSL_get0_certificate_types(ssl, &ctype); |
| 7800 | jobjectArray issuers = getPrincipalBytes(env, ssl->s3->tmp.ca_names); |
| 7801 | #endif |
| 7802 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7803 | #ifdef WITH_JNI_TRACE |
| 7804 | for (int i = 0; i < ctype_num; i++) { |
| 7805 | JNI_TRACE("ssl=%p clientCertificateRequested keyTypes[%d]=%d", ssl, i, ctype[i]); |
| 7806 | } |
| 7807 | #endif |
| 7808 | |
| 7809 | jbyteArray keyTypes = env->NewByteArray(ctype_num); |
| 7810 | if (keyTypes == NULL) { |
| 7811 | JNI_TRACE("ssl=%p client_cert_cb bytes == null => 0", ssl); |
| 7812 | return 0; |
| 7813 | } |
| 7814 | env->SetByteArrayRegion(keyTypes, 0, ctype_num, reinterpret_cast<const jbyte*>(ctype)); |
| 7815 | |
| 7816 | JNI_TRACE("ssl=%p clientCertificateRequested calling clientCertificateRequested " |
| 7817 | "keyTypes=%p issuers=%p", ssl, keyTypes, issuers); |
| 7818 | env->CallVoidMethod(sslHandshakeCallbacks, methodID, keyTypes, issuers); |
| 7819 | |
| 7820 | if (env->ExceptionCheck()) { |
| 7821 | JNI_TRACE("ssl=%p client_cert_cb exception => 0", ssl); |
| 7822 | return -1; |
| 7823 | } |
| 7824 | |
| 7825 | // Check for values set from Java |
| 7826 | X509* certificate = SSL_get_certificate(ssl); |
| 7827 | EVP_PKEY* privatekey = SSL_get_privatekey(ssl); |
| 7828 | int result = 0; |
| 7829 | if (certificate != NULL && privatekey != NULL) { |
| 7830 | *x509Out = certificate; |
| 7831 | *pkeyOut = privatekey; |
| 7832 | result = 1; |
Kenny Root | db88d05 | 2013-06-05 10:01:27 -0700 | [diff] [blame] | 7833 | } else { |
| 7834 | // Some error conditions return NULL, so make sure it doesn't linger. |
| 7835 | freeOpenSslErrorState(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7836 | } |
| 7837 | JNI_TRACE("ssl=%p client_cert_cb => *x509=%p *pkey=%p %d", ssl, *x509Out, *pkeyOut, result); |
| 7838 | return result; |
| 7839 | } |
| 7840 | |
Alex Klyubin | 01cce89 | 2014-05-09 03:44:42 -0700 | [diff] [blame] | 7841 | /** |
| 7842 | * Pre-Shared Key (PSK) client callback. |
| 7843 | */ |
| 7844 | static unsigned int psk_client_callback(SSL* ssl, const char *hint, |
| 7845 | char *identity, unsigned int max_identity_len, |
| 7846 | unsigned char *psk, unsigned int max_psk_len) { |
| 7847 | JNI_TRACE("ssl=%p psk_client_callback", ssl); |
| 7848 | |
| 7849 | AppData* appData = toAppData(ssl); |
| 7850 | JNIEnv* env = appData->env; |
| 7851 | if (env == NULL) { |
| 7852 | ALOGE("AppData->env missing in psk_client_callback"); |
| 7853 | JNI_TRACE("ssl=%p psk_client_callback env error", ssl); |
| 7854 | return 0; |
| 7855 | } |
| 7856 | if (env->ExceptionCheck()) { |
| 7857 | JNI_TRACE("ssl=%p psk_client_callback already pending exception", ssl); |
| 7858 | return 0; |
| 7859 | } |
| 7860 | |
| 7861 | jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; |
| 7862 | jclass cls = env->GetObjectClass(sslHandshakeCallbacks); |
| 7863 | jmethodID methodID = |
| 7864 | env->GetMethodID(cls, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I"); |
| 7865 | JNI_TRACE("ssl=%p psk_client_callback calling clientPSKKeyRequested", ssl); |
| 7866 | ScopedLocalRef<jstring> identityHintJava( |
| 7867 | env, |
| 7868 | (hint != NULL) ? env->NewStringUTF(hint) : NULL); |
| 7869 | ScopedLocalRef<jbyteArray> identityJava(env, env->NewByteArray(max_identity_len)); |
| 7870 | if (identityJava.get() == NULL) { |
| 7871 | JNI_TRACE("ssl=%p psk_client_callback failed to allocate identity bufffer", ssl); |
| 7872 | return 0; |
| 7873 | } |
| 7874 | ScopedLocalRef<jbyteArray> keyJava(env, env->NewByteArray(max_psk_len)); |
| 7875 | if (keyJava.get() == NULL) { |
| 7876 | JNI_TRACE("ssl=%p psk_client_callback failed to allocate key bufffer", ssl); |
| 7877 | return 0; |
| 7878 | } |
| 7879 | jint keyLen = env->CallIntMethod(sslHandshakeCallbacks, methodID, |
| 7880 | identityHintJava.get(), identityJava.get(), keyJava.get()); |
| 7881 | if (env->ExceptionCheck()) { |
| 7882 | JNI_TRACE("ssl=%p psk_client_callback exception", ssl); |
| 7883 | return 0; |
| 7884 | } |
| 7885 | if (keyLen <= 0) { |
| 7886 | JNI_TRACE("ssl=%p psk_client_callback failed to get key", ssl); |
| 7887 | return 0; |
| 7888 | } else if ((unsigned int) keyLen > max_psk_len) { |
| 7889 | JNI_TRACE("ssl=%p psk_client_callback got key which is too long", ssl); |
| 7890 | return 0; |
| 7891 | } |
| 7892 | ScopedByteArrayRO keyJavaRo(env, keyJava.get()); |
| 7893 | if (keyJavaRo.get() == NULL) { |
| 7894 | JNI_TRACE("ssl=%p psk_client_callback failed to get key bytes", ssl); |
| 7895 | return 0; |
| 7896 | } |
| 7897 | memcpy(psk, keyJavaRo.get(), keyLen); |
| 7898 | |
| 7899 | ScopedByteArrayRO identityJavaRo(env, identityJava.get()); |
| 7900 | if (identityJavaRo.get() == NULL) { |
| 7901 | JNI_TRACE("ssl=%p psk_client_callback failed to get identity bytes", ssl); |
| 7902 | return 0; |
| 7903 | } |
| 7904 | memcpy(identity, identityJavaRo.get(), max_identity_len); |
| 7905 | |
| 7906 | JNI_TRACE("ssl=%p psk_client_callback completed", ssl); |
| 7907 | return keyLen; |
| 7908 | } |
| 7909 | |
| 7910 | /** |
| 7911 | * Pre-Shared Key (PSK) server callback. |
| 7912 | */ |
| 7913 | static unsigned int psk_server_callback(SSL* ssl, const char *identity, |
| 7914 | unsigned char *psk, unsigned int max_psk_len) { |
| 7915 | JNI_TRACE("ssl=%p psk_server_callback", ssl); |
| 7916 | |
| 7917 | AppData* appData = toAppData(ssl); |
| 7918 | JNIEnv* env = appData->env; |
| 7919 | if (env == NULL) { |
| 7920 | ALOGE("AppData->env missing in psk_server_callback"); |
| 7921 | JNI_TRACE("ssl=%p psk_server_callback env error", ssl); |
| 7922 | return 0; |
| 7923 | } |
| 7924 | if (env->ExceptionCheck()) { |
| 7925 | JNI_TRACE("ssl=%p psk_server_callback already pending exception", ssl); |
| 7926 | return 0; |
| 7927 | } |
| 7928 | |
| 7929 | jobject sslHandshakeCallbacks = appData->sslHandshakeCallbacks; |
| 7930 | jclass cls = env->GetObjectClass(sslHandshakeCallbacks); |
| 7931 | jmethodID methodID = env->GetMethodID( |
| 7932 | cls, "serverPSKKeyRequested", "(Ljava/lang/String;Ljava/lang/String;[B)I"); |
| 7933 | JNI_TRACE("ssl=%p psk_server_callback calling serverPSKKeyRequested", ssl); |
| 7934 | const char* identityHint = SSL_get_psk_identity_hint(ssl); |
| 7935 | // identityHint = NULL; |
| 7936 | // identity = NULL; |
| 7937 | ScopedLocalRef<jstring> identityHintJava( |
| 7938 | env, |
| 7939 | (identityHint != NULL) ? env->NewStringUTF(identityHint) : NULL); |
| 7940 | ScopedLocalRef<jstring> identityJava( |
| 7941 | env, |
| 7942 | (identity != NULL) ? env->NewStringUTF(identity) : NULL); |
| 7943 | ScopedLocalRef<jbyteArray> keyJava(env, env->NewByteArray(max_psk_len)); |
| 7944 | if (keyJava.get() == NULL) { |
| 7945 | JNI_TRACE("ssl=%p psk_server_callback failed to allocate key bufffer", ssl); |
| 7946 | return 0; |
| 7947 | } |
| 7948 | jint keyLen = env->CallIntMethod(sslHandshakeCallbacks, methodID, |
| 7949 | identityHintJava.get(), identityJava.get(), keyJava.get()); |
| 7950 | if (env->ExceptionCheck()) { |
| 7951 | JNI_TRACE("ssl=%p psk_server_callback exception", ssl); |
| 7952 | return 0; |
| 7953 | } |
| 7954 | if (keyLen <= 0) { |
| 7955 | JNI_TRACE("ssl=%p psk_server_callback failed to get key", ssl); |
| 7956 | return 0; |
| 7957 | } else if ((unsigned int) keyLen > max_psk_len) { |
| 7958 | JNI_TRACE("ssl=%p psk_server_callback got key which is too long", ssl); |
| 7959 | return 0; |
| 7960 | } |
| 7961 | ScopedByteArrayRO keyJavaRo(env, keyJava.get()); |
| 7962 | if (keyJavaRo.get() == NULL) { |
| 7963 | JNI_TRACE("ssl=%p psk_server_callback failed to get key bytes", ssl); |
| 7964 | return 0; |
| 7965 | } |
| 7966 | memcpy(psk, keyJavaRo.get(), keyLen); |
| 7967 | |
| 7968 | JNI_TRACE("ssl=%p psk_server_callback completed", ssl); |
| 7969 | return keyLen; |
| 7970 | } |
| 7971 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 7972 | static RSA* rsaGenerateKey(int keylength) { |
| 7973 | Unique_BIGNUM bn(BN_new()); |
| 7974 | if (bn.get() == NULL) { |
| 7975 | return NULL; |
| 7976 | } |
| 7977 | int setWordResult = BN_set_word(bn.get(), RSA_F4); |
| 7978 | if (setWordResult != 1) { |
| 7979 | return NULL; |
| 7980 | } |
| 7981 | Unique_RSA rsa(RSA_new()); |
| 7982 | if (rsa.get() == NULL) { |
| 7983 | return NULL; |
| 7984 | } |
| 7985 | int generateResult = RSA_generate_key_ex(rsa.get(), keylength, bn.get(), NULL); |
| 7986 | if (generateResult != 1) { |
| 7987 | return NULL; |
| 7988 | } |
| 7989 | return rsa.release(); |
| 7990 | } |
| 7991 | |
| 7992 | /** |
| 7993 | * Call back to ask for an ephemeral RSA key for SSL_RSA_EXPORT_WITH_RC4_40_MD5 (aka EXP-RC4-MD5) |
| 7994 | */ |
| 7995 | static RSA* tmp_rsa_callback(SSL* ssl __attribute__ ((unused)), |
| 7996 | int is_export __attribute__ ((unused)), |
| 7997 | int keylength) { |
| 7998 | JNI_TRACE("ssl=%p tmp_rsa_callback is_export=%d keylength=%d", ssl, is_export, keylength); |
| 7999 | |
| 8000 | AppData* appData = toAppData(ssl); |
| 8001 | if (appData->ephemeralRsa.get() == NULL) { |
| 8002 | JNI_TRACE("ssl=%p tmp_rsa_callback generating ephemeral RSA key", ssl); |
| 8003 | appData->ephemeralRsa.reset(rsaGenerateKey(keylength)); |
| 8004 | } |
| 8005 | JNI_TRACE("ssl=%p tmp_rsa_callback => %p", ssl, appData->ephemeralRsa.get()); |
| 8006 | return appData->ephemeralRsa.get(); |
| 8007 | } |
| 8008 | |
| 8009 | static DH* dhGenerateParameters(int keylength) { |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8010 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8011 | /* |
| 8012 | * The SSL_CTX_set_tmp_dh_callback(3SSL) man page discusses two |
| 8013 | * different options for generating DH keys. One is generating the |
| 8014 | * keys using a single set of DH parameters. However, generating |
| 8015 | * DH parameters is slow enough (minutes) that they suggest doing |
| 8016 | * it once at install time. The other is to generate DH keys from |
| 8017 | * DSA parameters. Generating DSA parameters is faster than DH |
| 8018 | * parameters, but to prevent small subgroup attacks, they needed |
| 8019 | * to be regenerated for each set of DH keys. Setting the |
| 8020 | * SSL_OP_SINGLE_DH_USE option make sure OpenSSL will call back |
| 8021 | * for new DH parameters every type it needs to generate DH keys. |
| 8022 | */ |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8023 | |
| 8024 | // Fast path but must have SSL_OP_SINGLE_DH_USE set |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8025 | Unique_DSA dsa(DSA_new()); |
| 8026 | if (!DSA_generate_parameters_ex(dsa.get(), keylength, NULL, 0, NULL, NULL, NULL)) { |
| 8027 | return NULL; |
| 8028 | } |
| 8029 | DH* dh = DSA_dup_DH(dsa.get()); |
| 8030 | return dh; |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8031 | #else |
| 8032 | /* At the time of writing, OpenSSL and BoringSSL are hard coded to request |
| 8033 | * a 1024-bit DH. */ |
| 8034 | if (keylength <= 1024) { |
| 8035 | return DH_get_1024_160(NULL); |
| 8036 | } |
| 8037 | |
| 8038 | if (keylength <= 2048) { |
| 8039 | return DH_get_2048_224(NULL); |
| 8040 | } |
| 8041 | |
| 8042 | /* In the case of a large request, return the strongest DH group that |
| 8043 | * we have predefined. Generating a group takes far too long to be |
| 8044 | * reasonable. */ |
| 8045 | return DH_get_2048_256(NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8046 | #endif |
| 8047 | } |
| 8048 | |
| 8049 | /** |
| 8050 | * Call back to ask for Diffie-Hellman parameters |
| 8051 | */ |
| 8052 | static DH* tmp_dh_callback(SSL* ssl __attribute__ ((unused)), |
| 8053 | int is_export __attribute__ ((unused)), |
| 8054 | int keylength) { |
| 8055 | JNI_TRACE("ssl=%p tmp_dh_callback is_export=%d keylength=%d", ssl, is_export, keylength); |
| 8056 | DH* tmp_dh = dhGenerateParameters(keylength); |
| 8057 | JNI_TRACE("ssl=%p tmp_dh_callback => %p", ssl, tmp_dh); |
| 8058 | return tmp_dh; |
| 8059 | } |
| 8060 | |
| 8061 | static EC_KEY* ecGenerateKey(int keylength __attribute__ ((unused))) { |
| 8062 | // TODO selected curve based on keylength |
| 8063 | Unique_EC_KEY ec(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); |
| 8064 | if (ec.get() == NULL) { |
| 8065 | return NULL; |
| 8066 | } |
| 8067 | return ec.release(); |
| 8068 | } |
| 8069 | |
| 8070 | /** |
| 8071 | * Call back to ask for an ephemeral EC key for TLS_ECDHE_* cipher suites |
| 8072 | */ |
| 8073 | static EC_KEY* tmp_ecdh_callback(SSL* ssl __attribute__ ((unused)), |
| 8074 | int is_export __attribute__ ((unused)), |
| 8075 | int keylength) { |
| 8076 | JNI_TRACE("ssl=%p tmp_ecdh_callback is_export=%d keylength=%d", ssl, is_export, keylength); |
| 8077 | AppData* appData = toAppData(ssl); |
| 8078 | if (appData->ephemeralEc.get() == NULL) { |
| 8079 | JNI_TRACE("ssl=%p tmp_ecdh_callback generating ephemeral EC key", ssl); |
| 8080 | appData->ephemeralEc.reset(ecGenerateKey(keylength)); |
| 8081 | } |
| 8082 | JNI_TRACE("ssl=%p tmp_ecdh_callback => %p", ssl, appData->ephemeralEc.get()); |
| 8083 | return appData->ephemeralEc.get(); |
| 8084 | } |
| 8085 | |
| 8086 | /* |
| 8087 | * public static native int SSL_CTX_new(); |
| 8088 | */ |
| 8089 | static jlong NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) { |
| 8090 | Unique_SSL_CTX sslCtx(SSL_CTX_new(SSLv23_method())); |
| 8091 | if (sslCtx.get() == NULL) { |
| 8092 | throwExceptionIfNecessary(env, "SSL_CTX_new"); |
| 8093 | return 0; |
| 8094 | } |
| 8095 | SSL_CTX_set_options(sslCtx.get(), |
| 8096 | SSL_OP_ALL |
| 8097 | // Note: We explicitly do not allow SSLv2 to be used. |
| 8098 | | SSL_OP_NO_SSLv2 |
| 8099 | // We also disable session tickets for better compatibility b/2682876 |
| 8100 | | SSL_OP_NO_TICKET |
| 8101 | // We also disable compression for better compatibility b/2710492 b/2710497 |
| 8102 | | SSL_OP_NO_COMPRESSION |
| 8103 | // Because dhGenerateParameters uses DSA_generate_parameters_ex |
| 8104 | | SSL_OP_SINGLE_DH_USE |
| 8105 | // Because ecGenerateParameters uses a fixed named curve |
| 8106 | | SSL_OP_SINGLE_ECDH_USE); |
| 8107 | |
| 8108 | int mode = SSL_CTX_get_mode(sslCtx.get()); |
| 8109 | /* |
| 8110 | * Turn on "partial write" mode. This means that SSL_write() will |
| 8111 | * behave like Posix write() and possibly return after only |
| 8112 | * writing a partial buffer. Note: The alternative, perhaps |
| 8113 | * surprisingly, is not that SSL_write() always does full writes |
| 8114 | * but that it will force you to retry write calls having |
| 8115 | * preserved the full state of the original call. (This is icky |
| 8116 | * and undesirable.) |
| 8117 | */ |
| 8118 | mode |= SSL_MODE_ENABLE_PARTIAL_WRITE; |
| 8119 | |
| 8120 | // Reuse empty buffers within the SSL_CTX to save memory |
| 8121 | mode |= SSL_MODE_RELEASE_BUFFERS; |
| 8122 | |
| 8123 | SSL_CTX_set_mode(sslCtx.get(), mode); |
| 8124 | |
| 8125 | SSL_CTX_set_cert_verify_callback(sslCtx.get(), cert_verify_callback, NULL); |
| 8126 | SSL_CTX_set_info_callback(sslCtx.get(), info_callback); |
| 8127 | SSL_CTX_set_client_cert_cb(sslCtx.get(), client_cert_cb); |
| 8128 | SSL_CTX_set_tmp_rsa_callback(sslCtx.get(), tmp_rsa_callback); |
| 8129 | SSL_CTX_set_tmp_dh_callback(sslCtx.get(), tmp_dh_callback); |
| 8130 | SSL_CTX_set_tmp_ecdh_callback(sslCtx.get(), tmp_ecdh_callback); |
| 8131 | |
Alex Klyubin | 69c3647 | 2014-06-13 13:51:05 -0700 | [diff] [blame] | 8132 | // When TLS Channel ID extension is used, use the new version of it. |
| 8133 | sslCtx.get()->tlsext_channel_id_enabled_new = 1; |
| 8134 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8135 | JNI_TRACE("NativeCrypto_SSL_CTX_new => %p", sslCtx.get()); |
| 8136 | return (jlong) sslCtx.release(); |
| 8137 | } |
| 8138 | |
| 8139 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8140 | * public static native void SSL_CTX_free(long ssl_ctx) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8141 | */ |
| 8142 | static void NativeCrypto_SSL_CTX_free(JNIEnv* env, |
| 8143 | jclass, jlong ssl_ctx_address) |
| 8144 | { |
| 8145 | SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); |
| 8146 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_free", ssl_ctx); |
| 8147 | if (ssl_ctx == NULL) { |
| 8148 | return; |
| 8149 | } |
| 8150 | SSL_CTX_free(ssl_ctx); |
| 8151 | } |
| 8152 | |
| 8153 | static void NativeCrypto_SSL_CTX_set_session_id_context(JNIEnv* env, jclass, |
| 8154 | jlong ssl_ctx_address, jbyteArray sid_ctx) |
| 8155 | { |
| 8156 | SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); |
| 8157 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context sid_ctx=%p", ssl_ctx, sid_ctx); |
| 8158 | if (ssl_ctx == NULL) { |
| 8159 | return; |
| 8160 | } |
| 8161 | |
| 8162 | ScopedByteArrayRO buf(env, sid_ctx); |
| 8163 | if (buf.get() == NULL) { |
| 8164 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => threw exception", ssl_ctx); |
| 8165 | return; |
| 8166 | } |
| 8167 | |
| 8168 | unsigned int length = buf.size(); |
| 8169 | if (length > SSL_MAX_SSL_SESSION_ID_LENGTH) { |
| 8170 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8171 | "length > SSL_MAX_SSL_SESSION_ID_LENGTH"); |
| 8172 | JNI_TRACE("NativeCrypto_SSL_CTX_set_session_id_context => length = %d", length); |
| 8173 | return; |
| 8174 | } |
| 8175 | const unsigned char* bytes = reinterpret_cast<const unsigned char*>(buf.get()); |
| 8176 | int result = SSL_CTX_set_session_id_context(ssl_ctx, bytes, length); |
| 8177 | if (result == 0) { |
| 8178 | throwExceptionIfNecessary(env, "NativeCrypto_SSL_CTX_set_session_id_context"); |
| 8179 | return; |
| 8180 | } |
| 8181 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_set_session_id_context => ok", ssl_ctx); |
| 8182 | } |
| 8183 | |
| 8184 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8185 | * public static native int SSL_new(long ssl_ctx) throws SSLException; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8186 | */ |
| 8187 | static jlong NativeCrypto_SSL_new(JNIEnv* env, jclass, jlong ssl_ctx_address) |
| 8188 | { |
| 8189 | SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); |
| 8190 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new", ssl_ctx); |
| 8191 | if (ssl_ctx == NULL) { |
| 8192 | return 0; |
| 8193 | } |
| 8194 | Unique_SSL ssl(SSL_new(ssl_ctx)); |
| 8195 | if (ssl.get() == NULL) { |
| 8196 | throwSSLExceptionWithSslErrors(env, NULL, SSL_ERROR_NONE, |
| 8197 | "Unable to create SSL structure"); |
| 8198 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 8199 | return 0; |
| 8200 | } |
| 8201 | |
Kenny Root | 02fb057 | 2014-03-21 13:53:46 -0700 | [diff] [blame] | 8202 | /* |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 8203 | * Create our special application data. |
| 8204 | */ |
| 8205 | AppData* appData = AppData::create(); |
| 8206 | if (appData == NULL) { |
| 8207 | throwSSLExceptionStr(env, "Unable to create application data"); |
| 8208 | freeOpenSslErrorState(); |
| 8209 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new appData => 0", ssl_ctx); |
| 8210 | return 0; |
| 8211 | } |
| 8212 | SSL_set_app_data(ssl.get(), reinterpret_cast<char*>(appData)); |
| 8213 | |
| 8214 | /* |
Kenny Root | 02fb057 | 2014-03-21 13:53:46 -0700 | [diff] [blame] | 8215 | * Java code in class OpenSSLSocketImpl does the verification. Since |
| 8216 | * the callbacks do all the verification of the chain, this flag |
| 8217 | * simply controls whether to send protocol-level alerts or not. |
| 8218 | * SSL_VERIFY_NONE means don't send alerts and anything else means send |
| 8219 | * alerts. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8220 | */ |
Kenny Root | 02fb057 | 2014-03-21 13:53:46 -0700 | [diff] [blame] | 8221 | SSL_set_verify(ssl.get(), SSL_VERIFY_PEER, NULL); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8222 | |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 8223 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => ssl=%p appData=%p", ssl_ctx, ssl.get(), appData); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8224 | return (jlong) ssl.release(); |
| 8225 | } |
| 8226 | |
| 8227 | |
| 8228 | static void NativeCrypto_SSL_enable_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address) |
| 8229 | { |
| 8230 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8231 | JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_enable_tls_channel_id", ssl); |
| 8232 | if (ssl == NULL) { |
| 8233 | return; |
| 8234 | } |
| 8235 | |
| 8236 | long ret = SSL_enable_tls_channel_id(ssl); |
| 8237 | if (ret != 1L) { |
| 8238 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8239 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error enabling Channel ID"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8240 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8241 | JNI_TRACE("ssl=%p NativeCrypto_SSL_enable_tls_channel_id => error", ssl); |
| 8242 | return; |
| 8243 | } |
| 8244 | } |
| 8245 | |
| 8246 | static jbyteArray NativeCrypto_SSL_get_tls_channel_id(JNIEnv* env, jclass, jlong ssl_address) |
| 8247 | { |
| 8248 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8249 | JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id", ssl); |
| 8250 | if (ssl == NULL) { |
| 8251 | return NULL; |
| 8252 | } |
| 8253 | |
| 8254 | // Channel ID is 64 bytes long. Unfortunately, OpenSSL doesn't declare this length |
| 8255 | // as a constant anywhere. |
| 8256 | jbyteArray javaBytes = env->NewByteArray(64); |
| 8257 | ScopedByteArrayRW bytes(env, javaBytes); |
| 8258 | if (bytes.get() == NULL) { |
| 8259 | JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => NULL", ssl); |
| 8260 | return NULL; |
| 8261 | } |
| 8262 | |
| 8263 | unsigned char* tmp = reinterpret_cast<unsigned char*>(bytes.get()); |
| 8264 | // Unfortunately, the SSL_get_tls_channel_id method below always returns 64 (upon success) |
| 8265 | // regardless of the number of bytes copied into the output buffer "tmp". Thus, the correctness |
| 8266 | // of this code currently relies on the "tmp" buffer being exactly 64 bytes long. |
| 8267 | long ret = SSL_get_tls_channel_id(ssl, tmp, 64); |
| 8268 | if (ret == 0) { |
| 8269 | // Channel ID either not set or did not verify |
| 8270 | JNI_TRACE("NativeCrypto_SSL_get_tls_channel_id(%p) => not available", ssl); |
| 8271 | return NULL; |
| 8272 | } else if (ret != 64) { |
| 8273 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8274 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error getting Channel ID"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8275 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8276 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_tls_channel_id => error, returned %ld", ssl, ret); |
| 8277 | return NULL; |
| 8278 | } |
| 8279 | |
| 8280 | JNI_TRACE("ssl=%p NativeCrypto_NativeCrypto_SSL_get_tls_channel_id() => %p", ssl, javaBytes); |
| 8281 | return javaBytes; |
| 8282 | } |
| 8283 | |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8284 | static void NativeCrypto_SSL_set1_tls_channel_id(JNIEnv* env, jclass, |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 8285 | jlong ssl_address, jobject pkeyRef) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8286 | { |
| 8287 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 8288 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8289 | JNI_TRACE("ssl=%p SSL_set1_tls_channel_id privatekey=%p", ssl, pkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8290 | if (ssl == NULL) { |
| 8291 | return; |
| 8292 | } |
| 8293 | |
| 8294 | if (pkey == NULL) { |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8295 | JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => pkey == null", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8296 | return; |
| 8297 | } |
| 8298 | |
| 8299 | // SSL_set1_tls_channel_id requires ssl->server to be set to 0. |
| 8300 | // Unfortunately, the default value is 1 and it's only changed to 0 just |
| 8301 | // before the handshake starts (see NativeCrypto_SSL_do_handshake). |
| 8302 | ssl->server = 0; |
| 8303 | long ret = SSL_set1_tls_channel_id(ssl, pkey); |
| 8304 | |
| 8305 | if (ret != 1L) { |
| 8306 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8307 | throwSSLExceptionWithSslErrors( |
| 8308 | env, ssl, SSL_ERROR_NONE, "Error setting private key for Channel ID"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8309 | safeSslClear(ssl); |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8310 | JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => error", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8311 | return; |
| 8312 | } |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8313 | // SSL_set1_tls_channel_id expects to take ownership of the EVP_PKEY, but |
| 8314 | // we have an external reference from the caller such as an OpenSSLKey, |
| 8315 | // so we manually increment the reference count here. |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 8316 | #if defined(OPENSSL_IS_BORINGSSL) |
| 8317 | EVP_PKEY_up_ref(pkey); |
| 8318 | #else |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8319 | CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY); |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 8320 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8321 | |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8322 | JNI_TRACE("ssl=%p SSL_set1_tls_channel_id => ok", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8323 | } |
| 8324 | |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 8325 | static void NativeCrypto_SSL_use_PrivateKey(JNIEnv* env, jclass, jlong ssl_address, |
| 8326 | jobject pkeyRef) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8327 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 8328 | EVP_PKEY* pkey = fromContextObject<EVP_PKEY>(env, pkeyRef); |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8329 | JNI_TRACE("ssl=%p SSL_use_PrivateKey privatekey=%p", ssl, pkey); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8330 | if (ssl == NULL) { |
| 8331 | return; |
| 8332 | } |
| 8333 | |
| 8334 | if (pkey == NULL) { |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8335 | JNI_TRACE("ssl=%p SSL_use_PrivateKey => pkey == null", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8336 | return; |
| 8337 | } |
| 8338 | |
| 8339 | int ret = SSL_use_PrivateKey(ssl, pkey); |
| 8340 | if (ret != 1) { |
| 8341 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8342 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting private key"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8343 | safeSslClear(ssl); |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8344 | JNI_TRACE("ssl=%p SSL_use_PrivateKey => error", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8345 | return; |
| 8346 | } |
| 8347 | // SSL_use_PrivateKey expects to take ownership of the EVP_PKEY, |
| 8348 | // but we have an external reference from the caller such as an |
| 8349 | // OpenSSLKey, so we manually increment the reference count here. |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 8350 | #if defined(OPENSSL_IS_BORINGSSL) |
| 8351 | EVP_PKEY_up_ref(pkey); |
| 8352 | #else |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8353 | CRYPTO_add(&pkey->references,+1,CRYPTO_LOCK_EVP_PKEY); |
Adam Langley | ca6d8d3 | 2015-06-04 18:03:28 -0700 | [diff] [blame] | 8354 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8355 | |
Kenny Root | 1ecc048 | 2013-05-03 10:51:56 -0700 | [diff] [blame] | 8356 | JNI_TRACE("ssl=%p SSL_use_PrivateKey => ok", ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8357 | } |
| 8358 | |
| 8359 | static void NativeCrypto_SSL_use_certificate(JNIEnv* env, jclass, |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8360 | jlong ssl_address, jlongArray certificatesJava) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8361 | { |
| 8362 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8363 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate certificates=%p", ssl, certificatesJava); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8364 | if (ssl == NULL) { |
| 8365 | return; |
| 8366 | } |
| 8367 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8368 | if (certificatesJava == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8369 | jniThrowNullPointerException(env, "certificates == null"); |
| 8370 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl); |
| 8371 | return; |
| 8372 | } |
| 8373 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8374 | size_t length = env->GetArrayLength(certificatesJava); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8375 | if (length == 0) { |
| 8376 | jniThrowException(env, "java/lang/IllegalArgumentException", "certificates.length == 0"); |
| 8377 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates.length == 0", ssl); |
| 8378 | return; |
| 8379 | } |
| 8380 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8381 | ScopedLongArrayRO certificates(env, certificatesJava); |
| 8382 | if (certificates.get() == NULL) { |
| 8383 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates == null", ssl); |
| 8384 | return; |
| 8385 | } |
| 8386 | |
| 8387 | Unique_X509 serverCert( |
| 8388 | X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[0])))); |
| 8389 | if (serverCert.get() == NULL) { |
| 8390 | // Note this shouldn't happen since we checked the number of certificates above. |
| 8391 | jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); |
| 8392 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl); |
| 8393 | return; |
| 8394 | } |
| 8395 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8396 | int ret = SSL_use_certificate(ssl, serverCert.get()); |
| 8397 | if (ret != 1) { |
| 8398 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8399 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8400 | safeSslClear(ssl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8401 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate error", ssl); |
| 8402 | return; |
| 8403 | } |
| 8404 | OWNERSHIP_TRANSFERRED(serverCert); |
| 8405 | |
| 8406 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 8407 | Unique_sk_X509 chain(sk_X509_new_null()); |
| 8408 | if (chain.get() == NULL) { |
| 8409 | jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); |
| 8410 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => chain allocation error", ssl); |
| 8411 | return; |
| 8412 | } |
| 8413 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 8414 | for (size_t i = 1; i < length; i++) { |
| 8415 | Unique_X509 cert( |
| 8416 | X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[i])))); |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 8417 | if (cert.get() == NULL || !sk_X509_push(chain.get(), cert.get())) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8418 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8419 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8420 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8421 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl); |
| 8422 | return; |
| 8423 | } |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 8424 | OWNERSHIP_TRANSFERRED(cert); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8425 | } |
| 8426 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8427 | int chainResult = SSL_use_certificate_chain(ssl, chain.get()); |
| 8428 | if (chainResult == 0) { |
| 8429 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting certificate chain"); |
| 8430 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => SSL_use_certificate_chain error", |
| 8431 | ssl); |
| 8432 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8433 | } |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 8434 | OWNERSHIP_TRANSFERRED(chain); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8435 | #else |
| 8436 | for (size_t i = 1; i < length; i++) { |
| 8437 | Unique_X509 cert( |
| 8438 | X509_dup_nocopy(reinterpret_cast<X509*>(static_cast<uintptr_t>(certificates[i])))); |
| 8439 | if (cert.get() == NULL || !SSL_add0_chain_cert(ssl, cert.get())) { |
| 8440 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8441 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing certificate"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8442 | safeSslClear(ssl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8443 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => certificates parsing error", ssl); |
| 8444 | return; |
| 8445 | } |
| 8446 | OWNERSHIP_TRANSFERRED(cert); |
| 8447 | } |
| 8448 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8449 | |
| 8450 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_certificate => ok", ssl); |
| 8451 | } |
| 8452 | |
| 8453 | static void NativeCrypto_SSL_check_private_key(JNIEnv* env, jclass, jlong ssl_address) |
| 8454 | { |
| 8455 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8456 | JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key", ssl); |
| 8457 | if (ssl == NULL) { |
| 8458 | return; |
| 8459 | } |
| 8460 | int ret = SSL_check_private_key(ssl); |
| 8461 | if (ret != 1) { |
| 8462 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error checking private key"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8463 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8464 | JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => error", ssl); |
| 8465 | return; |
| 8466 | } |
| 8467 | JNI_TRACE("ssl=%p NativeCrypto_SSL_check_private_key => ok", ssl); |
| 8468 | } |
| 8469 | |
| 8470 | static void NativeCrypto_SSL_set_client_CA_list(JNIEnv* env, jclass, |
| 8471 | jlong ssl_address, jobjectArray principals) |
| 8472 | { |
| 8473 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8474 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list principals=%p", ssl, principals); |
| 8475 | if (ssl == NULL) { |
| 8476 | return; |
| 8477 | } |
| 8478 | |
| 8479 | if (principals == NULL) { |
| 8480 | jniThrowNullPointerException(env, "principals == null"); |
| 8481 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals == null", ssl); |
| 8482 | return; |
| 8483 | } |
| 8484 | |
| 8485 | int length = env->GetArrayLength(principals); |
| 8486 | if (length == 0) { |
| 8487 | jniThrowException(env, "java/lang/IllegalArgumentException", "principals.length == 0"); |
| 8488 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals.length == 0", ssl); |
| 8489 | return; |
| 8490 | } |
| 8491 | |
| 8492 | Unique_sk_X509_NAME principalsStack(sk_X509_NAME_new_null()); |
| 8493 | if (principalsStack.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 8494 | jniThrowOutOfMemory(env, "Unable to allocate principal stack"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8495 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => stack allocation error", ssl); |
| 8496 | return; |
| 8497 | } |
| 8498 | for (int i = 0; i < length; i++) { |
| 8499 | ScopedLocalRef<jbyteArray> principal(env, |
| 8500 | reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(principals, i))); |
| 8501 | if (principal.get() == NULL) { |
| 8502 | jniThrowNullPointerException(env, "principals element == null"); |
| 8503 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals element null", ssl); |
| 8504 | return; |
| 8505 | } |
| 8506 | |
| 8507 | ScopedByteArrayRO buf(env, principal.get()); |
| 8508 | if (buf.get() == NULL) { |
| 8509 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => threw exception", ssl); |
| 8510 | return; |
| 8511 | } |
| 8512 | const unsigned char* tmp = reinterpret_cast<const unsigned char*>(buf.get()); |
| 8513 | Unique_X509_NAME principalX509Name(d2i_X509_NAME(NULL, &tmp, buf.size())); |
| 8514 | |
| 8515 | if (principalX509Name.get() == NULL) { |
| 8516 | ALOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); |
| 8517 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error parsing principal"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8518 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8519 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principals parsing error", |
| 8520 | ssl); |
| 8521 | return; |
| 8522 | } |
| 8523 | |
| 8524 | if (!sk_X509_NAME_push(principalsStack.get(), principalX509Name.release())) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 8525 | jniThrowOutOfMemory(env, "Unable to push principal"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8526 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => principal push error", ssl); |
| 8527 | return; |
| 8528 | } |
| 8529 | } |
| 8530 | |
| 8531 | SSL_set_client_CA_list(ssl, principalsStack.release()); |
| 8532 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_client_CA_list => ok", ssl); |
| 8533 | } |
| 8534 | |
| 8535 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8536 | * public static native long SSL_get_mode(long ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8537 | */ |
| 8538 | static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, jlong ssl_address) { |
| 8539 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8540 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl); |
| 8541 | if (ssl == NULL) { |
| 8542 | return 0; |
| 8543 | } |
| 8544 | long mode = SSL_get_mode(ssl); |
| 8545 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode); |
| 8546 | return mode; |
| 8547 | } |
| 8548 | |
| 8549 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8550 | * public static native long SSL_set_mode(long ssl, long mode); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8551 | */ |
| 8552 | static jlong NativeCrypto_SSL_set_mode(JNIEnv* env, jclass, |
| 8553 | jlong ssl_address, jlong mode) { |
| 8554 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 8555 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode mode=0x%llx", ssl, (long long) mode); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8556 | if (ssl == NULL) { |
| 8557 | return 0; |
| 8558 | } |
| 8559 | long result = SSL_set_mode(ssl, mode); |
| 8560 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode => 0x%lx", ssl, result); |
| 8561 | return result; |
| 8562 | } |
| 8563 | |
| 8564 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8565 | * public static native long SSL_clear_mode(long ssl, long mode); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8566 | */ |
| 8567 | static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass, |
| 8568 | jlong ssl_address, jlong mode) { |
| 8569 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 8570 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, (long long) mode); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8571 | if (ssl == NULL) { |
| 8572 | return 0; |
| 8573 | } |
| 8574 | long result = SSL_clear_mode(ssl, mode); |
| 8575 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result); |
| 8576 | return result; |
| 8577 | } |
| 8578 | |
| 8579 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8580 | * public static native long SSL_get_options(long ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8581 | */ |
| 8582 | static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass, |
| 8583 | jlong ssl_address) { |
| 8584 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8585 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl); |
| 8586 | if (ssl == NULL) { |
| 8587 | return 0; |
| 8588 | } |
| 8589 | long options = SSL_get_options(ssl); |
| 8590 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options); |
| 8591 | return options; |
| 8592 | } |
| 8593 | |
| 8594 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8595 | * public static native long SSL_set_options(long ssl, long options); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8596 | */ |
| 8597 | static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass, |
| 8598 | jlong ssl_address, jlong options) { |
| 8599 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 8600 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options options=0x%llx", ssl, (long long) options); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8601 | if (ssl == NULL) { |
| 8602 | return 0; |
| 8603 | } |
| 8604 | long result = SSL_set_options(ssl, options); |
| 8605 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options => 0x%lx", ssl, result); |
| 8606 | return result; |
| 8607 | } |
| 8608 | |
| 8609 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 8610 | * public static native long SSL_clear_options(long ssl, long options); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8611 | */ |
| 8612 | static jlong NativeCrypto_SSL_clear_options(JNIEnv* env, jclass, |
| 8613 | jlong ssl_address, jlong options) { |
| 8614 | SSL* ssl = to_SSL(env, ssl_address, true); |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 8615 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options options=0x%llx", ssl, (long long) options); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8616 | if (ssl == NULL) { |
| 8617 | return 0; |
| 8618 | } |
| 8619 | long result = SSL_clear_options(ssl, options); |
| 8620 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options => 0x%lx", ssl, result); |
| 8621 | return result; |
| 8622 | } |
| 8623 | |
Alex Klyubin | 01cce89 | 2014-05-09 03:44:42 -0700 | [diff] [blame] | 8624 | |
| 8625 | static void NativeCrypto_SSL_use_psk_identity_hint(JNIEnv* env, jclass, |
| 8626 | jlong ssl_address, jstring identityHintJava) |
| 8627 | { |
| 8628 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8629 | JNI_TRACE("ssl=%p NativeCrypto_SSL_use_psk_identity_hint identityHint=%p", |
| 8630 | ssl, identityHintJava); |
| 8631 | if (ssl == NULL) { |
| 8632 | return; |
| 8633 | } |
| 8634 | |
| 8635 | int ret; |
| 8636 | if (identityHintJava == NULL) { |
| 8637 | ret = SSL_use_psk_identity_hint(ssl, NULL); |
| 8638 | } else { |
| 8639 | ScopedUtfChars identityHint(env, identityHintJava); |
| 8640 | if (identityHint.c_str() == NULL) { |
| 8641 | throwSSLExceptionStr(env, "Failed to obtain identityHint bytes"); |
| 8642 | return; |
| 8643 | } |
| 8644 | ret = SSL_use_psk_identity_hint(ssl, identityHint.c_str()); |
| 8645 | } |
| 8646 | |
| 8647 | if (ret != 1) { |
| 8648 | int sslErrorCode = SSL_get_error(ssl, ret); |
| 8649 | throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "Failed to set PSK identity hint"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8650 | safeSslClear(ssl); |
Alex Klyubin | 01cce89 | 2014-05-09 03:44:42 -0700 | [diff] [blame] | 8651 | } |
| 8652 | } |
| 8653 | |
| 8654 | static void NativeCrypto_set_SSL_psk_client_callback_enabled(JNIEnv* env, jclass, |
| 8655 | jlong ssl_address, jboolean enabled) |
| 8656 | { |
| 8657 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8658 | JNI_TRACE("ssl=%p NativeCrypto_set_SSL_psk_client_callback_enabled(%d)", |
| 8659 | ssl, enabled); |
| 8660 | if (ssl == NULL) { |
| 8661 | return; |
| 8662 | } |
| 8663 | |
| 8664 | SSL_set_psk_client_callback(ssl, (enabled) ? psk_client_callback : NULL); |
| 8665 | } |
| 8666 | |
| 8667 | static void NativeCrypto_set_SSL_psk_server_callback_enabled(JNIEnv* env, jclass, |
| 8668 | jlong ssl_address, jboolean enabled) |
| 8669 | { |
| 8670 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8671 | JNI_TRACE("ssl=%p NativeCrypto_set_SSL_psk_server_callback_enabled(%d)", |
| 8672 | ssl, enabled); |
| 8673 | if (ssl == NULL) { |
| 8674 | return; |
| 8675 | } |
| 8676 | |
| 8677 | SSL_set_psk_server_callback(ssl, (enabled) ? psk_server_callback : NULL); |
| 8678 | } |
| 8679 | |
Alex Klyubin | 2d089e1 | 2013-11-21 10:28:08 -0800 | [diff] [blame] | 8680 | static jlongArray NativeCrypto_SSL_get_ciphers(JNIEnv* env, jclass, jlong ssl_address) |
| 8681 | { |
| 8682 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8683 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_ciphers", ssl); |
| 8684 | |
| 8685 | STACK_OF(SSL_CIPHER)* cipherStack = SSL_get_ciphers(ssl); |
| 8686 | int count = (cipherStack != NULL) ? sk_SSL_CIPHER_num(cipherStack) : 0; |
| 8687 | ScopedLocalRef<jlongArray> ciphersArray(env, env->NewLongArray(count)); |
| 8688 | ScopedLongArrayRW ciphers(env, ciphersArray.get()); |
| 8689 | for (int i = 0; i < count; i++) { |
| 8690 | ciphers[i] = reinterpret_cast<jlong>(sk_SSL_CIPHER_value(cipherStack, i)); |
| 8691 | } |
| 8692 | |
| 8693 | JNI_TRACE("NativeCrypto_SSL_get_ciphers(%p) => %p [size=%d]", ssl, ciphersArray.get(), count); |
| 8694 | return ciphersArray.release(); |
| 8695 | } |
| 8696 | |
| 8697 | static jint NativeCrypto_get_SSL_CIPHER_algorithm_mkey(JNIEnv* env, jclass, |
| 8698 | jlong ssl_cipher_address) |
| 8699 | { |
| 8700 | SSL_CIPHER* cipher = to_SSL_CIPHER(env, ssl_cipher_address, true); |
Adam Langley | 8d18c8a | 2015-05-12 19:23:52 -0700 | [diff] [blame] | 8701 | JNI_TRACE("cipher=%p get_SSL_CIPHER_algorithm_mkey => %ld", cipher, (long) cipher->algorithm_mkey); |
Alex Klyubin | 2d089e1 | 2013-11-21 10:28:08 -0800 | [diff] [blame] | 8702 | return cipher->algorithm_mkey; |
| 8703 | } |
| 8704 | |
| 8705 | static jint NativeCrypto_get_SSL_CIPHER_algorithm_auth(JNIEnv* env, jclass, |
| 8706 | jlong ssl_cipher_address) |
| 8707 | { |
| 8708 | SSL_CIPHER* cipher = to_SSL_CIPHER(env, ssl_cipher_address, true); |
Adam Langley | 8d18c8a | 2015-05-12 19:23:52 -0700 | [diff] [blame] | 8709 | JNI_TRACE("cipher=%p get_SSL_CIPHER_algorithm_auth => %ld", cipher, (long) cipher->algorithm_auth); |
Alex Klyubin | 2d089e1 | 2013-11-21 10:28:08 -0800 | [diff] [blame] | 8710 | return cipher->algorithm_auth; |
| 8711 | } |
| 8712 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8713 | /** |
| 8714 | * Sets the ciphers suites that are enabled in the SSL |
| 8715 | */ |
Kenny Root | d65ea6d | 2015-06-10 09:52:58 -0700 | [diff] [blame] | 8716 | static void NativeCrypto_SSL_set_cipher_lists(JNIEnv* env, jclass, jlong ssl_address, |
| 8717 | jobjectArray cipherSuites) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8718 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8719 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=%p", ssl, cipherSuites); |
| 8720 | if (ssl == NULL) { |
| 8721 | return; |
| 8722 | } |
| 8723 | if (cipherSuites == NULL) { |
| 8724 | jniThrowNullPointerException(env, "cipherSuites == null"); |
| 8725 | return; |
| 8726 | } |
| 8727 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8728 | int length = env->GetArrayLength(cipherSuites); |
Kenny Root | d65ea6d | 2015-06-10 09:52:58 -0700 | [diff] [blame] | 8729 | |
| 8730 | /* |
| 8731 | * Special case for empty cipher list. This is considered an error by the |
| 8732 | * SSL_set_cipher_list API, but Java allows this silly configuration. |
| 8733 | * However, the SSL cipher list is still set even when SSL_set_cipher_list |
| 8734 | * returns 0 in this case. Just to make sure, we check the resulting cipher |
| 8735 | * list to make sure it's zero length. |
| 8736 | */ |
| 8737 | if (length == 0) { |
| 8738 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=empty", ssl); |
| 8739 | SSL_set_cipher_list(ssl, ""); |
| 8740 | freeOpenSslErrorState(); |
| 8741 | if (sk_SSL_CIPHER_num(SSL_get_ciphers(ssl)) != 0) { |
| 8742 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=empty => error", ssl); |
| 8743 | jniThrowRuntimeException(env, "SSL_set_cipher_list did not update ciphers!"); |
| 8744 | } |
| 8745 | return; |
| 8746 | } |
| 8747 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8748 | static const char noSSLv2[] = "!SSLv2"; |
| 8749 | size_t cipherStringLen = strlen(noSSLv2); |
| 8750 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8751 | for (int i = 0; i < length; i++) { |
| 8752 | ScopedLocalRef<jstring> cipherSuite(env, |
| 8753 | reinterpret_cast<jstring>(env->GetObjectArrayElement(cipherSuites, i))); |
| 8754 | ScopedUtfChars c(env, cipherSuite.get()); |
| 8755 | if (c.c_str() == NULL) { |
| 8756 | return; |
| 8757 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8758 | |
| 8759 | if (cipherStringLen + 1 < cipherStringLen) { |
| 8760 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8761 | "Overflow in cipher suite strings"); |
| 8762 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8763 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8764 | cipherStringLen += 1; /* For the separating colon */ |
| 8765 | |
| 8766 | if (cipherStringLen + c.size() < cipherStringLen) { |
| 8767 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8768 | "Overflow in cipher suite strings"); |
| 8769 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8770 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8771 | cipherStringLen += c.size(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8772 | } |
| 8773 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8774 | if (cipherStringLen + 1 < cipherStringLen) { |
| 8775 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8776 | "Overflow in cipher suite strings"); |
| 8777 | return; |
| 8778 | } |
| 8779 | cipherStringLen += 1; /* For final NUL. */ |
| 8780 | |
| 8781 | UniquePtr<char[]> cipherString(new char[cipherStringLen]); |
| 8782 | if (cipherString.get() == NULL) { |
| 8783 | jniThrowOutOfMemory(env, "Unable to alloc cipher string"); |
| 8784 | return; |
| 8785 | } |
| 8786 | memcpy(cipherString.get(), noSSLv2, strlen(noSSLv2)); |
| 8787 | size_t j = strlen(noSSLv2); |
| 8788 | |
| 8789 | for (int i = 0; i < length; i++) { |
| 8790 | ScopedLocalRef<jstring> cipherSuite(env, |
| 8791 | reinterpret_cast<jstring>(env->GetObjectArrayElement(cipherSuites, i))); |
| 8792 | ScopedUtfChars c(env, cipherSuite.get()); |
| 8793 | |
| 8794 | cipherString[j++] = ':'; |
| 8795 | memcpy(&cipherString[j], c.c_str(), c.size()); |
| 8796 | j += c.size(); |
| 8797 | } |
| 8798 | |
| 8799 | cipherString[j++] = 0; |
| 8800 | if (j != cipherStringLen) { |
| 8801 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8802 | "Internal error"); |
| 8803 | return; |
| 8804 | } |
| 8805 | |
Kenny Root | d65ea6d | 2015-06-10 09:52:58 -0700 | [diff] [blame] | 8806 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_lists cipherSuites=%s", ssl, cipherString.get()); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8807 | if (!SSL_set_cipher_list(ssl, cipherString.get())) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8808 | freeOpenSslErrorState(); |
| 8809 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 8810 | "Illegal cipher suite strings."); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8811 | return; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8812 | } |
| 8813 | } |
| 8814 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 8815 | static void NativeCrypto_SSL_set_accept_state(JNIEnv* env, jclass, jlong sslRef) { |
| 8816 | SSL* ssl = to_SSL(env, sslRef, true); |
| 8817 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_accept_state", ssl); |
| 8818 | if (ssl == NULL) { |
| 8819 | return; |
| 8820 | } |
| 8821 | SSL_set_accept_state(ssl); |
| 8822 | } |
| 8823 | |
| 8824 | static void NativeCrypto_SSL_set_connect_state(JNIEnv* env, jclass, jlong sslRef) { |
| 8825 | SSL* ssl = to_SSL(env, sslRef, true); |
| 8826 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_connect_state", ssl); |
| 8827 | if (ssl == NULL) { |
| 8828 | return; |
| 8829 | } |
| 8830 | SSL_set_connect_state(ssl); |
| 8831 | } |
| 8832 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8833 | /** |
| 8834 | * Sets certificate expectations, especially for server to request client auth |
| 8835 | */ |
| 8836 | static void NativeCrypto_SSL_set_verify(JNIEnv* env, |
| 8837 | jclass, jlong ssl_address, jint mode) |
| 8838 | { |
| 8839 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8840 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_verify mode=%x", ssl, mode); |
| 8841 | if (ssl == NULL) { |
| 8842 | return; |
| 8843 | } |
| 8844 | SSL_set_verify(ssl, (int)mode, NULL); |
| 8845 | } |
| 8846 | |
| 8847 | /** |
| 8848 | * Sets the ciphers suites that are enabled in the SSL |
| 8849 | */ |
| 8850 | static void NativeCrypto_SSL_set_session(JNIEnv* env, jclass, |
| 8851 | jlong ssl_address, jlong ssl_session_address) |
| 8852 | { |
| 8853 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8854 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, false); |
| 8855 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session ssl_session=%p", ssl, ssl_session); |
| 8856 | if (ssl == NULL) { |
| 8857 | return; |
| 8858 | } |
| 8859 | |
| 8860 | int ret = SSL_set_session(ssl, ssl_session); |
| 8861 | if (ret != 1) { |
| 8862 | /* |
| 8863 | * Translate the error, and throw if it turns out to be a real |
| 8864 | * problem. |
| 8865 | */ |
| 8866 | int sslErrorCode = SSL_get_error(ssl, ret); |
| 8867 | if (sslErrorCode != SSL_ERROR_ZERO_RETURN) { |
| 8868 | throwSSLExceptionWithSslErrors(env, ssl, sslErrorCode, "SSL session set"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8869 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8870 | } |
| 8871 | } |
| 8872 | } |
| 8873 | |
| 8874 | /** |
| 8875 | * Sets the ciphers suites that are enabled in the SSL |
| 8876 | */ |
| 8877 | static void NativeCrypto_SSL_set_session_creation_enabled(JNIEnv* env, jclass, |
| 8878 | jlong ssl_address, jboolean creation_enabled) |
| 8879 | { |
| 8880 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8881 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session_creation_enabled creation_enabled=%d", |
| 8882 | ssl, creation_enabled); |
| 8883 | if (ssl == NULL) { |
| 8884 | return; |
| 8885 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8886 | |
| 8887 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8888 | SSL_set_session_creation_enabled(ssl, creation_enabled); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 8889 | #else |
| 8890 | if (creation_enabled) { |
| 8891 | SSL_clear_mode(ssl, SSL_MODE_NO_SESSION_CREATION); |
| 8892 | } else { |
| 8893 | SSL_set_mode(ssl, SSL_MODE_NO_SESSION_CREATION); |
| 8894 | } |
| 8895 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8896 | } |
| 8897 | |
Kenny Root | 28328c3 | 2016-05-12 14:15:24 -0700 | [diff] [blame] | 8898 | static jboolean NativeCrypto_SSL_session_reused(JNIEnv* env, jclass, jlong ssl_address) { |
| 8899 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8900 | JNI_TRACE("ssl=%p NativeCrypto_SSL_session_reused", ssl); |
| 8901 | if (ssl == nullptr) { |
| 8902 | return JNI_FALSE; |
| 8903 | } |
| 8904 | |
| 8905 | int reused = SSL_session_reused(ssl); |
| 8906 | JNI_TRACE("ssl=%p NativeCrypto_SSL_session_reused => %d", ssl, reused); |
| 8907 | return reused == 1 ? JNI_TRUE : JNI_FALSE; |
| 8908 | } |
| 8909 | |
Adam Langley | 295b30e | 2015-06-26 17:32:18 -0700 | [diff] [blame] | 8910 | static void NativeCrypto_SSL_set_reject_peer_renegotiations(JNIEnv* env, jclass, |
| 8911 | jlong ssl_address, jboolean reject_renegotiations) |
| 8912 | { |
| 8913 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8914 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_reject_peer_renegotiations reject_renegotiations=%d", |
| 8915 | ssl, reject_renegotiations); |
| 8916 | if (ssl == NULL) { |
| 8917 | return; |
| 8918 | } |
| 8919 | |
| 8920 | #if defined(OPENSSL_IS_BORINGSSL) |
| 8921 | SSL_set_reject_peer_renegotiations(ssl, reject_renegotiations); |
| 8922 | #else |
| 8923 | (void) reject_renegotiations; |
| 8924 | /* OpenSSL doesn't support this call and accepts renegotiation requests by |
| 8925 | * default. */ |
| 8926 | #endif |
| 8927 | } |
| 8928 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8929 | static void NativeCrypto_SSL_set_tlsext_host_name(JNIEnv* env, jclass, |
| 8930 | jlong ssl_address, jstring hostname) |
| 8931 | { |
| 8932 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8933 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostname=%p", |
| 8934 | ssl, hostname); |
| 8935 | if (ssl == NULL) { |
| 8936 | return; |
| 8937 | } |
| 8938 | |
| 8939 | ScopedUtfChars hostnameChars(env, hostname); |
| 8940 | if (hostnameChars.c_str() == NULL) { |
| 8941 | return; |
| 8942 | } |
| 8943 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name hostnameChars=%s", |
| 8944 | ssl, hostnameChars.c_str()); |
| 8945 | |
| 8946 | int ret = SSL_set_tlsext_host_name(ssl, hostnameChars.c_str()); |
| 8947 | if (ret != 1) { |
| 8948 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, "Error setting host name"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 8949 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 8950 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => error", ssl); |
| 8951 | return; |
| 8952 | } |
| 8953 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_tlsext_host_name => ok", ssl); |
| 8954 | } |
| 8955 | |
| 8956 | static jstring NativeCrypto_SSL_get_servername(JNIEnv* env, jclass, jlong ssl_address) { |
| 8957 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 8958 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername", ssl); |
| 8959 | if (ssl == NULL) { |
| 8960 | return NULL; |
| 8961 | } |
| 8962 | const char* servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); |
| 8963 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_servername => %s", ssl, servername); |
| 8964 | return env->NewStringUTF(servername); |
| 8965 | } |
| 8966 | |
| 8967 | /** |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 8968 | * A common selection path for both NPN and ALPN since they're essentially the |
| 8969 | * same protocol. The list of protocols in "primary" is considered the order |
| 8970 | * which should take precedence. |
| 8971 | */ |
Elliott Hughes | ab3c653 | 2013-07-30 15:42:28 -0700 | [diff] [blame] | 8972 | static int proto_select(SSL* ssl __attribute__ ((unused)), |
| 8973 | unsigned char **out, unsigned char *outLength, |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 8974 | const unsigned char *primary, const unsigned int primaryLength, |
| 8975 | const unsigned char *secondary, const unsigned int secondaryLength) { |
Kenny Root | 5a8ca5b | 2014-08-27 13:53:03 -0700 | [diff] [blame] | 8976 | if (primary != NULL && secondary != NULL) { |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 8977 | JNI_TRACE("primary=%p, length=%d", primary, primaryLength); |
| 8978 | |
| 8979 | int status = SSL_select_next_proto(out, outLength, primary, primaryLength, secondary, |
| 8980 | secondaryLength); |
| 8981 | switch (status) { |
| 8982 | case OPENSSL_NPN_NEGOTIATED: |
| 8983 | JNI_TRACE("ssl=%p proto_select NPN/ALPN negotiated", ssl); |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 8984 | return SSL_TLSEXT_ERR_OK; |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 8985 | break; |
| 8986 | case OPENSSL_NPN_UNSUPPORTED: |
| 8987 | JNI_TRACE("ssl=%p proto_select NPN/ALPN unsupported", ssl); |
| 8988 | break; |
| 8989 | case OPENSSL_NPN_NO_OVERLAP: |
| 8990 | JNI_TRACE("ssl=%p proto_select NPN/ALPN no overlap", ssl); |
| 8991 | break; |
| 8992 | } |
| 8993 | } else { |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 8994 | if (out != NULL && outLength != NULL) { |
| 8995 | *out = NULL; |
| 8996 | *outLength = 0; |
| 8997 | } |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 8998 | JNI_TRACE("protocols=NULL"); |
| 8999 | } |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 9000 | return SSL_TLSEXT_ERR_NOACK; |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9001 | } |
| 9002 | |
| 9003 | /** |
| 9004 | * Callback for the server to select an ALPN protocol. |
| 9005 | */ |
| 9006 | static int alpn_select_callback(SSL* ssl, const unsigned char **out, unsigned char *outlen, |
| 9007 | const unsigned char *in, unsigned int inlen, void *) { |
| 9008 | JNI_TRACE("ssl=%p alpn_select_callback", ssl); |
| 9009 | |
| 9010 | AppData* appData = toAppData(ssl); |
| 9011 | JNI_TRACE("AppData=%p", appData); |
| 9012 | |
| 9013 | return proto_select(ssl, const_cast<unsigned char **>(out), outlen, |
| 9014 | reinterpret_cast<unsigned char*>(appData->alpnProtocolsData), |
| 9015 | appData->alpnProtocolsLength, in, inlen); |
| 9016 | } |
| 9017 | |
| 9018 | /** |
| 9019 | * Callback for the client to select an NPN protocol. |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9020 | */ |
Elliott Hughes | ab3c653 | 2013-07-30 15:42:28 -0700 | [diff] [blame] | 9021 | static int next_proto_select_callback(SSL* ssl, unsigned char** out, unsigned char* outlen, |
| 9022 | const unsigned char* in, unsigned int inlen, void*) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9023 | { |
| 9024 | JNI_TRACE("ssl=%p next_proto_select_callback", ssl); |
| 9025 | |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9026 | AppData* appData = toAppData(ssl); |
| 9027 | JNI_TRACE("AppData=%p", appData); |
| 9028 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9029 | // Enable False Start on the client if the server understands NPN |
| 9030 | // http://www.imperialviolet.org/2012/04/11/falsestart.html |
| 9031 | SSL_set_mode(ssl, SSL_MODE_HANDSHAKE_CUTTHROUGH); |
| 9032 | |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9033 | return proto_select(ssl, out, outlen, in, inlen, |
| 9034 | reinterpret_cast<unsigned char*>(appData->npnProtocolsData), |
| 9035 | appData->npnProtocolsLength); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9036 | } |
| 9037 | |
| 9038 | /** |
| 9039 | * Callback for the server to advertise available protocols. |
| 9040 | */ |
| 9041 | static int next_protos_advertised_callback(SSL* ssl, |
| 9042 | const unsigned char **out, unsigned int *outlen, void *) |
| 9043 | { |
| 9044 | JNI_TRACE("ssl=%p next_protos_advertised_callback", ssl); |
| 9045 | AppData* appData = toAppData(ssl); |
| 9046 | unsigned char* npnProtocols = reinterpret_cast<unsigned char*>(appData->npnProtocolsData); |
| 9047 | if (npnProtocols != NULL) { |
| 9048 | *out = npnProtocols; |
| 9049 | *outlen = appData->npnProtocolsLength; |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 9050 | return SSL_TLSEXT_ERR_OK; |
| 9051 | } else { |
| 9052 | *out = NULL; |
Kenny Root | 2a5460f | 2014-03-10 13:04:32 -0700 | [diff] [blame] | 9053 | *outlen = 0; |
Kenny Root | fc7924b | 2014-03-10 10:29:10 -0700 | [diff] [blame] | 9054 | return SSL_TLSEXT_ERR_NOACK; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9055 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9056 | } |
| 9057 | |
| 9058 | static void NativeCrypto_SSL_CTX_enable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address) |
| 9059 | { |
| 9060 | SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); |
| 9061 | if (ssl_ctx == NULL) { |
| 9062 | return; |
| 9063 | } |
| 9064 | SSL_CTX_set_next_proto_select_cb(ssl_ctx, next_proto_select_callback, NULL); // client |
| 9065 | SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_protos_advertised_callback, NULL); // server |
| 9066 | } |
| 9067 | |
| 9068 | static void NativeCrypto_SSL_CTX_disable_npn(JNIEnv* env, jclass, jlong ssl_ctx_address) |
| 9069 | { |
| 9070 | SSL_CTX* ssl_ctx = to_SSL_CTX(env, ssl_ctx_address, true); |
| 9071 | if (ssl_ctx == NULL) { |
| 9072 | return; |
| 9073 | } |
| 9074 | SSL_CTX_set_next_proto_select_cb(ssl_ctx, NULL, NULL); // client |
| 9075 | SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, NULL, NULL); // server |
| 9076 | } |
| 9077 | |
| 9078 | static jbyteArray NativeCrypto_SSL_get_npn_negotiated_protocol(JNIEnv* env, jclass, |
| 9079 | jlong ssl_address) |
| 9080 | { |
| 9081 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9082 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_npn_negotiated_protocol", ssl); |
| 9083 | if (ssl == NULL) { |
| 9084 | return NULL; |
| 9085 | } |
| 9086 | const jbyte* npn; |
| 9087 | unsigned npnLength; |
| 9088 | SSL_get0_next_proto_negotiated(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength); |
| 9089 | if (npnLength == 0) { |
| 9090 | return NULL; |
| 9091 | } |
| 9092 | jbyteArray result = env->NewByteArray(npnLength); |
| 9093 | if (result != NULL) { |
| 9094 | env->SetByteArrayRegion(result, 0, npnLength, npn); |
| 9095 | } |
| 9096 | return result; |
| 9097 | } |
| 9098 | |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9099 | static int NativeCrypto_SSL_set_alpn_protos(JNIEnv* env, jclass, jlong ssl_address, |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9100 | jbyteArray protos) { |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9101 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9102 | if (ssl == NULL) { |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9103 | return 0; |
| 9104 | } |
| 9105 | |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9106 | JNI_TRACE("ssl=%p SSL_set_alpn_protos protos=%p", ssl, protos); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9107 | |
| 9108 | if (protos == NULL) { |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9109 | JNI_TRACE("ssl=%p SSL_set_alpn_protos protos=NULL", ssl); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9110 | return 1; |
| 9111 | } |
| 9112 | |
| 9113 | ScopedByteArrayRO protosBytes(env, protos); |
| 9114 | if (protosBytes.get() == NULL) { |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9115 | JNI_TRACE("ssl=%p SSL_set_alpn_protos protos=%p => protosBytes == NULL", ssl, |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9116 | protos); |
| 9117 | return 0; |
| 9118 | } |
| 9119 | |
| 9120 | const unsigned char *tmp = reinterpret_cast<const unsigned char*>(protosBytes.get()); |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 9121 | int ret = SSL_set_alpn_protos(ssl, tmp, protosBytes.size()); |
| 9122 | JNI_TRACE("ssl=%p SSL_set_alpn_protos protos=%p => ret=%d", ssl, protos, ret); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9123 | return ret; |
| 9124 | } |
| 9125 | |
| 9126 | static jbyteArray NativeCrypto_SSL_get0_alpn_selected(JNIEnv* env, jclass, |
| 9127 | jlong ssl_address) |
| 9128 | { |
| 9129 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9130 | JNI_TRACE("ssl=%p SSL_get0_alpn_selected", ssl); |
| 9131 | if (ssl == NULL) { |
| 9132 | return NULL; |
| 9133 | } |
| 9134 | const jbyte* npn; |
| 9135 | unsigned npnLength; |
| 9136 | SSL_get0_alpn_selected(ssl, reinterpret_cast<const unsigned char**>(&npn), &npnLength); |
| 9137 | if (npnLength == 0) { |
| 9138 | return NULL; |
| 9139 | } |
| 9140 | jbyteArray result = env->NewByteArray(npnLength); |
| 9141 | if (result != NULL) { |
| 9142 | env->SetByteArrayRegion(result, 0, npnLength, npn); |
| 9143 | } |
| 9144 | return result; |
| 9145 | } |
| 9146 | |
Kenny Root | bcdb80d | 2013-05-28 14:51:51 -0700 | [diff] [blame] | 9147 | #ifdef WITH_JNI_TRACE_KEYS |
| 9148 | static inline char hex_char(unsigned char in) |
| 9149 | { |
| 9150 | if (in < 10) { |
| 9151 | return '0' + in; |
| 9152 | } else if (in <= 0xF0) { |
| 9153 | return 'A' + in - 10; |
| 9154 | } else { |
| 9155 | return '?'; |
| 9156 | } |
| 9157 | } |
| 9158 | |
| 9159 | static void hex_string(char **dest, unsigned char* input, int len) |
| 9160 | { |
| 9161 | *dest = (char*) malloc(len * 2 + 1); |
| 9162 | char *output = *dest; |
| 9163 | for (int i = 0; i < len; i++) { |
| 9164 | *output++ = hex_char(input[i] >> 4); |
| 9165 | *output++ = hex_char(input[i] & 0xF); |
| 9166 | } |
| 9167 | *output = '\0'; |
| 9168 | } |
| 9169 | |
| 9170 | static void debug_print_session_key(SSL_SESSION* session) |
| 9171 | { |
| 9172 | char *session_id_str; |
| 9173 | char *master_key_str; |
| 9174 | const char *key_type; |
| 9175 | char *keyline; |
| 9176 | |
| 9177 | hex_string(&session_id_str, session->session_id, session->session_id_length); |
| 9178 | hex_string(&master_key_str, session->master_key, session->master_key_length); |
| 9179 | |
| 9180 | X509* peer = SSL_SESSION_get0_peer(session); |
| 9181 | EVP_PKEY* pkey = X509_PUBKEY_get(peer->cert_info->key); |
| 9182 | switch (EVP_PKEY_type(pkey->type)) { |
| 9183 | case EVP_PKEY_RSA: |
| 9184 | key_type = "RSA"; |
| 9185 | break; |
| 9186 | case EVP_PKEY_DSA: |
| 9187 | key_type = "DSA"; |
| 9188 | break; |
| 9189 | case EVP_PKEY_EC: |
| 9190 | key_type = "EC"; |
| 9191 | break; |
| 9192 | default: |
| 9193 | key_type = "Unknown"; |
| 9194 | break; |
| 9195 | } |
| 9196 | |
| 9197 | asprintf(&keyline, "%s Session-ID:%s Master-Key:%s\n", key_type, session_id_str, |
| 9198 | master_key_str); |
| 9199 | JNI_TRACE("ssl_session=%p %s", session, keyline); |
| 9200 | |
| 9201 | free(session_id_str); |
| 9202 | free(master_key_str); |
| 9203 | free(keyline); |
| 9204 | } |
| 9205 | #endif /* WITH_JNI_TRACE_KEYS */ |
| 9206 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9207 | /** |
| 9208 | * Perform SSL handshake |
| 9209 | */ |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9210 | static jlong NativeCrypto_SSL_do_handshake_bio(JNIEnv* env, jclass, jlong ssl_address, |
| 9211 | jlong rbioRef, jlong wbioRef, jobject shc, jboolean client_mode, jbyteArray npnProtocols, |
| 9212 | jbyteArray alpnProtocols) { |
| 9213 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9214 | BIO* rbio = reinterpret_cast<BIO*>(rbioRef); |
| 9215 | BIO* wbio = reinterpret_cast<BIO*>(wbioRef); |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9216 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio rbio=%p wbio=%p shc=%p client_mode=%d npn=%p", |
| 9217 | ssl, rbio, wbio, shc, client_mode, npnProtocols); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9218 | if (ssl == NULL) { |
| 9219 | return 0; |
| 9220 | } |
| 9221 | if (shc == NULL) { |
| 9222 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 9223 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio sslHandshakeCallbacks == null => 0", ssl); |
| 9224 | return 0; |
| 9225 | } |
| 9226 | |
| 9227 | if (rbio == NULL || wbio == NULL) { |
| 9228 | jniThrowNullPointerException(env, "rbio == null || wbio == null"); |
| 9229 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio => rbio == null || wbio == NULL", ssl); |
| 9230 | return 0; |
| 9231 | } |
| 9232 | |
| 9233 | ScopedSslBio sslBio(ssl, rbio, wbio); |
| 9234 | |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9235 | AppData* appData = toAppData(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9236 | if (appData == NULL) { |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9237 | throwSSLExceptionStr(env, "Unable to retrieve application data"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9238 | safeSslClear(ssl); |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9239 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake appData => 0", ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9240 | return 0; |
| 9241 | } |
| 9242 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9243 | if (!client_mode && alpnProtocols != NULL) { |
| 9244 | SSL_CTX_set_alpn_select_cb(SSL_get_SSL_CTX(ssl), alpn_select_callback, NULL); |
| 9245 | } |
| 9246 | |
| 9247 | int ret = 0; |
| 9248 | errno = 0; |
| 9249 | |
| 9250 | if (!appData->setCallbackState(env, shc, NULL, npnProtocols, alpnProtocols)) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9251 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9252 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9253 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio setCallbackState => 0", ssl); |
| 9254 | return 0; |
| 9255 | } |
| 9256 | ret = SSL_do_handshake(ssl); |
| 9257 | appData->clearCallbackState(); |
| 9258 | // cert_verify_callback threw exception |
| 9259 | if (env->ExceptionCheck()) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9260 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9261 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9262 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio exception => 0", ssl); |
| 9263 | return 0; |
| 9264 | } |
| 9265 | |
| 9266 | if (ret <= 0) { // error. See SSL_do_handshake(3SSL) man page. |
| 9267 | // error case |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9268 | OpenSslError sslError(ssl, ret); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9269 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio ret=%d errno=%d sslError=%d", |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9270 | ssl, ret, errno, sslError.get()); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9271 | |
| 9272 | /* |
| 9273 | * If SSL_do_handshake doesn't succeed due to the socket being |
| 9274 | * either unreadable or unwritable, we need to exit to allow |
| 9275 | * the SSLEngine code to wrap or unwrap. |
| 9276 | */ |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9277 | if (sslError.get() == SSL_ERROR_NONE || |
Narayan Kamath | f6c8f8b | 2015-01-06 15:25:32 +0000 | [diff] [blame] | 9278 | (sslError.get() == SSL_ERROR_SYSCALL && errno == 0) || |
| 9279 | (sslError.get() == SSL_ERROR_ZERO_RETURN)) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9280 | throwSSLHandshakeExceptionStr(env, "Connection closed by peer"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9281 | safeSslClear(ssl); |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9282 | } else if (sslError.get() != SSL_ERROR_WANT_READ && |
| 9283 | sslError.get() != SSL_ERROR_WANT_WRITE) { |
| 9284 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), |
| 9285 | "SSL handshake terminated", throwSSLHandshakeExceptionStr); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9286 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9287 | } |
| 9288 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio error => 0", ssl); |
| 9289 | return 0; |
| 9290 | } |
| 9291 | |
| 9292 | // success. handshake completed |
| 9293 | SSL_SESSION* ssl_session = SSL_get1_session(ssl); |
| 9294 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake_bio => ssl_session=%p", ssl, ssl_session); |
| 9295 | #ifdef WITH_JNI_TRACE_KEYS |
| 9296 | debug_print_session_key(ssl_session); |
| 9297 | #endif |
| 9298 | return reinterpret_cast<uintptr_t>(ssl_session); |
| 9299 | } |
| 9300 | |
| 9301 | /** |
| 9302 | * Perform SSL handshake |
| 9303 | */ |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9304 | static jlong NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, |
| 9305 | jobject shc, jint timeout_millis, jboolean client_mode, jbyteArray npnProtocols, |
| 9306 | jbyteArray alpnProtocols) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9307 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9308 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd=%p shc=%p timeout_millis=%d client_mode=%d npn=%p", |
| 9309 | ssl, fdObject, shc, timeout_millis, client_mode, npnProtocols); |
| 9310 | if (ssl == NULL) { |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 9311 | return 0; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9312 | } |
| 9313 | if (fdObject == NULL) { |
| 9314 | jniThrowNullPointerException(env, "fd == null"); |
| 9315 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd == null => 0", ssl); |
| 9316 | return 0; |
| 9317 | } |
| 9318 | if (shc == NULL) { |
| 9319 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 9320 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslHandshakeCallbacks == null => 0", ssl); |
| 9321 | return 0; |
| 9322 | } |
| 9323 | |
| 9324 | NetFd fd(env, fdObject); |
| 9325 | if (fd.isClosed()) { |
| 9326 | // SocketException thrown by NetFd.isClosed |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9327 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9328 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake fd.isClosed() => 0", ssl); |
| 9329 | return 0; |
| 9330 | } |
| 9331 | |
| 9332 | int ret = SSL_set_fd(ssl, fd.get()); |
| 9333 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake s=%d", ssl, fd.get()); |
| 9334 | |
| 9335 | if (ret != 1) { |
| 9336 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_NONE, |
| 9337 | "Error setting the file descriptor"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9338 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9339 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake SSL_set_fd => 0", ssl); |
| 9340 | return 0; |
| 9341 | } |
| 9342 | |
| 9343 | /* |
| 9344 | * Make socket non-blocking, so SSL_connect SSL_read() and SSL_write() don't hang |
| 9345 | * forever and we can use select() to find out if the socket is ready. |
| 9346 | */ |
| 9347 | if (!setBlocking(fd.get(), false)) { |
| 9348 | throwSSLExceptionStr(env, "Unable to make socket non blocking"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9349 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9350 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setBlocking => 0", ssl); |
| 9351 | return 0; |
| 9352 | } |
| 9353 | |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9354 | AppData* appData = toAppData(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9355 | if (appData == NULL) { |
Kenny Root | de9b586 | 2014-04-22 09:46:20 -0700 | [diff] [blame] | 9356 | throwSSLExceptionStr(env, "Unable to retrieve application data"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9357 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9358 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake appData => 0", ssl); |
| 9359 | return 0; |
| 9360 | } |
| 9361 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9362 | if (client_mode) { |
| 9363 | SSL_set_connect_state(ssl); |
| 9364 | } else { |
| 9365 | SSL_set_accept_state(ssl); |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9366 | if (alpnProtocols != NULL) { |
| 9367 | SSL_CTX_set_alpn_select_cb(SSL_get_SSL_CTX(ssl), alpn_select_callback, NULL); |
| 9368 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9369 | } |
| 9370 | |
| 9371 | ret = 0; |
Kenny Root | 2ba24c8 | 2014-11-17 11:13:16 -0800 | [diff] [blame] | 9372 | OpenSslError sslError; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9373 | while (appData->aliveAndKicking) { |
| 9374 | errno = 0; |
| 9375 | |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9376 | if (!appData->setCallbackState(env, shc, fdObject, npnProtocols, alpnProtocols)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9377 | // SocketException thrown by NetFd.isClosed |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9378 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9379 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake setCallbackState => 0", ssl); |
| 9380 | return 0; |
| 9381 | } |
| 9382 | ret = SSL_do_handshake(ssl); |
| 9383 | appData->clearCallbackState(); |
| 9384 | // cert_verify_callback threw exception |
| 9385 | if (env->ExceptionCheck()) { |
Kenny Root | 7ca2049 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9386 | freeOpenSslErrorState(); |
| 9387 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9388 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake exception => 0", ssl); |
| 9389 | return 0; |
| 9390 | } |
| 9391 | // success case |
| 9392 | if (ret == 1) { |
| 9393 | break; |
| 9394 | } |
| 9395 | // retry case |
| 9396 | if (errno == EINTR) { |
| 9397 | continue; |
| 9398 | } |
| 9399 | // error case |
Kenny Root | 2ba24c8 | 2014-11-17 11:13:16 -0800 | [diff] [blame] | 9400 | sslError.reset(ssl, ret); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9401 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake ret=%d errno=%d sslError=%d timeout_millis=%d", |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9402 | ssl, ret, errno, sslError.get(), timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9403 | |
| 9404 | /* |
| 9405 | * If SSL_do_handshake doesn't succeed due to the socket being |
| 9406 | * either unreadable or unwritable, we use sslSelect to |
| 9407 | * wait for it to become ready. If that doesn't happen |
| 9408 | * before the specified timeout or an error occurs, we |
| 9409 | * cancel the handshake. Otherwise we try the SSL_connect |
| 9410 | * again. |
| 9411 | */ |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9412 | if (sslError.get() == SSL_ERROR_WANT_READ || sslError.get() == SSL_ERROR_WANT_WRITE) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9413 | appData->waitingThreads++; |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9414 | int selectResult = sslSelect(env, sslError.get(), fdObject, appData, timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9415 | |
| 9416 | if (selectResult == THROWN_EXCEPTION) { |
| 9417 | // SocketException thrown by NetFd.isClosed |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9418 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9419 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake sslSelect => 0", ssl); |
| 9420 | return 0; |
| 9421 | } |
| 9422 | if (selectResult == -1) { |
Kenny Root | a0c196d | 2014-03-26 13:56:24 -0700 | [diff] [blame] | 9423 | throwSSLExceptionWithSslErrors(env, ssl, SSL_ERROR_SYSCALL, "handshake error", |
| 9424 | throwSSLHandshakeExceptionStr); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9425 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9426 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == -1 => 0", ssl); |
| 9427 | return 0; |
| 9428 | } |
| 9429 | if (selectResult == 0) { |
| 9430 | throwSocketTimeoutException(env, "SSL handshake timed out"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9431 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9432 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9433 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake selectResult == 0 => 0", ssl); |
| 9434 | return 0; |
| 9435 | } |
| 9436 | } else { |
| 9437 | // ALOGE("Unknown error %d during handshake", error); |
| 9438 | break; |
| 9439 | } |
| 9440 | } |
| 9441 | |
| 9442 | // clean error. See SSL_do_handshake(3SSL) man page. |
| 9443 | if (ret == 0) { |
| 9444 | /* |
| 9445 | * The other side closed the socket before the handshake could be |
| 9446 | * completed, but everything is within the bounds of the TLS protocol. |
| 9447 | * We still might want to find out the real reason of the failure. |
| 9448 | */ |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9449 | if (sslError.get() == SSL_ERROR_NONE || |
Narayan Kamath | f6c8f8b | 2015-01-06 15:25:32 +0000 | [diff] [blame] | 9450 | (sslError.get() == SSL_ERROR_SYSCALL && errno == 0) || |
| 9451 | (sslError.get() == SSL_ERROR_ZERO_RETURN)) { |
Kenny Root | a0c196d | 2014-03-26 13:56:24 -0700 | [diff] [blame] | 9452 | throwSSLHandshakeExceptionStr(env, "Connection closed by peer"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9453 | } else { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9454 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), |
| 9455 | "SSL handshake terminated", throwSSLHandshakeExceptionStr); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9456 | } |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9457 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9458 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake clean error => 0", ssl); |
| 9459 | return 0; |
| 9460 | } |
| 9461 | |
| 9462 | // unclean error. See SSL_do_handshake(3SSL) man page. |
| 9463 | if (ret < 0) { |
| 9464 | /* |
| 9465 | * Translate the error and throw exception. We are sure it is an error |
| 9466 | * at this point. |
| 9467 | */ |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9468 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), "SSL handshake aborted", |
Kenny Root | a0c196d | 2014-03-26 13:56:24 -0700 | [diff] [blame] | 9469 | throwSSLHandshakeExceptionStr); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9470 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9471 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake unclean error => 0", ssl); |
| 9472 | return 0; |
| 9473 | } |
| 9474 | SSL_SESSION* ssl_session = SSL_get1_session(ssl); |
| 9475 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => ssl_session=%p", ssl, ssl_session); |
Kenny Root | bcdb80d | 2013-05-28 14:51:51 -0700 | [diff] [blame] | 9476 | #ifdef WITH_JNI_TRACE_KEYS |
| 9477 | debug_print_session_key(ssl_session); |
| 9478 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9479 | return (jlong) ssl_session; |
| 9480 | } |
| 9481 | |
| 9482 | /** |
| 9483 | * Perform SSL renegotiation |
| 9484 | */ |
| 9485 | static void NativeCrypto_SSL_renegotiate(JNIEnv* env, jclass, jlong ssl_address) |
| 9486 | { |
| 9487 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9488 | JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate", ssl); |
| 9489 | if (ssl == NULL) { |
| 9490 | return; |
| 9491 | } |
| 9492 | int result = SSL_renegotiate(ssl); |
| 9493 | if (result != 1) { |
| 9494 | throwSSLExceptionStr(env, "Problem with SSL_renegotiate"); |
| 9495 | return; |
| 9496 | } |
| 9497 | // first call asks client to perform renegotiation |
| 9498 | int ret = SSL_do_handshake(ssl); |
| 9499 | if (ret != 1) { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9500 | OpenSslError sslError(ssl, ret); |
| 9501 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9502 | "Problem with SSL_do_handshake after SSL_renegotiate"); |
| 9503 | return; |
| 9504 | } |
| 9505 | // if client agrees, set ssl state and perform renegotiation |
| 9506 | ssl->state = SSL_ST_ACCEPT; |
| 9507 | SSL_do_handshake(ssl); |
| 9508 | JNI_TRACE("ssl=%p NativeCrypto_SSL_renegotiate =>", ssl); |
| 9509 | } |
| 9510 | |
| 9511 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 9512 | * public static native byte[][] SSL_get_certificate(long ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9513 | */ |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 9514 | static jlongArray NativeCrypto_SSL_get_certificate(JNIEnv* env, jclass, jlong ssl_address) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9515 | { |
| 9516 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9517 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate", ssl); |
| 9518 | if (ssl == NULL) { |
| 9519 | return NULL; |
| 9520 | } |
| 9521 | X509* certificate = SSL_get_certificate(ssl); |
| 9522 | if (certificate == NULL) { |
| 9523 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
Kenny Root | db88d05 | 2013-06-05 10:01:27 -0700 | [diff] [blame] | 9524 | // SSL_get_certificate can return NULL during an error as well. |
| 9525 | freeOpenSslErrorState(); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9526 | return NULL; |
| 9527 | } |
| 9528 | |
| 9529 | Unique_sk_X509 chain(sk_X509_new_null()); |
| 9530 | if (chain.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 9531 | jniThrowOutOfMemory(env, "Unable to allocate local certificate chain"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9532 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => threw exception", ssl); |
| 9533 | return NULL; |
| 9534 | } |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 9535 | if (!sk_X509_push(chain.get(), X509_dup_nocopy(certificate))) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 9536 | jniThrowOutOfMemory(env, "Unable to push local certificate"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9537 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 9538 | return NULL; |
| 9539 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 9540 | |
| 9541 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9542 | STACK_OF(X509)* cert_chain = SSL_get_certificate_chain(ssl, certificate); |
| 9543 | for (int i=0; i<sk_X509_num(cert_chain); i++) { |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 9544 | if (!sk_X509_push(chain.get(), X509_dup_nocopy(sk_X509_value(cert_chain, i)))) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 9545 | jniThrowOutOfMemory(env, "Unable to push local certificate chain"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9546 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 9547 | return NULL; |
| 9548 | } |
| 9549 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 9550 | #else |
| 9551 | STACK_OF(X509) *cert_chain = NULL; |
| 9552 | if (!SSL_get0_chain_certs(ssl, &cert_chain)) { |
| 9553 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get0_chain_certs => NULL", ssl); |
| 9554 | freeOpenSslErrorState(); |
| 9555 | return NULL; |
| 9556 | } |
| 9557 | |
| 9558 | for (size_t i=0; i<sk_X509_num(cert_chain); i++) { |
| 9559 | if (!sk_X509_push(chain.get(), X509_dup_nocopy(sk_X509_value(cert_chain, i)))) { |
| 9560 | jniThrowOutOfMemory(env, "Unable to push local certificate chain"); |
| 9561 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 9562 | return NULL; |
| 9563 | } |
| 9564 | } |
| 9565 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9566 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 9567 | jlongArray refArray = getCertificateRefs(env, chain.get()); |
| 9568 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => %p", ssl, refArray); |
| 9569 | return refArray; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9570 | } |
| 9571 | |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 9572 | // Fills a long[] with the peer certificates in the chain. |
| 9573 | static jlongArray NativeCrypto_SSL_get_peer_cert_chain(JNIEnv* env, jclass, jlong ssl_address) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9574 | { |
| 9575 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9576 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain", ssl); |
| 9577 | if (ssl == NULL) { |
| 9578 | return NULL; |
| 9579 | } |
| 9580 | STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl); |
| 9581 | Unique_sk_X509 chain_copy(NULL); |
| 9582 | if (ssl->server) { |
| 9583 | X509* x509 = SSL_get_peer_certificate(ssl); |
| 9584 | if (x509 == NULL) { |
| 9585 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => NULL", ssl); |
| 9586 | return NULL; |
| 9587 | } |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 9588 | chain_copy.reset(sk_X509_new_null()); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9589 | if (chain_copy.get() == NULL) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 9590 | jniThrowOutOfMemory(env, "Unable to allocate peer certificate chain"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9591 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate dup error", ssl); |
| 9592 | return NULL; |
| 9593 | } |
Kenny Root | c58a186 | 2013-09-11 10:05:32 -0700 | [diff] [blame] | 9594 | size_t chain_size = sk_X509_num(chain); |
| 9595 | for (size_t i = 0; i < chain_size; i++) { |
| 9596 | if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(sk_X509_value(chain, i)))) { |
| 9597 | jniThrowOutOfMemory(env, "Unable to push server's peer certificate chain"); |
| 9598 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate chain push error", ssl); |
| 9599 | return NULL; |
| 9600 | } |
| 9601 | } |
| 9602 | if (!sk_X509_push(chain_copy.get(), X509_dup_nocopy(x509))) { |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 9603 | jniThrowOutOfMemory(env, "Unable to push server's peer certificate"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9604 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => certificate push error", ssl); |
| 9605 | return NULL; |
| 9606 | } |
| 9607 | chain = chain_copy.get(); |
| 9608 | } |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 9609 | jlongArray refArray = getCertificateRefs(env, chain); |
| 9610 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_peer_cert_chain => %p", ssl, refArray); |
| 9611 | return refArray; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9612 | } |
| 9613 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9614 | static int sslRead(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, char* buf, jint len, |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9615 | OpenSslError& sslError, int read_timeout_millis) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9616 | JNI_TRACE("ssl=%p sslRead buf=%p len=%d", ssl, buf, len); |
| 9617 | |
| 9618 | if (len == 0) { |
| 9619 | // Don't bother doing anything in this case. |
| 9620 | return 0; |
| 9621 | } |
| 9622 | |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 9623 | BIO* rbio = SSL_get_rbio(ssl); |
| 9624 | BIO* wbio = SSL_get_wbio(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9625 | |
| 9626 | AppData* appData = toAppData(ssl); |
Kenny Root | f43a94f | 2014-05-12 13:19:28 -0700 | [diff] [blame] | 9627 | JNI_TRACE("ssl=%p sslRead appData=%p", ssl, appData); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9628 | if (appData == NULL) { |
| 9629 | return THROW_SSLEXCEPTION; |
| 9630 | } |
| 9631 | |
| 9632 | while (appData->aliveAndKicking) { |
| 9633 | errno = 0; |
| 9634 | |
| 9635 | if (MUTEX_LOCK(appData->mutex) == -1) { |
| 9636 | return -1; |
| 9637 | } |
| 9638 | |
Kenny Root | 0931d51 | 2014-08-05 15:45:32 -0700 | [diff] [blame] | 9639 | if (!SSL_is_init_finished(ssl) && !SSL_cutthrough_complete(ssl) && |
| 9640 | !SSL_renegotiate_pending(ssl)) { |
| 9641 | JNI_TRACE("ssl=%p sslRead => init is not finished (state=0x%x)", ssl, |
| 9642 | SSL_get_state(ssl)); |
| 9643 | MUTEX_UNLOCK(appData->mutex); |
| 9644 | return THROW_SSLEXCEPTION; |
| 9645 | } |
| 9646 | |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 9647 | unsigned int bytesMoved = BIO_number_read(rbio) + BIO_number_written(wbio); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9648 | |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9649 | if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9650 | MUTEX_UNLOCK(appData->mutex); |
| 9651 | return THROWN_EXCEPTION; |
| 9652 | } |
| 9653 | int result = SSL_read(ssl, buf, len); |
| 9654 | appData->clearCallbackState(); |
| 9655 | // callbacks can happen if server requests renegotiation |
| 9656 | if (env->ExceptionCheck()) { |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9657 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9658 | JNI_TRACE("ssl=%p sslRead => THROWN_EXCEPTION", ssl); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 9659 | MUTEX_UNLOCK(appData->mutex); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9660 | return THROWN_EXCEPTION; |
| 9661 | } |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9662 | sslError.reset(ssl, result); |
| 9663 | JNI_TRACE("ssl=%p sslRead SSL_read result=%d sslError=%d", ssl, result, sslError.get()); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9664 | #ifdef WITH_JNI_TRACE_DATA |
| 9665 | for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 9666 | int n = result - i; |
| 9667 | if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 9668 | n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; |
| 9669 | } |
Kenny Root | a084cc7 | 2013-05-29 10:33:37 -0700 | [diff] [blame] | 9670 | JNI_TRACE("ssl=%p sslRead data: %d:\n%.*s", ssl, n, n, buf+i); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9671 | } |
| 9672 | #endif |
| 9673 | |
| 9674 | // If we have been successful in moving data around, check whether it |
| 9675 | // might make sense to wake up other blocked threads, so they can give |
| 9676 | // it a try, too. |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 9677 | if (BIO_number_read(rbio) + BIO_number_written(wbio) != bytesMoved |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9678 | && appData->waitingThreads > 0) { |
| 9679 | sslNotify(appData); |
| 9680 | } |
| 9681 | |
| 9682 | // If we are blocked by the underlying socket, tell the world that |
| 9683 | // there will be one more waiting thread now. |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9684 | if (sslError.get() == SSL_ERROR_WANT_READ || sslError.get() == SSL_ERROR_WANT_WRITE) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9685 | appData->waitingThreads++; |
| 9686 | } |
| 9687 | |
| 9688 | MUTEX_UNLOCK(appData->mutex); |
| 9689 | |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9690 | switch (sslError.get()) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9691 | // Successfully read at least one byte. |
| 9692 | case SSL_ERROR_NONE: { |
| 9693 | return result; |
| 9694 | } |
| 9695 | |
| 9696 | // Read zero bytes. End of stream reached. |
| 9697 | case SSL_ERROR_ZERO_RETURN: { |
| 9698 | return -1; |
| 9699 | } |
| 9700 | |
| 9701 | // Need to wait for availability of underlying layer, then retry. |
| 9702 | case SSL_ERROR_WANT_READ: |
| 9703 | case SSL_ERROR_WANT_WRITE: { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9704 | int selectResult = sslSelect(env, sslError.get(), fdObject, appData, read_timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9705 | if (selectResult == THROWN_EXCEPTION) { |
| 9706 | return THROWN_EXCEPTION; |
| 9707 | } |
| 9708 | if (selectResult == -1) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9709 | return THROW_SSLEXCEPTION; |
| 9710 | } |
| 9711 | if (selectResult == 0) { |
| 9712 | return THROW_SOCKETTIMEOUTEXCEPTION; |
| 9713 | } |
| 9714 | |
| 9715 | break; |
| 9716 | } |
| 9717 | |
| 9718 | // A problem occurred during a system call, but this is not |
| 9719 | // necessarily an error. |
| 9720 | case SSL_ERROR_SYSCALL: { |
| 9721 | // Connection closed without proper shutdown. Tell caller we |
| 9722 | // have reached end-of-stream. |
| 9723 | if (result == 0) { |
| 9724 | return -1; |
| 9725 | } |
| 9726 | |
| 9727 | // System call has been interrupted. Simply retry. |
| 9728 | if (errno == EINTR) { |
| 9729 | break; |
| 9730 | } |
| 9731 | |
| 9732 | // Note that for all other system call errors we fall through |
| 9733 | // to the default case, which results in an Exception. |
Kenny Root | 8a9fc46 | 2015-04-02 17:06:30 -0700 | [diff] [blame] | 9734 | FALLTHROUGH_INTENDED; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9735 | } |
| 9736 | |
| 9737 | // Everything else is basically an error. |
| 9738 | default: { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9739 | return THROW_SSLEXCEPTION; |
| 9740 | } |
| 9741 | } |
| 9742 | } |
| 9743 | |
| 9744 | return -1; |
| 9745 | } |
| 9746 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9747 | static jint NativeCrypto_SSL_read_BIO(JNIEnv* env, jclass, jlong sslRef, jbyteArray destJava, |
Kenny Root | 7ed0fae | 2014-07-22 13:03:09 -0700 | [diff] [blame] | 9748 | jint destOffset, jint destLength, jlong sourceBioRef, jlong sinkBioRef, jobject shc) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9749 | SSL* ssl = to_SSL(env, sslRef, true); |
| 9750 | BIO* rbio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(sourceBioRef)); |
| 9751 | BIO* wbio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(sinkBioRef)); |
| 9752 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO dest=%p sourceBio=%p sinkBio=%p shc=%p", |
| 9753 | ssl, destJava, rbio, wbio, shc); |
| 9754 | if (ssl == NULL) { |
| 9755 | return 0; |
| 9756 | } |
| 9757 | if (rbio == NULL || wbio == NULL) { |
| 9758 | jniThrowNullPointerException(env, "rbio == null || wbio == null"); |
| 9759 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => rbio == null || wbio == null", ssl); |
| 9760 | return -1; |
| 9761 | } |
| 9762 | if (shc == NULL) { |
| 9763 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 9764 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => sslHandshakeCallbacks == null", ssl); |
| 9765 | return -1; |
| 9766 | } |
| 9767 | |
| 9768 | ScopedByteArrayRW dest(env, destJava); |
| 9769 | if (dest.get() == NULL) { |
| 9770 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => threw exception", ssl); |
| 9771 | return -1; |
| 9772 | } |
Kenny Root | 7ed0fae | 2014-07-22 13:03:09 -0700 | [diff] [blame] | 9773 | if (destOffset < 0 || destOffset > ssize_t(dest.size()) || destLength < 0 |
| 9774 | || destLength > (ssize_t) dest.size() - destOffset) { |
| 9775 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => destOffset=%d, destLength=%d, size=%zd", |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 9776 | ssl, destOffset, destLength, dest.size()); |
Kenny Root | 7ed0fae | 2014-07-22 13:03:09 -0700 | [diff] [blame] | 9777 | jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL); |
| 9778 | return -1; |
| 9779 | } |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9780 | |
| 9781 | AppData* appData = toAppData(ssl); |
| 9782 | if (appData == NULL) { |
| 9783 | throwSSLExceptionStr(env, "Unable to retrieve application data"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9784 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9785 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => appData == NULL", ssl); |
| 9786 | return -1; |
| 9787 | } |
| 9788 | |
| 9789 | errno = 0; |
| 9790 | |
| 9791 | if (MUTEX_LOCK(appData->mutex) == -1) { |
| 9792 | return -1; |
| 9793 | } |
| 9794 | |
| 9795 | if (!appData->setCallbackState(env, shc, NULL, NULL, NULL)) { |
| 9796 | MUTEX_UNLOCK(appData->mutex); |
| 9797 | throwSSLExceptionStr(env, "Unable to set callback state"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9798 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9799 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => set callback state failed", ssl); |
| 9800 | return -1; |
| 9801 | } |
| 9802 | |
| 9803 | ScopedSslBio sslBio(ssl, rbio, wbio); |
| 9804 | |
Kenny Root | 7ed0fae | 2014-07-22 13:03:09 -0700 | [diff] [blame] | 9805 | int result = SSL_read(ssl, dest.get() + destOffset, destLength); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9806 | appData->clearCallbackState(); |
| 9807 | // callbacks can happen if server requests renegotiation |
| 9808 | if (env->ExceptionCheck()) { |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9809 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9810 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => threw exception", ssl); |
| 9811 | return THROWN_EXCEPTION; |
| 9812 | } |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9813 | OpenSslError sslError(ssl, result); |
| 9814 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO SSL_read result=%d sslError=%d", ssl, result, |
| 9815 | sslError.get()); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9816 | #ifdef WITH_JNI_TRACE_DATA |
| 9817 | for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 9818 | int n = result - i; |
| 9819 | if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 9820 | n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; |
| 9821 | } |
| 9822 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO data: %d:\n%.*s", ssl, n, n, buf+i); |
| 9823 | } |
| 9824 | #endif |
| 9825 | |
| 9826 | MUTEX_UNLOCK(appData->mutex); |
| 9827 | |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9828 | switch (sslError.get()) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9829 | // Successfully read at least one byte. |
| 9830 | case SSL_ERROR_NONE: |
| 9831 | break; |
| 9832 | |
| 9833 | // Read zero bytes. End of stream reached. |
| 9834 | case SSL_ERROR_ZERO_RETURN: |
| 9835 | result = -1; |
| 9836 | break; |
| 9837 | |
| 9838 | // Need to wait for availability of underlying layer, then retry. |
| 9839 | case SSL_ERROR_WANT_READ: |
| 9840 | case SSL_ERROR_WANT_WRITE: |
| 9841 | result = 0; |
| 9842 | break; |
| 9843 | |
| 9844 | // A problem occurred during a system call, but this is not |
| 9845 | // necessarily an error. |
| 9846 | case SSL_ERROR_SYSCALL: { |
| 9847 | // Connection closed without proper shutdown. Tell caller we |
| 9848 | // have reached end-of-stream. |
| 9849 | if (result == 0) { |
| 9850 | result = -1; |
| 9851 | break; |
| 9852 | } else if (errno == EINTR) { |
| 9853 | // System call has been interrupted. Simply retry. |
| 9854 | result = 0; |
| 9855 | break; |
| 9856 | } |
| 9857 | |
| 9858 | // Note that for all other system call errors we fall through |
| 9859 | // to the default case, which results in an Exception. |
Kenny Root | 8a9fc46 | 2015-04-02 17:06:30 -0700 | [diff] [blame] | 9860 | FALLTHROUGH_INTENDED; |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9861 | } |
| 9862 | |
| 9863 | // Everything else is basically an error. |
| 9864 | default: { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9865 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), "Read error"); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 9866 | return -1; |
| 9867 | } |
| 9868 | } |
| 9869 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_BIO => %d", ssl, result); |
| 9870 | return result; |
| 9871 | } |
| 9872 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9873 | /** |
| 9874 | * OpenSSL read function (2): read into buffer at offset n chunks. |
| 9875 | * Returns 1 (success) or value <= 0 (failure). |
| 9876 | */ |
| 9877 | static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, |
| 9878 | jobject shc, jbyteArray b, jint offset, jint len, |
| 9879 | jint read_timeout_millis) |
| 9880 | { |
| 9881 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 9882 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read fd=%p shc=%p b=%p offset=%d len=%d read_timeout_millis=%d", |
| 9883 | ssl, fdObject, shc, b, offset, len, read_timeout_millis); |
| 9884 | if (ssl == NULL) { |
| 9885 | return 0; |
| 9886 | } |
| 9887 | if (fdObject == NULL) { |
| 9888 | jniThrowNullPointerException(env, "fd == null"); |
| 9889 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read => fd == null", ssl); |
| 9890 | return 0; |
| 9891 | } |
| 9892 | if (shc == NULL) { |
| 9893 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 9894 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read => sslHandshakeCallbacks == null", ssl); |
| 9895 | return 0; |
| 9896 | } |
| 9897 | |
| 9898 | ScopedByteArrayRW bytes(env, b); |
| 9899 | if (bytes.get() == NULL) { |
| 9900 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read => threw exception", ssl); |
| 9901 | return 0; |
| 9902 | } |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9903 | |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9904 | OpenSslError sslError; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9905 | int ret = sslRead(env, ssl, fdObject, shc, reinterpret_cast<char*>(bytes.get() + offset), len, |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9906 | sslError, read_timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9907 | |
| 9908 | int result; |
| 9909 | switch (ret) { |
| 9910 | case THROW_SSLEXCEPTION: |
| 9911 | // See sslRead() regarding improper failure to handle normal cases. |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9912 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), "Read error"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9913 | result = -1; |
| 9914 | break; |
| 9915 | case THROW_SOCKETTIMEOUTEXCEPTION: |
| 9916 | throwSocketTimeoutException(env, "Read timed out"); |
| 9917 | result = -1; |
| 9918 | break; |
| 9919 | case THROWN_EXCEPTION: |
| 9920 | // SocketException thrown by NetFd.isClosed |
| 9921 | // or RuntimeException thrown by callback |
| 9922 | result = -1; |
| 9923 | break; |
| 9924 | default: |
| 9925 | result = ret; |
| 9926 | break; |
| 9927 | } |
| 9928 | |
| 9929 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read => %d", ssl, result); |
| 9930 | return result; |
| 9931 | } |
| 9932 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9933 | static int sslWrite(JNIEnv* env, SSL* ssl, jobject fdObject, jobject shc, const char* buf, jint len, |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9934 | OpenSslError& sslError, int write_timeout_millis) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9935 | JNI_TRACE("ssl=%p sslWrite buf=%p len=%d write_timeout_millis=%d", |
| 9936 | ssl, buf, len, write_timeout_millis); |
| 9937 | |
| 9938 | if (len == 0) { |
| 9939 | // Don't bother doing anything in this case. |
| 9940 | return 0; |
| 9941 | } |
| 9942 | |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 9943 | BIO* rbio = SSL_get_rbio(ssl); |
| 9944 | BIO* wbio = SSL_get_wbio(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9945 | |
| 9946 | AppData* appData = toAppData(ssl); |
Kenny Root | f43a94f | 2014-05-12 13:19:28 -0700 | [diff] [blame] | 9947 | JNI_TRACE("ssl=%p sslWrite appData=%p", ssl, appData); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9948 | if (appData == NULL) { |
| 9949 | return THROW_SSLEXCEPTION; |
| 9950 | } |
| 9951 | |
| 9952 | int count = len; |
| 9953 | |
| 9954 | while (appData->aliveAndKicking && ((len > 0) || (ssl->s3->wbuf.left > 0))) { |
| 9955 | errno = 0; |
| 9956 | |
| 9957 | if (MUTEX_LOCK(appData->mutex) == -1) { |
| 9958 | return -1; |
| 9959 | } |
| 9960 | |
Kenny Root | 0931d51 | 2014-08-05 15:45:32 -0700 | [diff] [blame] | 9961 | if (!SSL_is_init_finished(ssl) && !SSL_cutthrough_complete(ssl) && |
| 9962 | !SSL_renegotiate_pending(ssl)) { |
| 9963 | JNI_TRACE("ssl=%p sslWrite => init is not finished (state=0x%x)", ssl, |
| 9964 | SSL_get_state(ssl)); |
| 9965 | MUTEX_UNLOCK(appData->mutex); |
| 9966 | return THROW_SSLEXCEPTION; |
| 9967 | } |
| 9968 | |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 9969 | unsigned int bytesMoved = BIO_number_read(rbio) + BIO_number_written(wbio); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9970 | |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 9971 | if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9972 | MUTEX_UNLOCK(appData->mutex); |
| 9973 | return THROWN_EXCEPTION; |
| 9974 | } |
| 9975 | JNI_TRACE("ssl=%p sslWrite SSL_write len=%d left=%d", ssl, len, ssl->s3->wbuf.left); |
| 9976 | int result = SSL_write(ssl, buf, len); |
| 9977 | appData->clearCallbackState(); |
| 9978 | // callbacks can happen if server requests renegotiation |
| 9979 | if (env->ExceptionCheck()) { |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 9980 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9981 | JNI_TRACE("ssl=%p sslWrite exception => THROWN_EXCEPTION", ssl); |
| 9982 | return THROWN_EXCEPTION; |
| 9983 | } |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9984 | sslError.reset(ssl, result); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9985 | JNI_TRACE("ssl=%p sslWrite SSL_write result=%d sslError=%d left=%d", |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 9986 | ssl, result, sslError.get(), ssl->s3->wbuf.left); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9987 | #ifdef WITH_JNI_TRACE_DATA |
| 9988 | for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
Kenny Root | 74f1a2a | 2013-09-11 15:24:38 -0700 | [diff] [blame] | 9989 | int n = result - i; |
| 9990 | if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 9991 | n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; |
| 9992 | } |
Kenny Root | a084cc7 | 2013-05-29 10:33:37 -0700 | [diff] [blame] | 9993 | JNI_TRACE("ssl=%p sslWrite data: %d:\n%.*s", ssl, n, n, buf+i); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 9994 | } |
| 9995 | #endif |
| 9996 | |
| 9997 | // If we have been successful in moving data around, check whether it |
| 9998 | // might make sense to wake up other blocked threads, so they can give |
| 9999 | // it a try, too. |
Kenny Root | 93cfc3c | 2014-03-31 17:06:21 -0700 | [diff] [blame] | 10000 | if (BIO_number_read(rbio) + BIO_number_written(wbio) != bytesMoved |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10001 | && appData->waitingThreads > 0) { |
| 10002 | sslNotify(appData); |
| 10003 | } |
| 10004 | |
| 10005 | // If we are blocked by the underlying socket, tell the world that |
| 10006 | // there will be one more waiting thread now. |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10007 | if (sslError.get() == SSL_ERROR_WANT_READ || sslError.get() == SSL_ERROR_WANT_WRITE) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10008 | appData->waitingThreads++; |
| 10009 | } |
| 10010 | |
| 10011 | MUTEX_UNLOCK(appData->mutex); |
| 10012 | |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10013 | switch (sslError.get()) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10014 | // Successfully wrote at least one byte. |
| 10015 | case SSL_ERROR_NONE: { |
| 10016 | buf += result; |
| 10017 | len -= result; |
| 10018 | break; |
| 10019 | } |
| 10020 | |
| 10021 | // Wrote zero bytes. End of stream reached. |
| 10022 | case SSL_ERROR_ZERO_RETURN: { |
| 10023 | return -1; |
| 10024 | } |
| 10025 | |
| 10026 | // Need to wait for availability of underlying layer, then retry. |
| 10027 | // The concept of a write timeout doesn't really make sense, and |
| 10028 | // it's also not standard Java behavior, so we wait forever here. |
| 10029 | case SSL_ERROR_WANT_READ: |
| 10030 | case SSL_ERROR_WANT_WRITE: { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10031 | int selectResult = sslSelect(env, sslError.get(), fdObject, appData, |
| 10032 | write_timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10033 | if (selectResult == THROWN_EXCEPTION) { |
| 10034 | return THROWN_EXCEPTION; |
| 10035 | } |
| 10036 | if (selectResult == -1) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10037 | return THROW_SSLEXCEPTION; |
| 10038 | } |
| 10039 | if (selectResult == 0) { |
| 10040 | return THROW_SOCKETTIMEOUTEXCEPTION; |
| 10041 | } |
| 10042 | |
| 10043 | break; |
| 10044 | } |
| 10045 | |
| 10046 | // A problem occurred during a system call, but this is not |
| 10047 | // necessarily an error. |
| 10048 | case SSL_ERROR_SYSCALL: { |
| 10049 | // Connection closed without proper shutdown. Tell caller we |
| 10050 | // have reached end-of-stream. |
| 10051 | if (result == 0) { |
| 10052 | return -1; |
| 10053 | } |
| 10054 | |
| 10055 | // System call has been interrupted. Simply retry. |
| 10056 | if (errno == EINTR) { |
| 10057 | break; |
| 10058 | } |
| 10059 | |
| 10060 | // Note that for all other system call errors we fall through |
| 10061 | // to the default case, which results in an Exception. |
Kenny Root | 8a9fc46 | 2015-04-02 17:06:30 -0700 | [diff] [blame] | 10062 | FALLTHROUGH_INTENDED; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10063 | } |
| 10064 | |
| 10065 | // Everything else is basically an error. |
| 10066 | default: { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10067 | return THROW_SSLEXCEPTION; |
| 10068 | } |
| 10069 | } |
| 10070 | } |
| 10071 | JNI_TRACE("ssl=%p sslWrite => count=%d", ssl, count); |
| 10072 | |
| 10073 | return count; |
| 10074 | } |
| 10075 | |
| 10076 | /** |
| 10077 | * OpenSSL write function (2): write into buffer at offset n chunks. |
| 10078 | */ |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10079 | static int NativeCrypto_SSL_write_BIO(JNIEnv* env, jclass, jlong sslRef, jbyteArray sourceJava, jint len, |
| 10080 | jlong sinkBioRef, jobject shc) { |
| 10081 | SSL* ssl = to_SSL(env, sslRef, true); |
| 10082 | BIO* wbio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(sinkBioRef)); |
| 10083 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO source=%p len=%d wbio=%p shc=%p", |
| 10084 | ssl, sourceJava, len, wbio, shc); |
| 10085 | if (ssl == NULL) { |
| 10086 | return -1; |
| 10087 | } |
| 10088 | if (wbio == NULL) { |
| 10089 | jniThrowNullPointerException(env, "wbio == null"); |
| 10090 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO => wbio == null", ssl); |
| 10091 | return -1; |
| 10092 | } |
| 10093 | if (shc == NULL) { |
| 10094 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 10095 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO => sslHandshakeCallbacks == null", ssl); |
| 10096 | return -1; |
| 10097 | } |
| 10098 | |
| 10099 | AppData* appData = toAppData(ssl); |
| 10100 | if (appData == NULL) { |
| 10101 | throwSSLExceptionStr(env, "Unable to retrieve application data"); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10102 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10103 | freeOpenSslErrorState(); |
| 10104 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO appData => NULL", ssl); |
| 10105 | return -1; |
| 10106 | } |
| 10107 | |
| 10108 | errno = 0; |
| 10109 | |
| 10110 | if (MUTEX_LOCK(appData->mutex) == -1) { |
| 10111 | return 0; |
| 10112 | } |
| 10113 | |
| 10114 | if (!appData->setCallbackState(env, shc, NULL, NULL, NULL)) { |
| 10115 | MUTEX_UNLOCK(appData->mutex); |
| 10116 | throwSSLExceptionStr(env, "Unable to set appdata callback"); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10117 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10118 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10119 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO => appData can't set callback", ssl); |
| 10120 | return -1; |
| 10121 | } |
| 10122 | |
| 10123 | ScopedByteArrayRO source(env, sourceJava); |
| 10124 | if (source.get() == NULL) { |
| 10125 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO => threw exception", ssl); |
| 10126 | return -1; |
| 10127 | } |
| 10128 | |
Adam Langley | dd54621 | 2015-01-20 18:27:45 -0800 | [diff] [blame] | 10129 | #if defined(OPENSSL_IS_BORINGSSL) |
| 10130 | Unique_BIO nullBio(BIO_new_mem_buf(NULL, 0)); |
| 10131 | #else |
Kenny Root | 2fe55c8 | 2014-12-30 14:10:59 -0800 | [diff] [blame] | 10132 | Unique_BIO nullBio(BIO_new(BIO_s_null())); |
Adam Langley | dd54621 | 2015-01-20 18:27:45 -0800 | [diff] [blame] | 10133 | #endif |
Kenny Root | 2fe55c8 | 2014-12-30 14:10:59 -0800 | [diff] [blame] | 10134 | ScopedSslBio sslBio(ssl, nullBio.get(), wbio); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10135 | |
| 10136 | int result = SSL_write(ssl, reinterpret_cast<const char*>(source.get()), len); |
| 10137 | appData->clearCallbackState(); |
| 10138 | // callbacks can happen if server requests renegotiation |
| 10139 | if (env->ExceptionCheck()) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10140 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10141 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10142 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO exception => exception pending (reneg)", ssl); |
| 10143 | return -1; |
| 10144 | } |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10145 | OpenSslError sslError(ssl, result); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10146 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO SSL_write result=%d sslError=%d left=%d", |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10147 | ssl, result, sslError.get(), ssl->s3->wbuf.left); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10148 | #ifdef WITH_JNI_TRACE_DATA |
| 10149 | for (int i = 0; i < result; i+= WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 10150 | int n = result - i; |
| 10151 | if (n > WITH_JNI_TRACE_DATA_CHUNK_SIZE) { |
| 10152 | n = WITH_JNI_TRACE_DATA_CHUNK_SIZE; |
| 10153 | } |
| 10154 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_BIO data: %d:\n%.*s", ssl, n, n, buf+i); |
| 10155 | } |
| 10156 | #endif |
| 10157 | |
| 10158 | MUTEX_UNLOCK(appData->mutex); |
| 10159 | |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10160 | switch (sslError.get()) { |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10161 | case SSL_ERROR_NONE: |
| 10162 | return result; |
| 10163 | |
| 10164 | // Wrote zero bytes. End of stream reached. |
| 10165 | case SSL_ERROR_ZERO_RETURN: |
| 10166 | return -1; |
| 10167 | |
| 10168 | case SSL_ERROR_WANT_READ: |
| 10169 | case SSL_ERROR_WANT_WRITE: |
| 10170 | return 0; |
| 10171 | |
| 10172 | case SSL_ERROR_SYSCALL: { |
| 10173 | // Connection closed without proper shutdown. Tell caller we |
| 10174 | // have reached end-of-stream. |
| 10175 | if (result == 0) { |
| 10176 | return -1; |
| 10177 | } |
| 10178 | |
| 10179 | // System call has been interrupted. Simply retry. |
| 10180 | if (errno == EINTR) { |
| 10181 | return 0; |
| 10182 | } |
| 10183 | |
| 10184 | // Note that for all other system call errors we fall through |
| 10185 | // to the default case, which results in an Exception. |
Kenny Root | 8a9fc46 | 2015-04-02 17:06:30 -0700 | [diff] [blame] | 10186 | FALLTHROUGH_INTENDED; |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10187 | } |
| 10188 | |
| 10189 | // Everything else is basically an error. |
| 10190 | default: { |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10191 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), "Write error"); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10192 | break; |
| 10193 | } |
| 10194 | } |
| 10195 | return -1; |
| 10196 | } |
| 10197 | |
| 10198 | /** |
| 10199 | * OpenSSL write function (2): write into buffer at offset n chunks. |
| 10200 | */ |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10201 | static void NativeCrypto_SSL_write(JNIEnv* env, jclass, jlong ssl_address, jobject fdObject, |
| 10202 | jobject shc, jbyteArray b, jint offset, jint len, jint write_timeout_millis) |
| 10203 | { |
| 10204 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 10205 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write fd=%p shc=%p b=%p offset=%d len=%d write_timeout_millis=%d", |
| 10206 | ssl, fdObject, shc, b, offset, len, write_timeout_millis); |
| 10207 | if (ssl == NULL) { |
| 10208 | return; |
| 10209 | } |
| 10210 | if (fdObject == NULL) { |
| 10211 | jniThrowNullPointerException(env, "fd == null"); |
| 10212 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write => fd == null", ssl); |
| 10213 | return; |
| 10214 | } |
| 10215 | if (shc == NULL) { |
| 10216 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 10217 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write => sslHandshakeCallbacks == null", ssl); |
| 10218 | return; |
| 10219 | } |
| 10220 | |
| 10221 | ScopedByteArrayRO bytes(env, b); |
| 10222 | if (bytes.get() == NULL) { |
| 10223 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write => threw exception", ssl); |
| 10224 | return; |
| 10225 | } |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10226 | OpenSslError sslError; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10227 | int ret = sslWrite(env, ssl, fdObject, shc, reinterpret_cast<const char*>(bytes.get() + offset), |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10228 | len, sslError, write_timeout_millis); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10229 | |
| 10230 | switch (ret) { |
| 10231 | case THROW_SSLEXCEPTION: |
| 10232 | // See sslWrite() regarding improper failure to handle normal cases. |
Kenny Root | a260ee6 | 2014-08-12 15:38:10 -0700 | [diff] [blame] | 10233 | throwSSLExceptionWithSslErrors(env, ssl, sslError.release(), "Write error"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10234 | break; |
| 10235 | case THROW_SOCKETTIMEOUTEXCEPTION: |
| 10236 | throwSocketTimeoutException(env, "Write timed out"); |
| 10237 | break; |
| 10238 | case THROWN_EXCEPTION: |
| 10239 | // SocketException thrown by NetFd.isClosed |
| 10240 | break; |
| 10241 | default: |
| 10242 | break; |
| 10243 | } |
| 10244 | } |
| 10245 | |
| 10246 | /** |
| 10247 | * Interrupt any pending I/O before closing the socket. |
| 10248 | */ |
| 10249 | static void NativeCrypto_SSL_interrupt( |
| 10250 | JNIEnv* env, jclass, jlong ssl_address) { |
| 10251 | SSL* ssl = to_SSL(env, ssl_address, false); |
| 10252 | JNI_TRACE("ssl=%p NativeCrypto_SSL_interrupt", ssl); |
| 10253 | if (ssl == NULL) { |
| 10254 | return; |
| 10255 | } |
| 10256 | |
| 10257 | /* |
| 10258 | * Mark the connection as quasi-dead, then send something to the emergency |
| 10259 | * file descriptor, so any blocking select() calls are woken up. |
| 10260 | */ |
| 10261 | AppData* appData = toAppData(ssl); |
| 10262 | if (appData != NULL) { |
| 10263 | appData->aliveAndKicking = 0; |
| 10264 | |
| 10265 | // At most two threads can be waiting. |
| 10266 | sslNotify(appData); |
| 10267 | sslNotify(appData); |
| 10268 | } |
| 10269 | } |
| 10270 | |
| 10271 | /** |
| 10272 | * OpenSSL close SSL socket function. |
| 10273 | */ |
| 10274 | static void NativeCrypto_SSL_shutdown(JNIEnv* env, jclass, jlong ssl_address, |
| 10275 | jobject fdObject, jobject shc) { |
| 10276 | SSL* ssl = to_SSL(env, ssl_address, false); |
| 10277 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown fd=%p shc=%p", ssl, fdObject, shc); |
| 10278 | if (ssl == NULL) { |
| 10279 | return; |
| 10280 | } |
| 10281 | if (fdObject == NULL) { |
| 10282 | jniThrowNullPointerException(env, "fd == null"); |
| 10283 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => fd == null", ssl); |
| 10284 | return; |
| 10285 | } |
| 10286 | if (shc == NULL) { |
| 10287 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 10288 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => sslHandshakeCallbacks == null", ssl); |
| 10289 | return; |
| 10290 | } |
| 10291 | |
| 10292 | AppData* appData = toAppData(ssl); |
| 10293 | if (appData != NULL) { |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 10294 | if (!appData->setCallbackState(env, shc, fdObject, NULL, NULL)) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10295 | // SocketException thrown by NetFd.isClosed |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10296 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10297 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10298 | return; |
| 10299 | } |
| 10300 | |
| 10301 | /* |
| 10302 | * Try to make socket blocking again. OpenSSL literature recommends this. |
| 10303 | */ |
| 10304 | int fd = SSL_get_fd(ssl); |
| 10305 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown s=%d", ssl, fd); |
| 10306 | if (fd != -1) { |
| 10307 | setBlocking(fd, true); |
| 10308 | } |
| 10309 | |
| 10310 | int ret = SSL_shutdown(ssl); |
| 10311 | appData->clearCallbackState(); |
| 10312 | // callbacks can happen if server requests renegotiation |
| 10313 | if (env->ExceptionCheck()) { |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10314 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10315 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => exception", ssl); |
| 10316 | return; |
| 10317 | } |
| 10318 | switch (ret) { |
| 10319 | case 0: |
| 10320 | /* |
| 10321 | * Shutdown was not successful (yet), but there also |
| 10322 | * is no error. Since we can't know whether the remote |
| 10323 | * server is actually still there, and we don't want to |
| 10324 | * get stuck forever in a second SSL_shutdown() call, we |
| 10325 | * simply return. This is not security a problem as long |
| 10326 | * as we close the underlying socket, which we actually |
| 10327 | * do, because that's where we are just coming from. |
| 10328 | */ |
| 10329 | break; |
| 10330 | case 1: |
| 10331 | /* |
| 10332 | * Shutdown was successful. We can safely return. Hooray! |
| 10333 | */ |
| 10334 | break; |
| 10335 | default: |
| 10336 | /* |
| 10337 | * Everything else is a real error condition. We should |
| 10338 | * let the Java layer know about this by throwing an |
| 10339 | * exception. |
| 10340 | */ |
| 10341 | int sslError = SSL_get_error(ssl, ret); |
| 10342 | throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL shutdown failed"); |
| 10343 | break; |
| 10344 | } |
| 10345 | } |
| 10346 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10347 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10348 | safeSslClear(ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10349 | } |
| 10350 | |
| 10351 | /** |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10352 | * OpenSSL close SSL socket function. |
| 10353 | */ |
| 10354 | static void NativeCrypto_SSL_shutdown_BIO(JNIEnv* env, jclass, jlong ssl_address, jlong rbioRef, |
| 10355 | jlong wbioRef, jobject shc) { |
| 10356 | SSL* ssl = to_SSL(env, ssl_address, false); |
| 10357 | BIO* rbio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(rbioRef)); |
| 10358 | BIO* wbio = reinterpret_cast<BIO*>(static_cast<uintptr_t>(wbioRef)); |
| 10359 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown rbio=%p wbio=%p shc=%p", ssl, rbio, wbio, shc); |
| 10360 | if (ssl == NULL) { |
| 10361 | return; |
| 10362 | } |
| 10363 | if (rbio == NULL || wbio == NULL) { |
| 10364 | jniThrowNullPointerException(env, "rbio == null || wbio == null"); |
| 10365 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => rbio == null || wbio == null", ssl); |
| 10366 | return; |
| 10367 | } |
| 10368 | if (shc == NULL) { |
| 10369 | jniThrowNullPointerException(env, "sslHandshakeCallbacks == null"); |
| 10370 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => sslHandshakeCallbacks == null", ssl); |
| 10371 | return; |
| 10372 | } |
| 10373 | |
| 10374 | AppData* appData = toAppData(ssl); |
| 10375 | if (appData != NULL) { |
| 10376 | if (!appData->setCallbackState(env, shc, NULL, NULL, NULL)) { |
| 10377 | // SocketException thrown by NetFd.isClosed |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10378 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10379 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10380 | return; |
| 10381 | } |
| 10382 | |
| 10383 | ScopedSslBio scopedBio(ssl, rbio, wbio); |
| 10384 | |
| 10385 | int ret = SSL_shutdown(ssl); |
| 10386 | appData->clearCallbackState(); |
| 10387 | // callbacks can happen if server requests renegotiation |
| 10388 | if (env->ExceptionCheck()) { |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10389 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10390 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown => exception", ssl); |
| 10391 | return; |
| 10392 | } |
| 10393 | switch (ret) { |
| 10394 | case 0: |
| 10395 | /* |
| 10396 | * Shutdown was not successful (yet), but there also |
| 10397 | * is no error. Since we can't know whether the remote |
| 10398 | * server is actually still there, and we don't want to |
| 10399 | * get stuck forever in a second SSL_shutdown() call, we |
| 10400 | * simply return. This is not security a problem as long |
| 10401 | * as we close the underlying socket, which we actually |
| 10402 | * do, because that's where we are just coming from. |
| 10403 | */ |
| 10404 | break; |
| 10405 | case 1: |
| 10406 | /* |
| 10407 | * Shutdown was successful. We can safely return. Hooray! |
| 10408 | */ |
| 10409 | break; |
| 10410 | default: |
| 10411 | /* |
| 10412 | * Everything else is a real error condition. We should |
| 10413 | * let the Java layer know about this by throwing an |
| 10414 | * exception. |
| 10415 | */ |
| 10416 | int sslError = SSL_get_error(ssl, ret); |
| 10417 | throwSSLExceptionWithSslErrors(env, ssl, sslError, "SSL shutdown failed"); |
| 10418 | break; |
| 10419 | } |
| 10420 | } |
| 10421 | |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10422 | freeOpenSslErrorState(); |
Kenny Root | 86dd832 | 2014-12-01 12:01:44 -0800 | [diff] [blame] | 10423 | safeSslClear(ssl); |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10424 | } |
| 10425 | |
| 10426 | static jint NativeCrypto_SSL_get_shutdown(JNIEnv* env, jclass, jlong ssl_address) { |
| 10427 | const SSL* ssl = to_SSL(env, ssl_address, true); |
| 10428 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_shutdown", ssl); |
| 10429 | if (ssl == NULL) { |
| 10430 | jniThrowNullPointerException(env, "ssl == null"); |
| 10431 | return 0; |
| 10432 | } |
| 10433 | |
| 10434 | int status = SSL_get_shutdown(ssl); |
| 10435 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_shutdown => %d", ssl, status); |
| 10436 | return static_cast<jint>(status); |
| 10437 | } |
| 10438 | |
| 10439 | /** |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 10440 | * public static native void SSL_free(long ssl); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10441 | */ |
| 10442 | static void NativeCrypto_SSL_free(JNIEnv* env, jclass, jlong ssl_address) |
| 10443 | { |
| 10444 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 10445 | JNI_TRACE("ssl=%p NativeCrypto_SSL_free", ssl); |
| 10446 | if (ssl == NULL) { |
| 10447 | return; |
| 10448 | } |
| 10449 | |
| 10450 | AppData* appData = toAppData(ssl); |
| 10451 | SSL_set_app_data(ssl, NULL); |
| 10452 | delete appData; |
| 10453 | SSL_free(ssl); |
| 10454 | } |
| 10455 | |
| 10456 | /** |
| 10457 | * Gets and returns in a byte array the ID of the actual SSL session. |
| 10458 | */ |
| 10459 | static jbyteArray NativeCrypto_SSL_SESSION_session_id(JNIEnv* env, jclass, |
| 10460 | jlong ssl_session_address) { |
| 10461 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10462 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id", ssl_session); |
| 10463 | if (ssl_session == NULL) { |
| 10464 | return NULL; |
| 10465 | } |
| 10466 | jbyteArray result = env->NewByteArray(ssl_session->session_id_length); |
| 10467 | if (result != NULL) { |
| 10468 | jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id); |
| 10469 | env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src); |
| 10470 | } |
| 10471 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id => %p session_id_length=%d", |
| 10472 | ssl_session, result, ssl_session->session_id_length); |
| 10473 | return result; |
| 10474 | } |
| 10475 | |
| 10476 | /** |
| 10477 | * Gets and returns in a long integer the creation's time of the |
| 10478 | * actual SSL session. |
| 10479 | */ |
| 10480 | static jlong NativeCrypto_SSL_SESSION_get_time(JNIEnv* env, jclass, jlong ssl_session_address) { |
| 10481 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10482 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time", ssl_session); |
| 10483 | if (ssl_session == NULL) { |
| 10484 | return 0; |
| 10485 | } |
| 10486 | // result must be jlong, not long or *1000 will overflow |
| 10487 | jlong result = SSL_SESSION_get_time(ssl_session); |
| 10488 | result *= 1000; // OpenSSL uses seconds, Java uses milliseconds. |
Kenny Root | 6c523c0 | 2014-11-25 13:33:51 -0800 | [diff] [blame] | 10489 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time => %lld", ssl_session, (long long) result); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10490 | return result; |
| 10491 | } |
| 10492 | |
| 10493 | /** |
| 10494 | * Gets and returns in a string the version of the SSL protocol. If it |
| 10495 | * returns the string "unknown" it means that no connection is established. |
| 10496 | */ |
| 10497 | static jstring NativeCrypto_SSL_SESSION_get_version(JNIEnv* env, jclass, jlong ssl_session_address) { |
| 10498 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10499 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version", ssl_session); |
| 10500 | if (ssl_session == NULL) { |
| 10501 | return NULL; |
| 10502 | } |
| 10503 | const char* protocol = SSL_SESSION_get_version(ssl_session); |
| 10504 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version => %s", ssl_session, protocol); |
| 10505 | return env->NewStringUTF(protocol); |
| 10506 | } |
| 10507 | |
| 10508 | /** |
| 10509 | * Gets and returns in a string the cipher negotiated for the SSL session. |
| 10510 | */ |
| 10511 | static jstring NativeCrypto_SSL_SESSION_cipher(JNIEnv* env, jclass, jlong ssl_session_address) { |
| 10512 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10513 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher", ssl_session); |
| 10514 | if (ssl_session == NULL) { |
| 10515 | return NULL; |
| 10516 | } |
| 10517 | const SSL_CIPHER* cipher = ssl_session->cipher; |
| 10518 | const char* name = SSL_CIPHER_get_name(cipher); |
| 10519 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher => %s", ssl_session, name); |
| 10520 | return env->NewStringUTF(name); |
| 10521 | } |
| 10522 | |
| 10523 | /** |
| 10524 | * Frees the SSL session. |
| 10525 | */ |
| 10526 | static void NativeCrypto_SSL_SESSION_free(JNIEnv* env, jclass, jlong ssl_session_address) { |
| 10527 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10528 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_free", ssl_session); |
| 10529 | if (ssl_session == NULL) { |
| 10530 | return; |
| 10531 | } |
| 10532 | SSL_SESSION_free(ssl_session); |
| 10533 | } |
| 10534 | |
| 10535 | |
| 10536 | /** |
| 10537 | * Serializes the native state of the session (ID, cipher, and keys but |
| 10538 | * not certificates). Returns a byte[] containing the DER-encoded state. |
| 10539 | * See apache mod_ssl. |
| 10540 | */ |
| 10541 | static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jlong ssl_session_address) { |
| 10542 | SSL_SESSION* ssl_session = to_SSL_SESSION(env, ssl_session_address, true); |
| 10543 | JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION", ssl_session); |
Kenny Root | a2b8878 | 2013-05-03 13:56:00 -0700 | [diff] [blame] | 10544 | if (ssl_session == NULL) { |
| 10545 | return NULL; |
| 10546 | } |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 10547 | return ASN1ToByteArray<SSL_SESSION>(env, ssl_session, i2d_SSL_SESSION); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10548 | } |
| 10549 | |
| 10550 | /** |
| 10551 | * Deserialize the session. |
| 10552 | */ |
| 10553 | static jlong NativeCrypto_d2i_SSL_SESSION(JNIEnv* env, jclass, jbyteArray javaBytes) { |
| 10554 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION bytes=%p", javaBytes); |
| 10555 | |
| 10556 | ScopedByteArrayRO bytes(env, javaBytes); |
| 10557 | if (bytes.get() == NULL) { |
| 10558 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => threw exception"); |
| 10559 | return 0; |
| 10560 | } |
| 10561 | const unsigned char* ucp = reinterpret_cast<const unsigned char*>(bytes.get()); |
| 10562 | SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, bytes.size()); |
| 10563 | |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 10564 | #if !defined(OPENSSL_IS_BORINGSSL) |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10565 | // Initialize SSL_SESSION cipher field based on cipher_id http://b/7091840 |
| 10566 | if (ssl_session != NULL) { |
| 10567 | // based on ssl_get_prev_session |
| 10568 | uint32_t cipher_id_network_order = htonl(ssl_session->cipher_id); |
| 10569 | uint8_t* cipher_id_byte_pointer = reinterpret_cast<uint8_t*>(&cipher_id_network_order); |
| 10570 | if (ssl_session->ssl_version >= SSL3_VERSION_MAJOR) { |
| 10571 | cipher_id_byte_pointer += 2; // skip first two bytes for SSL3+ |
| 10572 | } else { |
| 10573 | cipher_id_byte_pointer += 1; // skip first byte for SSL2 |
| 10574 | } |
| 10575 | ssl_session->cipher = SSLv23_method()->get_cipher_by_char(cipher_id_byte_pointer); |
| 10576 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION cipher_id=%lx hton=%x 0=%x 1=%x cipher=%s", |
| 10577 | ssl_session->cipher_id, cipher_id_network_order, |
| 10578 | cipher_id_byte_pointer[0], cipher_id_byte_pointer[1], |
| 10579 | SSL_CIPHER_get_name(ssl_session->cipher)); |
Adam Langley | de5225d | 2014-10-06 15:55:30 -0700 | [diff] [blame] | 10580 | } |
| 10581 | #endif |
| 10582 | |
| 10583 | if (ssl_session == NULL) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10584 | freeOpenSslErrorState(); |
| 10585 | } |
| 10586 | |
| 10587 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => %p", ssl_session); |
| 10588 | return reinterpret_cast<uintptr_t>(ssl_session); |
| 10589 | } |
| 10590 | |
| 10591 | static jlong NativeCrypto_ERR_peek_last_error(JNIEnv*, jclass) { |
| 10592 | return ERR_peek_last_error(); |
| 10593 | } |
| 10594 | |
Adam Langley | 9b8d092 | 2015-04-24 07:36:32 -0700 | [diff] [blame] | 10595 | static jstring NativeCrypto_SSL_CIPHER_get_kx_name(JNIEnv* env, jclass, jlong cipher_address) { |
| 10596 | const SSL_CIPHER* cipher = to_SSL_CIPHER(env, cipher_address, true); |
| 10597 | const char *kx_name = NULL; |
| 10598 | |
| 10599 | #if defined(OPENSSL_IS_BORINGSSL) |
| 10600 | kx_name = SSL_CIPHER_get_kx_name(cipher); |
| 10601 | #else |
| 10602 | kx_name = SSL_CIPHER_authentication_method(cipher); |
| 10603 | #endif |
| 10604 | |
| 10605 | return env->NewStringUTF(kx_name); |
| 10606 | } |
| 10607 | |
Adam Langley | d9a68f6 | 2015-04-28 13:19:24 -0700 | [diff] [blame] | 10608 | static jobjectArray NativeCrypto_get_cipher_names(JNIEnv *env, jclass, jstring selectorJava) { |
| 10609 | ScopedUtfChars selector(env, selectorJava); |
| 10610 | if (selector.c_str() == NULL) { |
| 10611 | jniThrowException(env, "java/lang/IllegalArgumentException", "selector == NULL"); |
| 10612 | return 0; |
| 10613 | } |
| 10614 | |
| 10615 | JNI_TRACE("NativeCrypto_get_cipher_names %s", selector.c_str()); |
| 10616 | |
| 10617 | Unique_SSL_CTX sslCtx(SSL_CTX_new(SSLv23_method())); |
| 10618 | Unique_SSL ssl(SSL_new(sslCtx.get())); |
| 10619 | |
| 10620 | if (!SSL_set_cipher_list(ssl.get(), selector.c_str())) { |
| 10621 | jniThrowException(env, "java/lang/IllegalArgumentException", "Unable to set SSL cipher list"); |
| 10622 | return 0; |
| 10623 | } |
| 10624 | STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl.get()); |
| 10625 | |
| 10626 | size_t size = sk_SSL_CIPHER_num(ciphers); |
| 10627 | ScopedLocalRef<jobjectArray> cipherNamesArray(env, env->NewObjectArray(size, stringClass, NULL)); |
| 10628 | if (cipherNamesArray.get() == NULL) { |
| 10629 | return NULL; |
| 10630 | } |
| 10631 | |
| 10632 | for (size_t i = 0; i < size; i++) { |
| 10633 | const char *name = SSL_CIPHER_get_name(sk_SSL_CIPHER_value(ciphers, i)); |
| 10634 | ScopedLocalRef<jstring> cipherName(env, env->NewStringUTF(name)); |
| 10635 | env->SetObjectArrayElement(cipherNamesArray.get(), i, cipherName.get()); |
| 10636 | } |
| 10637 | |
| 10638 | JNI_TRACE("NativeCrypto_get_cipher_names(%s) => success (%zd entries)", selector.c_str(), size); |
| 10639 | return cipherNamesArray.release(); |
| 10640 | } |
| 10641 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10642 | #define FILE_DESCRIPTOR "Ljava/io/FileDescriptor;" |
| 10643 | #define SSL_CALLBACKS "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto$SSLHandshakeCallbacks;" |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 10644 | #define REF_EC_GROUP "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EC_GROUP;" |
| 10645 | #define REF_EC_POINT "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EC_POINT;" |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 10646 | #define REF_EVP_AEAD_CTX "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_AEAD_CTX;" |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 10647 | #define REF_EVP_CIPHER_CTX "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_CIPHER_CTX;" |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10648 | #define REF_EVP_PKEY "L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_PKEY;" |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10649 | static JNINativeMethod sNativeCryptoMethods[] = { |
Kenny Root | 4d7e1f9 | 2015-04-22 09:00:29 -0700 | [diff] [blame] | 10650 | NATIVE_METHOD(NativeCrypto, clinit, "()Z"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10651 | NATIVE_METHOD(NativeCrypto, ENGINE_load_dynamic, "()V"), |
| 10652 | NATIVE_METHOD(NativeCrypto, ENGINE_by_id, "(Ljava/lang/String;)J"), |
| 10653 | NATIVE_METHOD(NativeCrypto, ENGINE_add, "(J)I"), |
| 10654 | NATIVE_METHOD(NativeCrypto, ENGINE_init, "(J)I"), |
| 10655 | NATIVE_METHOD(NativeCrypto, ENGINE_finish, "(J)I"), |
| 10656 | NATIVE_METHOD(NativeCrypto, ENGINE_free, "(J)I"), |
| 10657 | NATIVE_METHOD(NativeCrypto, ENGINE_load_private_key, "(JLjava/lang/String;)J"), |
| 10658 | NATIVE_METHOD(NativeCrypto, ENGINE_get_id, "(J)Ljava/lang/String;"), |
| 10659 | NATIVE_METHOD(NativeCrypto, ENGINE_ctrl_cmd_string, "(JLjava/lang/String;Ljava/lang/String;I)I"), |
Kenny Root | 7b27ca7 | 2014-05-08 14:27:23 -0700 | [diff] [blame] | 10660 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_DH, "([B[B[B[B)J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10661 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_RSA, "([B[B[B[B[B[B[B[B)J"), |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 10662 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_EC_KEY, "(" REF_EC_GROUP REF_EC_POINT "[B)J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10663 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_new_mac_key, "(I[B)J"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10664 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_type, "(" REF_EVP_PKEY ")I"), |
| 10665 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_size, "(" REF_EVP_PKEY ")I"), |
| 10666 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_public, "(" REF_EVP_PKEY ")Ljava/lang/String;"), |
| 10667 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_print_private, "(" REF_EVP_PKEY ")Ljava/lang/String;"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10668 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_free, "(J)V"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10669 | NATIVE_METHOD(NativeCrypto, EVP_PKEY_cmp, "(" REF_EVP_PKEY REF_EVP_PKEY ")I"), |
| 10670 | NATIVE_METHOD(NativeCrypto, i2d_PKCS8_PRIV_KEY_INFO, "(" REF_EVP_PKEY ")[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10671 | NATIVE_METHOD(NativeCrypto, d2i_PKCS8_PRIV_KEY_INFO, "([B)J"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10672 | NATIVE_METHOD(NativeCrypto, i2d_PUBKEY, "(" REF_EVP_PKEY ")[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10673 | NATIVE_METHOD(NativeCrypto, d2i_PUBKEY, "([B)J"), |
Alex Klyubin | 7dab2fd | 2015-02-09 11:32:08 -0800 | [diff] [blame] | 10674 | NATIVE_METHOD(NativeCrypto, getRSAPrivateKeyWrapper, "(Ljava/security/PrivateKey;[B)J"), |
| 10675 | NATIVE_METHOD(NativeCrypto, getECPrivateKeyWrapper, "(Ljava/security/PrivateKey;" REF_EC_GROUP ")J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10676 | NATIVE_METHOD(NativeCrypto, RSA_generate_key_ex, "(I[B)J"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10677 | NATIVE_METHOD(NativeCrypto, RSA_size, "(" REF_EVP_PKEY ")I"), |
| 10678 | NATIVE_METHOD(NativeCrypto, RSA_private_encrypt, "(I[B[B" REF_EVP_PKEY "I)I"), |
| 10679 | NATIVE_METHOD(NativeCrypto, RSA_public_decrypt, "(I[B[B" REF_EVP_PKEY "I)I"), |
| 10680 | NATIVE_METHOD(NativeCrypto, RSA_public_encrypt, "(I[B[B" REF_EVP_PKEY "I)I"), |
| 10681 | NATIVE_METHOD(NativeCrypto, RSA_private_decrypt, "(I[B[B" REF_EVP_PKEY "I)I"), |
| 10682 | NATIVE_METHOD(NativeCrypto, get_RSA_private_params, "(" REF_EVP_PKEY ")[[B"), |
| 10683 | NATIVE_METHOD(NativeCrypto, get_RSA_public_params, "(" REF_EVP_PKEY ")[[B"), |
Kenny Root | 9b226f9 | 2014-07-10 14:50:48 -0700 | [diff] [blame] | 10684 | NATIVE_METHOD(NativeCrypto, DH_generate_parameters_ex, "(IJ)J"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10685 | NATIVE_METHOD(NativeCrypto, DH_generate_key, "(" REF_EVP_PKEY ")V"), |
| 10686 | NATIVE_METHOD(NativeCrypto, get_DH_params, "(" REF_EVP_PKEY ")[[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10687 | NATIVE_METHOD(NativeCrypto, EC_GROUP_new_by_curve_name, "(Ljava/lang/String;)J"), |
Adam Langley | 05b8e50 | 2015-05-12 19:24:49 -0700 | [diff] [blame] | 10688 | NATIVE_METHOD(NativeCrypto, EC_GROUP_new_arbitrary, "([B[B[B[B[B[BI)J"), |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 10689 | NATIVE_METHOD(NativeCrypto, EC_GROUP_set_asn1_flag, "(" REF_EC_GROUP "I)V"), |
| 10690 | NATIVE_METHOD(NativeCrypto, EC_GROUP_set_point_conversion_form, "(" REF_EC_GROUP "I)V"), |
| 10691 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve_name, "(" REF_EC_GROUP ")Ljava/lang/String;"), |
| 10692 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_curve, "(" REF_EC_GROUP ")[[B"), |
| 10693 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_order, "(" REF_EC_GROUP ")[B"), |
| 10694 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_degree, "(" REF_EC_GROUP ")I"), |
| 10695 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_cofactor, "(" REF_EC_GROUP ")[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10696 | NATIVE_METHOD(NativeCrypto, EC_GROUP_clear_free, "(J)V"), |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 10697 | NATIVE_METHOD(NativeCrypto, EC_GROUP_cmp, "(" REF_EC_GROUP REF_EC_GROUP ")Z"), |
| 10698 | NATIVE_METHOD(NativeCrypto, EC_GROUP_get_generator, "(" REF_EC_GROUP ")J"), |
| 10699 | NATIVE_METHOD(NativeCrypto, get_EC_GROUP_type, "(" REF_EC_GROUP ")I"), |
| 10700 | NATIVE_METHOD(NativeCrypto, EC_POINT_new, "(" REF_EC_GROUP ")J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10701 | NATIVE_METHOD(NativeCrypto, EC_POINT_clear_free, "(J)V"), |
Kenny Root | 7dc06b9 | 2014-11-26 10:07:51 -0800 | [diff] [blame] | 10702 | NATIVE_METHOD(NativeCrypto, EC_POINT_cmp, "(" REF_EC_GROUP REF_EC_POINT REF_EC_POINT ")Z"), |
| 10703 | NATIVE_METHOD(NativeCrypto, EC_POINT_set_affine_coordinates, "(" REF_EC_GROUP REF_EC_POINT "[B[B)V"), |
| 10704 | NATIVE_METHOD(NativeCrypto, EC_POINT_get_affine_coordinates, "(" REF_EC_GROUP REF_EC_POINT ")[[B"), |
| 10705 | NATIVE_METHOD(NativeCrypto, EC_KEY_generate_key, "(" REF_EC_GROUP ")J"), |
| 10706 | NATIVE_METHOD(NativeCrypto, EC_KEY_get1_group, "(" REF_EVP_PKEY ")J"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10707 | NATIVE_METHOD(NativeCrypto, EC_KEY_get_private_key, "(" REF_EVP_PKEY ")[B"), |
| 10708 | NATIVE_METHOD(NativeCrypto, EC_KEY_get_public_key, "(" REF_EVP_PKEY ")J"), |
| 10709 | NATIVE_METHOD(NativeCrypto, EC_KEY_set_nonce_from_hash, "(" REF_EVP_PKEY "Z)V"), |
| 10710 | NATIVE_METHOD(NativeCrypto, ECDH_compute_key, "([BI" REF_EVP_PKEY REF_EVP_PKEY ")I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10711 | NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_create, "()J"), |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10712 | NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_init, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10713 | NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_destroy, "(J)V"), |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10714 | NATIVE_METHOD(NativeCrypto, EVP_MD_CTX_copy, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;)I"), |
| 10715 | NATIVE_METHOD(NativeCrypto, EVP_DigestInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J)I"), |
| 10716 | NATIVE_METHOD(NativeCrypto, EVP_DigestUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"), |
| 10717 | NATIVE_METHOD(NativeCrypto, EVP_DigestFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BI)I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10718 | NATIVE_METHOD(NativeCrypto, EVP_get_digestbyname, "(Ljava/lang/String;)J"), |
| 10719 | NATIVE_METHOD(NativeCrypto, EVP_MD_block_size, "(J)I"), |
| 10720 | NATIVE_METHOD(NativeCrypto, EVP_MD_size, "(J)I"), |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10721 | NATIVE_METHOD(NativeCrypto, EVP_SignInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J)I"), |
| 10722 | NATIVE_METHOD(NativeCrypto, EVP_SignUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10723 | NATIVE_METHOD(NativeCrypto, EVP_SignFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BI" REF_EVP_PKEY ")I"), |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10724 | NATIVE_METHOD(NativeCrypto, EVP_VerifyInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J)I"), |
| 10725 | NATIVE_METHOD(NativeCrypto, EVP_VerifyUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII)V"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10726 | NATIVE_METHOD(NativeCrypto, EVP_VerifyFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[BII" REF_EVP_PKEY ")I"), |
| 10727 | NATIVE_METHOD(NativeCrypto, EVP_DigestSignInit, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;J" REF_EVP_PKEY ")V"), |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10728 | NATIVE_METHOD(NativeCrypto, EVP_DigestSignUpdate, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;[B)V"), |
| 10729 | NATIVE_METHOD(NativeCrypto, EVP_DigestSignFinal, "(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_MD_CTX;)[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10730 | NATIVE_METHOD(NativeCrypto, EVP_get_cipherbyname, "(Ljava/lang/String;)J"), |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 10731 | NATIVE_METHOD(NativeCrypto, EVP_CipherInit_ex, "(" REF_EVP_CIPHER_CTX "J[B[BZ)V"), |
| 10732 | NATIVE_METHOD(NativeCrypto, EVP_CipherUpdate, "(" REF_EVP_CIPHER_CTX "[BI[BII)I"), |
| 10733 | NATIVE_METHOD(NativeCrypto, EVP_CipherFinal_ex, "(" REF_EVP_CIPHER_CTX "[BI)I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10734 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_iv_length, "(J)I"), |
| 10735 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_new, "()J"), |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 10736 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_block_size, "(" REF_EVP_CIPHER_CTX ")I"), |
| 10737 | NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_buf_len, "(" REF_EVP_CIPHER_CTX ")I"), |
Sergio Giro | 1127c19 | 2015-06-08 11:36:14 +0100 | [diff] [blame] | 10738 | NATIVE_METHOD(NativeCrypto, get_EVP_CIPHER_CTX_final_used, "(" REF_EVP_CIPHER_CTX ")Z"), |
Kenny Root | 4757cdb | 2014-11-26 07:59:41 -0800 | [diff] [blame] | 10739 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_padding, "(" REF_EVP_CIPHER_CTX "Z)V"), |
| 10740 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_set_key_length, "(" REF_EVP_CIPHER_CTX "I)V"), |
Narayan Kamath | b578b39 | 2014-12-10 14:58:44 +0000 | [diff] [blame] | 10741 | NATIVE_METHOD(NativeCrypto, EVP_CIPHER_CTX_free, "(J)V"), |
Kenny Root | f6f6620 | 2015-05-08 14:01:56 -0700 | [diff] [blame] | 10742 | NATIVE_METHOD(NativeCrypto, EVP_aead_aes_128_gcm, "()J"), |
| 10743 | NATIVE_METHOD(NativeCrypto, EVP_aead_aes_256_gcm, "()J"), |
| 10744 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_init, "(J[BI)J"), |
| 10745 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_cleanup, "(J)V"), |
| 10746 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_max_overhead, "(J)I"), |
| 10747 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_nonce_length, "(J)I"), |
| 10748 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_max_tag_len, "(J)I"), |
| 10749 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_seal, "(" REF_EVP_AEAD_CTX "[BI[B[BII[B)I"), |
| 10750 | NATIVE_METHOD(NativeCrypto, EVP_AEAD_CTX_open, "(" REF_EVP_AEAD_CTX "[BI[B[BII[B)I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10751 | NATIVE_METHOD(NativeCrypto, RAND_seed, "([B)V"), |
| 10752 | NATIVE_METHOD(NativeCrypto, RAND_load_file, "(Ljava/lang/String;J)I"), |
| 10753 | NATIVE_METHOD(NativeCrypto, RAND_bytes, "([B)V"), |
| 10754 | NATIVE_METHOD(NativeCrypto, OBJ_txt2nid, "(Ljava/lang/String;)I"), |
| 10755 | NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_longName, "(Ljava/lang/String;)Ljava/lang/String;"), |
| 10756 | NATIVE_METHOD(NativeCrypto, OBJ_txt2nid_oid, "(Ljava/lang/String;)Ljava/lang/String;"), |
Adam Langley | d82dc06 | 2015-05-18 17:29:43 -0700 | [diff] [blame] | 10757 | NATIVE_METHOD(NativeCrypto, create_BIO_InputStream, ("(L" TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream;Z)J")), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10758 | NATIVE_METHOD(NativeCrypto, create_BIO_OutputStream, "(Ljava/io/OutputStream;)J"), |
| 10759 | NATIVE_METHOD(NativeCrypto, BIO_read, "(J[B)I"), |
| 10760 | NATIVE_METHOD(NativeCrypto, BIO_write, "(J[BII)V"), |
Kenny Root | 19fdf1a | 2014-04-10 11:45:19 -0700 | [diff] [blame] | 10761 | NATIVE_METHOD(NativeCrypto, BIO_free_all, "(J)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10762 | NATIVE_METHOD(NativeCrypto, X509_NAME_print_ex, "(JJ)Ljava/lang/String;"), |
| 10763 | NATIVE_METHOD(NativeCrypto, d2i_X509_bio, "(J)J"), |
| 10764 | NATIVE_METHOD(NativeCrypto, d2i_X509, "([B)J"), |
| 10765 | NATIVE_METHOD(NativeCrypto, i2d_X509, "(J)[B"), |
| 10766 | NATIVE_METHOD(NativeCrypto, i2d_X509_PUBKEY, "(J)[B"), |
| 10767 | NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509, "(J)J"), |
Adam Langley | 2e68e22 | 2015-02-26 17:46:47 -0800 | [diff] [blame] | 10768 | NATIVE_METHOD(NativeCrypto, PEM_read_bio_PKCS7, "(JI)[J"), |
| 10769 | NATIVE_METHOD(NativeCrypto, d2i_PKCS7_bio, "(JI)[J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10770 | NATIVE_METHOD(NativeCrypto, i2d_PKCS7, "([J)[B"), |
| 10771 | NATIVE_METHOD(NativeCrypto, ASN1_seq_unpack_X509_bio, "(J)[J"), |
| 10772 | NATIVE_METHOD(NativeCrypto, ASN1_seq_pack_X509, "([J)[B"), |
| 10773 | NATIVE_METHOD(NativeCrypto, X509_free, "(J)V"), |
| 10774 | NATIVE_METHOD(NativeCrypto, X509_cmp, "(JJ)I"), |
| 10775 | NATIVE_METHOD(NativeCrypto, get_X509_hashCode, "(J)I"), |
| 10776 | NATIVE_METHOD(NativeCrypto, X509_print_ex, "(JJJJ)V"), |
| 10777 | NATIVE_METHOD(NativeCrypto, X509_get_pubkey, "(J)J"), |
| 10778 | NATIVE_METHOD(NativeCrypto, X509_get_issuer_name, "(J)[B"), |
| 10779 | NATIVE_METHOD(NativeCrypto, X509_get_subject_name, "(J)[B"), |
| 10780 | NATIVE_METHOD(NativeCrypto, get_X509_pubkey_oid, "(J)Ljava/lang/String;"), |
| 10781 | NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_oid, "(J)Ljava/lang/String;"), |
| 10782 | NATIVE_METHOD(NativeCrypto, get_X509_sig_alg_parameter, "(J)[B"), |
| 10783 | NATIVE_METHOD(NativeCrypto, get_X509_issuerUID, "(J)[Z"), |
| 10784 | NATIVE_METHOD(NativeCrypto, get_X509_subjectUID, "(J)[Z"), |
| 10785 | NATIVE_METHOD(NativeCrypto, get_X509_ex_kusage, "(J)[Z"), |
| 10786 | NATIVE_METHOD(NativeCrypto, get_X509_ex_xkusage, "(J)[Ljava/lang/String;"), |
| 10787 | NATIVE_METHOD(NativeCrypto, get_X509_ex_pathlen, "(J)I"), |
| 10788 | NATIVE_METHOD(NativeCrypto, X509_get_ext_oid, "(JLjava/lang/String;)[B"), |
| 10789 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext_oid, "(JLjava/lang/String;)[B"), |
| 10790 | NATIVE_METHOD(NativeCrypto, get_X509_CRL_crl_enc, "(J)[B"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10791 | NATIVE_METHOD(NativeCrypto, X509_CRL_verify, "(J" REF_EVP_PKEY ")V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10792 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_lastUpdate, "(J)J"), |
| 10793 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_nextUpdate, "(J)J"), |
| 10794 | NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext_oid, "(JLjava/lang/String;)[B"), |
| 10795 | NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_serialNumber, "(J)[B"), |
| 10796 | NATIVE_METHOD(NativeCrypto, X509_REVOKED_print, "(JJ)V"), |
| 10797 | NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_revocationDate, "(J)J"), |
| 10798 | NATIVE_METHOD(NativeCrypto, get_X509_ext_oids, "(JI)[Ljava/lang/String;"), |
| 10799 | NATIVE_METHOD(NativeCrypto, get_X509_CRL_ext_oids, "(JI)[Ljava/lang/String;"), |
| 10800 | NATIVE_METHOD(NativeCrypto, get_X509_REVOKED_ext_oids, "(JI)[Ljava/lang/String;"), |
| 10801 | NATIVE_METHOD(NativeCrypto, get_X509_GENERAL_NAME_stack, "(JI)[[Ljava/lang/Object;"), |
| 10802 | NATIVE_METHOD(NativeCrypto, X509_get_notBefore, "(J)J"), |
| 10803 | NATIVE_METHOD(NativeCrypto, X509_get_notAfter, "(J)J"), |
| 10804 | NATIVE_METHOD(NativeCrypto, X509_get_version, "(J)J"), |
| 10805 | NATIVE_METHOD(NativeCrypto, X509_get_serialNumber, "(J)[B"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10806 | NATIVE_METHOD(NativeCrypto, X509_verify, "(J" REF_EVP_PKEY ")V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10807 | NATIVE_METHOD(NativeCrypto, get_X509_cert_info_enc, "(J)[B"), |
| 10808 | NATIVE_METHOD(NativeCrypto, get_X509_signature, "(J)[B"), |
| 10809 | NATIVE_METHOD(NativeCrypto, get_X509_CRL_signature, "(J)[B"), |
| 10810 | NATIVE_METHOD(NativeCrypto, get_X509_ex_flags, "(J)I"), |
Kenny Root | 35beb30 | 2013-05-06 11:49:28 -0700 | [diff] [blame] | 10811 | NATIVE_METHOD(NativeCrypto, X509_check_issued, "(JJ)I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10812 | NATIVE_METHOD(NativeCrypto, d2i_X509_CRL_bio, "(J)J"), |
| 10813 | NATIVE_METHOD(NativeCrypto, PEM_read_bio_X509_CRL, "(J)J"), |
| 10814 | NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_cert, "(JJ)J"), |
| 10815 | NATIVE_METHOD(NativeCrypto, X509_CRL_get0_by_serial, "(J[B)J"), |
| 10816 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_REVOKED, "(J)[J"), |
| 10817 | NATIVE_METHOD(NativeCrypto, i2d_X509_CRL, "(J)[B"), |
| 10818 | NATIVE_METHOD(NativeCrypto, X509_CRL_free, "(J)V"), |
| 10819 | NATIVE_METHOD(NativeCrypto, X509_CRL_print, "(JJ)V"), |
| 10820 | NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_oid, "(J)Ljava/lang/String;"), |
| 10821 | NATIVE_METHOD(NativeCrypto, get_X509_CRL_sig_alg_parameter, "(J)[B"), |
| 10822 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_issuer_name, "(J)[B"), |
| 10823 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_version, "(J)J"), |
| 10824 | NATIVE_METHOD(NativeCrypto, X509_CRL_get_ext, "(JLjava/lang/String;)J"), |
| 10825 | NATIVE_METHOD(NativeCrypto, X509_REVOKED_get_ext, "(JLjava/lang/String;)J"), |
| 10826 | NATIVE_METHOD(NativeCrypto, X509_REVOKED_dup, "(J)J"), |
| 10827 | NATIVE_METHOD(NativeCrypto, i2d_X509_REVOKED, "(J)[B"), |
| 10828 | NATIVE_METHOD(NativeCrypto, X509_supported_extension, "(J)I"), |
| 10829 | NATIVE_METHOD(NativeCrypto, ASN1_TIME_to_Calendar, "(JLjava/util/Calendar;)V"), |
| 10830 | NATIVE_METHOD(NativeCrypto, SSL_CTX_new, "()J"), |
| 10831 | NATIVE_METHOD(NativeCrypto, SSL_CTX_free, "(J)V"), |
| 10832 | NATIVE_METHOD(NativeCrypto, SSL_CTX_set_session_id_context, "(J[B)V"), |
| 10833 | NATIVE_METHOD(NativeCrypto, SSL_new, "(J)J"), |
| 10834 | NATIVE_METHOD(NativeCrypto, SSL_enable_tls_channel_id, "(J)V"), |
| 10835 | NATIVE_METHOD(NativeCrypto, SSL_get_tls_channel_id, "(J)[B"), |
Kenny Root | 37e58bb | 2014-11-25 14:29:25 -0800 | [diff] [blame] | 10836 | NATIVE_METHOD(NativeCrypto, SSL_set1_tls_channel_id, "(J" REF_EVP_PKEY ")V"), |
| 10837 | NATIVE_METHOD(NativeCrypto, SSL_use_PrivateKey, "(J" REF_EVP_PKEY ")V"), |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 10838 | NATIVE_METHOD(NativeCrypto, SSL_use_certificate, "(J[J)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10839 | NATIVE_METHOD(NativeCrypto, SSL_check_private_key, "(J)V"), |
| 10840 | NATIVE_METHOD(NativeCrypto, SSL_set_client_CA_list, "(J[[B)V"), |
| 10841 | NATIVE_METHOD(NativeCrypto, SSL_get_mode, "(J)J"), |
| 10842 | NATIVE_METHOD(NativeCrypto, SSL_set_mode, "(JJ)J"), |
| 10843 | NATIVE_METHOD(NativeCrypto, SSL_clear_mode, "(JJ)J"), |
| 10844 | NATIVE_METHOD(NativeCrypto, SSL_get_options, "(J)J"), |
| 10845 | NATIVE_METHOD(NativeCrypto, SSL_set_options, "(JJ)J"), |
| 10846 | NATIVE_METHOD(NativeCrypto, SSL_clear_options, "(JJ)J"), |
Alex Klyubin | 01cce89 | 2014-05-09 03:44:42 -0700 | [diff] [blame] | 10847 | NATIVE_METHOD(NativeCrypto, SSL_use_psk_identity_hint, "(JLjava/lang/String;)V"), |
| 10848 | NATIVE_METHOD(NativeCrypto, set_SSL_psk_client_callback_enabled, "(JZ)V"), |
| 10849 | NATIVE_METHOD(NativeCrypto, set_SSL_psk_server_callback_enabled, "(JZ)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10850 | NATIVE_METHOD(NativeCrypto, SSL_set_cipher_lists, "(J[Ljava/lang/String;)V"), |
Alex Klyubin | 2d089e1 | 2013-11-21 10:28:08 -0800 | [diff] [blame] | 10851 | NATIVE_METHOD(NativeCrypto, SSL_get_ciphers, "(J)[J"), |
| 10852 | NATIVE_METHOD(NativeCrypto, get_SSL_CIPHER_algorithm_auth, "(J)I"), |
| 10853 | NATIVE_METHOD(NativeCrypto, get_SSL_CIPHER_algorithm_mkey, "(J)I"), |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10854 | NATIVE_METHOD(NativeCrypto, SSL_set_accept_state, "(J)V"), |
| 10855 | NATIVE_METHOD(NativeCrypto, SSL_set_connect_state, "(J)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10856 | NATIVE_METHOD(NativeCrypto, SSL_set_verify, "(JI)V"), |
| 10857 | NATIVE_METHOD(NativeCrypto, SSL_set_session, "(JJ)V"), |
| 10858 | NATIVE_METHOD(NativeCrypto, SSL_set_session_creation_enabled, "(JZ)V"), |
Kenny Root | 28328c3 | 2016-05-12 14:15:24 -0700 | [diff] [blame] | 10859 | NATIVE_METHOD(NativeCrypto, SSL_session_reused, "(J)Z"), |
Adam Langley | 295b30e | 2015-06-26 17:32:18 -0700 | [diff] [blame] | 10860 | NATIVE_METHOD(NativeCrypto, SSL_set_reject_peer_renegotiations, "(JZ)V"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10861 | NATIVE_METHOD(NativeCrypto, SSL_set_tlsext_host_name, "(JLjava/lang/String;)V"), |
| 10862 | NATIVE_METHOD(NativeCrypto, SSL_get_servername, "(J)Ljava/lang/String;"), |
Matteo Franchin | 7dd8d0b | 2013-12-09 11:33:10 +0000 | [diff] [blame] | 10863 | NATIVE_METHOD(NativeCrypto, SSL_do_handshake, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "IZ[B[B)J"), |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10864 | NATIVE_METHOD(NativeCrypto, SSL_do_handshake_bio, "(JJJ" SSL_CALLBACKS "Z[B[B)J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10865 | NATIVE_METHOD(NativeCrypto, SSL_renegotiate, "(J)V"), |
Kenny Root | 0e9746b | 2013-09-12 15:14:48 -0700 | [diff] [blame] | 10866 | NATIVE_METHOD(NativeCrypto, SSL_get_certificate, "(J)[J"), |
| 10867 | NATIVE_METHOD(NativeCrypto, SSL_get_peer_cert_chain, "(J)[J"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10868 | NATIVE_METHOD(NativeCrypto, SSL_read, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)I"), |
Kenny Root | 7ed0fae | 2014-07-22 13:03:09 -0700 | [diff] [blame] | 10869 | NATIVE_METHOD(NativeCrypto, SSL_read_BIO, "(J[BIIJJ" SSL_CALLBACKS ")I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10870 | NATIVE_METHOD(NativeCrypto, SSL_write, "(J" FILE_DESCRIPTOR SSL_CALLBACKS "[BIII)V"), |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10871 | NATIVE_METHOD(NativeCrypto, SSL_write_BIO, "(J[BIJ" SSL_CALLBACKS ")I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10872 | NATIVE_METHOD(NativeCrypto, SSL_interrupt, "(J)V"), |
| 10873 | NATIVE_METHOD(NativeCrypto, SSL_shutdown, "(J" FILE_DESCRIPTOR SSL_CALLBACKS ")V"), |
Kenny Root | f878e43 | 2013-11-08 11:37:48 -0800 | [diff] [blame] | 10874 | NATIVE_METHOD(NativeCrypto, SSL_shutdown_BIO, "(JJJ" SSL_CALLBACKS ")V"), |
| 10875 | NATIVE_METHOD(NativeCrypto, SSL_get_shutdown, "(J)I"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10876 | NATIVE_METHOD(NativeCrypto, SSL_free, "(J)V"), |
| 10877 | NATIVE_METHOD(NativeCrypto, SSL_SESSION_session_id, "(J)[B"), |
| 10878 | NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_time, "(J)J"), |
| 10879 | NATIVE_METHOD(NativeCrypto, SSL_SESSION_get_version, "(J)Ljava/lang/String;"), |
| 10880 | NATIVE_METHOD(NativeCrypto, SSL_SESSION_cipher, "(J)Ljava/lang/String;"), |
| 10881 | NATIVE_METHOD(NativeCrypto, SSL_SESSION_free, "(J)V"), |
| 10882 | NATIVE_METHOD(NativeCrypto, i2d_SSL_SESSION, "(J)[B"), |
| 10883 | NATIVE_METHOD(NativeCrypto, d2i_SSL_SESSION, "([B)J"), |
| 10884 | NATIVE_METHOD(NativeCrypto, SSL_CTX_enable_npn, "(J)V"), |
| 10885 | NATIVE_METHOD(NativeCrypto, SSL_CTX_disable_npn, "(J)V"), |
| 10886 | NATIVE_METHOD(NativeCrypto, SSL_get_npn_negotiated_protocol, "(J)[B"), |
Kenny Root | f8a9b54 | 2014-03-31 09:41:48 -0700 | [diff] [blame] | 10887 | NATIVE_METHOD(NativeCrypto, SSL_set_alpn_protos, "(J[B)I"), |
Kenny Root | 6fcf0cb | 2013-06-24 15:54:18 -0700 | [diff] [blame] | 10888 | NATIVE_METHOD(NativeCrypto, SSL_get0_alpn_selected, "(J)[B"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10889 | NATIVE_METHOD(NativeCrypto, ERR_peek_last_error, "()J"), |
Adam Langley | 9b8d092 | 2015-04-24 07:36:32 -0700 | [diff] [blame] | 10890 | NATIVE_METHOD(NativeCrypto, SSL_CIPHER_get_kx_name, "(J)Ljava/lang/String;"), |
Adam Langley | d9a68f6 | 2015-04-28 13:19:24 -0700 | [diff] [blame] | 10891 | NATIVE_METHOD(NativeCrypto, get_cipher_names, "(Ljava/lang/String;)[Ljava/lang/String;"), |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10892 | }; |
| 10893 | |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 10894 | static jclass getGlobalRefToClass(JNIEnv* env, const char* className) { |
| 10895 | ScopedLocalRef<jclass> localClass(env, env->FindClass(className)); |
| 10896 | jclass globalRef = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get())); |
| 10897 | if (globalRef == NULL) { |
| 10898 | ALOGE("failed to find class %s", className); |
| 10899 | abort(); |
| 10900 | } |
| 10901 | return globalRef; |
| 10902 | } |
| 10903 | |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 10904 | static jmethodID getMethodRef(JNIEnv* env, jclass clazz, const char* name, const char* sig) { |
| 10905 | jmethodID localMethod = env->GetMethodID(clazz, name, sig); |
| 10906 | if (localMethod == NULL) { |
| 10907 | ALOGE("could not find method %s", name); |
| 10908 | abort(); |
| 10909 | } |
| 10910 | return localMethod; |
| 10911 | } |
| 10912 | |
| 10913 | static jfieldID getFieldRef(JNIEnv* env, jclass clazz, const char* name, const char* sig) { |
| 10914 | jfieldID localField = env->GetFieldID(clazz, name, sig); |
| 10915 | if (localField == NULL) { |
| 10916 | ALOGE("could not find field %s", name); |
| 10917 | abort(); |
| 10918 | } |
| 10919 | return localField; |
| 10920 | } |
| 10921 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10922 | static void initialize_conscrypt(JNIEnv* env) { |
| 10923 | jniRegisterNativeMethods(env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto", |
| 10924 | sNativeCryptoMethods, NELEM(sNativeCryptoMethods)); |
| 10925 | |
Kenny Root | f24ba06 | 2014-06-09 10:37:46 -0700 | [diff] [blame] | 10926 | cryptoUpcallsClass = getGlobalRefToClass(env, |
| 10927 | TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/CryptoUpcalls"); |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10928 | nativeRefClass = getGlobalRefToClass(env, |
| 10929 | TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef"); |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 10930 | openSslInputStreamClass = getGlobalRefToClass(env, |
Kenny Root | 652ff53 | 2014-02-24 12:35:11 -0800 | [diff] [blame] | 10931 | TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream"); |
| 10932 | |
Kenny Root | 4bff0a1 | 2014-11-25 12:02:21 -0800 | [diff] [blame] | 10933 | nativeRef_context = getFieldRef(env, nativeRefClass, "context", "J"); |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10934 | |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 10935 | calendar_setMethod = getMethodRef(env, calendarClass, "set", "(IIIIII)V"); |
| 10936 | inputStream_readMethod = getMethodRef(env, inputStreamClass, "read", "([B)I"); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 10937 | integer_valueOfMethod = env->GetStaticMethodID(integerClass, "valueOf", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10938 | "(I)Ljava/lang/Integer;"); |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 10939 | openSslInputStream_readLineMethod = getMethodRef(env, openSslInputStreamClass, "gets", |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10940 | "([B)I"); |
Kenny Root | fee2d0f | 2014-06-04 11:24:40 -0700 | [diff] [blame] | 10941 | outputStream_writeMethod = getMethodRef(env, outputStreamClass, "write", "([B)V"); |
| 10942 | outputStream_flushMethod = getMethodRef(env, outputStreamClass, "flush", "()V"); |
Kenny Root | 3e46e4e | 2014-05-23 13:35:10 -0700 | [diff] [blame] | 10943 | |
| 10944 | #ifdef CONSCRYPT_UNBUNDLED |
| 10945 | findAsynchronousCloseMonitorFuncs(); |
| 10946 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10947 | } |
| 10948 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 10949 | static jclass findClass(JNIEnv* env, const char* name) { |
| 10950 | ScopedLocalRef<jclass> localClass(env, env->FindClass(name)); |
| 10951 | jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get())); |
| 10952 | if (result == NULL) { |
| 10953 | ALOGE("failed to find class '%s'", name); |
| 10954 | abort(); |
| 10955 | } |
| 10956 | return result; |
| 10957 | } |
| 10958 | |
Justin Morey | e66dbe5 | 2014-06-10 14:35:13 -0500 | [diff] [blame] | 10959 | #ifdef STATIC_LIB |
| 10960 | // Give client libs everything they need to initialize our JNI |
| 10961 | int libconscrypt_JNI_OnLoad(JavaVM *vm, void*) { |
| 10962 | #else |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10963 | // Use JNI_OnLoad for when we're standalone |
Kenny Root | eaeedc3 | 2013-08-29 13:40:35 -0700 | [diff] [blame] | 10964 | int JNI_OnLoad(JavaVM *vm, void*) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10965 | JNI_TRACE("JNI_OnLoad NativeCrypto"); |
Justin Morey | e66dbe5 | 2014-06-10 14:35:13 -0500 | [diff] [blame] | 10966 | #endif |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10967 | gJavaVM = vm; |
| 10968 | |
| 10969 | JNIEnv *env; |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 10970 | if (vm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) { |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10971 | ALOGE("Could not get JNIEnv"); |
| 10972 | return JNI_ERR; |
| 10973 | } |
| 10974 | |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 10975 | byteArrayClass = findClass(env, "[B"); |
| 10976 | calendarClass = findClass(env, "java/util/Calendar"); |
| 10977 | inputStreamClass = findClass(env, "java/io/InputStream"); |
| 10978 | integerClass = findClass(env, "java/lang/Integer"); |
| 10979 | objectClass = findClass(env, "java/lang/Object"); |
| 10980 | objectArrayClass = findClass(env, "[Ljava/lang/Object;"); |
| 10981 | outputStreamClass = findClass(env, "java/io/OutputStream"); |
| 10982 | stringClass = findClass(env, "java/lang/String"); |
| 10983 | |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10984 | initialize_conscrypt(env); |
Kenny Root | 923e3c5 | 2013-05-01 12:17:23 -0700 | [diff] [blame] | 10985 | return JNI_VERSION_1_6; |
Kenny Root | 860d270 | 2013-04-23 15:50:31 -0700 | [diff] [blame] | 10986 | } |
Kenny Root | 6e1d9d2 | 2015-05-11 10:11:53 -0700 | [diff] [blame] | 10987 | |
| 10988 | /* vim: softtabstop=4:shiftwidth=4:expandtab */ |
| 10989 | |
| 10990 | /* Local Variables: */ |
| 10991 | /* mode: c++ */ |
| 10992 | /* tab-width: 4 */ |
| 10993 | /* indent-tabs-mode: nil */ |
| 10994 | /* c-basic-offset: 4 */ |
| 10995 | /* End: */ |