1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <conscrypt/jniutil.h>
18
19 #include <conscrypt/compat.h>
20 #include <conscrypt/trace.h>
21 #include <cstdlib>
22 #include <errno.h>
23
24 namespace conscrypt {
25 namespace jniutil {
26
27 JavaVM *gJavaVM;
28 jclass cryptoUpcallsClass;
29 jclass openSslInputStreamClass;
30 jclass nativeRefClass;
31 jclass nativeRefHpkeCtxClass;
32
33 jclass byteArrayClass;
34 jclass calendarClass;
35 jclass objectClass;
36 jclass objectArrayClass;
37 jclass integerClass;
38 jclass inputStreamClass;
39 jclass outputStreamClass;
40 jclass stringClass;
41 jclass byteBufferClass;
42 static jclass bufferClass;
43 static jclass fileDescriptorClass;
44 static jclass sslHandshakeCallbacksClass;
45
46 jfieldID nativeRef_address;
47 static jfieldID fileDescriptor_fd;
48
49 jmethodID calendar_setMethod;
50 jmethodID inputStream_readMethod;
51 jmethodID integer_valueOfMethod;
52 jmethodID openSslInputStream_readLineMethod;
53 jmethodID outputStream_writeMethod;
54 jmethodID outputStream_flushMethod;
55 jmethodID buffer_positionMethod;
56 jmethodID buffer_limitMethod;
57 jmethodID buffer_isDirectMethod;
58 jmethodID cryptoUpcallsClass_rawSignMethod;
59 jmethodID cryptoUpcallsClass_rsaSignMethod;
60 jmethodID cryptoUpcallsClass_rsaDecryptMethod;
61 jmethodID nativeRefHpkeCtxClass_constructor;
62 jmethodID sslHandshakeCallbacks_verifyCertificateChain;
63 jmethodID sslHandshakeCallbacks_onSSLStateChange;
64 jmethodID sslHandshakeCallbacks_clientCertificateRequested;
65 jmethodID sslHandshakeCallbacks_serverCertificateRequested;
66 jmethodID sslHandshakeCallbacks_clientPSKKeyRequested;
67 jmethodID sslHandshakeCallbacks_serverPSKKeyRequested;
68 jmethodID sslHandshakeCallbacks_onNewSessionEstablished;
69 jmethodID sslHandshakeCallbacks_selectApplicationProtocol;
70 jmethodID sslHandshakeCallbacks_serverSessionRequested;
71
init(JavaVM * vm,JNIEnv * env)72 void init(JavaVM* vm, JNIEnv* env) {
73 gJavaVM = vm;
74
75 byteArrayClass = findClass(env, "[B");
76 calendarClass = findClass(env, "java/util/Calendar");
77 inputStreamClass = findClass(env, "java/io/InputStream");
78 integerClass = findClass(env, "java/lang/Integer");
79 objectClass = findClass(env, "java/lang/Object");
80 objectArrayClass = findClass(env, "[Ljava/lang/Object;");
81 outputStreamClass = findClass(env, "java/io/OutputStream");
82 stringClass = findClass(env, "java/lang/String");
83 byteBufferClass = findClass(env, "java/nio/ByteBuffer");
84 bufferClass = findClass(env, "java/nio/Buffer");
85 fileDescriptorClass = findClass(env, "java/io/FileDescriptor");
86
87 cryptoUpcallsClass = getGlobalRefToClass(
88 env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/CryptoUpcalls");
89 nativeRefClass = getGlobalRefToClass(
90 env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef");
91 nativeRefHpkeCtxClass = getGlobalRefToClass(
92 env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeRef$EVP_HPKE_CTX");
93 openSslInputStreamClass = getGlobalRefToClass(
94 env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/OpenSSLBIOInputStream");
95 sslHandshakeCallbacksClass = getGlobalRefToClass(
96 env, TO_STRING(JNI_JARJAR_PREFIX) "org/conscrypt/NativeCrypto$SSLHandshakeCallbacks");
97
98 nativeRef_address = getFieldRef(env, nativeRefClass, "address", "J");
99 #if defined(ANDROID) && !defined(CONSCRYPT_OPENJDK)
100 fileDescriptor_fd = getFieldRef(env, fileDescriptorClass, "descriptor", "I");
101 #else /* !ANDROID || CONSCRYPT_OPENJDK */
102 fileDescriptor_fd = getFieldRef(env, fileDescriptorClass, "fd", "I");
103 #endif
104
105 calendar_setMethod = getMethodRef(env, calendarClass, "set", "(IIIIII)V");
106 inputStream_readMethod = getMethodRef(env, inputStreamClass, "read", "([B)I");
107 integer_valueOfMethod =
108 env->GetStaticMethodID(integerClass, "valueOf", "(I)Ljava/lang/Integer;");
109 openSslInputStream_readLineMethod =
110 getMethodRef(env, openSslInputStreamClass, "gets", "([B)I");
111 outputStream_writeMethod = getMethodRef(env, outputStreamClass, "write", "([B)V");
112 outputStream_flushMethod = getMethodRef(env, outputStreamClass, "flush", "()V");
113 buffer_positionMethod = getMethodRef(env, bufferClass, "position", "()I");
114 buffer_limitMethod = getMethodRef(env, bufferClass, "limit", "()I");
115 buffer_isDirectMethod = getMethodRef(env, bufferClass, "isDirect", "()Z");
116 sslHandshakeCallbacks_verifyCertificateChain =
117 getMethodRef(env, sslHandshakeCallbacksClass, "verifyCertificateChain", "([[BLjava/lang/String;)V");
118 sslHandshakeCallbacks_onSSLStateChange =
119 getMethodRef(env, sslHandshakeCallbacksClass, "onSSLStateChange", "(II)V");
120 sslHandshakeCallbacks_clientCertificateRequested = getMethodRef(
121 env, sslHandshakeCallbacksClass, "clientCertificateRequested", "([B[I[[B)V");
122 sslHandshakeCallbacks_serverCertificateRequested =
123 getMethodRef(env, sslHandshakeCallbacksClass, "serverCertificateRequested", "()V");
124 sslHandshakeCallbacks_clientPSKKeyRequested = getMethodRef(
125 env, sslHandshakeCallbacksClass, "clientPSKKeyRequested", "(Ljava/lang/String;[B[B)I");
126 sslHandshakeCallbacks_serverPSKKeyRequested =
127 getMethodRef(env, sslHandshakeCallbacksClass, "serverPSKKeyRequested",
128 "(Ljava/lang/String;Ljava/lang/String;[B)I");
129 sslHandshakeCallbacks_onNewSessionEstablished =
130 getMethodRef(env, sslHandshakeCallbacksClass, "onNewSessionEstablished", "(J)V");
131 sslHandshakeCallbacks_serverSessionRequested =
132 getMethodRef(env, sslHandshakeCallbacksClass, "serverSessionRequested", "([B)J");
133 sslHandshakeCallbacks_selectApplicationProtocol =
134 getMethodRef(env, sslHandshakeCallbacksClass, "selectApplicationProtocol", "([B)I");
135 cryptoUpcallsClass_rawSignMethod = env->GetStaticMethodID(
136 cryptoUpcallsClass, "ecSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;[B)[B");
137 if (cryptoUpcallsClass_rawSignMethod == nullptr) {
138 env->FatalError("Could not find ecSignDigestWithPrivateKey");
139 }
140 cryptoUpcallsClass_rsaSignMethod = env->GetStaticMethodID(
141 cryptoUpcallsClass, "rsaSignDigestWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B");
142 if (cryptoUpcallsClass_rsaSignMethod == nullptr) {
143 env->FatalError("Could not find rsaSignDigestWithPrivateKey");
144 }
145 cryptoUpcallsClass_rsaDecryptMethod = env->GetStaticMethodID(
146 cryptoUpcallsClass, "rsaDecryptWithPrivateKey", "(Ljava/security/PrivateKey;I[B)[B");
147 if (cryptoUpcallsClass_rsaDecryptMethod == nullptr) {
148 env->FatalError("Could not find rsaDecryptWithPrivateKey");
149 }
150 nativeRefHpkeCtxClass_constructor = env->GetMethodID(nativeRefHpkeCtxClass, "<init>", "(J)V");
151 }
152
jniRegisterNativeMethods(JNIEnv * env,const char * className,const JNINativeMethod * gMethods,int numMethods)153 void jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods,
154 int numMethods) {
155 CONSCRYPT_LOG_VERBOSE("Registering %s's %d native methods...", className, numMethods);
156
157 ScopedLocalRef<jclass> c(env, env->FindClass(className));
158 if (c.get() == nullptr) {
159 char* msg;
160 (void)asprintf(&msg, "Native registration unable to find class '%s'; aborting...",
161 className);
162 env->FatalError(msg);
163 }
164
165 if (env->RegisterNatives(c.get(), gMethods, numMethods) < 0) {
166 char* msg;
167 (void)asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
168 env->FatalError(msg);
169 }
170 }
171
jniGetFDFromFileDescriptor(JNIEnv * env,jobject fileDescriptor)172 int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor) {
173 if (fileDescriptor != nullptr) {
174 return env->GetIntField(fileDescriptor, fileDescriptor_fd);
175 } else {
176 return -1;
177 }
178 }
179
isDirectByteBufferInstance(JNIEnv * env,jobject buffer)180 extern bool isDirectByteBufferInstance(JNIEnv* env, jobject buffer) {
181 // Some versions of ART do not check the buffer validity when handling GetDirectBufferAddress()
182 // and GetDirectBufferCapacity().
183 if (buffer == nullptr) {
184 return false;
185 }
186 if (!env->IsInstanceOf(buffer, conscrypt::jniutil::byteBufferClass)) {
187 return false;
188 }
189 return env->CallBooleanMethod(buffer, conscrypt::jniutil::buffer_isDirectMethod) == JNI_TRUE;
190 }
191
isGetByteArrayElementsLikelyToReturnACopy(size_t size)192 bool isGetByteArrayElementsLikelyToReturnACopy(size_t size) {
193 #if defined(ANDROID) && !defined(CONSCRYPT_OPENJDK)
194 // ART's GetByteArrayElements creates copies only for arrays smaller than 12 kB.
195 return size <= 12 * 1024;
196 #else
197 (void)size;
198 // On OpenJDK based VMs GetByteArrayElements appears to always create a copy.
199 return true;
200 #endif
201 }
202
throwException(JNIEnv * env,const char * className,const char * msg)203 int throwException(JNIEnv* env, const char* className, const char* msg) {
204 jclass exceptionClass = env->FindClass(className);
205
206 if (exceptionClass == nullptr) {
207 CONSCRYPT_LOG_ERROR("Unable to find exception class %s", className);
208 /* ClassNotFoundException now pending */
209 return -1;
210 }
211
212 if (env->ThrowNew(exceptionClass, msg) != JNI_OK) {
213 CONSCRYPT_LOG_ERROR("Failed throwing '%s' '%s'", className, msg);
214 /* an exception, most likely OOM, will now be pending */
215 return -1;
216 }
217
218 env->DeleteLocalRef(exceptionClass);
219 return 0;
220 }
221
throwRuntimeException(JNIEnv * env,const char * msg)222 int throwRuntimeException(JNIEnv* env, const char* msg) {
223 return conscrypt::jniutil::throwException(env, "java/lang/RuntimeException", msg);
224 }
225
226 #ifdef CONSCRYPT_CHECK_ERROR_QUEUE
throwAssertionError(JNIEnv * env,const char * msg)227 int throwAssertionError(JNIEnv* env, const char* msg) {
228 return conscrypt::jniutil::throwException(env, "java/lang/AssertionError", msg);
229 }
230 #endif
231
throwNullPointerException(JNIEnv * env,const char * msg)232 int throwNullPointerException(JNIEnv* env, const char* msg) {
233 return conscrypt::jniutil::throwException(env, "java/lang/NullPointerException", msg);
234 }
235
throwOutOfMemory(JNIEnv * env,const char * message)236 int throwOutOfMemory(JNIEnv* env, const char* message) {
237 return conscrypt::jniutil::throwException(env, "java/lang/OutOfMemoryError", message);
238 }
239
throwBadPaddingException(JNIEnv * env,const char * message)240 int throwBadPaddingException(JNIEnv* env, const char* message) {
241 JNI_TRACE("throwBadPaddingException %s", message);
242 return conscrypt::jniutil::throwException(env, "javax/crypto/BadPaddingException", message);
243 }
244
throwSignatureException(JNIEnv * env,const char * message)245 int throwSignatureException(JNIEnv* env, const char* message) {
246 JNI_TRACE("throwSignatureException %s", message);
247 return conscrypt::jniutil::throwException(env, "java/security/SignatureException", message);
248 }
249
throwInvalidKeyException(JNIEnv * env,const char * message)250 int throwInvalidKeyException(JNIEnv* env, const char* message) {
251 JNI_TRACE("throwInvalidKeyException %s", message);
252 return conscrypt::jniutil::throwException(env, "java/security/InvalidKeyException", message);
253 }
254
throwIllegalArgumentException(JNIEnv * env,const char * message)255 int throwIllegalArgumentException(JNIEnv* env, const char* message) {
256 JNI_TRACE("throwIllegalArgumentException %s", message);
257 return conscrypt::jniutil::throwException(
258 env, "java/lang/IllegalArgumentException", message);
259 }
260
throwIllegalBlockSizeException(JNIEnv * env,const char * message)261 int throwIllegalBlockSizeException(JNIEnv* env, const char* message) {
262 JNI_TRACE("throwIllegalBlockSizeException %s", message);
263 return conscrypt::jniutil::throwException(
264 env, "javax/crypto/IllegalBlockSizeException", message);
265 }
266
throwShortBufferException(JNIEnv * env,const char * message)267 int throwShortBufferException(JNIEnv* env, const char* message) {
268 JNI_TRACE("throwShortBufferException %s", message);
269 return conscrypt::jniutil::throwException(
270 env, "javax/crypto/ShortBufferException", message);
271 }
272
throwNoSuchAlgorithmException(JNIEnv * env,const char * message)273 int throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
274 JNI_TRACE("throwUnknownAlgorithmException %s", message);
275 return conscrypt::jniutil::throwException(
276 env, "java/security/NoSuchAlgorithmException", message);
277 }
278
throwIOException(JNIEnv * env,const char * message)279 int throwIOException(JNIEnv* env, const char* message) {
280 JNI_TRACE("throwIOException %s", message);
281 return conscrypt::jniutil::throwException(env, "java/io/IOException", message);
282 }
283
throwCertificateException(JNIEnv * env,const char * message)284 int throwCertificateException(JNIEnv* env, const char* message) {
285 JNI_TRACE("throwCertificateException %s", message);
286 return conscrypt::jniutil::throwException(
287 env, "java/security/cert/CertificateException", message);
288 }
289
throwParsingException(JNIEnv * env,const char * message)290 int throwParsingException(JNIEnv* env, const char* message) {
291 return conscrypt::jniutil::throwException(env, TO_STRING(JNI_JARJAR_PREFIX)
292 "org/conscrypt/OpenSSLX509CertificateFactory$ParsingException",
293 message);
294 }
295
throwInvalidAlgorithmParameterException(JNIEnv * env,const char * message)296 int throwInvalidAlgorithmParameterException(JNIEnv* env, const char* message) {
297 JNI_TRACE("throwInvalidAlgorithmParameterException %s", message);
298 return conscrypt::jniutil::throwException(
299 env, "java/security/InvalidAlgorithmParameterException", message);
300 }
301
throwForAsn1Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))302 int throwForAsn1Error(JNIEnv* env, int reason, const char* message,
303 int (*defaultThrow)(JNIEnv*, const char*)) {
304 switch (reason) {
305 case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE:
306 case ASN1_R_WRONG_PUBLIC_KEY_TYPE:
307 return throwInvalidKeyException(env, message);
308 break;
309 case ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED:
310 case ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM:
311 case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
312 return throwNoSuchAlgorithmException(env, message);
313 break;
314 }
315 return defaultThrow(env, message);
316 }
317
throwForCipherError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))318 int throwForCipherError(JNIEnv* env, int reason, const char* message,
319 int (*defaultThrow)(JNIEnv*, const char*)) {
320 switch (reason) {
321 case CIPHER_R_BAD_DECRYPT:
322 return throwBadPaddingException(env, message);
323 break;
324 case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
325 case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
326 return throwIllegalBlockSizeException(env, message);
327 break;
328 // TODO(davidben): Remove these ifdefs after
329 // https://boringssl-review.googlesource.com/c/boringssl/+/35565 has
330 // rolled out to relevant BoringSSL copies.
331 #if defined(CIPHER_R_BAD_KEY_LENGTH)
332 case CIPHER_R_BAD_KEY_LENGTH:
333 #endif
334 #if defined(CIPHER_R_UNSUPPORTED_KEY_SIZE)
335 case CIPHER_R_UNSUPPORTED_KEY_SIZE:
336 #endif
337 case CIPHER_R_INVALID_KEY_LENGTH:
338 return throwInvalidKeyException(env, message);
339 break;
340 case CIPHER_R_BUFFER_TOO_SMALL:
341 return throwShortBufferException(env, message);
342 break;
343 }
344 return defaultThrow(env, message);
345 }
346
throwForEvpError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))347 int throwForEvpError(JNIEnv* env, int reason, const char* message,
348 int (*defaultThrow)(JNIEnv*, const char*)) {
349 switch (reason) {
350 case EVP_R_MISSING_PARAMETERS:
351 case EVP_R_INVALID_PEER_KEY:
352 case EVP_R_DECODE_ERROR:
353 case EVP_R_NOT_A_PRIVATE_KEY:
354 return throwInvalidKeyException(env, message);
355 break;
356 case EVP_R_UNSUPPORTED_ALGORITHM:
357 return throwNoSuchAlgorithmException(env, message);
358 break;
359 case EVP_R_INVALID_BUFFER_SIZE:
360 case EVP_R_BUFFER_TOO_SMALL:
361 return throwIllegalArgumentException(env, message);
362 break;
363 default:
364 return defaultThrow(env, message);
365 break;
366 }
367 }
368
throwForRsaError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))369 int throwForRsaError(JNIEnv* env, int reason, const char* message,
370 int (*defaultThrow)(JNIEnv*, const char*)) {
371 switch (reason) {
372 case RSA_R_BLOCK_TYPE_IS_NOT_01:
373 case RSA_R_PKCS_DECODING_ERROR:
374 return throwBadPaddingException(env, message);
375 break;
376 case RSA_R_BAD_SIGNATURE:
377 case RSA_R_INVALID_MESSAGE_LENGTH:
378 case RSA_R_WRONG_SIGNATURE_LENGTH:
379 return throwSignatureException(env, message);
380 break;
381 case RSA_R_UNKNOWN_ALGORITHM_TYPE:
382 return throwNoSuchAlgorithmException(env, message);
383 break;
384 case RSA_R_MODULUS_TOO_LARGE:
385 case RSA_R_NO_PUBLIC_EXPONENT:
386 return throwInvalidKeyException(env, message);
387 break;
388 case RSA_R_DATA_TOO_LARGE:
389 case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
390 case RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE:
391 return throwIllegalBlockSizeException(env, message);
392 break;
393 }
394 return defaultThrow(env, message);
395 }
396
throwForX509Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))397 int throwForX509Error(JNIEnv* env, int reason, const char* message,
398 int (*defaultThrow)(JNIEnv*, const char*)) {
399 switch (reason) {
400 case X509_R_UNSUPPORTED_ALGORITHM:
401 return throwNoSuchAlgorithmException(env, message);
402 break;
403 default:
404 return defaultThrow(env, message);
405 break;
406 }
407 }
408
throwExceptionFromBoringSSLError(JNIEnv * env,CONSCRYPT_UNUSED const char * location,int (* defaultThrow)(JNIEnv *,const char *))409 void throwExceptionFromBoringSSLError(JNIEnv* env, CONSCRYPT_UNUSED const char* location,
410 int (*defaultThrow)(JNIEnv*, const char*)) {
411 const char* file;
412 int line;
413 const char* data;
414 int flags;
415 // NOLINTNEXTLINE(runtime/int)
416 unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
417
418 if (error == 0) {
419 defaultThrow(env, "Unknown BoringSSL error");
420 return;
421 }
422
423 // If there's an error from BoringSSL it may have been caused by an exception in Java code, so
424 // ensure there isn't a pending exception before we throw a new one.
425 if (!env->ExceptionCheck()) {
426 char message[256];
427 ERR_error_string_n(error, message, sizeof(message));
428 int library = ERR_GET_LIB(error);
429 int reason = ERR_GET_REASON(error);
430 JNI_TRACE("BoringSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s", location,
431 error, library, reason, file, line, message,
432 (flags & ERR_TXT_STRING) ? data : "(no data)");
433 switch (library) {
434 case ERR_LIB_RSA:
435 throwForRsaError(env, reason, message, defaultThrow);
436 break;
437 case ERR_LIB_ASN1:
438 throwForAsn1Error(env, reason, message, defaultThrow);
439 break;
440 case ERR_LIB_CIPHER:
441 throwForCipherError(env, reason, message, defaultThrow);
442 break;
443 case ERR_LIB_EVP:
444 throwForEvpError(env, reason, message, defaultThrow);
445 break;
446 case ERR_LIB_X509:
447 throwForX509Error(env, reason, message, defaultThrow);
448 break;
449 case ERR_LIB_DSA:
450 throwInvalidKeyException(env, message);
451 break;
452 default:
453 defaultThrow(env, message);
454 break;
455 }
456 }
457
458 ERR_clear_error();
459 }
460
throwSocketTimeoutException(JNIEnv * env,const char * message)461 int throwSocketTimeoutException(JNIEnv* env, const char* message) {
462 JNI_TRACE("throwSocketTimeoutException %s", message);
463 return conscrypt::jniutil::throwException(env, "java/net/SocketTimeoutException", message);
464 }
465
throwSSLHandshakeExceptionStr(JNIEnv * env,const char * message)466 int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message) {
467 JNI_TRACE("throwSSLExceptionStr %s", message);
468 return conscrypt::jniutil::throwException(
469 env, "javax/net/ssl/SSLHandshakeException", message);
470 }
471
throwSSLExceptionStr(JNIEnv * env,const char * message)472 int throwSSLExceptionStr(JNIEnv* env, const char* message) {
473 JNI_TRACE("throwSSLExceptionStr %s", message);
474 return conscrypt::jniutil::throwException(env, "javax/net/ssl/SSLException", message);
475 }
476
throwSSLProtocolExceptionStr(JNIEnv * env,const char * message)477 int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
478 JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
479 return conscrypt::jniutil::throwException(
480 env, "javax/net/ssl/SSLProtocolException", message);
481 }
482
throwSSLExceptionWithSslErrors(JNIEnv * env,SSL * ssl,int sslErrorCode,const char * message,int (* actualThrow)(JNIEnv *,const char *))483 int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message,
484 int (*actualThrow)(JNIEnv*, const char*)) {
485 if (message == nullptr) {
486 message = "SSL error";
487 }
488
489 // First consult the SSL error code for the general message.
490 const char* sslErrorStr = nullptr;
491 switch (sslErrorCode) {
492 case SSL_ERROR_NONE:
493 if (ERR_peek_error() == 0) {
494 sslErrorStr = "OK";
495 } else {
496 sslErrorStr = "";
497 }
498 break;
499 case SSL_ERROR_SSL:
500 sslErrorStr = "Failure in SSL library, usually a protocol error";
501 break;
502 case SSL_ERROR_WANT_READ:
503 sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
504 break;
505 case SSL_ERROR_WANT_WRITE:
506 sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
507 break;
508 case SSL_ERROR_WANT_X509_LOOKUP:
509 sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
510 break;
511 case SSL_ERROR_SYSCALL:
512 sslErrorStr = "I/O error during system call";
513 break;
514 case SSL_ERROR_ZERO_RETURN:
515 sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
516 break;
517 case SSL_ERROR_WANT_CONNECT:
518 sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
519 break;
520 case SSL_ERROR_WANT_ACCEPT:
521 sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
522 break;
523 default:
524 sslErrorStr = "Unknown SSL error";
525 }
526
527 // Prepend either our explicit message or a default one.
528 char* str;
529 if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
530 // problem with asprintf, just throw argument message, log everything
531 int ret = actualThrow(env, message);
532 CONSCRYPT_LOG_VERBOSE("%s: ssl=%p: %s", message, ssl, sslErrorStr);
533 ERR_clear_error();
534 return ret;
535 }
536
537 char* allocStr = str;
538
539 // For protocol errors, SSL might have more information.
540 if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
541 // Append each error as an additional line to the message.
542 for (;;) {
543 char errStr[256];
544 const char* file;
545 int line;
546 const char* data;
547 int flags;
548 // NOLINTNEXTLINE(runtime/int)
549 unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
550 if (err == 0) {
551 break;
552 }
553
554 ERR_error_string_n(err, errStr, sizeof(errStr));
555
556 int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
557 (allocStr == nullptr) ? "" : allocStr, errStr, file, line,
558 (flags & ERR_TXT_STRING) ? data : "(no data)", flags);
559
560 if (ret < 0) {
561 break;
562 }
563
564 free(allocStr);
565 allocStr = str;
566 }
567 // For errors during system calls, errno might be our friend.
568 } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
569 if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
570 free(allocStr);
571 allocStr = str;
572 }
573 // If the error code is invalid, print it.
574 } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
575 if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
576 free(allocStr);
577 allocStr = str;
578 }
579 }
580
581 int ret;
582 if (sslErrorCode == SSL_ERROR_SSL) {
583 ret = throwSSLProtocolExceptionStr(env, allocStr);
584 } else {
585 ret = actualThrow(env, allocStr);
586 }
587
588 CONSCRYPT_LOG_VERBOSE("%s", allocStr);
589 free(allocStr);
590 ERR_clear_error();
591 return ret;
592 }
593
594 } // namespace jniutil
595 } // namespace conscrypt
596