xref: /haiku/src/kits/network/libnetapi/SecureSocket.cpp (revision c0936b5a0384bc6fe654d296ee54222a0f45d2b6)
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  */
8 
9 
10 #include <SecureSocket.h>
11 
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
17 
18 #include <pthread.h>
19 
20 #include <Certificate.h>
21 #include <FindDirectory.h>
22 #include <Path.h>
23 
24 #include <AutoDeleter.h>
25 
26 #include "CertificatePrivate.h"
27 
28 
29 //#define TRACE_SOCKET
30 #ifdef TRACE_SOCKET
31 #	define TRACE(x...) printf(x)
32 #else
33 #	define TRACE(x...) ;
34 #endif
35 
36 //#define TRACE_SESSION_KEY
37 
38 
39 #ifdef OPENSSL_ENABLED
40 
41 #ifdef TRACE_SESSION_KEY
42 #if OPENSSL_VERSION_NUMBER < 0x10100000L
43 /*
44  * print session id and master key in NSS keylog format (RSA
45  * Session-ID:<session id> Master-Key:<master key>)
46  */
47 int SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x)
48 {
49     size_t i;
50 
51     if (x == NULL)
52         goto err;
53     if (x->session_id_length == 0 || x->master_key_length == 0)
54         goto err;
55 
56     /*
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
60      */
61     if (BIO_puts(bp, "RSA ") <= 0)
62         goto err;
63 
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;
69     }
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;
75     }
76     if (BIO_puts(bp, "\n") <= 0)
77         goto err;
78 
79     return (1);
80  err:
81     return (0);
82 }
83 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
84 /*
85  * print client random id and master key in NSS keylog format
86  * as session ID is not enough.
87  */
88 int SSL_SESSION_print_client_random(BIO *bp, const SSL *ssl)
89 {
90 	const SSL_SESSION *x = SSL_get_session(ssl);
91     size_t i;
92 
93     if (x == NULL)
94         goto err;
95     if (x->session_id_length == 0 || x->master_key_length == 0)
96         goto err;
97 
98     /*
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
102      */
103     if (BIO_puts(bp, "CLIENT_RANDOM ") <= 0)
104         goto err;
105 
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;
109     }
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;
115     }
116     if (BIO_puts(bp, "\n") <= 0)
117         goto err;
118 
119     return (1);
120  err:
121     return (0);
122 }
123 #endif /* TRACE_SESSION_KEY */
124 
125 class BSecureSocket::Private {
126 public:
127 								Private();
128 								~Private();
129 
130 			status_t			InitCheck();
131 			status_t			ErrorCode(int returnValue);
132 
133 	static	SSL_CTX*			Context();
134 	static	int					VerifyCallback(int ok, X509_STORE_CTX* ctx);
135 
136 private:
137 	static	void				_CreateContext();
138 
139 public:
140 			SSL*				fSSL;
141 			BIO*				fBIO;
142 	static	int					sDataIndex;
143 
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
152 
153 };
154 
155 
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
163 
164 
165 BSecureSocket::Private::Private()
166 	:
167 	fSSL(NULL),
168 	fBIO(BIO_new(BIO_s_socket()))
169 {
170 }
171 
172 
173 BSecureSocket::Private::~Private()
174 {
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);
182 	}
183 }
184 
185 
186 status_t
187 BSecureSocket::Private::InitCheck()
188 {
189 	if (fBIO == NULL)
190 		return B_NO_MEMORY;
191 	return B_OK;
192 }
193 
194 
195 status_t
196 BSecureSocket::Private::ErrorCode(int returnValue)
197 {
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;
209 
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;
220 	}
221 }
222 
223 
224 /* static */ SSL_CTX*
225 BSecureSocket::Private::Context()
226 {
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);
231 
232 	return sContext;
233 }
234 
235 
236 /*!	This is called each time a certificate verification occurs. It allows us to
237 	catch failures and report them.
238 */
239 /* static */ int
240 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx)
241 {
242 	// OpenSSL already checked the certificate again the certificate store for
243 	// us, and tells the result of that in the ok parameter.
244 
245 	// If the verification succeeded, no need for any further checks. Let's
246 	// proceed with the connection.
247 	if (ok)
248 		return ok;
249 
250 	// The certificate verification failed. Signal this to the BSecureSocket.
251 
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);
256 
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);
263 
264 	if (certificate == NULL)
265 		return 0;
266 
267 	int error = X509_STORE_CTX_get_error(ctx);
268 	const char* message = X509_verify_cert_error_string(error);
269 
270 	// Let the BSecureSocket (or subclass) decide if we should continue anyway.
271 	BCertificate failedCertificate(certificate);
272 	return socket->CertificateVerificationFailed(failedCertificate, message);
273 }
274 
275 
276 #if TRACE_SSL
277 static void apps_ssl_info_callback(const SSL *s, int where, int ret)
278 {
279 	const char *str;
280 	int w;
281 
282 	w=where& ~SSL_ST_MASK;
283 
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";
290 
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));
306 		}
307 	}
308 }
309 #endif
310 
311 
312 /* static */ void
313 BSecureSocket::Private::_CreateContext()
314 {
315 	// We want SSL to report errors in human readable format.
316 	SSL_load_error_strings();
317 
318 	sContext = SSL_CTX_new(SSLv23_method());
319 
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
324 
325 	// Disable legacy protocols. They have known vulnerabilities.
326 	SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
327 
328 	// Disable SSL/TLS compression to prevent the CRIME attack.
329 	SSL_CTX_set_options(sContext, SSL_OP_NO_COMPRESSION);
330 
331 	// Don't bother us with ERROR_WANT_READ.
332 	SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY);
333 
334 	// Setup cipher suites.
335 	// Only accept reasonably secure ones ("HIGH") and disable some known
336 	// broken stuff (https://wiki.openssl.org/index.php/SSL/TLS_Client)
337 	SSL_CTX_set_cipher_list(sContext, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4");
338 
339 	SSL_CTX_set_ecdh_auto(sContext, 1);
340 
341 	// Setup certificate verification
342 	BPath certificateStore;
343 	find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore);
344 	certificateStore.Append("ssl/CARootCertificates.pem");
345 	// TODO we may want to add a non-packaged certificate directory?
346 	// (would make it possible to store user-added certificate exceptions
347 	// there)
348 	SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL);
349 	SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback);
350 
351 	// OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to validate certificate
352 	// chains. This makes the validation stop as soon as a recognized certificate is found in the
353 	// chain, instead of validating the whole chain, then seeing if the root certificate is known.
354 #ifdef X509_V_FLAG_TRUSTED_FIRST
355 	X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new();
356 	X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST);
357 	SSL_CTX_set1_param(sContext, verifyParam);
358 
359 	// TODO we need to free this after freeing the SSL context (which we currently never do)
360 	// X509_VERIFY_PARAM_free(verifyParam);
361 #endif
362 
363 	// Get an unique index number for storing application data in SSL
364 	// structs. We will store a pointer to the BSecureSocket class there.
365 	sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
366 
367 #ifdef TRACE_SESSION_KEY
368 	FILE *keylog = NULL;
369 	const char *logpath = getenv("SSLKEYLOGFILE");
370 	if (logpath)
371 		keylog = fopen(logpath, "w+");
372 	if (keylog) {
373 		fprintf(keylog, "# Key Log File generated by Haiku Network Kit\n");
374 		sKeyLogBIO = BIO_new_fp(keylog, BIO_NOCLOSE);
375 	}
376 #endif
377 }
378 
379 
380 // # pragma mark - BSecureSocket
381 
382 
383 BSecureSocket::BSecureSocket()
384 	:
385 	fPrivate(new(std::nothrow) BSecureSocket::Private())
386 {
387 	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
388 }
389 
390 
391 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
392 	:
393 	fPrivate(new(std::nothrow) BSecureSocket::Private())
394 {
395 	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
396 	Connect(peer, timeout);
397 }
398 
399 
400 BSecureSocket::BSecureSocket(const BSecureSocket& other)
401 	:
402 	BSocket(other)
403 {
404 	fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate);
405 		// TODO: this won't work this way! - write working copy constructor for
406 		// Private.
407 
408 	if (fPrivate != NULL)
409 		SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
410 	else
411 		fInitStatus = B_NO_MEMORY;
412 
413 }
414 
415 
416 BSecureSocket::~BSecureSocket()
417 {
418 	delete fPrivate;
419 }
420 
421 
422 status_t
423 BSecureSocket::Accept(BAbstractSocket*& _socket)
424 {
425 	int fd = -1;
426 	BNetworkAddress peer;
427 	status_t error = AcceptNext(fd, peer);
428 	if (error != B_OK)
429 		return error;
430 	BSecureSocket* socket = new(std::nothrow) BSecureSocket();
431 	ObjectDeleter<BSecureSocket> socketDeleter(socket);
432 	if (socket == NULL || socket->InitCheck() != B_OK) {
433 		close(fd);
434 		return B_NO_MEMORY;
435 	}
436 
437 	socket->_SetTo(fd, fLocal, peer);
438 	error = socket->_SetupAccept();
439 	if (error != B_OK)
440 		return error;
441 
442 	_socket = socket;
443 	socketDeleter.Detach();
444 
445 	return B_OK;
446 }
447 
448 
449 status_t
450 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
451 {
452 	status_t status = InitCheck();
453 	if (status != B_OK)
454 		return status;
455 
456 	status = BSocket::Connect(peer, timeout);
457 	if (status != B_OK)
458 		return status;
459 
460 	return _SetupConnect(peer.HostName().String());
461 }
462 
463 
464 void
465 BSecureSocket::Disconnect()
466 {
467 	if (IsConnected()) {
468 		if (fPrivate->fSSL != NULL)
469 			SSL_shutdown(fPrivate->fSSL);
470 
471 		BSocket::Disconnect();
472 	}
473 }
474 
475 
476 status_t
477 BSecureSocket::WaitForReadable(bigtime_t timeout) const
478 {
479 	if (fInitStatus != B_OK)
480 		return fInitStatus;
481 	if (!IsConnected())
482 		return B_ERROR;
483 
484 	if (SSL_pending(fPrivate->fSSL) > 0)
485 		return B_OK;
486 
487 	return BSocket::WaitForReadable(timeout);
488 }
489 
490 
491 status_t
492 BSecureSocket::InitCheck()
493 {
494 	if (fPrivate == NULL)
495 		return B_NO_MEMORY;
496 
497 	status_t state = fPrivate->InitCheck();
498 	return state;
499 }
500 
501 
502 bool
503 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*)
504 {
505 	// Until apps actually make use of the certificate API, let's keep the old
506 	// behavior and accept all connections, even if the certificate validation
507 	// didn't work.
508 	return true;
509 }
510 
511 
512 //	#pragma mark - BDataIO implementation
513 
514 
515 ssize_t
516 BSecureSocket::Read(void* buffer, size_t size)
517 {
518 	if (!IsConnected())
519 		return B_ERROR;
520 
521 	int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
522 	if (bytesRead >= 0)
523 		return bytesRead;
524 
525 	return fPrivate->ErrorCode(bytesRead);
526 }
527 
528 
529 ssize_t
530 BSecureSocket::Write(const void* buffer, size_t size)
531 {
532 	if (!IsConnected())
533 		return B_ERROR;
534 
535 	int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
536 	if (bytesWritten >= 0)
537 		return bytesWritten;
538 
539 	return fPrivate->ErrorCode(bytesWritten);
540 }
541 
542 
543 status_t
544 BSecureSocket::_SetupCommon(const char* host)
545 {
546 	// Do this only after BSocket::Connect has checked wether we're already
547 	// connected. We don't want to kill an existing SSL session, as that would
548 	// likely crash the protocol loop for it.
549 	if (fPrivate->fSSL != NULL) {
550 		SSL_free(fPrivate->fSSL);
551 	}
552 
553 	fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context());
554 	if (fPrivate->fSSL == NULL) {
555 		BSocket::Disconnect();
556 		return B_NO_MEMORY;
557 	}
558 
559 	BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE);
560 	SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
561 	SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
562 	if (host != NULL) {
563 		BString hostString = host;
564 		if (hostString != "")
565 			SSL_set_tlsext_host_name(fPrivate->fSSL, host);
566 	}
567 
568 
569 	return B_OK;
570 }
571 
572 
573 status_t
574 BSecureSocket::_SetupConnect(const char* host)
575 {
576 	status_t error = _SetupCommon(host);
577 	if (error != B_OK)
578 		return error;
579 
580 	int returnValue = SSL_connect(fPrivate->fSSL);
581 	if (returnValue <= 0) {
582 		TRACE("SSLConnection can't connect\n");
583 		BSocket::Disconnect();
584 		return fPrivate->ErrorCode(returnValue);
585 	}
586 
587 #ifdef TRACE_SESSION_KEY
588 	fprintf(stderr, "SSL SESSION INFO:\n");
589 	//SSL_SESSION_print_fp(stderr, SSL_get_session(fPrivate->fSSL));
590 	SSL_SESSION_print_keylog(fPrivate->sKeyLogBIO, SSL_get_session(fPrivate->fSSL));
591 	SSL_SESSION_print_client_random(fPrivate->sKeyLogBIO, fPrivate->fSSL);
592 	fprintf(stderr, "\n");
593 #endif
594 
595 	return B_OK;
596 }
597 
598 
599 status_t
600 BSecureSocket::_SetupAccept()
601 {
602 	status_t error = _SetupCommon();
603 	if (error != B_OK)
604 		return error;
605 
606 	int returnValue = SSL_accept(fPrivate->fSSL);
607 	if (returnValue <= 0) {
608 		TRACE("SSLConnection can't accept\n");
609 		BSocket::Disconnect();
610 		return fPrivate->ErrorCode(returnValue);
611 	}
612 
613 	return B_OK;
614 }
615 
616 
617 #else	// OPENSSL_ENABLED
618 
619 
620 // #pragma mark - No-SSL stubs
621 
622 
623 BSecureSocket::BSecureSocket()
624 {
625 }
626 
627 
628 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
629 {
630 	fInitStatus = B_UNSUPPORTED;
631 }
632 
633 
634 BSecureSocket::BSecureSocket(const BSecureSocket& other)
635 	:
636 	BSocket(other)
637 {
638 }
639 
640 
641 BSecureSocket::~BSecureSocket()
642 {
643 }
644 
645 
646 bool
647 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*)
648 {
649 	(void)certificate;
650 	return false;
651 }
652 
653 
654 status_t
655 BSecureSocket::Accept(BAbstractSocket*& _socket)
656 {
657 	return B_UNSUPPORTED;
658 }
659 
660 
661 status_t
662 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
663 {
664 	return fInitStatus = B_UNSUPPORTED;
665 }
666 
667 
668 void
669 BSecureSocket::Disconnect()
670 {
671 }
672 
673 
674 status_t
675 BSecureSocket::WaitForReadable(bigtime_t timeout) const
676 {
677 	return B_UNSUPPORTED;
678 }
679 
680 
681 //	#pragma mark - BDataIO implementation
682 
683 
684 ssize_t
685 BSecureSocket::Read(void* buffer, size_t size)
686 {
687 	return B_UNSUPPORTED;
688 }
689 
690 
691 ssize_t
692 BSecureSocket::Write(const void* buffer, size_t size)
693 {
694 	return B_UNSUPPORTED;
695 }
696 
697 
698 status_t
699 BSecureSocket::InitCheck()
700 {
701 	return B_UNSUPPORTED;
702 }
703 
704 
705 status_t
706 BSecureSocket::_SetupCommon(const char* host)
707 {
708 	return B_UNSUPPORTED;
709 }
710 
711 
712 status_t
713 BSecureSocket::_SetupConnect(const char* host)
714 {
715 	return B_UNSUPPORTED;
716 }
717 
718 
719 status_t
720 BSecureSocket::_SetupAccept()
721 {
722 	return B_UNSUPPORTED;
723 }
724 
725 
726 #endif	// !OPENSSL_ENABLED
727