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