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