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_APP_DATA_H_ 18 #define CONSCRYPT_APP_DATA_H_ 19 20 #include <conscrypt/NetFd.h> 21 #include <conscrypt/compat.h> 22 #include <conscrypt/jniutil.h> 23 #include <conscrypt/netutil.h> 24 #include <conscrypt/trace.h> 25 26 #include <jni.h> 27 #include <atomic> 28 #include <mutex> // NOLINT(build/c++11) 29 30 #ifdef _WIN32 31 // Needed for inet_ntop 32 #define _WIN32_WINNT _WIN32_WINNT_WIN8 33 #include <ws2ipdef.h> 34 #include <ws2tcpip.h> 35 #pragma comment(lib, "ws2_32.lib") 36 37 #include <winsock2.h> 38 #else // !_WIN32 39 #include <arpa/inet.h> 40 #include <poll.h> 41 #include <unistd.h> 42 #endif // !_WIN32 43 44 namespace conscrypt { 45 46 /** 47 * Our additional application data needed for getting synchronization right. 48 * This maybe warrants a bit of lengthy prose: 49 * 50 * (1) We use a flag to reflect whether we consider the SSL connection alive. 51 * Any read or write attempt loops will be cancelled once this flag becomes 0. 52 * 53 * (2) We use an int to count the number of threads that are blocked by the 54 * underlying socket. This may be at most two (one reader and one writer), since 55 * the Java layer ensures that no more threads will enter the native code at the 56 * same time. 57 * 58 * (3) The pipe is used primarily as a means of cancelling a blocking select() 59 * when we want to close the connection (aka "emergency button"). It is also 60 * necessary for dealing with a possible race condition situation: There might 61 * be cases where both threads see an SSL_ERROR_WANT_READ or 62 * SSL_ERROR_WANT_WRITE. Both will enter a select() with the proper argument. 63 * If one leaves the select() successfully before the other enters it, the 64 * "success" event is already consumed and the second thread will be blocked, 65 * possibly forever (depending on network conditions). 66 * 67 * The idea for solving the problem looks like this: Whenever a thread is 68 * successful in moving around data on the network, and it knows there is 69 * another thread stuck in a select(), it will write a byte to the pipe, waking 70 * up the other thread. A thread that returned from select(), on the other hand, 71 * knows whether it's been woken up by the pipe. If so, it will consume the 72 * byte, and the original state of affairs has been restored. 73 * 74 * The pipe may seem like a bit of overhead, but it fits in nicely with the 75 * other file descriptors of the select(), so there's only one condition to wait 76 * for. 77 * 78 * (4) Finally, a mutex is needed to make sure that at most one thread is in 79 * either SSL_read() or SSL_write() at any given time. This is an OpenSSL 80 * requirement. We use the same mutex to guard the field for counting the 81 * waiting threads. 82 * 83 * During handshaking, additional fields are used to up-call into 84 * Java to perform certificate verification and handshake 85 * completion. These are also used in any renegotiation. 86 * 87 * (5) the JNIEnv so we can invoke the Java callback 88 * 89 * (6) a NativeCrypto.SSLHandshakeCallbacks instance for callbacks from native to Java 90 * 91 * (7) a java.io.FileDescriptor wrapper to check for socket close 92 * 93 * We store the ALPN protocols list so we can either send it (from the server) or 94 * select a protocol (on the client). We eagerly acquire a pointer to the array 95 * data so the callback doesn't need to acquire resources that it cannot 96 * release. 97 * 98 * Because renegotiation can be requested by the peer at any time, 99 * care should be taken to maintain an appropriate JNIEnv on any 100 * downcall to openssl since it could result in an upcall to Java. The 101 * current code does try to cover these cases by conditionally setting 102 * the JNIEnv on calls that can read and write to the SSL such as 103 * SSL_do_handshake, SSL_read, SSL_write, and SSL_shutdown. 104 */ 105 class AppData { 106 public: 107 std::atomic<bool> aliveAndKicking; 108 int waitingThreads; 109 #ifdef _WIN32 110 HANDLE interruptEvent; 111 #else 112 int fdsEmergency[2]; 113 #endif 114 std::mutex mutex; 115 JNIEnv* env; 116 jobject sslHandshakeCallbacks; 117 char* applicationProtocolsData; 118 size_t applicationProtocolsLength; 119 jobject applicationProtocolSelector; 120 121 /** 122 * Creates the application data context for the SSL*. 123 */ create()124 static AppData* create() { 125 std::unique_ptr<AppData> appData(new AppData()); 126 #ifdef _WIN32 127 HANDLE interruptEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); 128 if (interruptEvent == nullptr) { 129 JNI_TRACE("AppData::create WSACreateEvent failed: %d", WSAGetLastError()); 130 return nullptr; 131 } 132 appData.get()->interruptEvent = interruptEvent; 133 #else 134 if (pipe(appData.get()->fdsEmergency) == -1) { 135 CONSCRYPT_LOG_ERROR("AppData::create pipe(2) failed: %s", strerror(errno)); 136 return nullptr; 137 } 138 if (!netutil::setBlocking(appData.get()->fdsEmergency[0], false)) { 139 CONSCRYPT_LOG_ERROR("AppData::create fcntl(2) failed: %s", strerror(errno)); 140 return nullptr; 141 } 142 #endif 143 return appData.release(); 144 } 145 ~AppData()146 ~AppData() { 147 aliveAndKicking = false; 148 #ifdef _WIN32 149 if (interruptEvent != nullptr) { 150 CloseHandle(interruptEvent); 151 } 152 #else 153 if (fdsEmergency[0] != -1) { 154 close(fdsEmergency[0]); 155 } 156 if (fdsEmergency[1] != -1) { 157 close(fdsEmergency[1]); 158 } 159 #endif 160 clearApplicationProtocols(); 161 clearApplicationProtocolSelector(env); 162 clearCallbackState(); 163 } 164 165 /** 166 * Only called in server mode. Sets the protocols for ALPN negotiation. 167 * 168 * @param env The JNIEnv 169 * @param alpnProtocols ALPN protocols so that they may be advertised (by the 170 * server) or selected (by the client). Passing 171 * non-null enables ALPN. This array is copied so that no 172 * global reference to the Java byte array is maintained. 173 */ setApplicationProtocols(JNIEnv * e,jbyteArray applicationProtocolsJava)174 bool setApplicationProtocols(JNIEnv* e, jbyteArray applicationProtocolsJava) { 175 clearApplicationProtocols(); 176 if (applicationProtocolsJava != nullptr) { 177 jbyte* applicationProtocols = 178 e->GetByteArrayElements(applicationProtocolsJava, nullptr); 179 if (applicationProtocols == nullptr) { 180 clearCallbackState(); 181 JNI_TRACE("appData=%p setApplicationCallbackState => applicationProtocols == null", 182 this); 183 return false; 184 } 185 applicationProtocolsLength = 186 static_cast<size_t>(e->GetArrayLength(applicationProtocolsJava)); 187 applicationProtocolsData = new char[applicationProtocolsLength]; 188 memcpy(applicationProtocolsData, applicationProtocols, applicationProtocolsLength); 189 e->ReleaseByteArrayElements(applicationProtocolsJava, applicationProtocols, JNI_ABORT); 190 } 191 return true; 192 } 193 194 /** 195 * Only called in server mode. Sets the application-provided ALPN protocol selector. 196 * This overrides the list of ALPN protocols, if set. 197 */ setApplicationProtocolSelector(JNIEnv * e,jobject selector)198 void setApplicationProtocolSelector(JNIEnv* e, jobject selector) { 199 clearApplicationProtocolSelector(e); 200 if (selector != nullptr) { 201 // Need to a global reference since we keep this around beyond a single JNI 202 // invocation. 203 applicationProtocolSelector = e->NewGlobalRef(selector); 204 } 205 } 206 207 /** 208 * Used to set the SSL-to-Java callback state before each SSL_* 209 * call that may result in a callback. It should be cleared after 210 * the operation returns with clearCallbackState. 211 * 212 * @param env The JNIEnv 213 * @param shc The SSLHandshakeCallbacks 214 * @param fd The FileDescriptor 215 */ setCallbackState(JNIEnv * e,jobject shc,jobject fd)216 bool setCallbackState(JNIEnv* e, jobject shc, jobject fd) { 217 std::unique_ptr<NetFd> netFd; 218 if (fd != nullptr) { 219 netFd.reset(new NetFd(e, fd)); 220 if (netFd->isClosed()) { 221 JNI_TRACE("appData=%p setCallbackState => netFd->isClosed() == true", this); 222 return false; 223 } 224 } 225 env = e; 226 sslHandshakeCallbacks = shc; 227 return true; 228 } 229 clearCallbackState()230 void clearCallbackState() { 231 sslHandshakeCallbacks = nullptr; 232 env = nullptr; 233 } 234 235 private: AppData()236 AppData() 237 : aliveAndKicking(true), 238 waitingThreads(0), 239 env(nullptr), 240 sslHandshakeCallbacks(nullptr), 241 applicationProtocolsData(nullptr), 242 applicationProtocolsLength(static_cast<size_t>(-1)), 243 applicationProtocolSelector(nullptr) { 244 #ifdef _WIN32 245 interruptEvent = nullptr; 246 #else 247 fdsEmergency[0] = -1; 248 fdsEmergency[1] = -1; 249 #endif 250 } 251 clearApplicationProtocols()252 void clearApplicationProtocols() { 253 if (applicationProtocolsData != nullptr) { 254 delete applicationProtocolsData; 255 applicationProtocolsData = nullptr; 256 applicationProtocolsLength = static_cast<size_t>(-1); 257 } 258 } 259 clearApplicationProtocolSelector(JNIEnv * e)260 void clearApplicationProtocolSelector(JNIEnv* e) { 261 if (applicationProtocolSelector != nullptr) { 262 if (e == nullptr) { 263 e = conscrypt::jniutil::getJNIEnv(); 264 } 265 e->DeleteGlobalRef(applicationProtocolSelector); 266 applicationProtocolSelector = nullptr; 267 } 268 } 269 }; 270 271 } // namespace conscrypt 272 273 #endif // CONSCRYPT_APP_DATA_H_ 274