1 /* 2 * Copyright 2013-2015 Haiku, Inc. 3 * Copyright 2011-2015, 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 status_t ErrorCode(int returnValue); 42 43 static SSL_CTX* Context(); 44 static int VerifyCallback(int ok, X509_STORE_CTX* ctx); 45 46 private: 47 static void _CreateContext(); 48 49 public: 50 SSL* fSSL; 51 BIO* fBIO; 52 static int sDataIndex; 53 54 private: 55 static SSL_CTX* sContext; 56 // FIXME When do we SSL_CTX_free it? 57 static pthread_once_t sInitOnce; 58 }; 59 60 61 /* static */ SSL_CTX* BSecureSocket::Private::sContext = NULL; 62 /* static */ int BSecureSocket::Private::sDataIndex; 63 /* static */ pthread_once_t BSecureSocket::Private::sInitOnce 64 = PTHREAD_ONCE_INIT; 65 66 67 BSecureSocket::Private::Private() 68 : 69 fSSL(NULL), 70 fBIO(BIO_new(BIO_s_socket())) 71 { 72 } 73 74 75 BSecureSocket::Private::~Private() 76 { 77 // SSL_free also frees the underlying BIO. 78 if (fSSL != NULL) 79 SSL_free(fSSL); 80 else { 81 // The SSL session was never created (Connect() was not called or 82 // failed). We must free the BIO we created in the constructor. 83 BIO_free(fBIO); 84 } 85 } 86 87 88 status_t 89 BSecureSocket::Private::InitCheck() 90 { 91 if (fBIO == NULL) 92 return B_NO_MEMORY; 93 return B_OK; 94 } 95 96 97 status_t 98 BSecureSocket::Private::ErrorCode(int returnValue) 99 { 100 int error = SSL_get_error(fSSL, returnValue); 101 switch (error) { 102 case SSL_ERROR_NONE: 103 // Shouldn't happen... 104 return B_NO_ERROR; 105 case SSL_ERROR_ZERO_RETURN: 106 // Socket is closed 107 return B_CANCELED; 108 case SSL_ERROR_SSL: 109 // Probably no certificate 110 return B_NOT_ALLOWED; 111 112 case SSL_ERROR_WANT_READ: 113 case SSL_ERROR_WANT_WRITE: 114 case SSL_ERROR_WANT_CONNECT: 115 case SSL_ERROR_WANT_ACCEPT: 116 case SSL_ERROR_WANT_X509_LOOKUP: 117 case SSL_ERROR_SYSCALL: 118 default: 119 // TODO: translate SSL error codes! 120 fprintf(stderr, "SSL error: %d\n", error); 121 return B_ERROR; 122 } 123 } 124 125 126 /* static */ SSL_CTX* 127 BSecureSocket::Private::Context() 128 { 129 // We use lazy initialisation here, because reading certificates from disk 130 // and parsing them is a relatively long operation and uses some memory. 131 // We don't want programs that don't use SSL to waste resources with that. 132 pthread_once(&sInitOnce, _CreateContext); 133 134 return sContext; 135 } 136 137 138 /*! This is called each time a certificate verification occurs. It allows us to 139 catch failures and report them. 140 */ 141 /* static */ int 142 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx) 143 { 144 // OpenSSL already checked the certificate again the certificate store for 145 // us, and tells the result of that in the ok parameter. 146 147 // If the verification succeeded, no need for any further checks. Let's 148 // proceed with the connection. 149 if (ok) 150 return ok; 151 152 // The certificate verification failed. Signal this to the BSecureSocket. 153 154 // First of all, get the affected BSecureSocket 155 SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, 156 SSL_get_ex_data_X509_STORE_CTX_idx()); 157 BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex); 158 159 // Get the certificate that we could not validate (this may not be the one 160 // we got from the server, but something higher up in the certificate 161 // chain) 162 X509* x509 = X509_STORE_CTX_get_current_cert(ctx); 163 BCertificate::Private* certificate 164 = new(std::nothrow) BCertificate::Private(x509); 165 166 if (certificate == NULL) 167 return 0; 168 169 int error = X509_STORE_CTX_get_error(ctx); 170 const char* message = X509_verify_cert_error_string(error); 171 172 // Let the BSecureSocket (or subclass) decide if we should continue anyway. 173 BCertificate failedCertificate(certificate); 174 return socket->CertificateVerificationFailed(failedCertificate, message); 175 } 176 177 178 /* static */ void 179 BSecureSocket::Private::_CreateContext() 180 { 181 sContext = SSL_CTX_new(SSLv23_method()); 182 183 // Disable legacy protocols. They have known vulnerabilities. 184 SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); 185 186 // Don't bother us with ERROR_WANT_READ. 187 SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY); 188 189 // Setup certificate verification 190 BPath certificateStore; 191 find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); 192 certificateStore.Append("ssl/CARootCertificates.pem"); 193 // TODO we may want to add a non-packaged certificate directory? 194 // (would make it possible to store user-added certificate exceptions 195 // there) 196 SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); 197 SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); 198 199 // OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to validate certificate 200 // chains. This makes the validation stop as soon as a recognized certificate is found in the 201 // chain, instead of validating the whole chain, then seeing if the root certificate is known. 202 #ifdef X509_V_FLAG_TRUSTED_FIRST 203 X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new(); 204 X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST); 205 SSL_CTX_set1_param(sContext, verifyParam); 206 207 // TODO we need to free this after freeing the SSL context (which we currently never do) 208 // X509_VERIFY_PARAM_free(verifyParam); 209 #endif 210 211 // Get an unique index number for storing application data in SSL 212 // structs. We will store a pointer to the BSecureSocket class there. 213 sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 214 } 215 216 217 // # pragma mark - BSecureSocket 218 219 220 BSecureSocket::BSecureSocket() 221 : 222 fPrivate(new(std::nothrow) BSecureSocket::Private()) 223 { 224 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 225 } 226 227 228 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 229 : 230 fPrivate(new(std::nothrow) BSecureSocket::Private()) 231 { 232 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 233 Connect(peer, timeout); 234 } 235 236 237 BSecureSocket::BSecureSocket(const BSecureSocket& other) 238 : 239 BSocket(other) 240 { 241 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate); 242 // TODO: this won't work this way! - write working copy constructor for 243 // Private. 244 245 if (fPrivate != NULL) 246 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 247 else 248 fInitStatus = B_NO_MEMORY; 249 250 } 251 252 253 BSecureSocket::~BSecureSocket() 254 { 255 delete fPrivate; 256 } 257 258 259 status_t 260 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 261 { 262 status_t status = InitCheck(); 263 if (status != B_OK) 264 return status; 265 266 status = BSocket::Connect(peer, timeout); 267 if (status != B_OK) 268 return status; 269 270 return _Setup(); 271 } 272 273 274 void 275 BSecureSocket::Disconnect() 276 { 277 if (IsConnected()) { 278 if (fPrivate->fSSL != NULL) 279 SSL_shutdown(fPrivate->fSSL); 280 281 BSocket::Disconnect(); 282 } 283 } 284 285 286 status_t 287 BSecureSocket::WaitForReadable(bigtime_t timeout) const 288 { 289 if (fInitStatus != B_OK) 290 return fInitStatus; 291 if (!IsConnected()) 292 return B_ERROR; 293 294 if (SSL_pending(fPrivate->fSSL) > 0) 295 return B_OK; 296 297 return BSocket::WaitForReadable(timeout); 298 } 299 300 301 status_t 302 BSecureSocket::InitCheck() 303 { 304 if (fPrivate == NULL) 305 return B_NO_MEMORY; 306 307 status_t state = fPrivate->InitCheck(); 308 return state; 309 } 310 311 312 bool 313 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*) 314 { 315 // Until apps actually make use of the certificate API, let's keep the old 316 // behavior and accept all connections, even if the certificate validation 317 // didn't work. 318 return true; 319 } 320 321 322 // #pragma mark - BDataIO implementation 323 324 325 ssize_t 326 BSecureSocket::Read(void* buffer, size_t size) 327 { 328 if (!IsConnected()) 329 return B_ERROR; 330 331 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 332 if (bytesRead >= 0) 333 return bytesRead; 334 335 return fPrivate->ErrorCode(bytesRead); 336 } 337 338 339 ssize_t 340 BSecureSocket::Write(const void* buffer, size_t size) 341 { 342 if (!IsConnected()) 343 return B_ERROR; 344 345 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 346 if (bytesWritten >= 0) 347 return bytesWritten; 348 349 return fPrivate->ErrorCode(bytesWritten); 350 } 351 352 353 status_t 354 BSecureSocket::_Setup() 355 { 356 // Do this only after BSocket::Connect has checked wether we're already 357 // connected. We don't want to kill an existing SSL session, as that would 358 // likely crash the protocol loop for it. 359 if (fPrivate->fSSL != NULL) { 360 SSL_free(fPrivate->fSSL); 361 } 362 363 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context()); 364 if (fPrivate->fSSL == NULL) { 365 BSocket::Disconnect(); 366 return B_NO_MEMORY; 367 } 368 369 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE); 370 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 371 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 372 373 int returnValue = SSL_connect(fPrivate->fSSL); 374 if (returnValue <= 0) { 375 TRACE("SSLConnection can't connect\n"); 376 BSocket::Disconnect(); 377 return fPrivate->ErrorCode(returnValue); 378 } 379 380 return B_OK; 381 } 382 383 384 #else // OPENSSL_ENABLED 385 386 387 // #pragma mark - No-SSL stubs 388 389 390 BSecureSocket::BSecureSocket() 391 { 392 } 393 394 395 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 396 { 397 fInitStatus = B_UNSUPPORTED; 398 } 399 400 401 BSecureSocket::BSecureSocket(const BSecureSocket& other) 402 : 403 BSocket(other) 404 { 405 } 406 407 408 BSecureSocket::~BSecureSocket() 409 { 410 } 411 412 413 bool 414 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*) 415 { 416 (void)certificate; 417 return false; 418 } 419 420 421 status_t 422 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 423 { 424 return fInitStatus = B_UNSUPPORTED; 425 } 426 427 428 void 429 BSecureSocket::Disconnect() 430 { 431 } 432 433 434 status_t 435 BSecureSocket::WaitForReadable(bigtime_t timeout) const 436 { 437 return B_UNSUPPORTED; 438 } 439 440 441 // #pragma mark - BDataIO implementation 442 443 444 ssize_t 445 BSecureSocket::Read(void* buffer, size_t size) 446 { 447 return B_UNSUPPORTED; 448 } 449 450 451 ssize_t 452 BSecureSocket::Write(const void* buffer, size_t size) 453 { 454 return B_UNSUPPORTED; 455 } 456 457 458 status_t 459 BSecureSocket::InitCheck() 460 { 461 return B_UNSUPPORTED; 462 } 463 464 465 status_t 466 BSecureSocket::_Setup() 467 { 468 return B_UNSUPPORTED; 469 } 470 471 472 #endif // !OPENSSL_ENABLED 473