• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
throwIllegalStateException(JNIEnv * env,const char * message)267 int throwIllegalStateException(JNIEnv* env, const char* message) {
268     JNI_TRACE("throwIllegalStateException %s", message);
269     return conscrypt::jniutil::throwException(
270             env, "java/lang/IllegalStateException", message);
271 }
272 
throwShortBufferException(JNIEnv * env,const char * message)273 int throwShortBufferException(JNIEnv* env, const char* message) {
274     JNI_TRACE("throwShortBufferException %s", message);
275     return conscrypt::jniutil::throwException(
276             env, "javax/crypto/ShortBufferException", message);
277 }
278 
throwNoSuchAlgorithmException(JNIEnv * env,const char * message)279 int throwNoSuchAlgorithmException(JNIEnv* env, const char* message) {
280     JNI_TRACE("throwUnknownAlgorithmException %s", message);
281     return conscrypt::jniutil::throwException(
282             env, "java/security/NoSuchAlgorithmException", message);
283 }
284 
throwIOException(JNIEnv * env,const char * message)285 int throwIOException(JNIEnv* env, const char* message) {
286     JNI_TRACE("throwIOException %s", message);
287     return conscrypt::jniutil::throwException(env, "java/io/IOException", message);
288 }
289 
throwCertificateException(JNIEnv * env,const char * message)290 int throwCertificateException(JNIEnv* env, const char* message) {
291     JNI_TRACE("throwCertificateException %s", message);
292     return conscrypt::jniutil::throwException(
293             env, "java/security/cert/CertificateException", message);
294 }
295 
throwParsingException(JNIEnv * env,const char * message)296 int throwParsingException(JNIEnv* env, const char* message) {
297     return conscrypt::jniutil::throwException(env, TO_STRING(JNI_JARJAR_PREFIX)
298                             "org/conscrypt/OpenSSLX509CertificateFactory$ParsingException",
299                             message);
300 }
301 
throwInvalidAlgorithmParameterException(JNIEnv * env,const char * message)302 int throwInvalidAlgorithmParameterException(JNIEnv* env, const char* message) {
303     JNI_TRACE("throwInvalidAlgorithmParameterException %s", message);
304     return conscrypt::jniutil::throwException(
305             env, "java/security/InvalidAlgorithmParameterException", message);
306 }
307 
throwForAsn1Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))308 int throwForAsn1Error(JNIEnv* env, int reason, const char* message,
309                       int (*defaultThrow)(JNIEnv*, const char*)) {
310     switch (reason) {
311         case ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE:
312         case ASN1_R_WRONG_PUBLIC_KEY_TYPE:
313             return throwInvalidKeyException(env, message);
314             break;
315         case ASN1_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED:
316         case ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM:
317         case ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM:
318             return throwNoSuchAlgorithmException(env, message);
319             break;
320     }
321     return defaultThrow(env, message);
322 }
323 
throwForCipherError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))324 int throwForCipherError(JNIEnv* env, int reason, const char* message,
325                         int (*defaultThrow)(JNIEnv*, const char*)) {
326     switch (reason) {
327         case CIPHER_R_BAD_DECRYPT:
328             return throwBadPaddingException(env, message);
329             break;
330         case CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
331         case CIPHER_R_WRONG_FINAL_BLOCK_LENGTH:
332             return throwIllegalBlockSizeException(env, message);
333             break;
334         // TODO(davidben): Remove these ifdefs after
335         // https://boringssl-review.googlesource.com/c/boringssl/+/35565 has
336         // rolled out to relevant BoringSSL copies.
337 #if defined(CIPHER_R_BAD_KEY_LENGTH)
338         case CIPHER_R_BAD_KEY_LENGTH:
339 #endif
340 #if defined(CIPHER_R_UNSUPPORTED_KEY_SIZE)
341         case CIPHER_R_UNSUPPORTED_KEY_SIZE:
342 #endif
343         case CIPHER_R_INVALID_KEY_LENGTH:
344             return throwInvalidKeyException(env, message);
345             break;
346         case CIPHER_R_BUFFER_TOO_SMALL:
347             return throwShortBufferException(env, message);
348             break;
349     }
350     return defaultThrow(env, message);
351 }
352 
throwForEvpError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))353 int throwForEvpError(JNIEnv* env, int reason, const char* message,
354                      int (*defaultThrow)(JNIEnv*, const char*)) {
355     switch (reason) {
356         case EVP_R_MISSING_PARAMETERS:
357         case EVP_R_INVALID_PEER_KEY:
358         case EVP_R_DECODE_ERROR:
359         case EVP_R_NOT_A_PRIVATE_KEY:
360             return throwInvalidKeyException(env, message);
361             break;
362         case EVP_R_UNSUPPORTED_ALGORITHM:
363             return throwNoSuchAlgorithmException(env, message);
364             break;
365         case EVP_R_INVALID_BUFFER_SIZE:
366         case EVP_R_BUFFER_TOO_SMALL:
367             return throwIllegalArgumentException(env, message);
368             break;
369         default:
370             return defaultThrow(env, message);
371             break;
372     }
373 }
374 
throwForRsaError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))375 int throwForRsaError(JNIEnv* env, int reason, const char* message,
376                      int (*defaultThrow)(JNIEnv*, const char*)) {
377     switch (reason) {
378         case RSA_R_BLOCK_TYPE_IS_NOT_01:
379         case RSA_R_PKCS_DECODING_ERROR:
380             return throwBadPaddingException(env, message);
381             break;
382         case RSA_R_BAD_SIGNATURE:
383         case RSA_R_INVALID_MESSAGE_LENGTH:
384         case RSA_R_WRONG_SIGNATURE_LENGTH:
385             return throwSignatureException(env, message);
386             break;
387         case RSA_R_UNKNOWN_ALGORITHM_TYPE:
388             return throwNoSuchAlgorithmException(env, message);
389             break;
390         case RSA_R_MODULUS_TOO_LARGE:
391         case RSA_R_NO_PUBLIC_EXPONENT:
392             return throwInvalidKeyException(env, message);
393             break;
394         case RSA_R_DATA_TOO_LARGE:
395         case RSA_R_DATA_TOO_LARGE_FOR_MODULUS:
396         case RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE:
397             return throwIllegalBlockSizeException(env, message);
398             break;
399     }
400     return defaultThrow(env, message);
401 }
402 
throwForX509Error(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))403 int throwForX509Error(JNIEnv* env, int reason, const char* message,
404                       int (*defaultThrow)(JNIEnv*, const char*)) {
405     switch (reason) {
406         case X509_R_UNSUPPORTED_ALGORITHM:
407             return throwNoSuchAlgorithmException(env, message);
408             break;
409         default:
410             return defaultThrow(env, message);
411             break;
412     }
413 }
414 
throwForCryptoError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))415 int throwForCryptoError(JNIEnv* env, int reason, const char* message,
416                       int (*defaultThrow)(JNIEnv*, const char*)) {
417     switch (reason) {
418         case ERR_R_INTERNAL_ERROR:
419             return throwIOException(env, message);
420             break;
421         default:
422             return defaultThrow(env, message);
423             break;
424     }
425 }
426 
throwForSslError(JNIEnv * env,int reason,const char * message,int (* defaultThrow)(JNIEnv *,const char *))427 int throwForSslError(JNIEnv* env, int reason, const char* message,
428                       int (*defaultThrow)(JNIEnv*, const char*)) {
429     switch (reason) {
430         case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED:
431             return throwIllegalStateException(env, message);
432             break;
433         default:
434             return defaultThrow(env, message);
435             break;
436     }
437 }
438 
throwExceptionFromBoringSSLError(JNIEnv * env,CONSCRYPT_UNUSED const char * location,int (* defaultThrow)(JNIEnv *,const char *))439 void throwExceptionFromBoringSSLError(JNIEnv* env, CONSCRYPT_UNUSED const char* location,
440                                       int (*defaultThrow)(JNIEnv*, const char*)) {
441     const char* file;
442     int line;
443     const char* data;
444     int flags;
445     // NOLINTNEXTLINE(runtime/int)
446     unsigned long error = ERR_get_error_line_data(&file, &line, &data, &flags);
447 
448     if (error == 0) {
449         defaultThrow(env, "Unknown BoringSSL error");
450         return;
451     }
452 
453     // If there's an error from BoringSSL it may have been caused by an exception in Java code, so
454     // ensure there isn't a pending exception before we throw a new one.
455     if (!env->ExceptionCheck()) {
456         char message[256];
457         ERR_error_string_n(error, message, sizeof(message));
458         int library = ERR_GET_LIB(error);
459         int reason = ERR_GET_REASON(error);
460         JNI_TRACE("BoringSSL error in %s error=%lx library=%x reason=%x (%s:%d): %s %s", location,
461                   error, library, reason, file, line, message,
462                   (flags & ERR_TXT_STRING) ? data : "(no data)");
463         switch (library) {
464             case ERR_LIB_RSA:
465                 throwForRsaError(env, reason, message, defaultThrow);
466                 break;
467             case ERR_LIB_ASN1:
468                 throwForAsn1Error(env, reason, message, defaultThrow);
469                 break;
470             case ERR_LIB_CIPHER:
471                 throwForCipherError(env, reason, message, defaultThrow);
472                 break;
473             case ERR_LIB_EVP:
474                 throwForEvpError(env, reason, message, defaultThrow);
475                 break;
476             case ERR_LIB_X509:
477                 throwForX509Error(env, reason, message, defaultThrow);
478                 break;
479             case ERR_LIB_DSA:
480                 throwInvalidKeyException(env, message);
481                 break;
482             case ERR_LIB_CRYPTO:
483                 throwForCryptoError(env, reason, message, defaultThrow);
484                 break;
485             case ERR_LIB_SSL:
486                 throwForSslError(env, reason, message, defaultThrow);
487                 break;
488             default:
489                 defaultThrow(env, message);
490                 break;
491         }
492     }
493 
494     ERR_clear_error();
495 }
496 
throwSocketTimeoutException(JNIEnv * env,const char * message)497 int throwSocketTimeoutException(JNIEnv* env, const char* message) {
498     JNI_TRACE("throwSocketTimeoutException %s", message);
499     return conscrypt::jniutil::throwException(env, "java/net/SocketTimeoutException", message);
500 }
501 
throwSSLHandshakeExceptionStr(JNIEnv * env,const char * message)502 int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message) {
503     JNI_TRACE("throwSSLExceptionStr %s", message);
504     return conscrypt::jniutil::throwException(
505             env, "javax/net/ssl/SSLHandshakeException", message);
506 }
507 
throwSSLExceptionStr(JNIEnv * env,const char * message)508 int throwSSLExceptionStr(JNIEnv* env, const char* message) {
509     JNI_TRACE("throwSSLExceptionStr %s", message);
510     return conscrypt::jniutil::throwException(env, "javax/net/ssl/SSLException", message);
511 }
512 
throwSSLProtocolExceptionStr(JNIEnv * env,const char * message)513 int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message) {
514     JNI_TRACE("throwSSLProtocolExceptionStr %s", message);
515     return conscrypt::jniutil::throwException(
516             env, "javax/net/ssl/SSLProtocolException", message);
517 }
518 
throwSSLExceptionWithSslErrors(JNIEnv * env,SSL * ssl,int sslErrorCode,const char * message,int (* actualThrow)(JNIEnv *,const char *))519 int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode, const char* message,
520                                    int (*actualThrow)(JNIEnv*, const char*)) {
521     if (message == nullptr) {
522         message = "SSL error";
523     }
524 
525     // First consult the SSL error code for the general message.
526     const char* sslErrorStr = nullptr;
527     switch (sslErrorCode) {
528         case SSL_ERROR_NONE:
529             if (ERR_peek_error() == 0) {
530                 sslErrorStr = "OK";
531             } else {
532                 sslErrorStr = "";
533             }
534             break;
535         case SSL_ERROR_SSL:
536             sslErrorStr = "Failure in SSL library, usually a protocol error";
537             break;
538         case SSL_ERROR_WANT_READ:
539             sslErrorStr = "SSL_ERROR_WANT_READ occurred. You should never see this.";
540             break;
541         case SSL_ERROR_WANT_WRITE:
542             sslErrorStr = "SSL_ERROR_WANT_WRITE occurred. You should never see this.";
543             break;
544         case SSL_ERROR_WANT_X509_LOOKUP:
545             sslErrorStr = "SSL_ERROR_WANT_X509_LOOKUP occurred. You should never see this.";
546             break;
547         case SSL_ERROR_SYSCALL:
548             sslErrorStr = "I/O error during system call";
549             break;
550         case SSL_ERROR_ZERO_RETURN:
551             sslErrorStr = "SSL_ERROR_ZERO_RETURN occurred. You should never see this.";
552             break;
553         case SSL_ERROR_WANT_CONNECT:
554             sslErrorStr = "SSL_ERROR_WANT_CONNECT occurred. You should never see this.";
555             break;
556         case SSL_ERROR_WANT_ACCEPT:
557             sslErrorStr = "SSL_ERROR_WANT_ACCEPT occurred. You should never see this.";
558             break;
559         default:
560             sslErrorStr = "Unknown SSL error";
561     }
562 
563     // Prepend either our explicit message or a default one.
564     char* str;
565     if (asprintf(&str, "%s: ssl=%p: %s", message, ssl, sslErrorStr) <= 0) {
566         // problem with asprintf, just throw argument message, log everything
567         int ret = actualThrow(env, message);
568         CONSCRYPT_LOG_VERBOSE("%s: ssl=%p: %s", message, ssl, sslErrorStr);
569         ERR_clear_error();
570         return ret;
571     }
572 
573     char* allocStr = str;
574 
575     // For protocol errors, SSL might have more information.
576     if (sslErrorCode == SSL_ERROR_NONE || sslErrorCode == SSL_ERROR_SSL) {
577         // Append each error as an additional line to the message.
578         for (;;) {
579             char errStr[256];
580             const char* file;
581             int line;
582             const char* data;
583             int flags;
584             // NOLINTNEXTLINE(runtime/int)
585             unsigned long err = ERR_get_error_line_data(&file, &line, &data, &flags);
586             if (err == 0) {
587                 break;
588             }
589 
590             ERR_error_string_n(err, errStr, sizeof(errStr));
591 
592             int ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
593                                (allocStr == nullptr) ? "" : allocStr, errStr, file, line,
594                                (flags & ERR_TXT_STRING) ? data : "(no data)", flags);
595 
596             if (ret < 0) {
597                 break;
598             }
599 
600             free(allocStr);
601             allocStr = str;
602         }
603         // For errors during system calls, errno might be our friend.
604     } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
605         if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
606             free(allocStr);
607             allocStr = str;
608         }
609         // If the error code is invalid, print it.
610     } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
611         if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
612             free(allocStr);
613             allocStr = str;
614         }
615     }
616 
617     int ret;
618     if (sslErrorCode == SSL_ERROR_SSL) {
619         ret = throwSSLProtocolExceptionStr(env, allocStr);
620     } else {
621         ret = actualThrow(env, allocStr);
622     }
623 
624     CONSCRYPT_LOG_VERBOSE("%s", allocStr);
625     free(allocStr);
626     ERR_clear_error();
627     return ret;
628 }
629 
630 }  // namespace jniutil
631 }  // namespace conscrypt
632