• 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 #ifndef CONSCRYPT_JNIUTIL_H_
18 #define CONSCRYPT_JNIUTIL_H_
19 
20 #include <jni.h>
21 #include <openssl/ssl.h>
22 
23 #include <conscrypt/logging.h>
24 #include <conscrypt/macros.h>
25 #include <nativehelper/scoped_local_ref.h>
26 
27 namespace conscrypt {
28 namespace jniutil {
29 
30 extern JavaVM* gJavaVM;
31 extern jclass cryptoUpcallsClass;
32 extern jclass openSslInputStreamClass;
33 extern jclass nativeRefClass;
34 
35 extern jclass byteArrayClass;
36 extern jclass calendarClass;
37 extern jclass objectClass;
38 extern jclass objectArrayClass;
39 extern jclass integerClass;
40 extern jclass inputStreamClass;
41 extern jclass outputStreamClass;
42 extern jclass stringClass;
43 extern jclass byteBufferClass;
44 extern jclass bufferClass;
45 
46 extern jfieldID nativeRef_address;
47 
48 extern jmethodID calendar_setMethod;
49 extern jmethodID inputStream_readMethod;
50 extern jmethodID integer_valueOfMethod;
51 extern jmethodID openSslInputStream_readLineMethod;
52 extern jmethodID outputStream_writeMethod;
53 extern jmethodID outputStream_flushMethod;
54 extern jmethodID buffer_positionMethod;
55 extern jmethodID buffer_limitMethod;
56 
57 /**
58  * Initializes the JNI constants from the environment.
59  */
60 void init(JavaVM* vm, JNIEnv* env);
61 
62 /**
63  * Obtains the current thread's JNIEnv
64  */
getJNIEnv(JavaVM * gJavaVM)65 inline JNIEnv* getJNIEnv(JavaVM* gJavaVM) {
66     JNIEnv* env;
67 
68 #ifdef ANDROID
69     int ret = gJavaVM->AttachCurrentThread(&env, nullptr);
70 #else
71     int ret = gJavaVM->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr);
72 #endif
73     if (ret < 0) {
74         CONSCRYPT_LOG_ERROR("Could not attach JavaVM to find current JNIEnv");
75         return nullptr;
76     }
77     return env;
78 }
79 
80 /**
81  * Obtains the current thread's JNIEnv
82  */
getJNIEnv()83 inline JNIEnv* getJNIEnv() {
84     return getJNIEnv(gJavaVM);
85 }
86 
getGlobalRefToClass(JNIEnv * env,const char * className)87 inline jclass getGlobalRefToClass(JNIEnv* env, const char* className) {
88     ScopedLocalRef<jclass> localClass(env, env->FindClass(className));
89     jclass globalRef = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
90     if (globalRef == nullptr) {
91         CONSCRYPT_LOG_ERROR("failed to find class %s", className);
92         abort();
93     }
94     return globalRef;
95 }
96 
getMethodRef(JNIEnv * env,jclass clazz,const char * name,const char * sig)97 inline jmethodID getMethodRef(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
98     jmethodID localMethod = env->GetMethodID(clazz, name, sig);
99     if (localMethod == nullptr) {
100         CONSCRYPT_LOG_ERROR("could not find method %s", name);
101         abort();
102     }
103     return localMethod;
104 }
105 
getFieldRef(JNIEnv * env,jclass clazz,const char * name,const char * sig)106 inline jfieldID getFieldRef(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
107     jfieldID localField = env->GetFieldID(clazz, name, sig);
108     if (localField == nullptr) {
109         CONSCRYPT_LOG_ERROR("could not find field %s", name);
110         abort();
111     }
112     return localField;
113 }
114 
findClass(JNIEnv * env,const char * name)115 inline jclass findClass(JNIEnv* env, const char* name) {
116     ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
117     jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
118     if (result == nullptr) {
119         CONSCRYPT_LOG_ERROR("failed to find class '%s'", name);
120         abort();
121     }
122     return result;
123 }
124 
125 /**
126  * Register one or more native methods with a particular class.
127  * "className" looks like "java/lang/String". Aborts on failure.
128  */
129 void jniRegisterNativeMethods(JNIEnv* env, const char* className, const JNINativeMethod* gMethods,
130                               int numMethods);
131 
132 /**
133  * Returns the int fd from a java.io.FileDescriptor.
134  */
135 extern int jniGetFDFromFileDescriptor(JNIEnv* env, jobject fileDescriptor);
136 
137 /**
138  * Returns true if the VM's JNI GetByteArrayElements method is likely to create a copy when
139  * invoked on an array of the provided size.
140  */
141 extern bool isGetByteArrayElementsLikelyToReturnACopy(size_t size);
142 
143 /**
144  * Throw an exception with the specified class and an optional message.
145  *
146  * The "className" argument will be passed directly to FindClass, which
147  * takes strings with slashes (e.g. "java/lang/Object").
148  *
149  * If an exception is currently pending, we log a warning message and
150  * clear it.
151  *
152  * Returns 0 on success, nonzero if something failed (e.g. the exception
153  * class couldn't be found, so *an* exception will still be pending).
154  */
155 extern int throwException(JNIEnv* env, const char* className, const char* msg);
156 
157 /**
158  * Throw a java.lang.RuntimeException, with an optional message.
159  */
160 extern int throwRuntimeException(JNIEnv* env, const char* msg);
161 
162 /**
163  * Throw a java.lang.AssertionError, with an optional message.
164  */
165 extern int throwAssertionError(JNIEnv* env, const char* msg);
166 
167 /*
168  * Throw a java.lang.NullPointerException, with an optional message.
169  */
170 extern int throwNullPointerException(JNIEnv* env, const char* msg);
171 
172 /**
173  * Throws a OutOfMemoryError with the given string as a message.
174  */
175 extern int throwOutOfMemory(JNIEnv* env, const char* message);
176 
177 /**
178  * Throws a BadPaddingException with the given string as a message.
179  */
180 extern int throwBadPaddingException(JNIEnv* env, const char* message);
181 
182 /**
183  * Throws a SignatureException with the given string as a message.
184  */
185 extern int throwSignatureException(JNIEnv* env, const char* message);
186 
187 /**
188  * Throws a InvalidKeyException with the given string as a message.
189  */
190 extern int throwInvalidKeyException(JNIEnv* env, const char* message);
191 
192 /**
193  * Throws a SignatureException with the given string as a message.
194  */
195 extern int throwIllegalBlockSizeException(JNIEnv* env, const char* message);
196 
197 /**
198  * Throws a NoSuchAlgorithmException with the given string as a message.
199  */
200 extern int throwNoSuchAlgorithmException(JNIEnv* env, const char* message);
201 
202 /**
203  * Throws an IOException with the given string as a message.
204  */
205 extern int throwIOException(JNIEnv* env, const char* message);
206 
207 /**
208  * Throws a CertificateException with the given string as a message.
209  */
210 extern int throwCertificateException(JNIEnv* env, const char* message);
211 
212 /**
213  * Throws a ParsingException with the given string as a message.
214  */
215 extern int throwParsingException(JNIEnv* env, const char* message);
216 
217 extern int throwInvalidAlgorithmParameterException(JNIEnv* env, const char* message);
218 
219 extern int throwForAsn1Error(JNIEnv* env, int reason, const char* message,
220                              int (*defaultThrow)(JNIEnv*, const char*));
221 
222 extern int throwForCipherError(JNIEnv* env, int reason, const char* message,
223                                int (*defaultThrow)(JNIEnv*, const char*));
224 
225 extern int throwForEvpError(JNIEnv* env, int reason, const char* message,
226                             int (*defaultThrow)(JNIEnv*, const char*));
227 
228 extern int throwForRsaError(JNIEnv* env, int reason, const char* message,
229                             int (*defaultThrow)(JNIEnv*, const char*));
230 
231 extern int throwForX509Error(JNIEnv* env, int reason, const char* message,
232                              int (*defaultThrow)(JNIEnv*, const char*));
233 
234 /*
235  * Checks this thread's OpenSSL error stack and throws an appropriate exception
236  * type based on the type of error found.  If no error is present, throws
237  * AssertionError.
238  */
239 extern void throwExceptionFromBoringSSLError(
240         JNIEnv* env, const char* location,
241         int (*defaultThrow)(JNIEnv*, const char*) = throwRuntimeException);
242 
243 /**
244  * Throws an SocketTimeoutException with the given string as a message.
245  */
246 extern int throwSocketTimeoutException(JNIEnv* env, const char* message);
247 
248 /**
249  * Throws a javax.net.ssl.SSLException with the given string as a message.
250  */
251 extern int throwSSLHandshakeExceptionStr(JNIEnv* env, const char* message);
252 
253 /**
254  * Throws a javax.net.ssl.SSLException with the given string as a message.
255  */
256 extern int throwSSLExceptionStr(JNIEnv* env, const char* message);
257 
258 /**
259  * Throws a javax.net.ssl.SSLProcotolException with the given string as a message.
260  */
261 extern int throwSSLProtocolExceptionStr(JNIEnv* env, const char* message);
262 
263 /**
264  * Throws an SSLException with a message constructed from the current
265  * SSL errors. This will also log the errors.
266  *
267  * @param env the JNI environment
268  * @param ssl the possibly null SSL
269  * @param sslErrorCode error code returned from SSL_get_error() or
270  * SSL_ERROR_NONE to probe with ERR_get_error
271  * @param message null-ok; general error message
272  */
273 extern int throwSSLExceptionWithSslErrors(JNIEnv* env, SSL* ssl, int sslErrorCode,
274                                           const char* message,
275                                           int (*actualThrow)(JNIEnv*,
276                                                              const char*) = throwSSLExceptionStr);
277 
278 #ifdef CONSCRYPT_CHECK_ERROR_QUEUE
279 /**
280  * Class that checks that the error queue is empty on destruction.  It should only be used
281  * via the macro CHECK_ERROR_QUEUE_ON_RETURN, which can be placed at the top of a function to
282  * ensure that the error queue is empty whenever the function exits.
283  */
284 class ErrorQueueChecker {
285  public:
ErrorQueueChecker(JNIEnv * env)286     explicit ErrorQueueChecker(JNIEnv* env) : env(env) {}
~ErrorQueueChecker()287     ~ErrorQueueChecker() {
288         if (ERR_peek_error() != 0) {
289             const char* file;
290             int line;
291             uint32_t error = ERR_get_error_line(&file, &line);
292             char message[256];
293             ERR_error_string_n(error, message, sizeof(message));
294             char result[500];
295             snprintf(result, sizeof(result),
296                      "Error queue should have been empty but was (%s:%d) %s", file, line, message);
297             // If there's a pending exception, we want to throw the assertion error instead
298             env->ExceptionClear();
299             throwAssertionError(env, result);
300         }
301     }
302 
303  private:
304     JNIEnv* env;
305 };
306 
307 #define CHECK_ERROR_QUEUE_ON_RETURN conscrypt::jniutil::ErrorQueueChecker __checker(env)
308 #else
309 #define CHECK_ERROR_QUEUE_ON_RETURN UNUSED_ARGUMENT(env)
310 #endif  // CONSCRYPT_CHECK_ERROR_QUEUE
311 
312 }  // namespace jniutil
313 }  // namespace conscrypt
314 
315 #endif  // CONSCRYPT_JNIUTIL_H_
316