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 // Setup certificate verification 187 BPath certificateStore; 188 find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); 189 certificateStore.Append("ssl/CARootCertificates.pem"); 190 // TODO we may want to add a non-packaged certificate directory? 191 // (would make it possible to store user-added certificate exceptions 192 // there) 193 SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); 194 SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); 195 196 // Get an unique index number for storing application data in SSL 197 // structs. We will store a pointer to the BSecureSocket class there. 198 sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); 199 } 200 201 202 // # pragma mark - BSecureSocket 203 204 205 BSecureSocket::BSecureSocket() 206 : 207 fPrivate(new(std::nothrow) BSecureSocket::Private()) 208 { 209 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 210 } 211 212 213 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 214 : 215 fPrivate(new(std::nothrow) BSecureSocket::Private()) 216 { 217 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 218 Connect(peer, timeout); 219 } 220 221 222 BSecureSocket::BSecureSocket(const BSecureSocket& other) 223 : 224 BSocket(other) 225 { 226 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate); 227 // TODO: this won't work this way! - write working copy constructor for 228 // Private. 229 230 if (fPrivate != NULL) 231 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 232 else 233 fInitStatus = B_NO_MEMORY; 234 235 } 236 237 238 BSecureSocket::~BSecureSocket() 239 { 240 delete fPrivate; 241 } 242 243 244 status_t 245 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 246 { 247 if (fPrivate == NULL) 248 return B_NO_MEMORY; 249 250 status_t state = fPrivate->InitCheck(); 251 if (state != B_OK) 252 return state; 253 254 status_t status = BSocket::Connect(peer, timeout); 255 if (status != B_OK) 256 return status; 257 258 // Do this only after BSocket::Connect has checked wether we're already 259 // connected. We don't want to kill an existing SSL session, as that would 260 // likely crash the protocol loop for it. 261 if (fPrivate->fSSL != NULL) { 262 SSL_free(fPrivate->fSSL); 263 } 264 265 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context()); 266 if (fPrivate->fSSL == NULL) { 267 BSocket::Disconnect(); 268 return B_NO_MEMORY; 269 } 270 271 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE); 272 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 273 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 274 275 int returnValue = SSL_connect(fPrivate->fSSL); 276 if (returnValue <= 0) { 277 TRACE("SSLConnection can't connect\n"); 278 BSocket::Disconnect(); 279 return fPrivate->ErrorCode(returnValue); 280 } 281 282 return B_OK; 283 } 284 285 286 void 287 BSecureSocket::Disconnect() 288 { 289 if (IsConnected()) { 290 if (fPrivate->fSSL != NULL) 291 SSL_shutdown(fPrivate->fSSL); 292 293 BSocket::Disconnect(); 294 } 295 } 296 297 298 status_t 299 BSecureSocket::WaitForReadable(bigtime_t timeout) const 300 { 301 if (fInitStatus != B_OK) 302 return fInitStatus; 303 if (!IsConnected()) 304 return B_ERROR; 305 306 if (SSL_pending(fPrivate->fSSL) > 0) 307 return B_OK; 308 309 return BSocket::WaitForReadable(timeout); 310 } 311 312 313 bool 314 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*) 315 { 316 // Until apps actually make use of the certificate API, let's keep the old 317 // behavior and accept all connections, even if the certificate validation 318 // didn't work. 319 return true; 320 } 321 322 323 // #pragma mark - BDataIO implementation 324 325 326 ssize_t 327 BSecureSocket::Read(void* buffer, size_t size) 328 { 329 if (!IsConnected()) 330 return B_ERROR; 331 332 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 333 if (bytesRead >= 0) 334 return bytesRead; 335 336 return fPrivate->ErrorCode(bytesRead); 337 } 338 339 340 ssize_t 341 BSecureSocket::Write(const void* buffer, size_t size) 342 { 343 if (!IsConnected()) 344 return B_ERROR; 345 346 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 347 if (bytesWritten >= 0) 348 return bytesWritten; 349 350 return fPrivate->ErrorCode(bytesWritten); 351 } 352 353 354 #else // OPENSSL_ENABLED 355 356 357 // #pragma mark - No-SSL stubs 358 359 360 BSecureSocket::BSecureSocket() 361 { 362 } 363 364 365 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 366 { 367 fInitStatus = B_UNSUPPORTED; 368 } 369 370 371 BSecureSocket::BSecureSocket(const BSecureSocket& other) 372 : 373 BSocket(other) 374 { 375 } 376 377 378 BSecureSocket::~BSecureSocket() 379 { 380 } 381 382 383 bool 384 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*) 385 { 386 (void)certificate; 387 return false; 388 } 389 390 391 status_t 392 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 393 { 394 return fInitStatus = B_UNSUPPORTED; 395 } 396 397 398 void 399 BSecureSocket::Disconnect() 400 { 401 } 402 403 404 status_t 405 BSecureSocket::WaitForReadable(bigtime_t timeout) const 406 { 407 return B_UNSUPPORTED; 408 } 409 410 411 // #pragma mark - BDataIO implementation 412 413 414 ssize_t 415 BSecureSocket::Read(void* buffer, size_t size) 416 { 417 return B_UNSUPPORTED; 418 } 419 420 421 ssize_t 422 BSecureSocket::Write(const void* buffer, size_t size) 423 { 424 return B_UNSUPPORTED; 425 } 426 427 428 #endif // !OPENSSL_ENABLED 429