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 // Disable legacy protocols. They have known vulnerabilities. 99 SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 100 101 // Setup certificate verification 102 BPath certificateStore; 103 find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); 104 certificateStore.Append("ssl/CARootCertificates.pem"); 105 // TODO we may want to add a non-packaged certificate directory? 106 // (would make it possible to store user-added certificate exceptions 107 // there) 108 SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); 109 SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); 110 111 // Get an unique index number for storing application data in SSL 112 // structs. We will store a pointer to the BSecureSocket class there. 113 sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 114 } 115 116 117 /* static */ SSL_CTX* 118 BSecureSocket::Private::Context() 119 { 120 // We use lazy initialisation here, because reading certificates from disk 121 // and parsing them is a relatively long operation and uses some memory. 122 // We don't want programs that don't use SSL to waste resources with that. 123 pthread_once(&sInitOnce, CreateContext); 124 125 return sContext; 126 } 127 128 129 // This is called each time a certificate verification occurs. It allows us to 130 // catch failures and report them. 131 /* static */ int 132 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx) 133 { 134 // OpenSSL already checked the certificate again the certificate store for 135 // us, and tells the result of that in the ok parameter. 136 137 // If the verification succeeded, no need for any further checks. Let's 138 // proceed with the connection. 139 if (ok) 140 return ok; 141 142 // The certificate verification failed. Signal this to the BSecureSocket. 143 144 // First of all, get the affected BSecureSocket 145 SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, 146 SSL_get_ex_data_X509_STORE_CTX_idx()); 147 BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex); 148 149 // Get the certificate that we could not validate (this may not be the one 150 // we got from the server, but something higher up in the certificate 151 // chain) 152 X509* x509 = X509_STORE_CTX_get_current_cert(ctx); 153 BCertificate::Private* certificate 154 = new(std::nothrow) BCertificate::Private(x509); 155 156 if (certificate == NULL) 157 return 0; 158 159 int error = X509_STORE_CTX_get_error(ctx); 160 const char* message = X509_verify_cert_error_string(error); 161 162 // Let the BSecureSocket (or subclass) decide if we should continue anyway. 163 BCertificate failedCertificate(certificate); 164 return socket->CertificateVerificationFailed(failedCertificate, message); 165 } 166 167 168 // # pragma mark - BSecureSocket 169 170 171 BSecureSocket::BSecureSocket() 172 : 173 fPrivate(new(std::nothrow) BSecureSocket::Private()) 174 { 175 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 176 } 177 178 179 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 180 : 181 fPrivate(new(std::nothrow) BSecureSocket::Private()) 182 { 183 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 184 Connect(peer, timeout); 185 } 186 187 188 BSecureSocket::BSecureSocket(const BSecureSocket& other) 189 : 190 BSocket(other) 191 { 192 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate); 193 // TODO: this won't work this way! - write working copy constructor for 194 // Private. 195 196 if (fPrivate != NULL) 197 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 198 else 199 fInitStatus = B_NO_MEMORY; 200 201 } 202 203 204 BSecureSocket::~BSecureSocket() 205 { 206 delete fPrivate; 207 } 208 209 210 status_t 211 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 212 { 213 if (fPrivate == NULL) 214 return B_NO_MEMORY; 215 216 status_t state = fPrivate->InitCheck(); 217 if (state != B_OK) 218 return state; 219 220 status_t status = BSocket::Connect(peer, timeout); 221 if (status != B_OK) 222 return status; 223 224 // Do this only after BSocket::Connect has checked wether we're already 225 // connected. We don't want to kill an existing SSL session, as that would 226 // likely crash the protocol loop for it. 227 if (fPrivate->fSSL != NULL) { 228 SSL_free(fPrivate->fSSL); 229 } 230 231 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context()); 232 if (fPrivate->fSSL == NULL) { 233 BSocket::Disconnect(); 234 return B_NO_MEMORY; 235 } 236 237 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE); 238 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 239 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 240 241 int sslStatus = SSL_connect(fPrivate->fSSL); 242 243 if (sslStatus <= 0) { 244 TRACE("SSLConnection can't connect\n"); 245 BSocket::Disconnect(); 246 247 switch (SSL_get_error(fPrivate->fSSL, sslStatus)) { 248 case SSL_ERROR_NONE: 249 // Shouldn't happen... 250 return B_NO_ERROR; 251 case SSL_ERROR_ZERO_RETURN: 252 // Socket is closed 253 return B_CANCELED; 254 case SSL_ERROR_SSL: 255 // Probably no certificate 256 return B_NOT_ALLOWED; 257 default: 258 return B_ERROR; 259 } 260 } 261 262 return B_OK; 263 } 264 265 266 void 267 BSecureSocket::Disconnect() 268 { 269 if (IsConnected()) { 270 if (fPrivate->fSSL != NULL) { 271 SSL_shutdown(fPrivate->fSSL); 272 } 273 274 BSocket::Disconnect(); 275 } 276 } 277 278 279 status_t 280 BSecureSocket::WaitForReadable(bigtime_t timeout) const 281 { 282 if (fInitStatus != B_OK) 283 return fInitStatus; 284 if (!IsConnected()) 285 return B_ERROR; 286 287 if (SSL_pending(fPrivate->fSSL) > 0) 288 return B_OK; 289 290 return BSocket::WaitForReadable(timeout); 291 } 292 293 294 bool 295 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*) 296 { 297 // Until apps actually make use of the certificate API, let's keep the old 298 // behavior and accept all connections, even if the certificate validation 299 // didn't work. 300 return true; 301 } 302 303 304 // #pragma mark - BDataIO implementation 305 306 307 ssize_t 308 BSecureSocket::Read(void* buffer, size_t size) 309 { 310 if (!IsConnected()) 311 return B_ERROR; 312 313 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 314 if (bytesRead >= 0) 315 return bytesRead; 316 317 // TODO: translate SSL error codes! 318 return B_ERROR; 319 } 320 321 322 ssize_t 323 BSecureSocket::Write(const void* buffer, size_t size) 324 { 325 if (!IsConnected()) 326 return B_ERROR; 327 328 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 329 if (bytesWritten >= 0) 330 return bytesWritten; 331 332 // TODO: translate SSL error codes! 333 return B_ERROR; 334 } 335 336 337 #else // OPENSSL_ENABLED 338 339 340 // #pragma mark - No-SSL stubs 341 342 343 BSecureSocket::BSecureSocket() 344 { 345 } 346 347 348 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 349 { 350 fInitStatus = B_UNSUPPORTED; 351 } 352 353 354 BSecureSocket::BSecureSocket(const BSecureSocket& other) 355 : 356 BSocket(other) 357 { 358 } 359 360 361 BSecureSocket::~BSecureSocket() 362 { 363 } 364 365 366 bool 367 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*) 368 { 369 (void)certificate; 370 return false; 371 } 372 373 374 status_t 375 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 376 { 377 return fInitStatus = B_UNSUPPORTED; 378 } 379 380 381 void 382 BSecureSocket::Disconnect() 383 { 384 } 385 386 387 status_t 388 BSecureSocket::WaitForReadable(bigtime_t timeout) const 389 { 390 return B_UNSUPPORTED; 391 } 392 393 394 // #pragma mark - BDataIO implementation 395 396 397 ssize_t 398 BSecureSocket::Read(void* buffer, size_t size) 399 { 400 return B_UNSUPPORTED; 401 } 402 403 404 ssize_t 405 BSecureSocket::Write(const void* buffer, size_t size) 406 { 407 return B_UNSUPPORTED; 408 } 409 410 411 #endif // !OPENSSL_ENABLED 412