The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 1 | /* |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2 | * Copyright (C) 2007-2008 The Android Open Source Project |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 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.apache.harmony.xnet.provider.jsse.NativeCrypto |
| 19 | */ |
| 20 | |
| 21 | #define LOG_TAG "NativeCrypto" |
| 22 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 23 | #include <fcntl.h> |
| 24 | #include <sys/socket.h> |
| 25 | #include <unistd.h> |
| 26 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 27 | #include <jni.h> |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 28 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 29 | #include <JNIHelp.h> |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 30 | #include <LocalArray.h> |
| 31 | |
| 32 | #include <openssl/dsa.h> |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 33 | #include <openssl/err.h> |
| 34 | #include <openssl/evp.h> |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 35 | #include <openssl/rand.h> |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 36 | #include <openssl/rsa.h> |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 37 | #include <openssl/ssl.h> |
| 38 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 39 | #include "ScopedByteArray.h" |
| 40 | #include "ScopedGlobalRef.h" |
| 41 | #include "ScopedUtfChars.h" |
| 42 | #include "UniquePtr.h" |
| 43 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 44 | #undef WITH_JNI_TRACE |
| 45 | #ifdef WITH_JNI_TRACE |
| 46 | #define JNI_TRACE(...) \ |
| 47 | ((void)LOG(LOG_INFO, LOG_TAG "-jni", __VA_ARGS__)); \ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 48 | /* |
| 49 | ((void)printf("I/" LOG_TAG "-jni:")); \ |
| 50 | ((void)printf(__VA_ARGS__)); \ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 51 | ((void)printf("\n")) |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 52 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 53 | #else |
| 54 | #define JNI_TRACE(...) ((void)0) |
| 55 | #endif |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 56 | /** |
| 57 | * Frees the SSL error state. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 58 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 59 | * OpenSSL keeps an "error stack" per thread, and given that this code |
| 60 | * can be called from arbitrary threads that we don't keep track of, |
| 61 | * we err on the side of freeing the error state promptly (instead of, |
| 62 | * say, at thread death). |
| 63 | */ |
| 64 | static void freeSslErrorState(void) { |
| 65 | ERR_clear_error(); |
| 66 | ERR_remove_state(0); |
| 67 | } |
| 68 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 69 | /* |
| 70 | * Checks this thread's OpenSSL error queue and throws a RuntimeException if |
| 71 | * necessary. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 72 | * |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 73 | * @return 1 if an exception was thrown, 0 if not. |
| 74 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 75 | static int throwExceptionIfNecessary(JNIEnv* env, const char* /*location*/) { |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 76 | int error = ERR_get_error(); |
| 77 | int result = 0; |
| 78 | |
| 79 | if (error != 0) { |
| 80 | char message[50]; |
| 81 | ERR_error_string_n(error, message, sizeof(message)); |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 82 | // LOGD("OpenSSL error in %s %d: %s", location, error, message); |
Elliott Hughes | da4f31d | 2010-01-28 13:43:39 -0800 | [diff] [blame] | 83 | jniThrowRuntimeException(env, message); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 84 | result = 1; |
| 85 | } |
| 86 | |
| 87 | freeSslErrorState(); |
| 88 | return result; |
| 89 | } |
| 90 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 91 | |
| 92 | /** |
| 93 | * Throws an SocketTimeoutException with the given string as a message. |
| 94 | */ |
| 95 | static void throwSocketTimeoutException(JNIEnv* env, const char* message) { |
| 96 | if (jniThrowException(env, "java/net/SocketTimeoutException", message)) { |
| 97 | LOGE("Unable to throw"); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 102 | * Throws a javax.net.ssl.SSLException with the given string as a message. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 103 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 104 | static void throwSSLExceptionStr(JNIEnv* env, const char* message) { |
| 105 | if (jniThrowException(env, "javax/net/ssl/SSLException", message)) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 106 | LOGE("Unable to throw"); |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 111 | * Throws an SSLException with a message constructed from the current |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 112 | * SSL errors. This will also log the errors. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 113 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 114 | * @param env the JNI environment |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 115 | * @param sslErrorCode error code returned from SSL_get_error() |
| 116 | * @param message null-ok; general error message |
| 117 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 118 | static void throwSSLExceptionWithSslErrors(JNIEnv* env, int sslErrorCode, const char* message) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 119 | const char* messageStr = NULL; |
| 120 | char* str; |
| 121 | int ret; |
| 122 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 123 | // First consult the SSL error code for the general message. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 124 | switch (sslErrorCode) { |
| 125 | case SSL_ERROR_NONE: |
| 126 | messageStr = "Ok"; |
| 127 | break; |
| 128 | case SSL_ERROR_SSL: |
| 129 | messageStr = "Failure in SSL library, usually a protocol error"; |
| 130 | break; |
| 131 | case SSL_ERROR_WANT_READ: |
| 132 | messageStr = "SSL_ERROR_WANT_READ occured. You should never see this."; |
| 133 | break; |
| 134 | case SSL_ERROR_WANT_WRITE: |
| 135 | messageStr = "SSL_ERROR_WANT_WRITE occured. You should never see this."; |
| 136 | break; |
| 137 | case SSL_ERROR_WANT_X509_LOOKUP: |
| 138 | messageStr = "SSL_ERROR_WANT_X509_LOOKUP occured. You should never see this."; |
| 139 | break; |
| 140 | case SSL_ERROR_SYSCALL: |
| 141 | messageStr = "I/O error during system call"; |
| 142 | break; |
| 143 | case SSL_ERROR_ZERO_RETURN: |
| 144 | messageStr = "SSL_ERROR_ZERO_RETURN occured. You should never see this."; |
| 145 | break; |
| 146 | case SSL_ERROR_WANT_CONNECT: |
| 147 | messageStr = "SSL_ERROR_WANT_CONNECT occured. You should never see this."; |
| 148 | break; |
| 149 | case SSL_ERROR_WANT_ACCEPT: |
| 150 | messageStr = "SSL_ERROR_WANT_ACCEPT occured. You should never see this."; |
| 151 | break; |
| 152 | default: |
| 153 | messageStr = "Unknown SSL error"; |
| 154 | } |
| 155 | |
| 156 | // Prepend either our explicit message or a default one. |
| 157 | if (asprintf(&str, "%s: %s", |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 158 | (message != NULL) ? message : "SSL error", messageStr) <= 0) { |
| 159 | // problem with asprintf |
| 160 | throwSSLExceptionStr(env, messageStr); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 161 | LOGV("%s", messageStr); |
| 162 | freeSslErrorState(); |
| 163 | return; |
| 164 | } |
| 165 | |
| 166 | char* allocStr = str; |
| 167 | |
| 168 | // For SSL protocol errors, SSL might have more information. |
| 169 | if (sslErrorCode == SSL_ERROR_SSL) { |
| 170 | // Append each error as an additional line to the message. |
| 171 | for (;;) { |
| 172 | char errStr[256]; |
| 173 | const char* file; |
| 174 | int line; |
| 175 | const char* data; |
| 176 | int flags; |
| 177 | unsigned long err = |
| 178 | ERR_get_error_line_data(&file, &line, &data, &flags); |
| 179 | if (err == 0) { |
| 180 | break; |
| 181 | } |
| 182 | |
| 183 | ERR_error_string_n(err, errStr, sizeof(errStr)); |
| 184 | |
| 185 | ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)", |
| 186 | (allocStr == NULL) ? "" : allocStr, |
| 187 | errStr, |
| 188 | file, |
| 189 | line, |
| 190 | data, |
| 191 | flags); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 192 | |
| 193 | if (ret < 0) { |
| 194 | break; |
| 195 | } |
| 196 | |
| 197 | free(allocStr); |
| 198 | allocStr = str; |
| 199 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 200 | // For errors during system calls, errno might be our friend. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 201 | } else if (sslErrorCode == SSL_ERROR_SYSCALL) { |
| 202 | if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) { |
| 203 | free(allocStr); |
| 204 | allocStr = str; |
| 205 | } |
| 206 | // If the error code is invalid, print it. |
| 207 | } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) { |
| 208 | if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) { |
| 209 | free(allocStr); |
| 210 | allocStr = str; |
| 211 | } |
| 212 | } |
| 213 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 214 | throwSSLExceptionStr(env, allocStr); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 215 | |
| 216 | LOGV("%s", allocStr); |
| 217 | free(allocStr); |
| 218 | freeSslErrorState(); |
| 219 | } |
| 220 | |
| 221 | /** |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 222 | * Helper function that grabs the casts an ssl pointer and then checks for nullness. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 223 | * If this function returns NULL and <code>throwIfNull</code> is |
| 224 | * passed as <code>true</code>, then this function will call |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 225 | * <code>throwSSLExceptionStr</code> before returning, so in this case of |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 226 | * NULL, a caller of this function should simply return and allow JNI |
| 227 | * to do its thing. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 228 | * |
| 229 | * @param env the JNI environment |
| 230 | * @param ssl_address; the ssl_address pointer as an integer |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 231 | * @param throwIfNull whether to throw if the SSL pointer is NULL |
| 232 | * @returns the pointer, which may be NULL |
| 233 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 234 | static SSL* to_SSL(JNIEnv* env, int ssl_address, bool throwIfNull) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 235 | SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address)); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 236 | if ((ssl == NULL) && throwIfNull) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 237 | throwSSLExceptionStr(env, "null SSL pointer"); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 238 | } |
| 239 | |
| 240 | return ssl; |
| 241 | } |
| 242 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 243 | static SSL_CTX* to_SSL_CTX(int ssl_ctx_address) { |
| 244 | return reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address)); |
| 245 | } |
| 246 | |
| 247 | static SSL_SESSION* to_SSL_SESSION(int ssl_session_address) { |
| 248 | return reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address)); |
| 249 | } |
| 250 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 251 | /** |
| 252 | * Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the |
| 253 | * fly. |
| 254 | */ |
| 255 | static BIGNUM* arrayToBignum(JNIEnv* env, jbyteArray source) { |
| 256 | // LOGD("Entering arrayToBignum()"); |
| 257 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 258 | ScopedByteArray sourceBytes(env, source); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 259 | int sourceLength = env->GetArrayLength(source); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 260 | BIGNUM* bignum = BN_bin2bn((unsigned char*) sourceBytes.bytes(), sourceLength, NULL); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 261 | return bignum; |
| 262 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 263 | |
| 264 | /** |
| 265 | * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I |
| 266 | * suppose there are not many other ways to do this on a Linux system (modulo |
| 267 | * isomorphism). |
| 268 | */ |
| 269 | #define MUTEX_TYPE pthread_mutex_t |
| 270 | #define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) |
| 271 | #define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) |
| 272 | #define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) |
| 273 | #define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) |
| 274 | #define THREAD_ID pthread_self() |
| 275 | #define THROW_EXCEPTION (-2) |
| 276 | #define THROW_SOCKETTIMEOUTEXCEPTION (-3) |
| 277 | |
| 278 | static MUTEX_TYPE *mutex_buf = NULL; |
| 279 | |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 280 | static void locking_function(int mode, int n, const char*, int) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 281 | if (mode & CRYPTO_LOCK) { |
| 282 | MUTEX_LOCK(mutex_buf[n]); |
| 283 | } else { |
| 284 | MUTEX_UNLOCK(mutex_buf[n]); |
| 285 | } |
| 286 | } |
| 287 | |
| 288 | static unsigned long id_function(void) { |
| 289 | return ((unsigned long)THREAD_ID); |
| 290 | } |
| 291 | |
| 292 | int THREAD_setup(void) { |
| 293 | int i; |
| 294 | |
| 295 | mutex_buf = (MUTEX_TYPE *)malloc(CRYPTO_num_locks( ) * sizeof(MUTEX_TYPE)); |
| 296 | |
| 297 | if(!mutex_buf) { |
| 298 | return 0; |
| 299 | } |
| 300 | |
| 301 | for (i = 0; i < CRYPTO_num_locks( ); i++) { |
| 302 | MUTEX_SETUP(mutex_buf[i]); |
| 303 | } |
| 304 | |
| 305 | CRYPTO_set_id_callback(id_function); |
| 306 | CRYPTO_set_locking_callback(locking_function); |
| 307 | |
| 308 | return 1; |
| 309 | } |
| 310 | |
| 311 | int THREAD_cleanup(void) { |
| 312 | int i; |
| 313 | |
| 314 | if (!mutex_buf) { |
| 315 | return 0; |
| 316 | } |
| 317 | |
| 318 | CRYPTO_set_id_callback(NULL); |
| 319 | CRYPTO_set_locking_callback(NULL); |
| 320 | |
| 321 | for (i = 0; i < CRYPTO_num_locks( ); i++) { |
| 322 | MUTEX_CLEANUP(mutex_buf[i]); |
| 323 | } |
| 324 | |
| 325 | free(mutex_buf); |
| 326 | mutex_buf = NULL; |
| 327 | |
| 328 | return 1; |
| 329 | } |
| 330 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 331 | /** |
| 332 | * Initialization phase for every OpenSSL job: Loads the Error strings, the |
| 333 | * crypto algorithms and reset the OpenSSL library |
| 334 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 335 | static void NativeCrypto_clinit(JNIEnv*, jclass) |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 336 | { |
| 337 | SSL_load_error_strings(); |
| 338 | ERR_load_crypto_strings(); |
| 339 | SSL_library_init(); |
| 340 | OpenSSL_add_all_algorithms(); |
| 341 | THREAD_setup(); |
| 342 | } |
| 343 | |
| 344 | /** |
| 345 | * public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g, byte[] pub_key, byte[] priv_key); |
| 346 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 347 | static EVP_PKEY* NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass, jbyteArray p, jbyteArray q, jbyteArray g, jbyteArray pub_key, jbyteArray priv_key) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 348 | // LOGD("Entering EVP_PKEY_new_DSA()"); |
| 349 | |
| 350 | DSA* dsa = DSA_new(); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 351 | if (dsa == NULL) { |
| 352 | jniThrowRuntimeException(env, "DSA_new failed"); |
| 353 | return NULL; |
| 354 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 355 | |
| 356 | dsa->p = arrayToBignum(env, p); |
| 357 | dsa->q = arrayToBignum(env, q); |
| 358 | dsa->g = arrayToBignum(env, g); |
| 359 | dsa->pub_key = arrayToBignum(env, pub_key); |
| 360 | |
| 361 | if (priv_key != NULL) { |
| 362 | dsa->priv_key = arrayToBignum(env, priv_key); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 363 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 364 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 365 | if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL || dsa->pub_key == NULL) { |
| 366 | DSA_free(dsa); |
| 367 | jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); |
| 368 | return NULL; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 369 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 370 | |
| 371 | EVP_PKEY* pkey = EVP_PKEY_new(); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 372 | if (pkey == NULL) { |
| 373 | jniThrowRuntimeException(env, "EVP_PKEY_new failed"); |
| 374 | return NULL; |
| 375 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 376 | EVP_PKEY_assign_DSA(pkey, dsa); |
| 377 | |
| 378 | return pkey; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 379 | } |
| 380 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 381 | /** |
| 382 | * private static native int EVP_PKEY_new_RSA(byte[] n, byte[] e, byte[] d, byte[] p, byte[] q); |
| 383 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 384 | static EVP_PKEY* NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass, jbyteArray n, jbyteArray e, jbyteArray d, jbyteArray p, jbyteArray q) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 385 | // LOGD("Entering EVP_PKEY_new_RSA()"); |
| 386 | |
| 387 | RSA* rsa = RSA_new(); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 388 | if (rsa == NULL) { |
| 389 | jniThrowRuntimeException(env, "RSA_new failed"); |
| 390 | return NULL; |
| 391 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 392 | |
| 393 | rsa->n = arrayToBignum(env, n); |
| 394 | rsa->e = arrayToBignum(env, e); |
| 395 | |
| 396 | if (d != NULL) { |
| 397 | rsa->d = arrayToBignum(env, d); |
| 398 | } |
| 399 | |
| 400 | if (p != NULL) { |
| 401 | rsa->p = arrayToBignum(env, p); |
| 402 | } |
| 403 | |
| 404 | if (q != NULL) { |
| 405 | rsa->q = arrayToBignum(env, q); |
| 406 | } |
| 407 | |
| 408 | // int check = RSA_check_key(rsa); |
| 409 | // LOGI("RSA_check_key returns %d", check); |
| 410 | |
| 411 | if (rsa->n == NULL || rsa->e == NULL) { |
| 412 | RSA_free(rsa); |
| 413 | jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM"); |
| 414 | return NULL; |
| 415 | } |
| 416 | |
| 417 | EVP_PKEY* pkey = EVP_PKEY_new(); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 418 | if (pkey == NULL) { |
| 419 | RSA_free(rsa); |
| 420 | jniThrowRuntimeException(env, "EVP_PKEY_new failed"); |
| 421 | return NULL; |
| 422 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 423 | EVP_PKEY_assign_RSA(pkey, rsa); |
| 424 | |
| 425 | return pkey; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 426 | } |
| 427 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 428 | /** |
| 429 | * private static native void EVP_PKEY_free(int pkey); |
| 430 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 431 | static void NativeCrypto_EVP_PKEY_free(JNIEnv*, jclass, EVP_PKEY* pkey) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 432 | // LOGD("Entering EVP_PKEY_free()"); |
| 433 | |
| 434 | if (pkey != NULL) { |
| 435 | EVP_PKEY_free(pkey); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | /* |
| 440 | * public static native int EVP_new() |
| 441 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 442 | static jint NativeCrypto_EVP_new(JNIEnv*, jclass) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 443 | // LOGI("NativeCrypto_EVP_DigestNew"); |
| 444 | |
| 445 | return (jint)EVP_MD_CTX_create(); |
| 446 | } |
| 447 | |
| 448 | /* |
| 449 | * public static native void EVP_free(int) |
| 450 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 451 | static void NativeCrypto_EVP_free(JNIEnv*, jclass, EVP_MD_CTX* ctx) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 452 | // LOGI("NativeCrypto_EVP_DigestFree"); |
| 453 | |
| 454 | if (ctx != NULL) { |
| 455 | EVP_MD_CTX_destroy(ctx); |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | /* |
| 460 | * public static native int EVP_DigestFinal(int, byte[], int) |
| 461 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 462 | static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray hash, jint offset) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 463 | // LOGI("NativeCrypto_EVP_DigestFinal%x, %x, %d, %d", ctx, hash, offset); |
| 464 | |
| 465 | if (ctx == NULL || hash == NULL) { |
| 466 | jniThrowNullPointerException(env, NULL); |
| 467 | return -1; |
| 468 | } |
| 469 | |
| 470 | int result = -1; |
| 471 | |
| 472 | jbyte* hashBytes = env->GetByteArrayElements(hash, NULL); |
| 473 | EVP_DigestFinal(ctx, (unsigned char*) (hashBytes + offset), (unsigned int*)&result); |
| 474 | env->ReleaseByteArrayElements(hash, hashBytes, 0); |
| 475 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 476 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestFinal"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 477 | |
| 478 | return result; |
| 479 | } |
| 480 | |
| 481 | /* |
| 482 | * public static native void EVP_DigestInit(int, java.lang.String) |
| 483 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 484 | static void NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jstring algorithm) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 485 | // LOGI("NativeCrypto_EVP_DigestInit"); |
| 486 | |
| 487 | if (ctx == NULL || algorithm == NULL) { |
| 488 | jniThrowNullPointerException(env, NULL); |
| 489 | return; |
| 490 | } |
| 491 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 492 | ScopedUtfChars algorithmChars(env, algorithm); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 493 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 494 | const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str())); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 495 | |
| 496 | if (digest == NULL) { |
| 497 | jniThrowRuntimeException(env, "Hash algorithm not found"); |
| 498 | return; |
| 499 | } |
| 500 | |
| 501 | EVP_DigestInit(ctx, digest); |
| 502 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 503 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestInit"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 504 | } |
| 505 | |
| 506 | /* |
| 507 | * public static native void EVP_DigestSize(int) |
| 508 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 509 | static jint NativeCrypto_EVP_DigestSize(JNIEnv* env, jclass, EVP_MD_CTX* ctx) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 510 | // LOGI("NativeCrypto_EVP_DigestSize"); |
| 511 | |
| 512 | if (ctx == NULL) { |
| 513 | jniThrowNullPointerException(env, NULL); |
| 514 | return -1; |
| 515 | } |
| 516 | |
| 517 | int result = EVP_MD_CTX_size(ctx); |
| 518 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 519 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestSize"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 520 | |
| 521 | return result; |
| 522 | } |
| 523 | |
| 524 | /* |
| 525 | * public static native void EVP_DigestBlockSize(int) |
| 526 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 527 | static jint NativeCrypto_EVP_DigestBlockSize(JNIEnv* env, jclass, EVP_MD_CTX* ctx) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 528 | // LOGI("NativeCrypto_EVP_DigestBlockSize"); |
| 529 | |
| 530 | if (ctx == NULL) { |
| 531 | jniThrowNullPointerException(env, NULL); |
| 532 | return -1; |
| 533 | } |
| 534 | |
| 535 | int result = EVP_MD_CTX_block_size(ctx); |
| 536 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 537 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestBlockSize"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 538 | |
| 539 | return result; |
| 540 | } |
| 541 | |
| 542 | /* |
| 543 | * public static native void EVP_DigestUpdate(int, byte[], int, int) |
| 544 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 545 | static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 546 | // LOGI("NativeCrypto_EVP_DigestUpdate %x, %x, %d, %d", ctx, buffer, offset, length); |
| 547 | |
| 548 | if (ctx == NULL || buffer == NULL) { |
| 549 | jniThrowNullPointerException(env, NULL); |
| 550 | return; |
| 551 | } |
| 552 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 553 | ScopedByteArray bufferBytes(env, buffer); |
| 554 | EVP_DigestUpdate(ctx, (unsigned char*) (bufferBytes.bytes() + offset), length); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 555 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 556 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_DigestUpdate"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 557 | } |
| 558 | |
| 559 | /* |
| 560 | * public static native void EVP_VerifyInit(int, java.lang.String) |
| 561 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 562 | static void NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jstring algorithm) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 563 | // LOGI("NativeCrypto_EVP_VerifyInit"); |
| 564 | |
| 565 | if (ctx == NULL || algorithm == NULL) { |
| 566 | jniThrowNullPointerException(env, NULL); |
| 567 | return; |
| 568 | } |
| 569 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 570 | ScopedUtfChars algorithmChars(env, algorithm); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 571 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 572 | const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars.c_str())); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 573 | |
| 574 | if (digest == NULL) { |
| 575 | jniThrowRuntimeException(env, "Hash algorithm not found"); |
| 576 | return; |
| 577 | } |
| 578 | |
| 579 | EVP_VerifyInit(ctx, digest); |
| 580 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 581 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyInit"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 582 | } |
| 583 | |
| 584 | /* |
| 585 | * public static native void EVP_VerifyUpdate(int, byte[], int, int) |
| 586 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 587 | static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 588 | // LOGI("NativeCrypto_EVP_VerifyUpdate %x, %x, %d, %d", ctx, buffer, offset, length); |
| 589 | |
| 590 | if (ctx == NULL || buffer == NULL) { |
| 591 | jniThrowNullPointerException(env, NULL); |
| 592 | return; |
| 593 | } |
| 594 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 595 | ScopedByteArray bufferBytes(env, buffer); |
| 596 | EVP_VerifyUpdate(ctx, (unsigned char*) (bufferBytes.bytes() + offset), length); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 597 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 598 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyUpdate"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 599 | } |
| 600 | |
| 601 | /* |
| 602 | * public static native void EVP_VerifyFinal(int, byte[], int, int, int) |
| 603 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 604 | static int NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length, EVP_PKEY* pkey) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 605 | // LOGI("NativeCrypto_EVP_VerifyFinal %x, %x, %d, %d %x", ctx, buffer, offset, length, pkey); |
| 606 | |
| 607 | if (ctx == NULL || buffer == NULL || pkey == NULL) { |
| 608 | jniThrowNullPointerException(env, NULL); |
| 609 | return -1; |
| 610 | } |
| 611 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 612 | ScopedByteArray bufferBytes(env, buffer); |
| 613 | int result = EVP_VerifyFinal(ctx, (unsigned char*) (bufferBytes.bytes() + offset), length, pkey); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 614 | |
Brian Carlstrom | 02d23a6 | 2010-05-04 22:44:46 -0700 | [diff] [blame] | 615 | throwExceptionIfNecessary(env, "NativeCrypto_EVP_VerifyFinal"); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 616 | |
| 617 | return result; |
| 618 | } |
| 619 | |
| 620 | /** |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 621 | * Helper function that creates an RSA public key from two buffers containing |
| 622 | * the big-endian bit representation of the modulus and the public exponent. |
| 623 | * |
| 624 | * @param mod The data of the modulus |
| 625 | * @param modLen The length of the modulus data |
| 626 | * @param exp The data of the exponent |
| 627 | * @param expLen The length of the exponent data |
| 628 | * |
| 629 | * @return A pointer to the new RSA structure, or NULL on error |
| 630 | */ |
| 631 | static RSA* rsaCreateKey(unsigned char* mod, int modLen, unsigned char* exp, int expLen) { |
| 632 | // LOGD("Entering rsaCreateKey()"); |
| 633 | |
| 634 | RSA* rsa = RSA_new(); |
| 635 | if (rsa == NULL) { |
| 636 | return NULL; |
| 637 | } |
| 638 | |
| 639 | rsa->n = BN_bin2bn(mod, modLen, NULL); |
| 640 | rsa->e = BN_bin2bn(exp, expLen, NULL); |
| 641 | |
| 642 | if (rsa->n == NULL || rsa->e == NULL) { |
| 643 | RSA_free(rsa); |
| 644 | return NULL; |
| 645 | } |
| 646 | |
| 647 | return rsa; |
| 648 | } |
| 649 | |
| 650 | /** |
| 651 | * Helper function that verifies a given RSA signature for a given message. |
| 652 | * |
| 653 | * @param msg The message to verify |
| 654 | * @param msgLen The length of the message |
| 655 | * @param sig The signature to verify |
| 656 | * @param sigLen The length of the signature |
| 657 | * @param algorithm The name of the hash/sign algorithm to use, e.g. "RSA-SHA1" |
| 658 | * @param rsa The RSA public key to use |
| 659 | * |
| 660 | * @return 1 on success, 0 on failure, -1 on error (check SSL errors then) |
| 661 | * |
| 662 | */ |
| 663 | static int rsaVerify(unsigned char* msg, unsigned int msgLen, unsigned char* sig, |
| 664 | unsigned int sigLen, char* algorithm, RSA* rsa) { |
| 665 | |
| 666 | // LOGD("Entering rsaVerify(%x, %d, %x, %d, %s, %x)", msg, msgLen, sig, sigLen, algorithm, rsa); |
| 667 | |
| 668 | EVP_PKEY* pkey = EVP_PKEY_new(); |
| 669 | if (pkey == NULL) { |
| 670 | return -1; |
| 671 | } |
| 672 | EVP_PKEY_set1_RSA(pkey, rsa); |
| 673 | |
| 674 | const EVP_MD *type = EVP_get_digestbyname(algorithm); |
| 675 | if (type == NULL) { |
| 676 | EVP_PKEY_free(pkey); |
| 677 | return -1; |
| 678 | } |
| 679 | |
| 680 | EVP_MD_CTX ctx; |
| 681 | EVP_MD_CTX_init(&ctx); |
| 682 | if (EVP_VerifyInit_ex(&ctx, type, NULL) == 0) { |
| 683 | EVP_PKEY_free(pkey); |
| 684 | return -1; |
| 685 | } |
| 686 | |
| 687 | EVP_VerifyUpdate(&ctx, msg, msgLen); |
| 688 | int result = EVP_VerifyFinal(&ctx, sig, sigLen, pkey); |
| 689 | EVP_MD_CTX_cleanup(&ctx); |
| 690 | EVP_PKEY_free(pkey); |
| 691 | return result; |
| 692 | } |
| 693 | |
| 694 | /** |
| 695 | * Verifies an RSA signature. |
| 696 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 697 | static int NativeCrypto_verifysignature(JNIEnv* env, jclass, |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 698 | jbyteArray msg, jbyteArray sig, jstring algorithm, jbyteArray mod, jbyteArray exp) { |
| 699 | |
| 700 | JNI_TRACE("NativeCrypto_verifysignature msg=%p sig=%p algorithm=%p mod=%p exp%p", |
| 701 | msg, sig, algorithm, mod, exp); |
| 702 | |
| 703 | if (msg == NULL || sig == NULL || algorithm == NULL || mod == NULL || exp == NULL) { |
| 704 | jniThrowNullPointerException(env, NULL); |
| 705 | JNI_TRACE("NativeCrypto_verifysignature => -1"); |
| 706 | return -1; |
| 707 | } |
| 708 | |
| 709 | int result = -1; |
| 710 | |
| 711 | ScopedByteArray msgBytes(env, msg); |
| 712 | jint msgLength = env->GetArrayLength(msg); |
| 713 | |
| 714 | ScopedByteArray sigBytes(env, sig); |
| 715 | jint sigLength = env->GetArrayLength(sig); |
| 716 | |
| 717 | ScopedByteArray modBytes(env, mod); |
| 718 | jint modLength = env->GetArrayLength(mod); |
| 719 | |
| 720 | ScopedByteArray expBytes(env, exp); |
| 721 | jint expLength = env->GetArrayLength(exp); |
| 722 | |
| 723 | ScopedUtfChars algorithmChars(env, algorithm); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 724 | JNI_TRACE("NativeCrypto_verifysignature algorithmChars=%s", algorithmChars.c_str()); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 725 | |
| 726 | RSA* rsa = rsaCreateKey((unsigned char*) modBytes.bytes(), modLength, (unsigned char*) expBytes.bytes(), expLength); |
| 727 | if (rsa != NULL) { |
| 728 | result = rsaVerify((unsigned char*) msgBytes.bytes(), msgLength, (unsigned char*) sigBytes.bytes(), sigLength, |
| 729 | (char*) algorithmChars.c_str(), rsa); |
| 730 | RSA_free(rsa); |
| 731 | } |
| 732 | |
| 733 | if (result == -1) { |
| 734 | if (!throwExceptionIfNecessary(env, "NativeCrypto_verifysignature")) { |
| 735 | jniThrowRuntimeException(env, "Internal error during verification"); |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | JNI_TRACE("NativeCrypto_verifysignature => %d", result); |
| 740 | return result; |
| 741 | } |
| 742 | |
| 743 | /** |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 744 | * Convert ssl version constant to string. Based on SSL_get_version |
| 745 | */ |
Brian Carlstrom | f002bdd | 2010-05-05 13:23:14 -0700 | [diff] [blame] | 746 | // TODO move to jsse.patch |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 747 | static const char* get_ssl_version(int ssl_version) { |
| 748 | switch (ssl_version) { |
| 749 | // newest to oldest |
| 750 | case TLS1_VERSION: { |
| 751 | return SSL_TXT_TLSV1; |
| 752 | } |
| 753 | case SSL3_VERSION: { |
| 754 | return SSL_TXT_SSLV3; |
| 755 | } |
| 756 | case SSL2_VERSION: { |
| 757 | return SSL_TXT_SSLV2; |
| 758 | } |
| 759 | default: { |
| 760 | return "unknown"; |
| 761 | } |
| 762 | } |
| 763 | } |
| 764 | |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 765 | #ifdef WITH_JNI_TRACE |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 766 | /** |
| 767 | * Convert content type constant to string. |
| 768 | */ |
Brian Carlstrom | f002bdd | 2010-05-05 13:23:14 -0700 | [diff] [blame] | 769 | // TODO move to jsse.patch |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 770 | static const char* get_content_type(int content_type) { |
| 771 | switch (content_type) { |
| 772 | case SSL3_RT_CHANGE_CIPHER_SPEC: { |
| 773 | return "SSL3_RT_CHANGE_CIPHER_SPEC"; |
| 774 | } |
| 775 | case SSL3_RT_ALERT: { |
| 776 | return "SSL3_RT_ALERT"; |
| 777 | } |
| 778 | case SSL3_RT_HANDSHAKE: { |
| 779 | return "SSL3_RT_HANDSHAKE"; |
| 780 | } |
| 781 | case SSL3_RT_APPLICATION_DATA: { |
| 782 | return "SSL3_RT_APPLICATION_DATA"; |
| 783 | } |
| 784 | default: { |
| 785 | LOGD("Unknown TLS/SSL content type %d", content_type); |
| 786 | return "<unknown>"; |
| 787 | } |
| 788 | } |
| 789 | } |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 790 | #endif |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 791 | |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 792 | #ifdef WITH_JNI_TRACE |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 793 | /** |
| 794 | * Simple logging call back to show hand shake messages |
| 795 | */ |
| 796 | static void ssl_msg_callback_LOG(int write_p, int ssl_version, int content_type, |
| 797 | const void *buf, size_t len, SSL* ssl, void* arg) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 798 | JNI_TRACE("ssl=%p SSL msg %s %s %s %p %d %p", |
| 799 | ssl, |
| 800 | (write_p) ? "send" : "recv", |
| 801 | get_ssl_version(ssl_version), |
| 802 | get_content_type(content_type), |
| 803 | buf, |
| 804 | len, |
| 805 | arg); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 806 | } |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 807 | #endif |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 808 | |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 809 | #ifdef WITH_JNI_TRACE |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 810 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 811 | * Based on example logging call back from SSL_CTX_set_info_callback man page |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 812 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 813 | static void info_callback_LOG(const SSL* s __attribute__ ((unused)), int where, int ret) |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 814 | { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 815 | int w = where & ~SSL_ST_MASK; |
| 816 | const char* str; |
| 817 | if (w & SSL_ST_CONNECT) { |
| 818 | str = "SSL_connect"; |
| 819 | } else if (w & SSL_ST_ACCEPT) { |
| 820 | str = "SSL_accept"; |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 821 | } else { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 822 | str = "undefined"; |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 823 | } |
| 824 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 825 | if (where & SSL_CB_LOOP) { |
| 826 | JNI_TRACE("ssl=%p %s:%s %s", s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 827 | } else if (where & SSL_CB_ALERT) { |
| 828 | str = (where & SSL_CB_READ) ? "read" : "write"; |
| 829 | JNI_TRACE("ssl=%p SSL3 alert %s:%s:%s %s %s", |
| 830 | s, |
| 831 | str, |
| 832 | SSL_alert_type_string(ret), |
| 833 | SSL_alert_desc_string(ret), |
| 834 | SSL_alert_type_string_long(ret), |
| 835 | SSL_alert_desc_string_long(ret)); |
| 836 | } else if (where & SSL_CB_EXIT) { |
| 837 | if (ret == 0) { |
| 838 | JNI_TRACE("ssl=%p %s:failed exit in %s %s", |
| 839 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 840 | } else if (ret < 0) { |
| 841 | JNI_TRACE("ssl=%p %s:error exit in %s %s", |
| 842 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 843 | } else if (ret == 1) { |
| 844 | JNI_TRACE("ssl=%p %s:ok exit in %s %s", |
| 845 | s, str, SSL_state_string(s), SSL_state_string_long(s)); |
| 846 | } else { |
| 847 | JNI_TRACE("ssl=%p %s:unknown exit %d in %s %s", |
| 848 | s, str, ret, SSL_state_string(s), SSL_state_string_long(s)); |
| 849 | } |
| 850 | } else if (where & SSL_CB_HANDSHAKE_START) { |
| 851 | JNI_TRACE("ssl=%p handshake start in %s %s", |
| 852 | s, SSL_state_string(s), SSL_state_string_long(s)); |
| 853 | } else if (where & SSL_CB_HANDSHAKE_DONE) { |
| 854 | JNI_TRACE("ssl=%p handshake done in %s %s", |
| 855 | s, SSL_state_string(s), SSL_state_string_long(s)); |
| 856 | } else { |
| 857 | JNI_TRACE("ssl=%p %s:unknown where %d in %s %s", |
| 858 | s, str, where, SSL_state_string(s), SSL_state_string_long(s)); |
| 859 | } |
| 860 | } |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 861 | #endif |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 862 | |
| 863 | /** |
| 864 | * Returns an array containing all the X509 certificate's bytes. |
| 865 | */ |
| 866 | static jobjectArray getCertificateBytes(JNIEnv* env, |
| 867 | const STACK_OF(X509) *chain) |
| 868 | { |
| 869 | if (chain == NULL) { |
| 870 | // Chain can be NULL if the associated cipher doesn't do certs. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 871 | return NULL; |
| 872 | } |
| 873 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 874 | int count = sk_X509_num(chain); |
| 875 | if (count <= 0) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 876 | return NULL; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 877 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 878 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 879 | jobjectArray joa = env->NewObjectArray(count, env->FindClass("[B"), NULL); |
| 880 | if (joa == NULL) { |
| 881 | return NULL; |
| 882 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 883 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 884 | BIO* bio = BIO_new(BIO_s_mem()); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 885 | if (bio == NULL) { |
| 886 | jniThrowRuntimeException(env, "BIO_new failed"); |
| 887 | return NULL; |
| 888 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 889 | |
| 890 | // LOGD("Start fetching the certificates"); |
| 891 | for (int i = 0; i < count; i++) { |
| 892 | X509* cert = sk_X509_value(chain, i); |
| 893 | |
| 894 | BIO_reset(bio); |
| 895 | PEM_write_bio_X509(bio, cert); |
| 896 | |
| 897 | BUF_MEM* bptr; |
| 898 | BIO_get_mem_ptr(bio, &bptr); |
| 899 | jbyteArray bytes = env->NewByteArray(bptr->length); |
| 900 | |
| 901 | if (bytes == NULL) { |
| 902 | /* |
| 903 | * Indicate an error by resetting joa to NULL. It will |
| 904 | * eventually get gc'ed. |
| 905 | */ |
| 906 | joa = NULL; |
| 907 | break; |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 908 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 909 | jbyte* src = reinterpret_cast<jbyte*>(bptr->data); |
| 910 | env->SetByteArrayRegion(bytes, 0, bptr->length, src); |
| 911 | env->SetObjectArrayElement(joa, i, bytes); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 912 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 913 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 914 | // LOGD("Certificate fetching complete"); |
| 915 | BIO_free(bio); |
| 916 | return joa; |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 917 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 918 | |
| 919 | /** |
| 920 | * Our additional application data needed for getting synchronization right. |
| 921 | * This maybe warrants a bit of lengthy prose: |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 922 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 923 | * (1) We use a flag to reflect whether we consider the SSL connection alive. |
| 924 | * Any read or write attempt loops will be cancelled once this flag becomes 0. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 925 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 926 | * (2) We use an int to count the number of threads that are blocked by the |
| 927 | * underlying socket. This may be at most two (one reader and one writer), since |
| 928 | * the Java layer ensures that no more threads will enter the native code at the |
| 929 | * same time. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 930 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 931 | * (3) The pipe is used primarily as a means of cancelling a blocking select() |
| 932 | * when we want to close the connection (aka "emergency button"). It is also |
| 933 | * necessary for dealing with a possible race condition situation: There might |
| 934 | * be cases where both threads see an SSL_ERROR_WANT_READ or |
| 935 | * SSL_ERROR_WANT_WRITE. Both will enter a select() with the proper argument. |
| 936 | * If one leaves the select() successfully before the other enters it, the |
| 937 | * "success" event is already consumed and the second thread will be blocked, |
| 938 | * possibly forever (depending on network conditions). |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 939 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 940 | * The idea for solving the problem looks like this: Whenever a thread is |
| 941 | * successful in moving around data on the network, and it knows there is |
| 942 | * another thread stuck in a select(), it will write a byte to the pipe, waking |
| 943 | * up the other thread. A thread that returned from select(), on the other hand, |
| 944 | * knows whether it's been woken up by the pipe. If so, it will consume the |
| 945 | * byte, and the original state of affairs has been restored. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 946 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 947 | * The pipe may seem like a bit of overhead, but it fits in nicely with the |
| 948 | * other file descriptors of the select(), so there's only one condition to wait |
| 949 | * for. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 950 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 951 | * (4) Finally, a mutex is needed to make sure that at most one thread is in |
| 952 | * either SSL_read() or SSL_write() at any given time. This is an OpenSSL |
| 953 | * requirement. We use the same mutex to guard the field for counting the |
| 954 | * waiting threads. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 955 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 956 | * Note: The current implementation assumes that we don't have to deal with |
| 957 | * problems induced by multiple cores or processors and their respective |
| 958 | * memory caches. One possible problem is that of inconsistent views on the |
| 959 | * "aliveAndKicking" field. This could be worked around by also enclosing all |
| 960 | * accesses to that field inside a lock/unlock sequence of our mutex, but |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 961 | * currently this seems a bit like overkill. Marking volatile at the very least. |
| 962 | * |
| 963 | * During handshaking, three additional fields are used to up-call into |
| 964 | * Java to perform certificate verification and handshake completion. |
| 965 | * |
| 966 | * (5) the JNIEnv so we can invoke the Java callback |
| 967 | * |
| 968 | * (6) a NativeCrypto.CertificateChainVerifier to call with the peer certificate chain |
| 969 | * |
| 970 | * (7) a NativeCrypto.HandshakeCompletedCallback to call back when handshake is done |
| 971 | * |
| 972 | * These fields are cleared by the info_callback the handshake has |
| 973 | * completed. SSL_VERIFY_CLIENT_ONCE is currently used to disable |
| 974 | * renegotiation but if that changes, care would need to be taken to |
| 975 | * maintain an appropriate JNIEnv on any downcall to openssl that |
| 976 | * could result in an upcall to Java. The current code does try to |
| 977 | * cover these cases by conditionally setting the JNIenv on calls that |
| 978 | * can read and write to the SSL such as SSL_do_handshake, SSL_read, |
| 979 | * SSL_write, and SSL_shutdown if handshaking is not complete. |
| 980 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 981 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 982 | class AppData { |
| 983 | public: |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 984 | volatile int aliveAndKicking; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 985 | int waitingThreads; |
| 986 | int fdsEmergency[2]; |
| 987 | MUTEX_TYPE mutex; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 988 | JNIEnv* env; |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 989 | ScopedGlobalRef certificateChainVerifier; |
| 990 | ScopedGlobalRef handshakeCompletedCallback; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 991 | |
| 992 | /** |
| 993 | * Creates our application data and attaches it to a given SSL connection. |
| 994 | * |
| 995 | * @param ssl The SSL connection to attach the data to. |
| 996 | * @param env The JNIEnv |
| 997 | * @param ccv The CertificateChainVerifier |
| 998 | * @param hcc The HandshakeCompletedCallback |
| 999 | */ |
| 1000 | public: |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1001 | static AppData* create(JNIEnv* e, |
| 1002 | jobject certificateChainVerifier, |
| 1003 | jobject handshakeCompletedCallback) { |
| 1004 | if (certificateChainVerifier == NULL) { |
| 1005 | return NULL; |
| 1006 | } |
| 1007 | if (handshakeCompletedCallback == NULL) { |
| 1008 | return NULL; |
| 1009 | } |
| 1010 | UniquePtr<AppData> appData(new AppData(e, certificateChainVerifier, handshakeCompletedCallback)); |
| 1011 | if (appData->certificateChainVerifier.get() == NULL) { |
| 1012 | return NULL; |
| 1013 | } |
| 1014 | if (appData->handshakeCompletedCallback.get() == NULL) { |
| 1015 | return NULL; |
| 1016 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1017 | if (pipe(appData->fdsEmergency) == -1) { |
| 1018 | return NULL; |
| 1019 | } |
| 1020 | if (MUTEX_SETUP(appData->mutex) == -1) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1021 | return NULL; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1022 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1023 | return appData.release(); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1024 | } |
| 1025 | |
| 1026 | private: |
| 1027 | AppData(JNIEnv* e, jobject ccv, jobject hcc) : |
| 1028 | aliveAndKicking(1), |
| 1029 | waitingThreads(0), |
| 1030 | env(e), |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1031 | certificateChainVerifier(e, ccv), |
| 1032 | handshakeCompletedCallback(e, hcc) { |
| 1033 | fdsEmergency[0] = -1; |
| 1034 | fdsEmergency[1] = -1; |
| 1035 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1036 | |
| 1037 | /** |
| 1038 | * Destroys our application data, cleaning up everything in the process. |
| 1039 | */ |
| 1040 | public: |
| 1041 | ~AppData() { |
| 1042 | aliveAndKicking = 0; |
| 1043 | if (fdsEmergency[0] != -1) { |
| 1044 | close(fdsEmergency[0]); |
| 1045 | } |
| 1046 | if (fdsEmergency[1] != -1) { |
| 1047 | close(fdsEmergency[1]); |
| 1048 | } |
| 1049 | MUTEX_CLEANUP(mutex); |
| 1050 | } |
| 1051 | |
| 1052 | void setEnv(JNIEnv* e) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1053 | if (handshakeCompletedCallback.get() == NULL) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1054 | return; |
| 1055 | } |
| 1056 | env = e; |
| 1057 | } |
| 1058 | void clearEnv() { |
| 1059 | env = NULL; |
| 1060 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1061 | |
| 1062 | void handshakeCompleted() { |
| 1063 | certificateChainVerifier.reset(); |
| 1064 | handshakeCompletedCallback.reset(); |
| 1065 | clearEnv(); |
| 1066 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1067 | }; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1068 | |
| 1069 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1070 | * Dark magic helper function that checks, for a given SSL session, whether it |
| 1071 | * can SSL_read() or SSL_write() without blocking. Takes into account any |
| 1072 | * concurrent attempts to close the SSL session from the Java side. This is |
| 1073 | * needed to get rid of the hangs that occur when thread #1 closes the SSLSocket |
| 1074 | * while thread #2 is sitting in a blocking read or write. The type argument |
| 1075 | * specifies whether we are waiting for readability or writability. It expects |
| 1076 | * to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we |
| 1077 | * only need to wait in case one of these problems occurs. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1078 | * |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1079 | * @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE |
| 1080 | * @param fd The file descriptor to wait for (the underlying socket) |
| 1081 | * @param data The application data structure with mutex info etc. |
| 1082 | * @param timeout The timeout value for select call, with the special value |
| 1083 | * 0 meaning no timeout at all (wait indefinitely). Note: This is |
| 1084 | * the Java semantics of the timeout value, not the usual |
| 1085 | * select() semantics. |
| 1086 | * @return The result of the inner select() call, -1 on additional errors |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1087 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1088 | static int sslSelect(int type, int fd, AppData* appData, int timeout) { |
| 1089 | fd_set rfds; |
| 1090 | fd_set wfds; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1091 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1092 | FD_ZERO(&rfds); |
| 1093 | FD_ZERO(&wfds); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1094 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1095 | if (type == SSL_ERROR_WANT_READ) { |
| 1096 | FD_SET(fd, &rfds); |
| 1097 | } else { |
| 1098 | FD_SET(fd, &wfds); |
| 1099 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1100 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1101 | FD_SET(appData->fdsEmergency[0], &rfds); |
| 1102 | |
| 1103 | int max = fd > appData->fdsEmergency[0] ? fd : appData->fdsEmergency[0]; |
| 1104 | |
| 1105 | // Build a struct for the timeout data if we actually want a timeout. |
| 1106 | struct timeval tv; |
| 1107 | struct timeval *ptv; |
| 1108 | if (timeout > 0) { |
| 1109 | tv.tv_sec = timeout / 1000; |
| 1110 | tv.tv_usec = 0; |
| 1111 | ptv = &tv; |
| 1112 | } else { |
| 1113 | ptv = NULL; |
| 1114 | } |
| 1115 | |
| 1116 | // LOGD("Doing select() for SSL_ERROR_WANT_%s...", type == SSL_ERROR_WANT_READ ? "READ" : "WRITE"); |
| 1117 | int result = select(max + 1, &rfds, &wfds, NULL, ptv); |
| 1118 | // LOGD("Returned from select(), result is %d", result); |
| 1119 | |
| 1120 | // Lock |
| 1121 | if (MUTEX_LOCK(appData->mutex) == -1) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1122 | return -1; |
| 1123 | } |
| 1124 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1125 | // If we have been woken up by the emergency pipe, there must be a token in |
| 1126 | // it. Thus we can safely read it (even in a blocking way). |
| 1127 | if (FD_ISSET(appData->fdsEmergency[0], &rfds)) { |
| 1128 | char token; |
| 1129 | do { |
| 1130 | read(appData->fdsEmergency[0], &token, 1); |
| 1131 | } while (errno == EINTR); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1132 | } |
| 1133 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1134 | // Tell the world that there is now one thread less waiting for the |
| 1135 | // underlying network. |
| 1136 | appData->waitingThreads--; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1137 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1138 | // Unlock |
| 1139 | MUTEX_UNLOCK(appData->mutex); |
| 1140 | // LOGD("leave sslSelect"); |
| 1141 | return result; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1142 | } |
| 1143 | |
| 1144 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1145 | * Helper function that wakes up a thread blocked in select(), in case there is |
| 1146 | * one. Is being called by sslRead() and sslWrite() as well as by JNI glue |
| 1147 | * before closing the connection. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1148 | * |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1149 | * @param data The application data structure with mutex info etc. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1150 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1151 | static void sslNotify(AppData* appData) { |
| 1152 | // Write a byte to the emergency pipe, so a concurrent select() can return. |
| 1153 | // Note we have to restore the errno of the original system call, since the |
| 1154 | // caller relies on it for generating error messages. |
| 1155 | int errnoBackup = errno; |
| 1156 | char token = '*'; |
| 1157 | do { |
| 1158 | errno = 0; |
| 1159 | write(appData->fdsEmergency[1], &token, 1); |
| 1160 | } while (errno == EINTR); |
| 1161 | errno = errnoBackup; |
| 1162 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1163 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1164 | // From private header file external/openssl/ssl_locl.h |
Brian Carlstrom | f002bdd | 2010-05-05 13:23:14 -0700 | [diff] [blame] | 1165 | // TODO move dependant code to jsse.patch to avoid dependency |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1166 | #define SSL_aRSA 0x00000001L |
| 1167 | #define SSL_aDSS 0x00000002L |
| 1168 | #define SSL_aNULL 0x00000004L |
| 1169 | #define SSL_aDH 0x00000008L |
| 1170 | #define SSL_aECDH 0x00000010L |
| 1171 | #define SSL_aKRB5 0x00000020L |
| 1172 | #define SSL_aECDSA 0x00000040L |
| 1173 | #define SSL_aPSK 0x00000080L |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1174 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1175 | /** |
| 1176 | * Converts an SSL_CIPHER's algorithms field to a TrustManager auth argument |
| 1177 | */ |
Brian Carlstrom | f002bdd | 2010-05-05 13:23:14 -0700 | [diff] [blame] | 1178 | // TODO move to jsse.patch |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1179 | static const char* SSL_CIPHER_authentication_method(const SSL_CIPHER* cipher) |
| 1180 | { |
| 1181 | unsigned long alg_auth = cipher->algorithm_auth; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1182 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1183 | const char *au; |
| 1184 | switch (alg_auth) { |
| 1185 | case SSL_aRSA: |
| 1186 | au="RSA"; |
| 1187 | break; |
| 1188 | case SSL_aDSS: |
| 1189 | au="DSS"; |
| 1190 | break; |
| 1191 | case SSL_aDH: |
| 1192 | au="DH"; |
| 1193 | break; |
| 1194 | case SSL_aKRB5: |
| 1195 | au="KRB5"; |
| 1196 | break; |
| 1197 | case SSL_aECDH: |
| 1198 | au = "ECDH"; |
| 1199 | break; |
| 1200 | case SSL_aNULL: |
| 1201 | au="None"; |
| 1202 | break; |
| 1203 | case SSL_aECDSA: |
| 1204 | au="ECDSA"; |
| 1205 | break; |
| 1206 | case SSL_aPSK: |
| 1207 | au="PSK"; |
| 1208 | break; |
| 1209 | default: |
| 1210 | au="unknown"; |
| 1211 | break; |
| 1212 | } |
| 1213 | return au; |
| 1214 | } |
| 1215 | |
| 1216 | /** |
| 1217 | * Verify the X509 certificate via SSL_CTX_set_cert_verify_callback |
| 1218 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1219 | static int cert_verify_callback(X509_STORE_CTX* x509_store_ctx, void* arg __attribute__ ((unused))) |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1220 | { |
| 1221 | /* Get the correct index to the SSLobject stored into X509_STORE_CTX. */ |
| 1222 | SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(x509_store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); |
| 1223 | JNI_TRACE("ssl=%p cert_verify_callback x509_store_ctx=%p arg=%p", ssl, x509_store_ctx, arg); |
| 1224 | |
| 1225 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 1226 | JNIEnv* env = appData->env; |
| 1227 | if (env == NULL) { |
| 1228 | LOGE("AppData->env missing in cert_verify_callback"); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1229 | JNI_TRACE("ssl=%p cert_verify_callback => 0", ssl); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1230 | return 0; |
| 1231 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1232 | jobject certificateChainVerifier = appData->certificateChainVerifier.get(); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1233 | |
| 1234 | jclass cls = env->GetObjectClass(certificateChainVerifier); |
| 1235 | jmethodID methodID = env->GetMethodID(cls, "verifyCertificateChain", "([[BLjava/lang/String;)V"); |
| 1236 | |
| 1237 | jobjectArray objectArray = getCertificateBytes(env, x509_store_ctx->untrusted); |
| 1238 | |
| 1239 | const char* authMethod; |
| 1240 | switch (ssl->version) { |
| 1241 | case SSL2_VERSION: |
| 1242 | authMethod = "RSA"; |
| 1243 | break; |
| 1244 | case SSL3_VERSION: |
| 1245 | case TLS1_VERSION: |
| 1246 | case DTLS1_VERSION: |
| 1247 | authMethod = SSL_CIPHER_authentication_method(ssl->s3->tmp.new_cipher); |
| 1248 | break; |
| 1249 | default: |
| 1250 | authMethod = "unknown"; |
| 1251 | break; |
| 1252 | } |
| 1253 | jstring authMethodString = env->NewStringUTF(authMethod); |
| 1254 | |
| 1255 | env->CallVoidMethod(certificateChainVerifier, methodID, objectArray, authMethodString); |
| 1256 | |
| 1257 | int result = (env->ExceptionCheck()) ? 0 : 1; |
| 1258 | JNI_TRACE("ssl=%p cert_verify_callback => %d", ssl, result); |
| 1259 | return result; |
| 1260 | } |
| 1261 | |
| 1262 | /** |
| 1263 | * Call back to watch for handshake to be completed. This is necessary |
| 1264 | * for SSL_MODE_HANDSHAKE_CUTTHROUGH support, since SSL_do_handshake |
| 1265 | * returns before the handshake is completed in this case. |
| 1266 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1267 | static void info_callback(const SSL *ssl, int where, int ret __attribute__ ((unused))) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1268 | JNI_TRACE("ssl=%p info_callback where=0x%x ret=%d", ssl, where, ret); |
| 1269 | #ifdef WITH_JNI_TRACE |
| 1270 | info_callback_LOG(ssl, where, ret); |
| 1271 | #endif |
| 1272 | if (!(where & SSL_CB_HANDSHAKE_DONE)) { |
| 1273 | JNI_TRACE("ssl=%p info_callback ignored", ssl); |
| 1274 | return; |
| 1275 | } |
| 1276 | |
| 1277 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 1278 | JNIEnv* env = appData->env; |
| 1279 | if (env == NULL) { |
| 1280 | LOGE("AppData->env missing in info_callback"); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1281 | JNI_TRACE("ssl=%p info_callback env error", ssl); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1282 | return; |
| 1283 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1284 | jobject handshakeCompletedCallback = appData->handshakeCompletedCallback.get(); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1285 | |
| 1286 | jclass cls = env->GetObjectClass(handshakeCompletedCallback); |
| 1287 | jmethodID methodID = env->GetMethodID(cls, "handshakeCompleted", "()V"); |
| 1288 | |
| 1289 | JNI_TRACE("ssl=%p info_callback calling handshakeCompleted", ssl); |
| 1290 | env->CallVoidMethod(handshakeCompletedCallback, methodID); |
| 1291 | |
| 1292 | if (env->ExceptionCheck()) { |
| 1293 | JNI_TRACE("ssl=%p info_callback exception", ssl); |
| 1294 | } |
| 1295 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1296 | appData->handshakeCompleted(); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1297 | JNI_TRACE("ssl=%p info_callback completed", ssl); |
| 1298 | } |
| 1299 | |
| 1300 | /* |
| 1301 | * public static native int SSL_CTX_new(); |
| 1302 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1303 | static int NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1304 | SSL_CTX* sslCtx = SSL_CTX_new(SSLv23_method()); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1305 | if (sslCtx == NULL) { |
| 1306 | jniThrowRuntimeException(env, "SSL_CTX_new"); |
| 1307 | return NULL; |
| 1308 | } |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1309 | // Note: We explicitly do not allow SSLv2 to be used. |
| 1310 | SSL_CTX_set_options(sslCtx, SSL_OP_ALL | SSL_OP_NO_SSLv2); |
| 1311 | |
| 1312 | int mode = SSL_CTX_get_mode(sslCtx); |
| 1313 | /* |
| 1314 | * Turn on "partial write" mode. This means that SSL_write() will |
| 1315 | * behave like Posix write() and possibly return after only |
| 1316 | * writing a partial buffer. Note: The alternative, perhaps |
| 1317 | * surprisingly, is not that SSL_write() always does full writes |
| 1318 | * but that it will force you to retry write calls having |
| 1319 | * preserved the full state of the original call. (This is icky |
| 1320 | * and undesirable.) |
| 1321 | */ |
| 1322 | mode |= SSL_MODE_ENABLE_PARTIAL_WRITE; |
| 1323 | #if defined(SSL_MODE_SMALL_BUFFERS) /* not all SSL versions have this */ |
| 1324 | mode |= SSL_MODE_SMALL_BUFFERS; /* lazily allocate record buffers; usually saves |
| 1325 | * 44k over the default */ |
| 1326 | #endif |
| 1327 | #if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) /* not all SSL versions have this */ |
| 1328 | mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH; /* enable sending of client data as soon as |
| 1329 | * ClientCCS and ClientFinished are sent */ |
| 1330 | #endif |
| 1331 | SSL_CTX_set_mode(sslCtx, mode); |
| 1332 | |
| 1333 | SSL_CTX_set_cert_verify_callback(sslCtx, cert_verify_callback, NULL); |
| 1334 | SSL_CTX_set_info_callback(sslCtx, info_callback); |
| 1335 | |
| 1336 | #ifdef WITH_JNI_TRACE |
| 1337 | SSL_CTX_set_msg_callback(sslCtx, ssl_msg_callback_LOG); /* enable for message debug */ |
| 1338 | #endif |
| 1339 | JNI_TRACE("NativeCrypto_SSL_CTX_new => %p", sslCtx); |
| 1340 | return (jint) sslCtx; |
| 1341 | } |
| 1342 | |
| 1343 | static jobjectArray makeCipherList(JNIEnv* env, STACK_OF(SSL_CIPHER)* cipher_list) { |
| 1344 | // Create a String[]. |
| 1345 | jclass stringClass = env->FindClass("java/lang/String"); |
| 1346 | if (stringClass == NULL) { |
| 1347 | return NULL; |
| 1348 | } |
| 1349 | int cipherCount = sk_SSL_CIPHER_num(cipher_list); |
| 1350 | jobjectArray array = env->NewObjectArray(cipherCount, stringClass, NULL); |
| 1351 | if (array == NULL) { |
| 1352 | return NULL; |
| 1353 | } |
| 1354 | |
| 1355 | // Fill in the cipher names. |
| 1356 | for (int i = 0; i < cipherCount; ++i) { |
| 1357 | const char* c = sk_SSL_CIPHER_value(cipher_list, i)->name; |
| 1358 | JNI_TRACE("makeCipherList[i=%d]=%s", i, c); |
| 1359 | env->SetObjectArrayElement(array, i, env->NewStringUTF(c)); |
| 1360 | } |
| 1361 | return array; |
| 1362 | } |
| 1363 | |
| 1364 | /** |
| 1365 | * Loads the ciphers suites that are supported by an SSL_CTX |
| 1366 | * and returns them in a string array. |
| 1367 | */ |
| 1368 | static jobjectArray NativeCrypto_SSL_CTX_get_ciphers(JNIEnv* env, |
| 1369 | jclass, jint ssl_ctx_address) |
| 1370 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1371 | SSL_CTX* ssl_ctx = to_SSL_CTX(ssl_ctx_address); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1372 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_get_ciphers", ssl_ctx); |
| 1373 | if (ssl_ctx == NULL) { |
| 1374 | jniThrowNullPointerException(env, "SSL_CTX is null"); |
| 1375 | return NULL; |
| 1376 | } |
| 1377 | return makeCipherList(env, ssl_ctx->cipher_list); |
| 1378 | } |
| 1379 | |
| 1380 | /** |
| 1381 | * public static native void SSL_CTX_free(int ssl_ctx) |
| 1382 | */ |
| 1383 | static void NativeCrypto_SSL_CTX_free(JNIEnv* env, |
| 1384 | jclass, jint ssl_ctx_address) |
| 1385 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1386 | SSL_CTX* ssl_ctx = to_SSL_CTX(ssl_ctx_address); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1387 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_CTX_free", ssl_ctx); |
| 1388 | if (ssl_ctx == NULL) { |
| 1389 | jniThrowNullPointerException(env, "SSL_CTX is null"); |
| 1390 | return; |
| 1391 | } |
| 1392 | env->DeleteGlobalRef((jobject) ssl_ctx->app_verify_arg); |
| 1393 | SSL_CTX_free(ssl_ctx); |
| 1394 | } |
| 1395 | |
| 1396 | /** |
| 1397 | * Gets the chars of a String object as a '\0'-terminated UTF-8 string, |
| 1398 | * stored in a freshly-allocated BIO memory buffer. |
| 1399 | */ |
| 1400 | static BIO* stringToMemBuf(JNIEnv* env, jstring string) { |
| 1401 | jsize byteCount = env->GetStringUTFLength(string); |
| 1402 | LocalArray<1024> buf(byteCount + 1); |
| 1403 | env->GetStringUTFRegion(string, 0, env->GetStringLength(string), &buf[0]); |
| 1404 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1405 | BIO* bio = BIO_new(BIO_s_mem()); |
| 1406 | if (bio == NULL) { |
| 1407 | jniThrowRuntimeException(env, "BIO_new failed"); |
| 1408 | return NULL; |
| 1409 | } |
| 1410 | BIO_puts(bio, &buf[0]); |
| 1411 | return bio; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1412 | } |
| 1413 | |
| 1414 | /** |
| 1415 | * public static native int SSL_new(int ssl_ctx, String privatekey, String certificate, byte[] seed, |
| 1416 | * CertificateChainVerifier ccv) throws SSLException; |
| 1417 | */ |
| 1418 | static jint NativeCrypto_SSL_new(JNIEnv* env, jclass, |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1419 | jint ssl_ctx_address, jstring privatekey, jstring certificates, jbyteArray seed) |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1420 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1421 | SSL_CTX* ssl_ctx = to_SSL_CTX(ssl_ctx_address); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1422 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new privatekey=%p certificates=%p seed=%p", |
| 1423 | ssl_ctx, privatekey, certificates, seed); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1424 | if (ssl_ctx == NULL) { |
| 1425 | jniThrowNullPointerException(env, "SSL_CTX is null"); |
| 1426 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1427 | return NULL; |
| 1428 | } |
| 1429 | |
| 1430 | // 'seed == null' when no SecureRandom Object is set |
| 1431 | // in the SSLContext. |
| 1432 | if (seed != NULL) { |
| 1433 | jbyte* randseed = env->GetByteArrayElements(seed, NULL); |
| 1434 | RAND_seed((unsigned char*) randseed, 1024); |
| 1435 | env->ReleaseByteArrayElements(seed, randseed, 0); |
| 1436 | } else { |
| 1437 | RAND_load_file("/dev/urandom", 1024); |
| 1438 | } |
| 1439 | |
| 1440 | SSL* ssl = SSL_new(ssl_ctx); |
| 1441 | if (ssl == NULL) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1442 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1443 | "Unable to create SSL structure"); |
| 1444 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1445 | return NULL; |
| 1446 | } |
| 1447 | |
| 1448 | /* Java code in class OpenSSLSocketImpl does the verification. Meaning of |
| 1449 | * SSL_VERIFY_NONE flag in client mode: if not using an anonymous cipher |
| 1450 | * (by default disabled), the server will send a certificate which will |
| 1451 | * be checked. The result of the certificate verification process can be |
| 1452 | * checked after the TLS/SSL handshake using the SSL_get_verify_result(3) |
| 1453 | * function. The handshake will be continued regardless of the |
| 1454 | * verification result. |
| 1455 | */ |
| 1456 | SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); |
| 1457 | |
| 1458 | if (privatekey != NULL) { |
| 1459 | BIO* privatekeybio = stringToMemBuf(env, (jstring) privatekey); |
| 1460 | EVP_PKEY* privatekeyevp = |
| 1461 | PEM_read_bio_PrivateKey(privatekeybio, NULL, 0, NULL); |
| 1462 | BIO_free(privatekeybio); |
| 1463 | |
| 1464 | if (privatekeyevp == NULL) { |
| 1465 | LOGE(ERR_error_string(ERR_get_error(), NULL)); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1466 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1467 | "Error parsing the private key"); |
| 1468 | SSL_free(ssl); |
| 1469 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1470 | return NULL; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1471 | } |
| 1472 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1473 | BIO* certificatesbio = stringToMemBuf(env, (jstring) certificates); |
| 1474 | X509* certificatesx509 = |
| 1475 | PEM_read_bio_X509(certificatesbio, NULL, 0, NULL); |
| 1476 | BIO_free(certificatesbio); |
| 1477 | |
| 1478 | if (certificatesx509 == NULL) { |
| 1479 | LOGE(ERR_error_string(ERR_get_error(), NULL)); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1480 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1481 | "Error parsing the certificates"); |
| 1482 | EVP_PKEY_free(privatekeyevp); |
| 1483 | SSL_free(ssl); |
| 1484 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1485 | return NULL; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1486 | } |
| 1487 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1488 | int ret = SSL_use_certificate(ssl, certificatesx509); |
| 1489 | if (ret != 1) { |
| 1490 | LOGE(ERR_error_string(ERR_get_error(), NULL)); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1491 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1492 | "Error setting the certificates"); |
| 1493 | X509_free(certificatesx509); |
| 1494 | EVP_PKEY_free(privatekeyevp); |
| 1495 | SSL_free(ssl); |
| 1496 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1497 | return NULL; |
| 1498 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1499 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1500 | ret = SSL_use_PrivateKey(ssl, privatekeyevp); |
| 1501 | if (ret != 1) { |
| 1502 | LOGE(ERR_error_string(ERR_get_error(), NULL)); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1503 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1504 | "Error setting the private key"); |
| 1505 | X509_free(certificatesx509); |
| 1506 | EVP_PKEY_free(privatekeyevp); |
| 1507 | SSL_free(ssl); |
| 1508 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1509 | return NULL; |
| 1510 | } |
| 1511 | |
| 1512 | ret = SSL_check_private_key(ssl); |
| 1513 | if (ret != 1) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1514 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1515 | "Error checking the private key"); |
| 1516 | X509_free(certificatesx509); |
| 1517 | EVP_PKEY_free(privatekeyevp); |
| 1518 | SSL_free(ssl); |
| 1519 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => NULL", ssl_ctx); |
| 1520 | return NULL; |
| 1521 | } |
| 1522 | } |
| 1523 | JNI_TRACE("ssl_ctx=%p NativeCrypto_SSL_new => ssl=%p", ssl_ctx, ssl); |
| 1524 | return (jint)ssl; |
| 1525 | } |
| 1526 | |
| 1527 | /** |
| 1528 | * public static native long SSL_get_mode(int ssl); |
| 1529 | */ |
| 1530 | static jlong NativeCrypto_SSL_get_mode(JNIEnv* env, jclass, |
| 1531 | jint ssl_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1532 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1533 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode", ssl); |
| 1534 | if (ssl == NULL) { |
| 1535 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0", ssl); |
| 1536 | return 0; |
| 1537 | } |
| 1538 | long mode = SSL_get_mode(ssl); |
| 1539 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_mode => 0x%lx", ssl, mode); |
| 1540 | return mode; |
| 1541 | } |
| 1542 | |
| 1543 | /** |
| 1544 | * public static native long SSL_set_mode(int ssl, long mode); |
| 1545 | */ |
| 1546 | static jlong NativeCrypto_SSL_set_mode(JNIEnv* env, jclass, |
| 1547 | jint ssl_address, jlong mode) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1548 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1549 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode mode=0x%llx", ssl, mode); |
| 1550 | if (ssl == NULL) { |
| 1551 | return 0; |
| 1552 | } |
| 1553 | long result = SSL_set_mode(ssl, mode); |
| 1554 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_mode => 0x%lx", ssl, result); |
| 1555 | return result; |
| 1556 | } |
| 1557 | |
| 1558 | /** |
| 1559 | * public static native long SSL_clear_mode(int ssl, long mode); |
| 1560 | */ |
| 1561 | static jlong NativeCrypto_SSL_clear_mode(JNIEnv* env, jclass, |
| 1562 | jint ssl_address, jlong mode) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1563 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1564 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode mode=0x%llx", ssl, mode); |
| 1565 | if (ssl == NULL) { |
| 1566 | return 0; |
| 1567 | } |
| 1568 | long result = SSL_clear_mode(ssl, mode); |
| 1569 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_mode => 0x%lx", ssl, result); |
| 1570 | return result; |
| 1571 | } |
| 1572 | |
| 1573 | /** |
| 1574 | * public static native long SSL_get_options(int ssl); |
| 1575 | */ |
| 1576 | static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass, |
| 1577 | jint ssl_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1578 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1579 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options", ssl); |
| 1580 | if (ssl == NULL) { |
| 1581 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0", ssl); |
| 1582 | return 0; |
| 1583 | } |
| 1584 | long options = SSL_get_options(ssl); |
| 1585 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_options => 0x%lx", ssl, options); |
| 1586 | return options; |
| 1587 | } |
| 1588 | |
| 1589 | /** |
| 1590 | * public static native long SSL_set_options(int ssl, long options); |
| 1591 | */ |
| 1592 | static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass, |
| 1593 | jint ssl_address, jlong options) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1594 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1595 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options options=0x%llx", ssl, options); |
| 1596 | if (ssl == NULL) { |
| 1597 | return 0; |
| 1598 | } |
| 1599 | long result = SSL_set_options(ssl, options); |
| 1600 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_options => 0x%lx", ssl, result); |
| 1601 | return result; |
| 1602 | } |
| 1603 | |
| 1604 | /** |
| 1605 | * public static native long SSL_clear_options(int ssl, long options); |
| 1606 | */ |
| 1607 | static jlong NativeCrypto_SSL_clear_options(JNIEnv* env, jclass, |
| 1608 | jint ssl_address, jlong options) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1609 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1610 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options options=0x%llx", ssl, options); |
| 1611 | if (ssl == NULL) { |
| 1612 | return 0; |
| 1613 | } |
| 1614 | long result = SSL_clear_options(ssl, options); |
| 1615 | JNI_TRACE("ssl=%p NativeCrypto_SSL_clear_options => 0x%lx", ssl, result); |
| 1616 | return result; |
| 1617 | } |
| 1618 | |
| 1619 | /** |
| 1620 | * Loads the ciphers suites that are enabled in the SSL |
| 1621 | * and returns them in a string array. |
| 1622 | */ |
| 1623 | static jobjectArray NativeCrypto_SSL_get_ciphers(JNIEnv* env, |
| 1624 | jclass, jint ssl_address) |
| 1625 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1626 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1627 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_ciphers", ssl); |
| 1628 | if (ssl == NULL) { |
| 1629 | return NULL; |
| 1630 | } |
| 1631 | return makeCipherList(env, SSL_get_ciphers(ssl)); |
| 1632 | } |
| 1633 | |
| 1634 | /** |
| 1635 | * Sets the ciphers suites that are enabled in the SSL |
| 1636 | */ |
| 1637 | static void NativeCrypto_SSL_set_cipher_list(JNIEnv* env, jclass, |
| 1638 | jint ssl_address, jstring controlString) |
| 1639 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1640 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1641 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_cipher_list controlString=%p", ssl, controlString); |
| 1642 | if (ssl == NULL) { |
| 1643 | return; |
| 1644 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1645 | ScopedUtfChars str(env, controlString); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1646 | JNI_TRACE("ssl=%p NativeCrypto_SSL_controlString str=%s", ssl, str.c_str()); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1647 | int rc = SSL_set_cipher_list(ssl, str.c_str()); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1648 | if (rc == 0) { |
| 1649 | freeSslErrorState(); |
| 1650 | jniThrowException(env, "java/lang/IllegalArgumentException", |
| 1651 | "Illegal cipher suite strings."); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1652 | } |
| 1653 | } |
| 1654 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1655 | /** |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1656 | * Sets certificate expectations, especially for server to request client auth |
| 1657 | */ |
| 1658 | static void NativeCrypto_SSL_set_verify(JNIEnv* env, |
| 1659 | jclass, jint ssl_address, jint mode) |
| 1660 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1661 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1662 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_verify", ssl); |
| 1663 | if (ssl == NULL) { |
| 1664 | return; |
| 1665 | } |
| 1666 | SSL_set_verify(ssl, (int)mode, NULL); |
| 1667 | } |
| 1668 | |
| 1669 | /** |
| 1670 | * Sets the ciphers suites that are enabled in the SSL |
| 1671 | */ |
| 1672 | static void NativeCrypto_SSL_set_session(JNIEnv* env, jclass, |
| 1673 | jint ssl_address, jint ssl_session_address) |
| 1674 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1675 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 1676 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1677 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session ssl_session=%p", ssl, ssl_session); |
| 1678 | if (ssl == NULL) { |
| 1679 | return; |
| 1680 | } |
| 1681 | |
| 1682 | int ret = SSL_set_session(ssl, ssl_session); |
| 1683 | if (ret != 1) { |
| 1684 | /* |
| 1685 | * Translate the error, and throw if it turns out to be a real |
| 1686 | * problem. |
| 1687 | */ |
| 1688 | int sslErrorCode = SSL_get_error(ssl, ret); |
| 1689 | if (sslErrorCode != SSL_ERROR_ZERO_RETURN) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1690 | throwSSLExceptionWithSslErrors(env, sslErrorCode, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1691 | "SSL session set"); |
| 1692 | SSL_clear(ssl); |
| 1693 | } |
| 1694 | } |
| 1695 | } |
| 1696 | |
| 1697 | /** |
| 1698 | * Sets the ciphers suites that are enabled in the SSL |
| 1699 | */ |
| 1700 | static void NativeCrypto_SSL_set_session_creation_enabled(JNIEnv* env, jclass, |
| 1701 | jint ssl_address, jboolean creation_enabled) |
| 1702 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1703 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1704 | JNI_TRACE("ssl=%p NativeCrypto_SSL_set_session_creation_enabled creation_enabled=%d", ssl, creation_enabled); |
| 1705 | if (ssl == NULL) { |
| 1706 | return; |
| 1707 | } |
| 1708 | SSL_set_session_creation_enabled(ssl, creation_enabled); |
| 1709 | } |
| 1710 | |
| 1711 | /** |
| 1712 | * Module scope variables initialized during JNI registration. |
| 1713 | */ |
| 1714 | static jfieldID field_Socket_mImpl; |
| 1715 | static jfieldID field_Socket_mFD; |
| 1716 | |
| 1717 | /** |
| 1718 | * Perform SSL handshake |
| 1719 | */ |
| 1720 | static jint NativeCrypto_SSL_do_handshake(JNIEnv* env, jclass, |
| 1721 | jint ssl_address, jobject socketObject, jobject ccv, jobject hcc, jint timeout, jboolean client_mode) |
| 1722 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1723 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1724 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake socketObject=%p ccv=%p timeout=%d client_mode=%d", |
| 1725 | ssl, socketObject, ccv, timeout, client_mode); |
| 1726 | if (ssl == NULL) { |
| 1727 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1728 | return 0; |
| 1729 | } |
| 1730 | |
| 1731 | if (socketObject == NULL) { |
| 1732 | jniThrowNullPointerException(env, "Socket is null"); |
| 1733 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1734 | return 0; |
| 1735 | } |
| 1736 | if (ccv == NULL) { |
| 1737 | jniThrowNullPointerException(env, "CertificateChainVerifier is null"); |
| 1738 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1739 | return 0; |
| 1740 | } |
| 1741 | |
| 1742 | jobject socketImplObject = env->GetObjectField(socketObject, field_Socket_mImpl); |
| 1743 | if (socketImplObject == NULL) { |
| 1744 | throwSSLExceptionStr(env, |
| 1745 | "couldn't get the socket impl from the socket"); |
| 1746 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1747 | return 0; |
| 1748 | } |
| 1749 | |
| 1750 | jobject fdObject = env->GetObjectField(socketImplObject, field_Socket_mFD); |
| 1751 | if (fdObject == NULL) { |
| 1752 | throwSSLExceptionStr(env, |
| 1753 | "couldn't get the file descriptor from the socket impl"); |
| 1754 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1755 | return 0; |
| 1756 | } |
| 1757 | |
| 1758 | int fd = jniGetFDFromFileDescriptor(env, fdObject); |
| 1759 | if (fd == -1) { |
| 1760 | throwSSLExceptionStr(env, "Invalid file descriptor"); |
| 1761 | SSL_clear(ssl); |
| 1762 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1763 | return 0; |
| 1764 | } |
| 1765 | |
| 1766 | int ret = SSL_set_fd(ssl, fd); |
| 1767 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake s=%d", ssl, fd); |
| 1768 | |
| 1769 | if (ret != 1) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1770 | throwSSLExceptionWithSslErrors(env, 0, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1771 | "Error setting the file descriptor"); |
| 1772 | SSL_clear(ssl); |
| 1773 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1774 | return 0; |
| 1775 | } |
| 1776 | |
| 1777 | /* |
| 1778 | * Make socket non-blocking, so SSL_connect SSL_read() and SSL_write() don't hang |
| 1779 | * forever and we can use select() to find out if the socket is ready. |
| 1780 | */ |
| 1781 | int mode = fcntl(fd, F_GETFL); |
| 1782 | if (mode == -1 || fcntl(fd, F_SETFL, mode | O_NONBLOCK) == -1) { |
| 1783 | throwSSLExceptionStr(env, "Unable to make socket non blocking"); |
| 1784 | SSL_clear(ssl); |
| 1785 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1786 | return 0; |
| 1787 | } |
| 1788 | |
| 1789 | /* |
| 1790 | * Create our special application data. |
| 1791 | */ |
| 1792 | AppData* appData = AppData::create(env, ccv, hcc); |
| 1793 | if (appData == NULL) { |
| 1794 | throwSSLExceptionStr(env, "Unable to create application data"); |
| 1795 | SSL_clear(ssl); |
| 1796 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1797 | return 0; |
| 1798 | } |
| 1799 | SSL_set_app_data(ssl, (char*) appData); |
| 1800 | |
| 1801 | if (client_mode) { |
| 1802 | SSL_set_connect_state(ssl); |
| 1803 | } else { |
| 1804 | SSL_set_accept_state(ssl); |
| 1805 | } |
| 1806 | |
| 1807 | while (appData->aliveAndKicking) { |
| 1808 | errno = 0; |
| 1809 | appData->setEnv(env); |
| 1810 | ret = SSL_do_handshake(ssl); |
| 1811 | appData->clearEnv(); |
| 1812 | // cert_verify_callback threw exception |
| 1813 | if (env->ExceptionCheck()) { |
| 1814 | SSL_clear(ssl); |
| 1815 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1816 | return 0; |
| 1817 | } |
| 1818 | if (ret == 1) { |
| 1819 | break; |
| 1820 | } else if (errno == EINTR) { |
| 1821 | continue; |
| 1822 | } else { |
| 1823 | // LOGD("SSL_connect: result %d, errno %d, timeout %d", ret, errno, timeout); |
| 1824 | int error = SSL_get_error(ssl, ret); |
| 1825 | |
| 1826 | /* |
| 1827 | * If SSL_connect doesn't succeed due to the socket being |
| 1828 | * either unreadable or unwritable, we use sslSelect to |
| 1829 | * wait for it to become ready. If that doesn't happen |
| 1830 | * before the specified timeout or an error occurs, we |
| 1831 | * cancel the handshake. Otherwise we try the SSL_connect |
| 1832 | * again. |
| 1833 | */ |
| 1834 | if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) { |
| 1835 | appData->waitingThreads++; |
| 1836 | int selectResult = sslSelect(error, fd, appData, timeout); |
| 1837 | |
| 1838 | if (selectResult == -1) { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1839 | throwSSLExceptionWithSslErrors(env, error, "handshake error"); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1840 | SSL_clear(ssl); |
| 1841 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1842 | return 0; |
| 1843 | } else if (selectResult == 0) { |
| 1844 | throwSocketTimeoutException(env, "SSL handshake timed out"); |
| 1845 | SSL_clear(ssl); |
| 1846 | freeSslErrorState(); |
| 1847 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1848 | return 0; |
| 1849 | } |
| 1850 | } else { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1851 | // LOGE("Unknown error %d during handshake", error); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1852 | break; |
| 1853 | } |
| 1854 | } |
| 1855 | } |
| 1856 | |
| 1857 | if (ret == 0) { |
| 1858 | /* |
| 1859 | * The other side closed the socket before the handshake could be |
| 1860 | * completed, but everything is within the bounds of the TLS protocol. |
| 1861 | * We still might want to find out the real reason of the failure. |
| 1862 | */ |
| 1863 | int sslErrorCode = SSL_get_error(ssl, ret); |
| 1864 | if (sslErrorCode == SSL_ERROR_NONE || |
| 1865 | (sslErrorCode == SSL_ERROR_SYSCALL && errno == 0)) { |
| 1866 | throwSSLExceptionStr(env, "Connection closed by peer"); |
| 1867 | } else { |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1868 | throwSSLExceptionWithSslErrors(env, sslErrorCode, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1869 | "Trouble accepting connection"); |
| 1870 | } |
| 1871 | SSL_clear(ssl); |
| 1872 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1873 | return 0; |
| 1874 | } |
| 1875 | if (ret < 0) { |
| 1876 | /* |
| 1877 | * Translate the error and throw exception. We are sure it is an error |
| 1878 | * at this point. |
| 1879 | */ |
| 1880 | int sslErrorCode = SSL_get_error(ssl, ret); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 1881 | throwSSLExceptionWithSslErrors(env, sslErrorCode, |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1882 | "Trouble accepting connection"); |
| 1883 | SSL_clear(ssl); |
| 1884 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => 0", ssl); |
| 1885 | return 0; |
| 1886 | } |
| 1887 | SSL_SESSION* ssl_session = SSL_get1_session(ssl); |
| 1888 | JNI_TRACE("ssl=%p NativeCrypto_SSL_do_handshake => ssl_session=%p", ssl, ssl_session); |
| 1889 | return (jint) ssl_session; |
| 1890 | } |
| 1891 | |
| 1892 | /** |
| 1893 | * public static native byte[][] SSL_get_certificate(int ssl); |
| 1894 | */ |
| 1895 | static jobjectArray NativeCrypto_SSL_get_certificate(JNIEnv* env, jclass, jint ssl_address) |
| 1896 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 1897 | SSL* ssl = to_SSL(env, ssl_address, true); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1898 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate", ssl); |
| 1899 | if (ssl == NULL) { |
| 1900 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 1901 | return NULL; |
| 1902 | } |
| 1903 | X509* certificate = SSL_get_certificate(ssl); |
| 1904 | if (certificate == NULL) { |
| 1905 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 1906 | return NULL; |
| 1907 | } |
| 1908 | // TODO convert from single certificate to chain properly. One |
| 1909 | // option would be to have the chain remembered where |
| 1910 | // SSL_use_certificate is used. Another would be to save the |
| 1911 | // intermediate CAs with SSL_CTX SSL_CTX_add_extra_chain_cert. |
| 1912 | STACK_OF(X509)* chain = sk_X509_new_null(); |
| 1913 | if (chain == NULL) { |
| 1914 | jniThrowRuntimeException(env, "Unable to allocate local certificate chain"); |
| 1915 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => NULL", ssl); |
| 1916 | return NULL; |
| 1917 | } |
| 1918 | sk_X509_push(chain, certificate); |
| 1919 | jobjectArray objectArray = getCertificateBytes(env, chain); |
| 1920 | sk_X509_free(chain); |
| 1921 | JNI_TRACE("ssl=%p NativeCrypto_SSL_get_certificate => %p", ssl, objectArray); |
| 1922 | return objectArray; |
| 1923 | } |
| 1924 | |
| 1925 | |
| 1926 | /** |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1927 | * Helper function which does the actual reading. The Java layer guarantees that |
| 1928 | * at most one thread will enter this function at any given time. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1929 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1930 | * @param ssl non-null; the SSL context |
| 1931 | * @param buf non-null; buffer to read into |
| 1932 | * @param len length of the buffer, in bytes |
| 1933 | * @param sslReturnCode original SSL return code |
| 1934 | * @param sslErrorCode filled in with the SSL error code in case of error |
| 1935 | * @return number of bytes read on success, -1 if the connection was |
| 1936 | * cleanly shut down, or THROW_EXCEPTION if an exception should be thrown. |
| 1937 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1938 | static int sslRead(JNIEnv* env, SSL* ssl, char* buf, jint len, int* sslReturnCode, |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1939 | int* sslErrorCode, int timeout) { |
| 1940 | |
| 1941 | // LOGD("Entering sslRead, caller requests to read %d bytes...", len); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1942 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1943 | if (len == 0) { |
| 1944 | // Don't bother doing anything in this case. |
| 1945 | return 0; |
| 1946 | } |
| 1947 | |
| 1948 | int fd = SSL_get_fd(ssl); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1949 | BIO* bio = SSL_get_rbio(ssl); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1950 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1951 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1952 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1953 | while (appData->aliveAndKicking) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1954 | errno = 0; |
| 1955 | |
| 1956 | // Lock |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1957 | if (MUTEX_LOCK(appData->mutex) == -1) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1958 | return -1; |
| 1959 | } |
| 1960 | |
| 1961 | unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1962 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1963 | // LOGD("Doing SSL_Read()"); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1964 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 1965 | appData->setEnv(env); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1966 | int result = SSL_read(ssl, buf, len); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1967 | appData->clearEnv(); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1968 | int error = SSL_ERROR_NONE; |
| 1969 | if (result <= 0) { |
| 1970 | error = SSL_get_error(ssl, result); |
| 1971 | freeSslErrorState(); |
| 1972 | } |
| 1973 | // LOGD("Returned from SSL_Read() with result %d, error code %d", result, error); |
| 1974 | |
| 1975 | // If we have been successful in moving data around, check whether it |
| 1976 | // might make sense to wake up other blocked threads, so they can give |
| 1977 | // it a try, too. |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1978 | if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved && appData->waitingThreads > 0) { |
| 1979 | sslNotify(appData); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1980 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1981 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1982 | // If we are blocked by the underlying socket, tell the world that |
| 1983 | // there will be one more waiting thread now. |
| 1984 | if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1985 | appData->waitingThreads++; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1986 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 1987 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1988 | // Unlock |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 1989 | MUTEX_UNLOCK(appData->mutex); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 1990 | |
| 1991 | switch (error) { |
| 1992 | // Sucessfully read at least one byte. |
| 1993 | case SSL_ERROR_NONE: { |
| 1994 | return result; |
| 1995 | } |
| 1996 | |
| 1997 | // Read zero bytes. End of stream reached. |
| 1998 | case SSL_ERROR_ZERO_RETURN: { |
| 1999 | return -1; |
| 2000 | } |
| 2001 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2002 | // Need to wait for availability of underlying layer, then retry. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2003 | case SSL_ERROR_WANT_READ: |
| 2004 | case SSL_ERROR_WANT_WRITE: { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2005 | int selectResult = sslSelect(error, fd, appData, timeout); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2006 | if (selectResult == -1) { |
| 2007 | *sslReturnCode = -1; |
| 2008 | *sslErrorCode = error; |
| 2009 | return THROW_EXCEPTION; |
| 2010 | } else if (selectResult == 0) { |
| 2011 | return THROW_SOCKETTIMEOUTEXCEPTION; |
| 2012 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2013 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2014 | break; |
| 2015 | } |
| 2016 | |
| 2017 | // A problem occured during a system call, but this is not |
| 2018 | // necessarily an error. |
| 2019 | case SSL_ERROR_SYSCALL: { |
| 2020 | // Connection closed without proper shutdown. Tell caller we |
| 2021 | // have reached end-of-stream. |
| 2022 | if (result == 0) { |
| 2023 | return -1; |
| 2024 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2025 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2026 | // System call has been interrupted. Simply retry. |
| 2027 | if (errno == EINTR) { |
| 2028 | break; |
| 2029 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2030 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2031 | // Note that for all other system call errors we fall through |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2032 | // to the default case, which results in an Exception. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2033 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2034 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2035 | // Everything else is basically an error. |
| 2036 | default: { |
| 2037 | *sslReturnCode = result; |
| 2038 | *sslErrorCode = error; |
| 2039 | return THROW_EXCEPTION; |
| 2040 | } |
| 2041 | } |
| 2042 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2043 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2044 | return -1; |
| 2045 | } |
| 2046 | |
| 2047 | /** |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2048 | * OpenSSL read function (1): only one chunk is read (returned as jint). |
| 2049 | */ |
| 2050 | static jint NativeCrypto_SSL_read_byte(JNIEnv* env, jclass, jint ssl_address, jint timeout) |
| 2051 | { |
| 2052 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 2053 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_byte timeout=%d", ssl, timeout); |
| 2054 | if (ssl == NULL) { |
| 2055 | return 0; |
| 2056 | } |
| 2057 | |
| 2058 | unsigned char byteRead; |
| 2059 | int returnCode = 0; |
| 2060 | int errorCode = 0; |
| 2061 | |
| 2062 | int ret = sslRead(env, ssl, (char *) &byteRead, 1, &returnCode, &errorCode, timeout); |
| 2063 | |
| 2064 | int result; |
| 2065 | switch (ret) { |
| 2066 | case THROW_EXCEPTION: |
| 2067 | // See sslRead() regarding improper failure to handle normal cases. |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2068 | throwSSLExceptionWithSslErrors(env, errorCode, "Read error"); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2069 | result = -1; |
| 2070 | break; |
| 2071 | case THROW_SOCKETTIMEOUTEXCEPTION: |
| 2072 | throwSocketTimeoutException(env, "Read timed out"); |
| 2073 | result = -1; |
| 2074 | break; |
| 2075 | case -1: |
| 2076 | // Propagate EOF upwards. |
| 2077 | result = -1; |
| 2078 | break; |
| 2079 | default: |
| 2080 | // Return the actual char read, make sure it stays 8 bits wide. |
| 2081 | result = ((jint) byteRead) & 0xFF; |
| 2082 | break; |
| 2083 | } |
| 2084 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read_byte => %d", ssl, result); |
| 2085 | return result; |
| 2086 | } |
| 2087 | |
| 2088 | /** |
| 2089 | * OpenSSL read function (2): read into buffer at offset n chunks. |
| 2090 | * Returns 1 (success) or value <= 0 (failure). |
| 2091 | */ |
| 2092 | static jint NativeCrypto_SSL_read(JNIEnv* env, jclass, jint ssl_address, jbyteArray dest, jint offset, jint len, jint timeout) |
| 2093 | { |
| 2094 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 2095 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read dest=%p offset=%d len=%d timeout=%d", ssl, dest, offset, len, timeout); |
| 2096 | if (ssl == NULL) { |
| 2097 | return 0; |
| 2098 | } |
| 2099 | |
| 2100 | jbyte* bytes = env->GetByteArrayElements(dest, NULL); |
| 2101 | int returnCode = 0; |
| 2102 | int errorCode = 0; |
| 2103 | |
| 2104 | int ret = sslRead(env, ssl, (char*) (bytes + offset), len, &returnCode, &errorCode, timeout); |
| 2105 | |
| 2106 | env->ReleaseByteArrayElements(dest, bytes, 0); |
| 2107 | |
| 2108 | int result; |
| 2109 | if (ret == THROW_EXCEPTION) { |
| 2110 | // See sslRead() regarding improper failure to handle normal cases. |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2111 | throwSSLExceptionWithSslErrors(env, errorCode, |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2112 | "Read error"); |
| 2113 | result = -1; |
| 2114 | } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) { |
| 2115 | throwSocketTimeoutException(env, "Read timed out"); |
| 2116 | result = -1; |
| 2117 | } else { |
| 2118 | result = ret; |
| 2119 | } |
| 2120 | |
| 2121 | JNI_TRACE("ssl=%p NativeCrypto_SSL_read => %d", ssl, result); |
| 2122 | return result; |
| 2123 | } |
| 2124 | |
| 2125 | /** |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2126 | * Helper function which does the actual writing. The Java layer guarantees that |
| 2127 | * at most one thread will enter this function at any given time. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2128 | * |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2129 | * @param ssl non-null; the SSL context |
| 2130 | * @param buf non-null; buffer to write |
| 2131 | * @param len length of the buffer, in bytes |
| 2132 | * @param sslReturnCode original SSL return code |
| 2133 | * @param sslErrorCode filled in with the SSL error code in case of error |
| 2134 | * @return number of bytes read on success, -1 if the connection was |
| 2135 | * cleanly shut down, or THROW_EXCEPTION if an exception should be thrown. |
| 2136 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2137 | static int sslWrite(JNIEnv* env, SSL* ssl, const char* buf, jint len, int* sslReturnCode, |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2138 | int* sslErrorCode) { |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2139 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2140 | // LOGD("Entering sslWrite(), caller requests to write %d bytes...", len); |
| 2141 | |
| 2142 | if (len == 0) { |
| 2143 | // Don't bother doing anything in this case. |
| 2144 | return 0; |
| 2145 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2146 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2147 | int fd = SSL_get_fd(ssl); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2148 | BIO* bio = SSL_get_wbio(ssl); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2149 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2150 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2151 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2152 | int count = len; |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2153 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2154 | while (appData->aliveAndKicking && len > 0) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2155 | errno = 0; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2156 | if (MUTEX_LOCK(appData->mutex) == -1) { |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2157 | return -1; |
| 2158 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2159 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2160 | unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2161 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2162 | // LOGD("Doing SSL_write() with %d bytes to go", len); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2163 | appData->setEnv(env); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2164 | int result = SSL_write(ssl, buf, len); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2165 | appData->clearEnv(); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2166 | int error = SSL_ERROR_NONE; |
| 2167 | if (result <= 0) { |
| 2168 | error = SSL_get_error(ssl, result); |
| 2169 | freeSslErrorState(); |
| 2170 | } |
| 2171 | // LOGD("Returned from SSL_write() with result %d, error code %d", result, error); |
| 2172 | |
| 2173 | // If we have been successful in moving data around, check whether it |
| 2174 | // might make sense to wake up other blocked threads, so they can give |
| 2175 | // it a try, too. |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2176 | if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved && appData->waitingThreads > 0) { |
| 2177 | sslNotify(appData); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2178 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2179 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2180 | // If we are blocked by the underlying socket, tell the world that |
| 2181 | // there will be one more waiting thread now. |
| 2182 | if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2183 | appData->waitingThreads++; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2184 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2185 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2186 | MUTEX_UNLOCK(appData->mutex); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2187 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2188 | switch (error) { |
| 2189 | // Sucessfully write at least one byte. |
| 2190 | case SSL_ERROR_NONE: { |
| 2191 | buf += result; |
| 2192 | len -= result; |
| 2193 | break; |
| 2194 | } |
| 2195 | |
| 2196 | // Wrote zero bytes. End of stream reached. |
| 2197 | case SSL_ERROR_ZERO_RETURN: { |
| 2198 | return -1; |
| 2199 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2200 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2201 | // Need to wait for availability of underlying layer, then retry. |
| 2202 | // The concept of a write timeout doesn't really make sense, and |
| 2203 | // it's also not standard Java behavior, so we wait forever here. |
| 2204 | case SSL_ERROR_WANT_READ: |
| 2205 | case SSL_ERROR_WANT_WRITE: { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2206 | int selectResult = sslSelect(error, fd, appData, 0); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2207 | if (selectResult == -1) { |
| 2208 | *sslReturnCode = -1; |
| 2209 | *sslErrorCode = error; |
| 2210 | return THROW_EXCEPTION; |
| 2211 | } else if (selectResult == 0) { |
| 2212 | return THROW_SOCKETTIMEOUTEXCEPTION; |
| 2213 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2214 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2215 | break; |
| 2216 | } |
| 2217 | |
| 2218 | // An problem occured during a system call, but this is not |
| 2219 | // necessarily an error. |
| 2220 | case SSL_ERROR_SYSCALL: { |
| 2221 | // Connection closed without proper shutdown. Tell caller we |
| 2222 | // have reached end-of-stream. |
| 2223 | if (result == 0) { |
| 2224 | return -1; |
| 2225 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2226 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2227 | // System call has been interrupted. Simply retry. |
| 2228 | if (errno == EINTR) { |
| 2229 | break; |
| 2230 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2231 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2232 | // Note that for all other system call errors we fall through |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2233 | // to the default case, which results in an Exception. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2234 | } |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2235 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2236 | // Everything else is basically an error. |
| 2237 | default: { |
| 2238 | *sslReturnCode = result; |
| 2239 | *sslErrorCode = error; |
| 2240 | return THROW_EXCEPTION; |
| 2241 | } |
| 2242 | } |
| 2243 | } |
| 2244 | // LOGD("Successfully wrote %d bytes", count); |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2245 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2246 | return count; |
| 2247 | } |
| 2248 | |
| 2249 | /** |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2250 | * OpenSSL write function (1): only one chunk is written. |
| 2251 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2252 | static void NativeCrypto_SSL_write_byte(JNIEnv* env, jclass, jint ssl_address, jint b) |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2253 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2254 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 2255 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write_byte b=%d", ssl, b); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2256 | if (ssl == NULL) { |
| 2257 | return; |
| 2258 | } |
| 2259 | |
| 2260 | int returnCode = 0; |
| 2261 | int errorCode = 0; |
| 2262 | char buf[1] = { (char) b }; |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2263 | int ret = sslWrite(env, ssl, buf, 1, &returnCode, &errorCode); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2264 | |
| 2265 | if (ret == THROW_EXCEPTION) { |
| 2266 | // See sslWrite() regarding improper failure to handle normal cases. |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2267 | throwSSLExceptionWithSslErrors(env, errorCode, |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2268 | "Write error"); |
| 2269 | } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) { |
| 2270 | throwSocketTimeoutException(env, "Write timed out"); |
| 2271 | } |
| 2272 | } |
| 2273 | |
| 2274 | /** |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2275 | * OpenSSL write function (2): write into buffer at offset n chunks. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2276 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2277 | static void NativeCrypto_SSL_write(JNIEnv* env, jclass, |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2278 | jint ssl_address, jbyteArray dest, jint offset, jint len) |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2279 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2280 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 2281 | JNI_TRACE("ssl=%p NativeCrypto_SSL_write dest=%p offset=%d len=%d", ssl, dest, offset, len); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2282 | if (ssl == NULL) { |
| 2283 | return; |
| 2284 | } |
| 2285 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2286 | ScopedByteArray bytes(env, dest); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2287 | int returnCode = 0; |
| 2288 | int errorCode = 0; |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2289 | int ret = sslWrite(env, ssl, (const char *) (bytes.bytes() + offset), len, &returnCode, &errorCode); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2290 | |
| 2291 | if (ret == THROW_EXCEPTION) { |
| 2292 | // See sslWrite() regarding improper failure to handle normal cases. |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2293 | throwSSLExceptionWithSslErrors(env, errorCode, |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2294 | "Write error"); |
| 2295 | } else if(ret == THROW_SOCKETTIMEOUTEXCEPTION) { |
| 2296 | throwSocketTimeoutException(env, "Write timed out"); |
| 2297 | } |
| 2298 | } |
| 2299 | |
| 2300 | /** |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2301 | * Interrupt any pending IO before closing the socket. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2302 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2303 | static void NativeCrypto_SSL_interrupt( |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2304 | JNIEnv* env, jclass, jint ssl_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2305 | SSL* ssl = to_SSL(env, ssl_address, false); |
| 2306 | JNI_TRACE("ssl=%p NativeCrypto_SSL_interrupt", ssl); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2307 | if (ssl == NULL) { |
| 2308 | return; |
| 2309 | } |
| 2310 | |
| 2311 | /* |
| 2312 | * Mark the connection as quasi-dead, then send something to the emergency |
| 2313 | * file descriptor, so any blocking select() calls are woken up. |
| 2314 | */ |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2315 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 2316 | if (appData != NULL) { |
| 2317 | appData->aliveAndKicking = 0; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2318 | |
| 2319 | // At most two threads can be waiting. |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2320 | sslNotify(appData); |
| 2321 | sslNotify(appData); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2322 | } |
| 2323 | } |
| 2324 | |
| 2325 | /** |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2326 | * OpenSSL close SSL socket function. |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2327 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2328 | static void NativeCrypto_SSL_shutdown( |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2329 | JNIEnv* env, jclass, jint ssl_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2330 | SSL* ssl = to_SSL(env, ssl_address, false); |
| 2331 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown", ssl); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2332 | if (ssl == NULL) { |
| 2333 | return; |
| 2334 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2335 | /* |
| 2336 | * Try to make socket blocking again. OpenSSL literature recommends this. |
| 2337 | */ |
| 2338 | int fd = SSL_get_fd(ssl); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2339 | JNI_TRACE("ssl=%p NativeCrypto_SSL_shutdown s=%d", ssl, fd); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2340 | if (fd != -1) { |
| 2341 | int mode = fcntl(fd, F_GETFL); |
| 2342 | if (mode == -1 || fcntl(fd, F_SETFL, mode & ~O_NONBLOCK) == -1) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2343 | // throwSSLExceptionStr(env, "Unable to make socket blocking again"); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2344 | // LOGW("Unable to make socket blocking again"); |
| 2345 | } |
| 2346 | } |
| 2347 | |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2348 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 2349 | appData->setEnv(env); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2350 | int ret = SSL_shutdown(ssl); |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2351 | appData->clearEnv(); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2352 | switch (ret) { |
| 2353 | case 0: |
| 2354 | /* |
| 2355 | * Shutdown was not successful (yet), but there also |
| 2356 | * is no error. Since we can't know whether the remote |
| 2357 | * server is actually still there, and we don't want to |
| 2358 | * get stuck forever in a second SSL_shutdown() call, we |
| 2359 | * simply return. This is not security a problem as long |
| 2360 | * as we close the underlying socket, which we actually |
| 2361 | * do, because that's where we are just coming from. |
| 2362 | */ |
| 2363 | break; |
| 2364 | case 1: |
| 2365 | /* |
| 2366 | * Shutdown was sucessful. We can safely return. Hooray! |
| 2367 | */ |
| 2368 | break; |
| 2369 | default: |
| 2370 | /* |
| 2371 | * Everything else is a real error condition. We should |
| 2372 | * let the Java layer know about this by throwing an |
| 2373 | * exception. |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2374 | */ |
Brian Carlstrom | 83db378 | 2010-04-09 17:49:11 -0700 | [diff] [blame] | 2375 | int sslErrorCode = SSL_get_error(ssl, ret); |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2376 | throwSSLExceptionWithSslErrors(env, sslErrorCode, "SSL shutdown failed"); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2377 | break; |
| 2378 | } |
| 2379 | |
Brian Carlstrom | ecaf759 | 2010-03-02 16:55:35 -0800 | [diff] [blame] | 2380 | SSL_clear(ssl); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2381 | freeSslErrorState(); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2382 | } |
| 2383 | |
| 2384 | /** |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2385 | * public static native void SSL_free(int ssl); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2386 | */ |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2387 | static void NativeCrypto_SSL_free(JNIEnv* env, jclass, jint ssl_address) |
| 2388 | { |
| 2389 | SSL* ssl = to_SSL(env, ssl_address, true); |
| 2390 | JNI_TRACE("ssl=%p NativeCrypto_SSL_free", ssl); |
| 2391 | if (ssl == NULL) { |
| 2392 | return; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2393 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2394 | AppData* appData = (AppData*) SSL_get_app_data(ssl); |
| 2395 | SSL_set_app_data(ssl, NULL); |
| 2396 | delete appData; |
| 2397 | SSL_free(ssl); |
| 2398 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2399 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2400 | /** |
| 2401 | * Gets and returns in a byte array the ID of the actual SSL session. |
| 2402 | */ |
| 2403 | static jbyteArray NativeCrypto_SSL_SESSION_session_id(JNIEnv* env, jclass, jint ssl_session_address) { |
| 2404 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2405 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id", ssl_session); |
| 2406 | jbyteArray result = env->NewByteArray(ssl_session->session_id_length); |
| 2407 | if (result != NULL) { |
| 2408 | jbyte* src = reinterpret_cast<jbyte*>(ssl_session->session_id); |
| 2409 | env->SetByteArrayRegion(result, 0, ssl_session->session_id_length, src); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2410 | } |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2411 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_session_id => %p session_id_length=%d", |
| 2412 | ssl_session, result, ssl_session->session_id_length); |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2413 | return result; |
| 2414 | } |
| 2415 | |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2416 | /** |
| 2417 | * Our implementation of what might be considered |
| 2418 | * SSL_SESSION_get_peer_cert_chain |
| 2419 | * |
| 2420 | */ |
| 2421 | // TODO move to jsse.patch |
| 2422 | static STACK_OF(X509)* SSL_SESSION_get_peer_cert_chain(SSL_CTX* ssl_ctx, SSL_SESSION* ssl_session) { |
| 2423 | SSL* ssl = SSL_new(ssl_ctx); |
| 2424 | if (ssl == NULL) { |
| 2425 | return NULL; |
| 2426 | } |
| 2427 | SSL_set_session(ssl, ssl_session); |
| 2428 | STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl); |
| 2429 | SSL_free(ssl); |
| 2430 | return chain; |
| 2431 | } |
| 2432 | |
| 2433 | // Fills a byte[][] with the peer certificates in the chain. |
| 2434 | static jobjectArray NativeCrypto_SSL_SESSION_get_peer_cert_chain(JNIEnv* env, |
| 2435 | jclass, jint ssl_ctx_address, jint ssl_session_address) |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2436 | { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2437 | SSL_CTX* ssl_ctx = to_SSL_CTX(ssl_ctx_address); |
| 2438 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2439 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_peer_cert_chain ssl_ctx=%p", ssl_session, ssl_ctx); |
| 2440 | if (ssl_ctx == NULL) { |
| 2441 | jniThrowNullPointerException(env, "SSL_CTX is null"); |
| 2442 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_peer_cert_chain => NULL", ssl_session); |
| 2443 | return NULL; |
| 2444 | } |
| 2445 | STACK_OF(X509)* chain = SSL_SESSION_get_peer_cert_chain(ssl_ctx, ssl_session); |
| 2446 | jobjectArray objectArray = getCertificateBytes(env, chain); |
| 2447 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_peer_cert_chain => %p", ssl_session, objectArray); |
| 2448 | return objectArray; |
| 2449 | } |
| 2450 | |
| 2451 | /** |
| 2452 | * Gets and returns in a long integer the creation's time of the |
| 2453 | * actual SSL session. |
| 2454 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2455 | static jlong NativeCrypto_SSL_SESSION_get_time(JNIEnv*, jclass, jint ssl_session_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2456 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2457 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time", ssl_session); |
| 2458 | jlong result = SSL_SESSION_get_time(ssl_session); // must be jlong, not long or *1000 will overflow |
| 2459 | result *= 1000; // OpenSSL uses seconds, Java uses milliseconds. |
| 2460 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_time => %lld", ssl_session, result); |
| 2461 | return result; |
| 2462 | } |
| 2463 | |
| 2464 | /** |
| 2465 | * Our implementation of what might be considered |
| 2466 | * SSL_SESSION_get_version, based on SSL_get_version. |
| 2467 | * See get_ssl_version above. |
| 2468 | */ |
| 2469 | // TODO move to jsse.patch |
| 2470 | static const char* SSL_SESSION_get_version(SSL_SESSION* ssl_session) { |
| 2471 | return get_ssl_version(ssl_session->ssl_version); |
| 2472 | } |
| 2473 | |
| 2474 | /** |
| 2475 | * Gets and returns in a string the version of the SSL protocol. If it |
| 2476 | * returns the string "unknown" it means that no connection is established. |
| 2477 | */ |
| 2478 | static jstring NativeCrypto_SSL_SESSION_get_version(JNIEnv* env, jclass, jint ssl_session_address) { |
| 2479 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2480 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version", ssl_session); |
| 2481 | const char* protocol = SSL_SESSION_get_version(ssl_session); |
| 2482 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_get_version => %s", ssl_session, protocol); |
| 2483 | return env->NewStringUTF(protocol); |
| 2484 | } |
| 2485 | |
| 2486 | /** |
| 2487 | * Gets and returns in a string the set of ciphers the actual SSL session uses. |
| 2488 | */ |
| 2489 | static jstring NativeCrypto_SSL_SESSION_cipher(JNIEnv* env, jclass, jint ssl_session_address) { |
| 2490 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2491 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher", ssl_session); |
| 2492 | const SSL_CIPHER* cipher = ssl_session->cipher; |
| 2493 | const char* name = SSL_CIPHER_get_name(cipher); |
| 2494 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_cipher => %s", ssl_session, name); |
| 2495 | return env->NewStringUTF(name); |
| 2496 | } |
| 2497 | |
| 2498 | /** |
| 2499 | * Frees the SSL session. |
| 2500 | */ |
Brian Carlstrom | 44e0e56 | 2010-05-06 23:44:16 -0700 | [diff] [blame^] | 2501 | static void NativeCrypto_SSL_SESSION_free(JNIEnv*, jclass, jint ssl_session_address) { |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2502 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2503 | JNI_TRACE("ssl_session=%p NativeCrypto_SSL_SESSION_free", ssl_session); |
| 2504 | SSL_SESSION_free(ssl_session); |
| 2505 | } |
| 2506 | |
| 2507 | |
| 2508 | /** |
| 2509 | * Serializes the native state of the session (ID, cipher, and keys but |
| 2510 | * not certificates). Returns a byte[] containing the DER-encoded state. |
| 2511 | * See apache mod_ssl. |
| 2512 | */ |
| 2513 | static jbyteArray NativeCrypto_i2d_SSL_SESSION(JNIEnv* env, jclass, jint ssl_session_address) { |
| 2514 | SSL_SESSION* ssl_session = to_SSL_SESSION(ssl_session_address); |
| 2515 | JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION", ssl_session); |
| 2516 | if (ssl_session == NULL) { |
| 2517 | JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION => NULL", ssl_session); |
| 2518 | return NULL; |
| 2519 | } |
| 2520 | |
| 2521 | // Compute the size of the DER data |
| 2522 | int size = i2d_SSL_SESSION(ssl_session, NULL); |
| 2523 | if (size == 0) { |
| 2524 | JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION => NULL", ssl_session); |
| 2525 | return NULL; |
| 2526 | } |
| 2527 | |
| 2528 | jbyteArray bytes = env->NewByteArray(size); |
| 2529 | if (bytes != NULL) { |
| 2530 | jbyte* tmp = env->GetByteArrayElements(bytes, NULL); |
| 2531 | unsigned char* ucp = reinterpret_cast<unsigned char*>(tmp); |
| 2532 | i2d_SSL_SESSION(ssl_session, &ucp); |
| 2533 | env->ReleaseByteArrayElements(bytes, tmp, 0); |
| 2534 | } |
| 2535 | |
| 2536 | JNI_TRACE("ssl_session=%p NativeCrypto_i2d_SSL_SESSION => size=%d", ssl_session, size); |
| 2537 | return bytes; |
| 2538 | } |
| 2539 | |
| 2540 | /** |
| 2541 | * Deserialize the session. |
| 2542 | */ |
| 2543 | static jint NativeCrypto_d2i_SSL_SESSION(JNIEnv* env, jclass, jbyteArray bytes, jint size) { |
| 2544 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION bytes=%p size=%d", bytes, size); |
| 2545 | if (bytes == NULL) { |
| 2546 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => 0"); |
| 2547 | return 0; |
| 2548 | } |
| 2549 | |
| 2550 | ScopedByteArray tmp(env, bytes); |
| 2551 | const unsigned char* ucp = reinterpret_cast<const unsigned char*>(tmp.bytes()); |
| 2552 | SSL_SESSION* ssl_session = d2i_SSL_SESSION(NULL, &ucp, size); |
| 2553 | |
| 2554 | JNI_TRACE("NativeCrypto_d2i_SSL_SESSION => %p", ssl_session); |
| 2555 | return static_cast<jint>(reinterpret_cast<uintptr_t>(ssl_session)); |
| 2556 | } |
| 2557 | |
| 2558 | /* |
| 2559 | * Defines the mapping from Java methods and their signatures |
| 2560 | * to native functions. Order is (1) Java name, (2) signature, |
| 2561 | * (3) pointer to C function. |
| 2562 | */ |
| 2563 | static JNINativeMethod sNativeCryptoMethods[] = { |
| 2564 | { "clinit", "()V", (void*)NativeCrypto_clinit}, |
| 2565 | { "EVP_PKEY_new_DSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_DSA }, |
| 2566 | { "EVP_PKEY_new_RSA", "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_RSA }, |
| 2567 | { "EVP_PKEY_free", "(I)V", (void*)NativeCrypto_EVP_PKEY_free }, |
| 2568 | { "EVP_new", "()I", (void*)NativeCrypto_EVP_new }, |
| 2569 | { "EVP_free", "(I)V", (void*)NativeCrypto_EVP_free }, |
| 2570 | { "EVP_DigestFinal", "(I[BI)I", (void*)NativeCrypto_EVP_DigestFinal }, |
| 2571 | { "EVP_DigestInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_DigestInit }, |
| 2572 | { "EVP_DigestBlockSize", "(I)I", (void*)NativeCrypto_EVP_DigestBlockSize }, |
| 2573 | { "EVP_DigestSize", "(I)I", (void*)NativeCrypto_EVP_DigestSize }, |
| 2574 | { "EVP_DigestUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_DigestUpdate }, |
| 2575 | { "EVP_VerifyInit", "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_VerifyInit }, |
| 2576 | { "EVP_VerifyUpdate", "(I[BII)V", (void*)NativeCrypto_EVP_VerifyUpdate }, |
| 2577 | { "EVP_VerifyFinal", "(I[BIII)I", (void*)NativeCrypto_EVP_VerifyFinal }, |
| 2578 | { "verifySignature", "([B[BLjava/lang/String;[B[B)I", (void*)NativeCrypto_verifysignature}, |
| 2579 | { "SSL_CTX_new", "()I", (void*)NativeCrypto_SSL_CTX_new }, |
| 2580 | { "SSL_CTX_get_ciphers", "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_CTX_get_ciphers}, |
| 2581 | { "SSL_CTX_free", "(I)V", (void*)NativeCrypto_SSL_CTX_free }, |
| 2582 | { "SSL_new", "(ILjava/lang/String;Ljava/lang/String;[B)I", (void*)NativeCrypto_SSL_new}, |
| 2583 | { "SSL_get_mode", "(I)J", (void*)NativeCrypto_SSL_get_mode }, |
| 2584 | { "SSL_set_mode", "(IJ)J", (void*)NativeCrypto_SSL_set_mode }, |
| 2585 | { "SSL_clear_mode", "(IJ)J", (void*)NativeCrypto_SSL_clear_mode }, |
| 2586 | { "SSL_get_options", "(I)J", (void*)NativeCrypto_SSL_get_options }, |
| 2587 | { "SSL_set_options", "(IJ)J", (void*)NativeCrypto_SSL_set_options }, |
| 2588 | { "SSL_clear_options", "(IJ)J", (void*)NativeCrypto_SSL_clear_options }, |
| 2589 | { "SSL_get_ciphers", "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_get_ciphers }, |
| 2590 | { "SSL_set_cipher_list", "(ILjava/lang/String;)V", (void*)NativeCrypto_SSL_set_cipher_list }, |
| 2591 | { "SSL_set_verify", "(II)V", (void*)NativeCrypto_SSL_set_verify}, |
| 2592 | { "SSL_set_session", "(II)V", (void*)NativeCrypto_SSL_set_session }, |
| 2593 | { "SSL_set_session_creation_enabled", "(IZ)V", (void*)NativeCrypto_SSL_set_session_creation_enabled }, |
| 2594 | { "SSL_do_handshake", "(ILjava/net/Socket;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$CertificateChainVerifier;Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto$HandshakeCompletedCallback;IZ)I",(void*)NativeCrypto_SSL_do_handshake}, |
| 2595 | { "SSL_get_certificate", "(I)[[B", (void*)NativeCrypto_SSL_get_certificate}, |
| 2596 | { "SSL_read_byte", "(II)I", (void*)NativeCrypto_SSL_read_byte}, |
| 2597 | { "SSL_read", "(I[BIII)I", (void*)NativeCrypto_SSL_read}, |
| 2598 | { "SSL_write_byte", "(II)V", (void*)NativeCrypto_SSL_write_byte}, |
| 2599 | { "SSL_write", "(I[BII)V", (void*)NativeCrypto_SSL_write}, |
| 2600 | { "SSL_interrupt", "(I)V", (void*)NativeCrypto_SSL_interrupt}, |
| 2601 | { "SSL_shutdown", "(I)V", (void*)NativeCrypto_SSL_shutdown}, |
| 2602 | { "SSL_free", "(I)V", (void*)NativeCrypto_SSL_free}, |
| 2603 | { "SSL_SESSION_session_id", "(I)[B", (void*)NativeCrypto_SSL_SESSION_session_id }, |
| 2604 | { "SSL_SESSION_get_peer_cert_chain", "(II)[[B", (void*)NativeCrypto_SSL_SESSION_get_peer_cert_chain }, |
| 2605 | { "SSL_SESSION_get_time", "(I)J", (void*)NativeCrypto_SSL_SESSION_get_time }, |
| 2606 | { "SSL_SESSION_get_version", "(I)Ljava/lang/String;", (void*)NativeCrypto_SSL_SESSION_get_version }, |
| 2607 | { "SSL_SESSION_cipher", "(I)Ljava/lang/String;", (void*)NativeCrypto_SSL_SESSION_cipher }, |
| 2608 | { "SSL_SESSION_free", "(I)V", (void*)NativeCrypto_SSL_SESSION_free }, |
| 2609 | { "i2d_SSL_SESSION", "(I)[B", (void*)NativeCrypto_i2d_SSL_SESSION }, |
| 2610 | { "d2i_SSL_SESSION", "([BI)I", (void*)NativeCrypto_d2i_SSL_SESSION }, |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2611 | }; |
| 2612 | |
Elliott Hughes | c08f9fb | 2010-04-16 17:44:12 -0700 | [diff] [blame] | 2613 | int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) { |
Brian Carlstrom | bcfb325 | 2010-05-02 11:27:52 -0700 | [diff] [blame] | 2614 | JNI_TRACE("register_org_apache_harmony_xnet_provider_jsse_NativeCrypto"); |
Brian Carlstrom | 3e24c53 | 2010-05-06 00:23:21 -0700 | [diff] [blame] | 2615 | // Register org.apache.harmony.xnet.provider.jsse.NativeCrypto methods |
| 2616 | int result = jniRegisterNativeMethods(env, |
| 2617 | "org/apache/harmony/xnet/provider/jsse/NativeCrypto", |
| 2618 | sNativeCryptoMethods, |
| 2619 | NELEM(sNativeCryptoMethods)); |
| 2620 | if (result == -1) { |
| 2621 | return -1; |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2622 | } |
| 2623 | |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2624 | // java.net.Socket |
| 2625 | jclass socket = env->FindClass("java/net/Socket"); |
| 2626 | if (socket == NULL) { |
| 2627 | LOGE("Can't find class java.net.Socket"); |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 2628 | return -1; |
| 2629 | } |
Brian Carlstrom | 0348e62 | 2010-02-10 22:56:47 -0800 | [diff] [blame] | 2630 | field_Socket_mImpl = env->GetFieldID(socket, "impl", "Ljava/net/SocketImpl;"); |
| 2631 | if (field_Socket_mImpl == NULL) { |
| 2632 | LOGE("Can't find field impl in class java.net.Socket"); |
| 2633 | return -1; |
| 2634 | } |
| 2635 | |
| 2636 | // java.net.SocketImpl |
| 2637 | jclass socketImplClass = env->FindClass("java/net/SocketImpl"); |
| 2638 | if (socketImplClass == NULL) { |
| 2639 | LOGE("Can't find class java.net.SocketImpl"); |
| 2640 | return -1; |
| 2641 | } |
| 2642 | field_Socket_mFD = env->GetFieldID(socketImplClass, "fd", "Ljava/io/FileDescriptor;"); |
| 2643 | if (field_Socket_mFD == NULL) { |
| 2644 | LOGE("Can't find field fd in java.net.SocketImpl"); |
| 2645 | return -1; |
| 2646 | } |
| 2647 | |
The Android Open Source Project | adc854b | 2009-03-03 19:28:47 -0800 | [diff] [blame] | 2648 | return 0; |
| 2649 | } |