1 /* 2 * Copyright 2014 Haiku, Inc. 3 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de. 4 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <SecureSocket.h> 10 11 #ifdef OPENSSL_ENABLED 12 # include <openssl/ssl.h> 13 #endif 14 15 #include <pthread.h> 16 17 #include <Certificate.h> 18 #include <FindDirectory.h> 19 #include <Path.h> 20 21 #include "CertificatePrivate.h" 22 23 24 //#define TRACE_SOCKET 25 #ifdef TRACE_SOCKET 26 # define TRACE(x...) printf(x) 27 #else 28 # define TRACE(x...) ; 29 #endif 30 31 32 #ifdef OPENSSL_ENABLED 33 34 35 class BSecureSocket::Private { 36 public: 37 Private(); 38 ~Private(); 39 40 status_t InitCheck(); 41 42 static SSL_CTX* Context(); 43 static int VerifyCallback(int ok, X509_STORE_CTX* ctx); 44 private: 45 static void CreateContext(); 46 public: 47 SSL* fSSL; 48 BIO* fBIO; 49 static int sDataIndex; 50 private: 51 static SSL_CTX* sContext; 52 // FIXME When do we SSL_CTX_free it? 53 static pthread_once_t sInitOnce; 54 }; 55 56 57 /* static */ SSL_CTX* BSecureSocket::Private::sContext = NULL; 58 /* static */ int BSecureSocket::Private::sDataIndex; 59 /* static */ pthread_once_t BSecureSocket::Private::sInitOnce 60 = PTHREAD_ONCE_INIT; 61 62 63 BSecureSocket::Private::Private() 64 : 65 fSSL(NULL), 66 fBIO(BIO_new(BIO_s_socket())) 67 { 68 } 69 70 71 BSecureSocket::Private::~Private() 72 { 73 // SSL_free also frees the underlying BIO. 74 if (fSSL != NULL) 75 SSL_free(fSSL); 76 else { 77 // The SSL session was never created (Connect() was not called or 78 // failed). We must free the BIO we created in the constructor. 79 BIO_free(fBIO); 80 } 81 } 82 83 84 status_t 85 BSecureSocket::Private::InitCheck() 86 { 87 if (fBIO == NULL) 88 return B_NO_MEMORY; 89 return B_OK; 90 } 91 92 93 /* static */ void 94 BSecureSocket::Private::CreateContext() 95 { 96 sContext = SSL_CTX_new(SSLv23_method()); 97 98 // Setup certificate verification 99 BPath certificateStore; 100 find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); 101 certificateStore.Append("ssl/CARootCertificates.pem"); 102 // TODO we may want to add a non-packaged certificate directory? 103 // (would make it possible to store user-added certificate exceptions 104 // there) 105 SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); 106 SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); 107 108 // Get an unique index number for storing application data in SSL 109 // structs. We will store a pointer to the BSecureSocket class there. 110 sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 111 } 112 113 114 /* static */ SSL_CTX* 115 BSecureSocket::Private::Context() 116 { 117 // We use lazy initialisation here, because reading certificates from disk 118 // and parsing them is a relatively long operation and uses some memory. 119 // We don't want programs that don't use SSL to waste resources with that. 120 pthread_once(&sInitOnce, CreateContext); 121 122 return sContext; 123 } 124 125 126 // This is called each time a certificate verification occurs. It allows us to 127 // catch failures and report them. 128 /* static */ int 129 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx) 130 { 131 // OpenSSL already checked the certificate again the certificate store for 132 // us, and tells the result of that in the ok parameter. 133 134 // If the verification succeeded, no need for any further checks. Let's 135 // proceed with the connection. 136 if (ok) 137 return ok; 138 139 // The certificate verification failed. Signal this to the BSecureSocket. 140 141 // First of all, get the affected BSecureSocket 142 SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, 143 SSL_get_ex_data_X509_STORE_CTX_idx()); 144 BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex); 145 146 // Get the certificate that we could not validate (this may not be the one 147 // we got from the server, but something higher up in the certificate 148 // chain) 149 X509* x509 = X509_STORE_CTX_get_current_cert(ctx); 150 BCertificate::Private* certificate 151 = new(std::nothrow) BCertificate::Private(x509); 152 153 if (certificate == NULL) 154 return 0; 155 156 // Let the BSecureSocket (or subclass) decide if we should continue anyway. 157 return socket->CertificateVerificationFailed(BCertificate(certificate)); 158 } 159 160 161 // # pragma mark - BSecureSocket 162 163 164 BSecureSocket::BSecureSocket() 165 : 166 fPrivate(new(std::nothrow) BSecureSocket::Private()) 167 { 168 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 169 } 170 171 172 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 173 : 174 fPrivate(new(std::nothrow) BSecureSocket::Private()) 175 { 176 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 177 Connect(peer, timeout); 178 } 179 180 181 BSecureSocket::BSecureSocket(const BSecureSocket& other) 182 : 183 BSocket(other) 184 { 185 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate); 186 // TODO: this won't work this way! - write working copy constructor for 187 // Private. 188 189 if (fPrivate != NULL) 190 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 191 else 192 fInitStatus = B_NO_MEMORY; 193 194 } 195 196 197 BSecureSocket::~BSecureSocket() 198 { 199 delete fPrivate; 200 } 201 202 203 status_t 204 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 205 { 206 if (fPrivate == NULL) 207 return B_NO_MEMORY; 208 209 status_t state = fPrivate->InitCheck(); 210 if (state != B_OK) 211 return state; 212 213 status_t status = BSocket::Connect(peer, timeout); 214 if (status != B_OK) 215 return status; 216 217 // Do this only after BSocket::Connect has checked wether we're already 218 // connected. We don't want to kill an existing SSL session, as that would 219 // likely crash the protocol loop for it. 220 if (fPrivate->fSSL != NULL) { 221 SSL_free(fPrivate->fSSL); 222 } 223 224 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context()); 225 if (fPrivate->fSSL == NULL) { 226 BSocket::Disconnect(); 227 return B_NO_MEMORY; 228 } 229 230 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE); 231 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 232 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 233 234 int sslStatus = SSL_connect(fPrivate->fSSL); 235 236 if (sslStatus <= 0) { 237 TRACE("SSLConnection can't connect\n"); 238 BSocket::Disconnect(); 239 240 switch (SSL_get_error(fPrivate->fSSL, sslStatus)) { 241 case SSL_ERROR_NONE: 242 // Shouldn't happen... 243 return B_NO_ERROR; 244 case SSL_ERROR_ZERO_RETURN: 245 // Socket is closed 246 return B_CANCELED; 247 case SSL_ERROR_SSL: 248 // Probably no certificate 249 return B_NOT_ALLOWED; 250 default: 251 return B_ERROR; 252 } 253 } 254 255 return B_OK; 256 } 257 258 259 void 260 BSecureSocket::Disconnect() 261 { 262 if (IsConnected()) { 263 if (fPrivate->fSSL != NULL) { 264 SSL_shutdown(fPrivate->fSSL); 265 } 266 267 BSocket::Disconnect(); 268 } 269 } 270 271 272 status_t 273 BSecureSocket::WaitForReadable(bigtime_t timeout) const 274 { 275 if (fInitStatus != B_OK) 276 return fInitStatus; 277 if (!IsConnected()) 278 return B_ERROR; 279 280 if (SSL_pending(fPrivate->fSSL) > 0) 281 return B_OK; 282 283 return BSocket::WaitForReadable(timeout); 284 } 285 286 287 bool 288 BSecureSocket::CertificateVerificationFailed(BCertificate) 289 { 290 // Until apps actually make use of the certificate API, let's keep the old 291 // behavior and accept all connections, even if the certificate validation 292 // didn't work. 293 return true; 294 } 295 296 297 // #pragma mark - BDataIO implementation 298 299 300 ssize_t 301 BSecureSocket::Read(void* buffer, size_t size) 302 { 303 if (!IsConnected()) 304 return B_ERROR; 305 306 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 307 if (bytesRead >= 0) 308 return bytesRead; 309 310 // TODO: translate SSL error codes! 311 return B_ERROR; 312 } 313 314 315 ssize_t 316 BSecureSocket::Write(const void* buffer, size_t size) 317 { 318 if (!IsConnected()) 319 return B_ERROR; 320 321 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 322 if (bytesWritten >= 0) 323 return bytesWritten; 324 325 // TODO: translate SSL error codes! 326 return B_ERROR; 327 } 328 329 330 #else // OPENSSL_ENABLED 331 332 333 // #pragma mark - No-SSL stubs 334 335 336 BSecureSocket::BSecureSocket() 337 { 338 } 339 340 341 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 342 { 343 fInitStatus = B_UNSUPPORTED; 344 } 345 346 347 BSecureSocket::BSecureSocket(const BSecureSocket& other) 348 : 349 BSocket(other) 350 { 351 } 352 353 354 BSecureSocket::~BSecureSocket() 355 { 356 } 357 358 359 bool 360 BSecureSocket::CertificateVerificationFailed(BCertificate) 361 { 362 return false; 363 } 364 365 366 status_t 367 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 368 { 369 return fInitStatus = B_UNSUPPORTED; 370 } 371 372 373 void 374 BSecureSocket::Disconnect() 375 { 376 } 377 378 379 status_t 380 BSecureSocket::WaitForReadable(bigtime_t timeout) const 381 { 382 return B_UNSUPPORTED; 383 } 384 385 386 // #pragma mark - BDataIO implementation 387 388 389 ssize_t 390 BSecureSocket::Read(void* buffer, size_t size) 391 { 392 return B_UNSUPPORTED; 393 } 394 395 396 ssize_t 397 BSecureSocket::Write(const void* buffer, size_t size) 398 { 399 return B_UNSUPPORTED; 400 } 401 402 403 #endif // !OPENSSL_ENABLED 404