libbnetapi: style fixes only.
[haiku.git] / src / kits / network / libnetapi / SecureSocket.cpp
blobae8d6fd4549bbce2c583e73499b27cc7d4c3d535
1 /*
2 * Copyright 2013-2016 Haiku, Inc.
3 * Copyright 2011-2015, Axel Dörfler, axeld@pinc-software.de.
4 * Copyright 2016, Rene Gollent, rene@gollent.com.
5 * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
6 * Distributed under the terms of the MIT License.
7 */
10 #include <SecureSocket.h>
12 #ifdef OPENSSL_ENABLED
13 # include <openssl/ssl.h>
14 # include <openssl/ssl3.h> // for TRACE_SESSION_KEY only
15 # include <openssl/err.h>
16 #endif
18 #include <pthread.h>
20 #include <Certificate.h>
21 #include <FindDirectory.h>
22 #include <Path.h>
24 #include <AutoDeleter.h>
26 #include "CertificatePrivate.h"
29 //#define TRACE_SOCKET
30 #ifdef TRACE_SOCKET
31 # define TRACE(x...) printf(x)
32 #else
33 # define TRACE(x...) ;
34 #endif
36 //#define TRACE_SESSION_KEY
39 #ifdef OPENSSL_ENABLED
41 #ifdef TRACE_SESSION_KEY
42 #if OPENSSL_VERSION_NUMBER < 0x10100000L
44 * print session id and master key in NSS keylog format (RSA
45 * Session-ID:<session id> Master-Key:<master key>)
47 int SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x)
49 size_t i;
51 if (x == NULL)
52 goto err;
53 if (x->session_id_length == 0 || x->master_key_length == 0)
54 goto err;
57 * the RSA prefix is required by the format's definition although there's
58 * nothing RSA-specific in the output, therefore, we don't have to check if
59 * the cipher suite is based on RSA
61 if (BIO_puts(bp, "RSA ") <= 0)
62 goto err;
64 if (BIO_puts(bp, "Session-ID:") <= 0)
65 goto err;
66 for (i = 0; i < x->session_id_length; i++) {
67 if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0)
68 goto err;
70 if (BIO_puts(bp, " Master-Key:") <= 0)
71 goto err;
72 for (i = 0; i < (size_t)x->master_key_length; i++) {
73 if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
74 goto err;
76 if (BIO_puts(bp, "\n") <= 0)
77 goto err;
79 return (1);
80 err:
81 return (0);
83 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
85 * print client random id and master key in NSS keylog format
86 * as session ID is not enough.
88 int SSL_SESSION_print_client_random(BIO *bp, const SSL *ssl)
90 const SSL_SESSION *x = SSL_get_session(ssl);
91 size_t i;
93 if (x == NULL)
94 goto err;
95 if (x->session_id_length == 0 || x->master_key_length == 0)
96 goto err;
99 * the RSA prefix is required by the format's definition although there's
100 * nothing RSA-specific in the output, therefore, we don't have to check if
101 * the cipher suite is based on RSA
103 if (BIO_puts(bp, "CLIENT_RANDOM ") <= 0)
104 goto err;
106 for (i = 0; i < sizeof(ssl->s3->client_random); i++) {
107 if (BIO_printf(bp, "%02X", ssl->s3->client_random[i]) <= 0)
108 goto err;
110 if (BIO_puts(bp, " ") <= 0)
111 goto err;
112 for (i = 0; i < (size_t)x->master_key_length; i++) {
113 if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
114 goto err;
116 if (BIO_puts(bp, "\n") <= 0)
117 goto err;
119 return (1);
120 err:
121 return (0);
123 #endif /* TRACE_SESSION_KEY */
125 class BSecureSocket::Private {
126 public:
127 Private();
128 ~Private();
130 status_t InitCheck();
131 status_t ErrorCode(int returnValue);
133 static SSL_CTX* Context();
134 static int VerifyCallback(int ok, X509_STORE_CTX* ctx);
136 private:
137 static void _CreateContext();
139 public:
140 SSL* fSSL;
141 BIO* fBIO;
142 static int sDataIndex;
144 private:
145 static SSL_CTX* sContext;
146 // FIXME When do we SSL_CTX_free it?
147 static pthread_once_t sInitOnce;
148 #ifdef TRACE_SESSION_KEY
149 public:
150 static BIO* sKeyLogBIO;
151 #endif
156 /* static */ SSL_CTX* BSecureSocket::Private::sContext = NULL;
157 /* static */ int BSecureSocket::Private::sDataIndex;
158 /* static */ pthread_once_t BSecureSocket::Private::sInitOnce
159 = PTHREAD_ONCE_INIT;
160 #ifdef TRACE_SESSION_KEY
161 /* static */ BIO* BSecureSocket::Private::sKeyLogBIO = NULL;
162 #endif
165 BSecureSocket::Private::Private()
167 fSSL(NULL),
168 fBIO(BIO_new(BIO_s_socket()))
173 BSecureSocket::Private::~Private()
175 // SSL_free also frees the underlying BIO.
176 if (fSSL != NULL)
177 SSL_free(fSSL);
178 else {
179 // The SSL session was never created (Connect() was not called or
180 // failed). We must free the BIO we created in the constructor.
181 BIO_free(fBIO);
186 status_t
187 BSecureSocket::Private::InitCheck()
189 if (fBIO == NULL)
190 return B_NO_MEMORY;
191 return B_OK;
195 status_t
196 BSecureSocket::Private::ErrorCode(int returnValue)
198 int error = SSL_get_error(fSSL, returnValue);
199 switch (error) {
200 case SSL_ERROR_NONE:
201 // Shouldn't happen...
202 return B_NO_ERROR;
203 case SSL_ERROR_ZERO_RETURN:
204 // Socket is closed
205 return B_CANCELED;
206 case SSL_ERROR_SSL:
207 // Probably no certificate
208 return B_NOT_ALLOWED;
210 case SSL_ERROR_WANT_READ:
211 case SSL_ERROR_WANT_WRITE:
212 case SSL_ERROR_WANT_CONNECT:
213 case SSL_ERROR_WANT_ACCEPT:
214 case SSL_ERROR_WANT_X509_LOOKUP:
215 case SSL_ERROR_SYSCALL:
216 default:
217 // TODO: translate SSL error codes!
218 fprintf(stderr, "SSL %s\n", ERR_error_string(error, NULL));
219 return B_ERROR;
224 /* static */ SSL_CTX*
225 BSecureSocket::Private::Context()
227 // We use lazy initialisation here, because reading certificates from disk
228 // and parsing them is a relatively long operation and uses some memory.
229 // We don't want programs that don't use SSL to waste resources with that.
230 pthread_once(&sInitOnce, _CreateContext);
232 return sContext;
236 /*! This is called each time a certificate verification occurs. It allows us to
237 catch failures and report them.
239 /* static */ int
240 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx)
242 // OpenSSL already checked the certificate again the certificate store for
243 // us, and tells the result of that in the ok parameter.
245 // If the verification succeeded, no need for any further checks. Let's
246 // proceed with the connection.
247 if (ok)
248 return ok;
250 // The certificate verification failed. Signal this to the BSecureSocket.
252 // First of all, get the affected BSecureSocket
253 SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx,
254 SSL_get_ex_data_X509_STORE_CTX_idx());
255 BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex);
257 // Get the certificate that we could not validate (this may not be the one
258 // we got from the server, but something higher up in the certificate
259 // chain)
260 X509* x509 = X509_STORE_CTX_get_current_cert(ctx);
261 BCertificate::Private* certificate
262 = new(std::nothrow) BCertificate::Private(x509);
264 if (certificate == NULL)
265 return 0;
267 int error = X509_STORE_CTX_get_error(ctx);
268 const char* message = X509_verify_cert_error_string(error);
270 // Let the BSecureSocket (or subclass) decide if we should continue anyway.
271 BCertificate failedCertificate(certificate);
272 return socket->CertificateVerificationFailed(failedCertificate, message);
276 #if TRACE_SSL
277 static void apps_ssl_info_callback(const SSL *s, int where, int ret)
279 const char *str;
280 int w;
282 w=where& ~SSL_ST_MASK;
284 if (w & SSL_ST_CONNECT)
285 str="SSL_connect";
286 else if (w & SSL_ST_ACCEPT)
287 str="SSL_accept";
288 else
289 str="undefined";
291 if (where & SSL_CB_LOOP) {
292 fprintf(stderr,"%s:%s\n", str, SSL_state_string_long(s));
293 } else if (where & SSL_CB_ALERT) {
294 str = (where & SSL_CB_READ) ? "read" : "write";
295 fprintf(stderr,"SSL3 alert %s:%s:%s\n",
296 str,
297 SSL_alert_type_string_long(ret),
298 SSL_alert_desc_string_long(ret));
299 } else if (where & SSL_CB_EXIT) {
300 if (ret == 0)
301 fprintf(stderr,"%s:failed in %s\n",
302 str,SSL_state_string_long(s));
303 else if (ret < 0) {
304 fprintf(stderr,"%s:error in %s\n",
305 str,SSL_state_string_long(s));
309 #endif
312 /* static */ void
313 BSecureSocket::Private::_CreateContext()
315 // We want SSL to report errors in human readable format.
316 SSL_load_error_strings();
318 sContext = SSL_CTX_new(SSLv23_method());
320 #if TRACE_SSL
321 // For debugging purposes: get all SSL messages to the standard error.
322 SSL_CTX_set_info_callback(sContext, apps_ssl_info_callback);
323 #endif
325 // Disable legacy protocols. They have known vulnerabilities.
326 SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
328 // Disable SSL/TLS compression to prevent the CRIME attack.
329 SSL_CTX_set_options(sContext, SSL_OP_NO_COMPRESSION);
331 // Don't bother us with ERROR_WANT_READ.
332 SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY);
334 // Setup cipher suites.
335 // These suites are mostly the same ones used by Firefox 47 and Chrome 50.
336 SSL_CTX_set_cipher_list(sContext,
337 "ECDHE-ECDSA-AES128-GCM-SHA256:"
338 "ECDHE-RSA-AES128-GCM-SHA256:"
339 "ECDHE-ECDSA-AES256-GCM-SHA384:"
340 "ECDHE-RSA-AES256-GCM-SHA384:"
341 "ECDHE-ECDSA-CHACHA20-POLY1305-SHA256:"
342 "ECDHE-RSA-CHACHA20-POLY1305-SHA256:"
343 "ECDHE-ECDSA-AES256-SHA:"
344 "ECDHE-ECDSA-AES128-SHA:"
345 "ECDHE-RSA-AES128-SHA:"
346 "ECDHE-RSA-AES256-SHA:"
347 "DHE-RSA-AES128-SHA:"
348 "DHE-RSA-AES256-SHA:"
349 "AES128-SHA:"
350 "AES256-SHA");
352 // Let OpenSSL choose the most appropriate D-H curve for us
353 SSL_CTX_set_ecdh_auto(sContext, 1);
355 // Setup certificate verification
356 BPath certificateStore;
357 find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore);
358 certificateStore.Append("ssl/CARootCertificates.pem");
359 // TODO we may want to add a non-packaged certificate directory?
360 // (would make it possible to store user-added certificate exceptions
361 // there)
362 SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL);
363 SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback);
365 // OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to validate certificate
366 // chains. This makes the validation stop as soon as a recognized certificate is found in the
367 // chain, instead of validating the whole chain, then seeing if the root certificate is known.
368 #ifdef X509_V_FLAG_TRUSTED_FIRST
369 X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new();
370 X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST);
371 SSL_CTX_set1_param(sContext, verifyParam);
373 // TODO we need to free this after freeing the SSL context (which we currently never do)
374 // X509_VERIFY_PARAM_free(verifyParam);
375 #endif
377 // Get an unique index number for storing application data in SSL
378 // structs. We will store a pointer to the BSecureSocket class there.
379 sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
381 #ifdef TRACE_SESSION_KEY
382 FILE *keylog = NULL;
383 const char *logpath = getenv("SSLKEYLOGFILE");
384 if (logpath)
385 keylog = fopen(logpath, "w+");
386 if (keylog) {
387 fprintf(keylog, "# Key Log File generated by Haiku Network Kit\n");
388 sKeyLogBIO = BIO_new_fp(keylog, BIO_NOCLOSE);
390 #endif
394 // # pragma mark - BSecureSocket
397 BSecureSocket::BSecureSocket()
399 fPrivate(new(std::nothrow) BSecureSocket::Private())
401 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
405 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
407 fPrivate(new(std::nothrow) BSecureSocket::Private())
409 fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
410 Connect(peer, timeout);
414 BSecureSocket::BSecureSocket(const BSecureSocket& other)
416 BSocket(other)
418 fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate);
419 // TODO: this won't work this way! - write working copy constructor for
420 // Private.
422 if (fPrivate != NULL)
423 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
424 else
425 fInitStatus = B_NO_MEMORY;
430 BSecureSocket::~BSecureSocket()
432 delete fPrivate;
436 status_t
437 BSecureSocket::Accept(BAbstractSocket*& _socket)
439 int fd = -1;
440 BNetworkAddress peer;
441 status_t error = AcceptNext(fd, peer);
442 if (error != B_OK)
443 return error;
444 BSecureSocket* socket = new(std::nothrow) BSecureSocket();
445 ObjectDeleter<BSecureSocket> socketDeleter(socket);
446 if (socket == NULL || socket->InitCheck() != B_OK) {
447 close(fd);
448 return B_NO_MEMORY;
451 socket->_SetTo(fd, fLocal, peer);
452 error = socket->_SetupAccept();
453 if (error != B_OK)
454 return error;
456 _socket = socket;
457 socketDeleter.Detach();
459 return B_OK;
463 status_t
464 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
466 status_t status = InitCheck();
467 if (status != B_OK)
468 return status;
470 status = BSocket::Connect(peer, timeout);
471 if (status != B_OK)
472 return status;
474 return _SetupConnect(peer.HostName().String());
478 void
479 BSecureSocket::Disconnect()
481 if (IsConnected()) {
482 if (fPrivate->fSSL != NULL)
483 SSL_shutdown(fPrivate->fSSL);
485 BSocket::Disconnect();
490 status_t
491 BSecureSocket::WaitForReadable(bigtime_t timeout) const
493 if (fInitStatus != B_OK)
494 return fInitStatus;
495 if (!IsConnected())
496 return B_ERROR;
498 if (SSL_pending(fPrivate->fSSL) > 0)
499 return B_OK;
501 return BSocket::WaitForReadable(timeout);
505 status_t
506 BSecureSocket::InitCheck()
508 if (fPrivate == NULL)
509 return B_NO_MEMORY;
511 status_t state = fPrivate->InitCheck();
512 return state;
516 bool
517 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*)
519 // Until apps actually make use of the certificate API, let's keep the old
520 // behavior and accept all connections, even if the certificate validation
521 // didn't work.
522 return true;
526 // #pragma mark - BDataIO implementation
529 ssize_t
530 BSecureSocket::Read(void* buffer, size_t size)
532 if (!IsConnected())
533 return B_ERROR;
535 int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
536 if (bytesRead >= 0)
537 return bytesRead;
539 return fPrivate->ErrorCode(bytesRead);
543 ssize_t
544 BSecureSocket::Write(const void* buffer, size_t size)
546 if (!IsConnected())
547 return B_ERROR;
549 int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
550 if (bytesWritten >= 0)
551 return bytesWritten;
553 return fPrivate->ErrorCode(bytesWritten);
557 status_t
558 BSecureSocket::_SetupCommon(const char* host)
560 // Do this only after BSocket::Connect has checked wether we're already
561 // connected. We don't want to kill an existing SSL session, as that would
562 // likely crash the protocol loop for it.
563 if (fPrivate->fSSL != NULL) {
564 SSL_free(fPrivate->fSSL);
567 fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context());
568 if (fPrivate->fSSL == NULL) {
569 BSocket::Disconnect();
570 return B_NO_MEMORY;
573 BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE);
574 SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
575 SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
576 if (host != NULL) {
577 BString hostString = host;
578 if (hostString != "")
579 SSL_set_tlsext_host_name(fPrivate->fSSL, host);
583 return B_OK;
587 status_t
588 BSecureSocket::_SetupConnect(const char* host)
590 status_t error = _SetupCommon(host);
591 if (error != B_OK)
592 return error;
594 int returnValue = SSL_connect(fPrivate->fSSL);
595 if (returnValue <= 0) {
596 TRACE("SSLConnection can't connect\n");
597 BSocket::Disconnect();
598 return fPrivate->ErrorCode(returnValue);
601 #ifdef TRACE_SESSION_KEY
602 fprintf(stderr, "SSL SESSION INFO:\n");
603 //SSL_SESSION_print_fp(stderr, SSL_get_session(fPrivate->fSSL));
604 SSL_SESSION_print_keylog(fPrivate->sKeyLogBIO, SSL_get_session(fPrivate->fSSL));
605 SSL_SESSION_print_client_random(fPrivate->sKeyLogBIO, fPrivate->fSSL);
606 fprintf(stderr, "\n");
607 #endif
609 return B_OK;
613 status_t
614 BSecureSocket::_SetupAccept()
616 status_t error = _SetupCommon();
617 if (error != B_OK)
618 return error;
620 int returnValue = SSL_accept(fPrivate->fSSL);
621 if (returnValue <= 0) {
622 TRACE("SSLConnection can't accept\n");
623 BSocket::Disconnect();
624 return fPrivate->ErrorCode(returnValue);
627 return B_OK;
631 #else // OPENSSL_ENABLED
634 // #pragma mark - No-SSL stubs
637 BSecureSocket::BSecureSocket()
642 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
644 fInitStatus = B_UNSUPPORTED;
648 BSecureSocket::BSecureSocket(const BSecureSocket& other)
650 BSocket(other)
655 BSecureSocket::~BSecureSocket()
660 bool
661 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*)
663 (void)certificate;
664 return false;
668 status_t
669 BSecureSocket::Accept(BAbstractSocket*& _socket)
671 return B_UNSUPPORTED;
675 status_t
676 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
678 return fInitStatus = B_UNSUPPORTED;
682 void
683 BSecureSocket::Disconnect()
688 status_t
689 BSecureSocket::WaitForReadable(bigtime_t timeout) const
691 return B_UNSUPPORTED;
695 // #pragma mark - BDataIO implementation
698 ssize_t
699 BSecureSocket::Read(void* buffer, size_t size)
701 return B_UNSUPPORTED;
705 ssize_t
706 BSecureSocket::Write(const void* buffer, size_t size)
708 return B_UNSUPPORTED;
712 status_t
713 BSecureSocket::InitCheck()
715 return B_UNSUPPORTED;
719 status_t
720 BSecureSocket::_SetupCommon(const char* host)
722 return B_UNSUPPORTED;
726 status_t
727 BSecureSocket::_SetupConnect(const char* host)
729 return B_UNSUPPORTED;
733 status_t
734 BSecureSocket::_SetupAccept()
736 return B_UNSUPPORTED;
740 #endif // !OPENSSL_ENABLED