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 BCertificate failedCertificate(certificate); 158 return socket->CertificateVerificationFailed(failedCertificate); 159 } 160 161 162 // # pragma mark - BSecureSocket 163 164 165 BSecureSocket::BSecureSocket() 166 : 167 fPrivate(new(std::nothrow) BSecureSocket::Private()) 168 { 169 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 170 } 171 172 173 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 174 : 175 fPrivate(new(std::nothrow) BSecureSocket::Private()) 176 { 177 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY; 178 Connect(peer, timeout); 179 } 180 181 182 BSecureSocket::BSecureSocket(const BSecureSocket& other) 183 : 184 BSocket(other) 185 { 186 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate); 187 // TODO: this won't work this way! - write working copy constructor for 188 // Private. 189 190 if (fPrivate != NULL) 191 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 192 else 193 fInitStatus = B_NO_MEMORY; 194 195 } 196 197 198 BSecureSocket::~BSecureSocket() 199 { 200 delete fPrivate; 201 } 202 203 204 status_t 205 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 206 { 207 if (fPrivate == NULL) 208 return B_NO_MEMORY; 209 210 status_t state = fPrivate->InitCheck(); 211 if (state != B_OK) 212 return state; 213 214 status_t status = BSocket::Connect(peer, timeout); 215 if (status != B_OK) 216 return status; 217 218 // Do this only after BSocket::Connect has checked wether we're already 219 // connected. We don't want to kill an existing SSL session, as that would 220 // likely crash the protocol loop for it. 221 if (fPrivate->fSSL != NULL) { 222 SSL_free(fPrivate->fSSL); 223 } 224 225 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context()); 226 if (fPrivate->fSSL == NULL) { 227 BSocket::Disconnect(); 228 return B_NO_MEMORY; 229 } 230 231 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE); 232 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO); 233 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this); 234 235 int sslStatus = SSL_connect(fPrivate->fSSL); 236 237 if (sslStatus <= 0) { 238 TRACE("SSLConnection can't connect\n"); 239 BSocket::Disconnect(); 240 241 switch (SSL_get_error(fPrivate->fSSL, sslStatus)) { 242 case SSL_ERROR_NONE: 243 // Shouldn't happen... 244 return B_NO_ERROR; 245 case SSL_ERROR_ZERO_RETURN: 246 // Socket is closed 247 return B_CANCELED; 248 case SSL_ERROR_SSL: 249 // Probably no certificate 250 return B_NOT_ALLOWED; 251 default: 252 return B_ERROR; 253 } 254 } 255 256 return B_OK; 257 } 258 259 260 void 261 BSecureSocket::Disconnect() 262 { 263 if (IsConnected()) { 264 if (fPrivate->fSSL != NULL) { 265 SSL_shutdown(fPrivate->fSSL); 266 } 267 268 BSocket::Disconnect(); 269 } 270 } 271 272 273 status_t 274 BSecureSocket::WaitForReadable(bigtime_t timeout) const 275 { 276 if (fInitStatus != B_OK) 277 return fInitStatus; 278 if (!IsConnected()) 279 return B_ERROR; 280 281 if (SSL_pending(fPrivate->fSSL) > 0) 282 return B_OK; 283 284 return BSocket::WaitForReadable(timeout); 285 } 286 287 288 bool 289 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate) 290 { 291 // Until apps actually make use of the certificate API, let's keep the old 292 // behavior and accept all connections, even if the certificate validation 293 // didn't work. 294 (void)certificate; 295 return true; 296 } 297 298 299 // #pragma mark - BDataIO implementation 300 301 302 ssize_t 303 BSecureSocket::Read(void* buffer, size_t size) 304 { 305 if (!IsConnected()) 306 return B_ERROR; 307 308 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size); 309 if (bytesRead >= 0) 310 return bytesRead; 311 312 // TODO: translate SSL error codes! 313 return B_ERROR; 314 } 315 316 317 ssize_t 318 BSecureSocket::Write(const void* buffer, size_t size) 319 { 320 if (!IsConnected()) 321 return B_ERROR; 322 323 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size); 324 if (bytesWritten >= 0) 325 return bytesWritten; 326 327 // TODO: translate SSL error codes! 328 return B_ERROR; 329 } 330 331 332 #else // OPENSSL_ENABLED 333 334 335 // #pragma mark - No-SSL stubs 336 337 338 BSecureSocket::BSecureSocket() 339 { 340 } 341 342 343 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout) 344 { 345 fInitStatus = B_UNSUPPORTED; 346 } 347 348 349 BSecureSocket::BSecureSocket(const BSecureSocket& other) 350 : 351 BSocket(other) 352 { 353 } 354 355 356 BSecureSocket::~BSecureSocket() 357 { 358 } 359 360 361 bool 362 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate) 363 { 364 (void)certificate; 365 return false; 366 } 367 368 369 status_t 370 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout) 371 { 372 return fInitStatus = B_UNSUPPORTED; 373 } 374 375 376 void 377 BSecureSocket::Disconnect() 378 { 379 } 380 381 382 status_t 383 BSecureSocket::WaitForReadable(bigtime_t timeout) const 384 { 385 return B_UNSUPPORTED; 386 } 387 388 389 // #pragma mark - BDataIO implementation 390 391 392 ssize_t 393 BSecureSocket::Read(void* buffer, size_t size) 394 { 395 return B_UNSUPPORTED; 396 } 397 398 399 ssize_t 400 BSecureSocket::Write(const void* buffer, size_t size) 401 { 402 return B_UNSUPPORTED; 403 } 404 405 406 #endif // !OPENSSL_ENABLED 407