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