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