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