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