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