10e478f5aSAxel Dörfler/*
2c9dd7d0dSRene Gollent * Copyright 2013-2016 Haiku, Inc.
3c500331fSAxel Dörfler * Copyright 2011-2015, Axel D��rfler, axeld@pinc-software.de.
4c9dd7d0dSRene Gollent * Copyright 2016, Rene Gollent, rene@gollent.com.
50e478f5aSAxel Dörfler * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
60e478f5aSAxel Dörfler * Distributed under the terms of the MIT License.
70e478f5aSAxel Dörfler */
80e478f5aSAxel Dörfler
90e478f5aSAxel Dörfler
100e478f5aSAxel Dörfler#include <SecureSocket.h>
110e478f5aSAxel Dörfler
120e478f5aSAxel Dörfler#ifdef OPENSSL_ENABLED
130e478f5aSAxel Dörfler#	include <openssl/ssl.h>
14e62e979eSFrançois Revol#	include <openssl/ssl3.h> // for TRACE_SESSION_KEY only
15b515f3b4SAugustin Cavalier#	include <openssl/err.h>
160e478f5aSAxel Dörfler#endif
170e478f5aSAxel Dörfler
18b70c72a6SAdrien Destugues#include <pthread.h>
19b70c72a6SAdrien Destugues
205ebdc799SAdrien Destugues#include <Certificate.h>
215ebdc799SAdrien Destugues#include <FindDirectory.h>
225ebdc799SAdrien Destugues#include <Path.h>
235ebdc799SAdrien Destugues
24c9dd7d0dSRene Gollent#include <AutoDeleter.h>
25c9dd7d0dSRene Gollent
265ebdc799SAdrien Destugues#include "CertificatePrivate.h"
275ebdc799SAdrien Destugues
280e478f5aSAxel Dörfler
290e478f5aSAxel Dörfler//#define TRACE_SOCKET
300e478f5aSAxel Dörfler#ifdef TRACE_SOCKET
310e478f5aSAxel Dörfler#	define TRACE(x...) printf(x)
320e478f5aSAxel Dörfler#else
330e478f5aSAxel Dörfler#	define TRACE(x...) ;
340e478f5aSAxel Dörfler#endif
350e478f5aSAxel Dörfler
36e62e979eSFrançois Revol//#define TRACE_SESSION_KEY
37e62e979eSFrançois Revol
380e478f5aSAxel Dörfler
390e478f5aSAxel Dörfler#ifdef OPENSSL_ENABLED
400e478f5aSAxel Dörfler
41e62e979eSFrançois Revol#ifdef TRACE_SESSION_KEY
42e62e979eSFrançois Revol#if OPENSSL_VERSION_NUMBER < 0x10100000L
43e62e979eSFrançois Revol/*
44e62e979eSFrançois Revol * print session id and master key in NSS keylog format (RSA
45e62e979eSFrançois Revol * Session-ID:<session id> Master-Key:<master key>)
46e62e979eSFrançois Revol */
47e62e979eSFrançois Revolint SSL_SESSION_print_keylog(BIO *bp, const SSL_SESSION *x)
48e62e979eSFrançois Revol{
4920312cfeSAdrien Destugues	size_t i;
5020312cfeSAdrien Destugues
5120312cfeSAdrien Destugues	if (x == NULL)
5220312cfeSAdrien Destugues		goto err;
5320312cfeSAdrien Destugues	if (x->session_id_length == 0 || x->master_key_length == 0)
5420312cfeSAdrien Destugues		goto err;
5520312cfeSAdrien Destugues
5620312cfeSAdrien Destugues	// the RSA prefix is required by the format's definition although there's
5720312cfeSAdrien Destugues	// nothing RSA-specific in the output, therefore, we don't have to check if
5820312cfeSAdrien Destugues	// the cipher suite is based on RSA
5920312cfeSAdrien Destugues	if (BIO_puts(bp, "RSA ") <= 0)
6020312cfeSAdrien Destugues		goto err;
6120312cfeSAdrien Destugues
6220312cfeSAdrien Destugues	if (BIO_puts(bp, "Session-ID:") <= 0)
6320312cfeSAdrien Destugues		goto err;
6420312cfeSAdrien Destugues	for (i = 0; i < x->session_id_length; i++) {
6520312cfeSAdrien Destugues		if (BIO_printf(bp, "%02X", x->session_id[i]) <= 0)
6620312cfeSAdrien Destugues			goto err;
6720312cfeSAdrien Destugues	}
6820312cfeSAdrien Destugues	if (BIO_puts(bp, " Master-Key:") <= 0)
6920312cfeSAdrien Destugues		goto err;
7020312cfeSAdrien Destugues	for (i = 0; i < (size_t)x->master_key_length; i++) {
7120312cfeSAdrien Destugues		if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
7220312cfeSAdrien Destugues			goto err;
7320312cfeSAdrien Destugues	}
7420312cfeSAdrien Destugues	if (BIO_puts(bp, "\n") <= 0)
7520312cfeSAdrien Destugues		goto err;
7620312cfeSAdrien Destugues
7720312cfeSAdrien Destugues	return (1);
7820312cfeSAdrien Destugueserr:
7920312cfeSAdrien Destugues	return (0);
80e62e979eSFrançois Revol}
8120312cfeSAdrien Destugues
8220312cfeSAdrien Destugues
83e62e979eSFrançois Revol#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
8420312cfeSAdrien Destugues
8520312cfeSAdrien Destugues
8620312cfeSAdrien Destugues// print client random id and master key in NSS keylog format
8720312cfeSAdrien Destugues// as session ID is not enough.
88e62e979eSFrançois Revolint SSL_SESSION_print_client_random(BIO *bp, const SSL *ssl)
89e62e979eSFrançois Revol{
90e62e979eSFrançois Revol	const SSL_SESSION *x = SSL_get_session(ssl);
9120312cfeSAdrien Destugues	size_t i;
9220312cfeSAdrien Destugues
9320312cfeSAdrien Destugues	if (x == NULL)
9420312cfeSAdrien Destugues		goto err;
9520312cfeSAdrien Destugues	if (x->session_id_length == 0 || x->master_key_length == 0)
9620312cfeSAdrien Destugues		goto err;
9720312cfeSAdrien Destugues
9820312cfeSAdrien Destugues	if (BIO_puts(bp, "CLIENT_RANDOM ") <= 0)
9920312cfeSAdrien Destugues		goto err;
10020312cfeSAdrien Destugues
10120312cfeSAdrien Destugues	for (i = 0; i < sizeof(ssl->s3->client_random); i++) {
10220312cfeSAdrien Destugues		if (BIO_printf(bp, "%02X", ssl->s3->client_random[i]) <= 0)
10320312cfeSAdrien Destugues			goto err;
10420312cfeSAdrien Destugues	}
10520312cfeSAdrien Destugues	if (BIO_puts(bp, " ") <= 0)
10620312cfeSAdrien Destugues		goto err;
10720312cfeSAdrien Destugues	for (i = 0; i < (size_t)x->master_key_length; i++) {
10820312cfeSAdrien Destugues		if (BIO_printf(bp, "%02X", x->master_key[i]) <= 0)
10920312cfeSAdrien Destugues			goto err;
11020312cfeSAdrien Destugues	}
11120312cfeSAdrien Destugues	if (BIO_puts(bp, "\n") <= 0)
11220312cfeSAdrien Destugues		goto err;
11320312cfeSAdrien Destugues
11420312cfeSAdrien Destugues	return (1);
11520312cfeSAdrien Destugueserr:
11620312cfeSAdrien Destugues	return (0);
117e62e979eSFrançois Revol}
11820312cfeSAdrien Destugues
11920312cfeSAdrien Destugues
120e62e979eSFrançois Revol#endif /* TRACE_SESSION_KEY */
1210e478f5aSAxel Dörfler
1220e478f5aSAxel Dörflerclass BSecureSocket::Private {
1230e478f5aSAxel Dörflerpublic:
124b70c72a6SAdrien Destugues								Private();
125b70c72a6SAdrien Destugues								~Private();
126b70c72a6SAdrien Destugues
127b70c72a6SAdrien Destugues			status_t			InitCheck();
128c500331fSAxel Dörfler			status_t			ErrorCode(int returnValue);
129b70c72a6SAdrien Destugues
1305ebdc799SAdrien Destugues	static	SSL_CTX*			Context();
1315ebdc799SAdrien Destugues	static	int					VerifyCallback(int ok, X509_STORE_CTX* ctx);
132c500331fSAxel Dörfler
133b70c72a6SAdrien Destuguesprivate:
134c500331fSAxel Dörfler	static	void				_CreateContext();
135c500331fSAxel Dörfler
1365ebdc799SAdrien Destuguespublic:
1370e478f5aSAxel Dörfler			SSL*				fSSL;
1380e478f5aSAxel Dörfler			BIO*				fBIO;
1395ebdc799SAdrien Destugues	static	int					sDataIndex;
140c500331fSAxel Dörfler
1415ebdc799SAdrien Destuguesprivate:
1425ebdc799SAdrien Destugues	static	SSL_CTX*			sContext;
1435ebdc799SAdrien Destugues		// FIXME When do we SSL_CTX_free it?
144b70c72a6SAdrien Destugues	static	pthread_once_t		sInitOnce;
145e62e979eSFrançois Revol#ifdef TRACE_SESSION_KEY
146e62e979eSFrançois Revolpublic:
147e62e979eSFrançois Revol	static	BIO*				sKeyLogBIO;
148e62e979eSFrançois Revol#endif
149e62e979eSFrançois Revol
1500e478f5aSAxel Dörfler};
1510e478f5aSAxel Dörfler
1520e478f5aSAxel Dörfler
1535ebdc799SAdrien Destugues/* static */ SSL_CTX* BSecureSocket::Private::sContext = NULL;
1545ebdc799SAdrien Destugues/* static */ int BSecureSocket::Private::sDataIndex;
155b70c72a6SAdrien Destugues/* static */ pthread_once_t BSecureSocket::Private::sInitOnce
156b70c72a6SAdrien Destugues	= PTHREAD_ONCE_INIT;
157e62e979eSFrançois Revol#ifdef TRACE_SESSION_KEY
158e62e979eSFrançois Revol/* static */ BIO* BSecureSocket::Private::sKeyLogBIO = NULL;
159e62e979eSFrançois Revol#endif
160b70c72a6SAdrien Destugues
161b70c72a6SAdrien Destugues
162b70c72a6SAdrien DestuguesBSecureSocket::Private::Private()
163b70c72a6SAdrien Destugues	:
164b70c72a6SAdrien Destugues	fSSL(NULL),
165b70c72a6SAdrien Destugues	fBIO(BIO_new(BIO_s_socket()))
166b70c72a6SAdrien Destugues{
167b70c72a6SAdrien Destugues}
168b70c72a6SAdrien Destugues
169b70c72a6SAdrien Destugues
170b70c72a6SAdrien DestuguesBSecureSocket::Private::~Private()
171b70c72a6SAdrien Destugues{
172b70c72a6SAdrien Destugues	// SSL_free also frees the underlying BIO.
173b70c72a6SAdrien Destugues	if (fSSL != NULL)
174b70c72a6SAdrien Destugues		SSL_free(fSSL);
175547c1486SAdrien Destugues	else {
176547c1486SAdrien Destugues		// The SSL session was never created (Connect() was not called or
177547c1486SAdrien Destugues		// failed). We must free the BIO we created in the constructor.
178547c1486SAdrien Destugues		BIO_free(fBIO);
179547c1486SAdrien Destugues	}
180b70c72a6SAdrien Destugues}
181b70c72a6SAdrien Destugues
182b70c72a6SAdrien Destugues
183b70c72a6SAdrien Destuguesstatus_t
184b70c72a6SAdrien DestuguesBSecureSocket::Private::InitCheck()
185b70c72a6SAdrien Destugues{
186b70c72a6SAdrien Destugues	if (fBIO == NULL)
187b70c72a6SAdrien Destugues		return B_NO_MEMORY;
188b70c72a6SAdrien Destugues	return B_OK;
189b70c72a6SAdrien Destugues}
190b70c72a6SAdrien Destugues
191b70c72a6SAdrien Destugues
192c500331fSAxel Dörflerstatus_t
193c500331fSAxel DörflerBSecureSocket::Private::ErrorCode(int returnValue)
194b70c72a6SAdrien Destugues{
195c500331fSAxel Dörfler	int error = SSL_get_error(fSSL, returnValue);
196c500331fSAxel Dörfler	switch (error) {
197c500331fSAxel Dörfler		case SSL_ERROR_NONE:
198c500331fSAxel Dörfler			// Shouldn't happen...
199c500331fSAxel Dörfler			return B_NO_ERROR;
200c500331fSAxel Dörfler		case SSL_ERROR_ZERO_RETURN:
201c500331fSAxel Dörfler			// Socket is closed
202c500331fSAxel Dörfler			return B_CANCELED;
203c500331fSAxel Dörfler		case SSL_ERROR_SSL:
204c500331fSAxel Dörfler			// Probably no certificate
205c500331fSAxel Dörfler			return B_NOT_ALLOWED;
206c500331fSAxel Dörfler
2077dba237fSAdrien Destugues		case SSL_ERROR_SYSCALL:
2087dba237fSAdrien Destugues		{
2097dba237fSAdrien Destugues			unsigned long error2;
2107dba237fSAdrien Destugues			// Check for extra errors in the error stack...
21120312cfeSAdrien Destugues			for (;;) {
2127dba237fSAdrien Destugues				error2 = ERR_get_error();
2137dba237fSAdrien Destugues				if (error2 == 0)
2147dba237fSAdrien Destugues					break;
2157dba237fSAdrien Destugues				fprintf(stderr, "SSL ERR %s\n", ERR_error_string(error2, NULL));
2167dba237fSAdrien Destugues			}
2177dba237fSAdrien Destugues
2187dba237fSAdrien Destugues			if (returnValue == 0)
2197dba237fSAdrien Destugues			{
2207dba237fSAdrien Destugues				// unexpected EOF, the remote host closed the socket without
2217dba237fSAdrien Destugues				// telling us why.
2227dba237fSAdrien Destugues				return ECONNREFUSED;
2237dba237fSAdrien Destugues			}
2247dba237fSAdrien Destugues
2257dba237fSAdrien Destugues			if (returnValue == -1)
2267dba237fSAdrien Destugues			{
2277dba237fSAdrien Destugues				fprintf(stderr, "SSL %s\n", ERR_error_string(error, NULL));
2287dba237fSAdrien Destugues				return errno;
2297dba237fSAdrien Destugues			}
2307dba237fSAdrien Destugues
2317dba237fSAdrien Destugues			fprintf(stderr, "SSL %s\n", ERR_error_string(error, NULL));
2327dba237fSAdrien Destugues			return B_ERROR;
2337dba237fSAdrien Destugues		}
2347dba237fSAdrien Destugues
235c500331fSAxel Dörfler		case SSL_ERROR_WANT_READ:
236c500331fSAxel Dörfler		case SSL_ERROR_WANT_WRITE:
237c500331fSAxel Dörfler		case SSL_ERROR_WANT_CONNECT:
238c500331fSAxel Dörfler		case SSL_ERROR_WANT_ACCEPT:
239c500331fSAxel Dörfler		case SSL_ERROR_WANT_X509_LOOKUP:
240c500331fSAxel Dörfler		default:
241c500331fSAxel Dörfler			// TODO: translate SSL error codes!
242b515f3b4SAugustin Cavalier			fprintf(stderr, "SSL %s\n", ERR_error_string(error, NULL));
243c500331fSAxel Dörfler			return B_ERROR;
244c500331fSAxel Dörfler	}
245b70c72a6SAdrien Destugues}
2465ebdc799SAdrien Destugues
2475ebdc799SAdrien Destugues
2485ebdc799SAdrien Destugues/* static */ SSL_CTX*
2495ebdc799SAdrien DestuguesBSecureSocket::Private::Context()
2505ebdc799SAdrien Destugues{
2515ebdc799SAdrien Destugues	// We use lazy initialisation here, because reading certificates from disk
2525ebdc799SAdrien Destugues	// and parsing them is a relatively long operation and uses some memory.
2535ebdc799SAdrien Destugues	// We don't want programs that don't use SSL to waste resources with that.
254c500331fSAxel Dörfler	pthread_once(&sInitOnce, _CreateContext);
2555ebdc799SAdrien Destugues
2565ebdc799SAdrien Destugues	return sContext;
2575ebdc799SAdrien Destugues}
2585ebdc799SAdrien Destugues
2595ebdc799SAdrien Destugues
260c500331fSAxel Dörfler/*!	This is called each time a certificate verification occurs. It allows us to
261c500331fSAxel Dörfler	catch failures and report them.
262c500331fSAxel Dörfler*/
2635ebdc799SAdrien Destugues/* static */ int
2645ebdc799SAdrien DestuguesBSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx)
2655ebdc799SAdrien Destugues{
2665ebdc799SAdrien Destugues	// OpenSSL already checked the certificate again the certificate store for
2675ebdc799SAdrien Destugues	// us, and tells the result of that in the ok parameter.
268b70c72a6SAdrien Destugues
2695ebdc799SAdrien Destugues	// If the verification succeeded, no need for any further checks. Let's
2705ebdc799SAdrien Destugues	// proceed with the connection.
2715ebdc799SAdrien Destugues	if (ok)
2725ebdc799SAdrien Destugues		return ok;
2735ebdc799SAdrien Destugues
274b70c72a6SAdrien Destugues	// The certificate verification failed. Signal this to the BSecureSocket.
2755ebdc799SAdrien Destugues
2765ebdc799SAdrien Destugues	// First of all, get the affected BSecureSocket
2775ebdc799SAdrien Destugues	SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx,
2785ebdc799SAdrien Destugues		SSL_get_ex_data_X509_STORE_CTX_idx());
2795ebdc799SAdrien Destugues	BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex);
2805ebdc799SAdrien Destugues
2815ebdc799SAdrien Destugues	// Get the certificate that we could not validate (this may not be the one
2825ebdc799SAdrien Destugues	// we got from the server, but something higher up in the certificate
2835ebdc799SAdrien Destugues	// chain)
284547c1486SAdrien Destugues	X509* x509 = X509_STORE_CTX_get_current_cert(ctx);
285ab390d3aSAdrien Destugues	BCertificate::Private* certificate
286ab390d3aSAdrien Destugues		= new(std::nothrow) BCertificate::Private(x509);
287547c1486SAdrien Destugues
288547c1486SAdrien Destugues	if (certificate == NULL)
289547c1486SAdrien Destugues		return 0;
2905ebdc799SAdrien Destugues
291c86ad7f9SAdrien Destugues	int error = X509_STORE_CTX_get_error(ctx);
292c86ad7f9SAdrien Destugues	const char* message = X509_verify_cert_error_string(error);
293c86ad7f9SAdrien Destugues
294b70c72a6SAdrien Destugues	// Let the BSecureSocket (or subclass) decide if we should continue anyway.
295c99d7ea4SJulian Harnath	BCertificate failedCertificate(certificate);
296c86ad7f9SAdrien Destugues	return socket->CertificateVerificationFailed(failedCertificate, message);
2975ebdc799SAdrien Destugues}
2985ebdc799SAdrien Destugues
2995ebdc799SAdrien Destugues
300ed6d3d88SAdrien Destugues#if TRACE_SSL
301ed6d3d88SAdrien Destuguesstatic void apps_ssl_info_callback(const SSL *s, int where, int ret)
302ed6d3d88SAdrien Destugues{
303ed6d3d88SAdrien Destugues	const char *str;
304ed6d3d88SAdrien Destugues	int w;
305ed6d3d88SAdrien Destugues
306ed6d3d88SAdrien Destugues	w=where& ~SSL_ST_MASK;
307ed6d3d88SAdrien Destugues
308e1ca6769SJérôme Duval	if (w & SSL_ST_CONNECT)
309e1ca6769SJérôme Duval		str="SSL_connect";
310e1ca6769SJérôme Duval	else if (w & SSL_ST_ACCEPT)
311e1ca6769SJérôme Duval		str="SSL_accept";
312e1ca6769SJérôme Duval	else
313e1ca6769SJérôme Duval		str="undefined";
314e1ca6769SJérôme Duval
315e1ca6769SJérôme Duval	if (where & SSL_CB_LOOP) {
31620312cfeSAdrien Destugues		fprintf(stderr, "%s:%s\n", str, SSL_state_string_long(s));
317e1ca6769SJérôme Duval	} else if (where & SSL_CB_ALERT) {
318e1ca6769SJérôme Duval		str = (where & SSL_CB_READ) ? "read" : "write";
31920312cfeSAdrien Destugues		fprintf(stderr, "SSL3 alert %s:%s:%s\n",
320ed6d3d88SAdrien Destugues				str,
321ed6d3d88SAdrien Destugues				SSL_alert_type_string_long(ret),
322ed6d3d88SAdrien Destugues				SSL_alert_desc_string_long(ret));
323e1ca6769SJérôme Duval	} else if (where & SSL_CB_EXIT) {
324ed6d3d88SAdrien Destugues		if (ret == 0)
32520312cfeSAdrien Destugues			fprintf(stderr, "%s:failed in %s\n",
32620312cfeSAdrien Destugues					str, SSL_state_string_long(s));
327e1ca6769SJérôme Duval		else if (ret < 0) {
32820312cfeSAdrien Destugues			fprintf(stderr, "%s:error in %s\n",
32920312cfeSAdrien Destugues					str, SSL_state_string_long(s));
330ed6d3d88SAdrien Destugues		}
331ed6d3d88SAdrien Destugues	}
332ed6d3d88SAdrien Destugues}
33320312cfeSAdrien Destugues
33420312cfeSAdrien Destugues
335ed6d3d88SAdrien Destugues#endif
336ed6d3d88SAdrien Destugues
337ed6d3d88SAdrien Destugues
338c500331fSAxel Dörfler/* static */ void
339c500331fSAxel DörflerBSecureSocket::Private::_CreateContext()
340c500331fSAxel Dörfler{
341ed6d3d88SAdrien Destugues	// We want SSL to report errors in human readable format.
342ed6d3d88SAdrien Destugues	SSL_load_error_strings();
343ed6d3d88SAdrien Destugues
34420312cfeSAdrien Destugues	// "SSLv23" means "any SSL or TLS version". We disable SSL v2 and v3 below
34520312cfeSAdrien Destugues	// to keep only TLS 1.0 and above.
346c500331fSAxel Dörfler	sContext = SSL_CTX_new(SSLv23_method());
347c500331fSAxel Dörfler
348ed6d3d88SAdrien Destugues#if TRACE_SSL
349ed6d3d88SAdrien Destugues	// For debugging purposes: get all SSL messages to the standard error.
350ed6d3d88SAdrien Destugues	SSL_CTX_set_info_callback(sContext, apps_ssl_info_callback);
351ed6d3d88SAdrien Destugues#endif
352ed6d3d88SAdrien Destugues
353c500331fSAxel Dörfler	// Disable legacy protocols. They have known vulnerabilities.
354c500331fSAxel Dörfler	SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
355c500331fSAxel Dörfler
356b39f9357SAugustin Cavalier	// Disable SSL/TLS compression to prevent the CRIME attack.
357b39f9357SAugustin Cavalier	SSL_CTX_set_options(sContext, SSL_OP_NO_COMPRESSION);
358b39f9357SAugustin Cavalier
3591f70a8dfSAdrien Destugues	// Don't bother us with ERROR_WANT_READ.
3601f70a8dfSAdrien Destugues	SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY);
3611f70a8dfSAdrien Destugues
36244ffe7c2SAugustin Cavalier	// Setup cipher suites.
363d1805b9aSAdrien Destugues	// Only accept reasonably secure ones ("HIGH") and disable some known
364d1805b9aSAdrien Destugues	// broken stuff (https://wiki.openssl.org/index.php/SSL/TLS_Client)
3657dba237fSAdrien Destugues	SSL_CTX_set_cipher_list(sContext, "HIGH:!aNULL:!PSK:!SRP:!MD5:!RC4");
366d1805b9aSAdrien Destugues
36700a3a794SAugustin Cavalier	SSL_CTX_set_ecdh_auto(sContext, 1);
36800a3a794SAugustin Cavalier
369c500331fSAxel Dörfler	// Setup certificate verification
370c500331fSAxel Dörfler	BPath certificateStore;
371c500331fSAxel Dörfler	find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore);
372c500331fSAxel Dörfler	certificateStore.Append("ssl/CARootCertificates.pem");
373c500331fSAxel Dörfler	// TODO we may want to add a non-packaged certificate directory?
374c500331fSAxel Dörfler	// (would make it possible to store user-added certificate exceptions
375c500331fSAxel Dörfler	// there)
376c500331fSAxel Dörfler	SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL);
377c500331fSAxel Dörfler	SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback);
378c500331fSAxel Dörfler
37920312cfeSAdrien Destugues	// OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to
38020312cfeSAdrien Destugues	// validate certificate chains. This makes the validation stop as soon as a
38120312cfeSAdrien Destugues	// recognized certificate is found in the chain, instead of validating the
38220312cfeSAdrien Destugues	// whole chain, then seeing if the root certificate is known.
383d3b6b9e5SAdrien Destugues#ifdef X509_V_FLAG_TRUSTED_FIRST
384d3b6b9e5SAdrien Destugues	X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new();
385d3b6b9e5SAdrien Destugues	X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST);
386d3b6b9e5SAdrien Destugues	SSL_CTX_set1_param(sContext, verifyParam);
387d3b6b9e5SAdrien Destugues
38820312cfeSAdrien Destugues	// TODO we need to free this after freeing the SSL context (which we
38920312cfeSAdrien Destugues	// currently never do)
390d3b6b9e5SAdrien Destugues	// X509_VERIFY_PARAM_free(verifyParam);
391d3b6b9e5SAdrien Destugues#endif
392d3b6b9e5SAdrien Destugues
393c500331fSAxel Dörfler	// Get an unique index number for storing application data in SSL
394c500331fSAxel Dörfler	// structs. We will store a pointer to the BSecureSocket class there.
395c500331fSAxel Dörfler	sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
396e62e979eSFrançois Revol
397e62e979eSFrançois Revol#ifdef TRACE_SESSION_KEY
398e62e979eSFrançois Revol	FILE *keylog = NULL;
399e62e979eSFrançois Revol	const char *logpath = getenv("SSLKEYLOGFILE");
400e62e979eSFrançois Revol	if (logpath)
401e62e979eSFrançois Revol		keylog = fopen(logpath, "w+");
402e62e979eSFrançois Revol	if (keylog) {
403e62e979eSFrançois Revol		fprintf(keylog, "# Key Log File generated by Haiku Network Kit\n");
404e62e979eSFrançois Revol		sKeyLogBIO = BIO_new_fp(keylog, BIO_NOCLOSE);
405e62e979eSFrançois Revol	}
406e62e979eSFrançois Revol#endif
407c500331fSAxel Dörfler}
408c500331fSAxel Dörfler
409c500331fSAxel Dörfler
4105ebdc799SAdrien Destugues// # pragma mark - BSecureSocket
4115ebdc799SAdrien Destugues
4125ebdc799SAdrien Destugues
4130e478f5aSAxel DörflerBSecureSocket::BSecureSocket()
4140e478f5aSAxel Dörfler	:
415547c1486SAdrien Destugues	fPrivate(new(std::nothrow) BSecureSocket::Private())
4160e478f5aSAxel Dörfler{
417b70c72a6SAdrien Destugues	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
4180e478f5aSAxel Dörfler}
4190e478f5aSAxel Dörfler
4200e478f5aSAxel Dörfler
4210e478f5aSAxel DörflerBSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
4220e478f5aSAxel Dörfler	:
423547c1486SAdrien Destugues	fPrivate(new(std::nothrow) BSecureSocket::Private())
4240e478f5aSAxel Dörfler{
425b70c72a6SAdrien Destugues	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
4260e478f5aSAxel Dörfler	Connect(peer, timeout);
4270e478f5aSAxel Dörfler}
4280e478f5aSAxel Dörfler
4290e478f5aSAxel Dörfler
4300e478f5aSAxel DörflerBSecureSocket::BSecureSocket(const BSecureSocket& other)
4310e478f5aSAxel Dörfler	:
4320e478f5aSAxel Dörfler	BSocket(other)
4330e478f5aSAxel Dörfler{
434547c1486SAdrien Destugues	fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate);
435b70c72a6SAdrien Destugues		// TODO: this won't work this way! - write working copy constructor for
436b70c72a6SAdrien Destugues		// Private.
437b70c72a6SAdrien Destugues
438b70c72a6SAdrien Destugues	if (fPrivate != NULL)
4395ebdc799SAdrien Destugues		SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
440b70c72a6SAdrien Destugues	else
4410e478f5aSAxel Dörfler		fInitStatus = B_NO_MEMORY;
4425ebdc799SAdrien Destugues
4430e478f5aSAxel Dörfler}
4440e478f5aSAxel Dörfler
4450e478f5aSAxel Dörfler
4460e478f5aSAxel DörflerBSecureSocket::~BSecureSocket()
4470e478f5aSAxel Dörfler{
448b70c72a6SAdrien Destugues	delete fPrivate;
4490e478f5aSAxel Dörfler}
4500e478f5aSAxel Dörfler
4510e478f5aSAxel Dörfler
452c9dd7d0dSRene Gollentstatus_t
453c9dd7d0dSRene GollentBSecureSocket::Accept(BAbstractSocket*& _socket)
454c9dd7d0dSRene Gollent{
455c9dd7d0dSRene Gollent	int fd = -1;
456c9dd7d0dSRene Gollent	BNetworkAddress peer;
457c9dd7d0dSRene Gollent	status_t error = AcceptNext(fd, peer);
458c9dd7d0dSRene Gollent	if (error != B_OK)
459c9dd7d0dSRene Gollent		return error;
460c9dd7d0dSRene Gollent	BSecureSocket* socket = new(std::nothrow) BSecureSocket();
461c9dd7d0dSRene Gollent	ObjectDeleter<BSecureSocket> socketDeleter(socket);
462c9dd7d0dSRene Gollent	if (socket == NULL || socket->InitCheck() != B_OK) {
463c9dd7d0dSRene Gollent		close(fd);
464c9dd7d0dSRene Gollent		return B_NO_MEMORY;
465c9dd7d0dSRene Gollent	}
466c9dd7d0dSRene Gollent
467c9dd7d0dSRene Gollent	socket->_SetTo(fd, fLocal, peer);
468c9dd7d0dSRene Gollent	error = socket->_SetupAccept();
469c9dd7d0dSRene Gollent	if (error != B_OK)
470c9dd7d0dSRene Gollent		return error;
471c9dd7d0dSRene Gollent
472c9dd7d0dSRene Gollent	_socket = socket;
473c9dd7d0dSRene Gollent	socketDeleter.Detach();
474c9dd7d0dSRene Gollent
475c9dd7d0dSRene Gollent	return B_OK;
476c9dd7d0dSRene Gollent}
477c9dd7d0dSRene Gollent
478c9dd7d0dSRene Gollent
4790e478f5aSAxel Dörflerstatus_t
4800e478f5aSAxel DörflerBSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
4810e478f5aSAxel Dörfler{
482c6149613SAdrien Destugues	status_t status = InitCheck();
4830e478f5aSAxel Dörfler	if (status != B_OK)
4840e478f5aSAxel Dörfler		return status;
4850e478f5aSAxel Dörfler
486c6149613SAdrien Destugues	status = BSocket::Connect(peer, timeout);
487c6149613SAdrien Destugues	if (status != B_OK)
488c6149613SAdrien Destugues		return status;
4890e478f5aSAxel Dörfler
490e1c98ceaSMark Hellegers	return _SetupConnect(peer.HostName().String());
4910e478f5aSAxel Dörfler}
4920e478f5aSAxel Dörfler
4930e478f5aSAxel Dörfler
4940e478f5aSAxel Dörflervoid
4950e478f5aSAxel DörflerBSecureSocket::Disconnect()
4960e478f5aSAxel Dörfler{
4970e478f5aSAxel Dörfler	if (IsConnected()) {
498c500331fSAxel Dörfler		if (fPrivate->fSSL != NULL)
4990e478f5aSAxel Dörfler			SSL_shutdown(fPrivate->fSSL);
5005bdd4157SAdrien Destugues
5015bdd4157SAdrien Destugues		BSocket::Disconnect();
5020e478f5aSAxel Dörfler	}
5030e478f5aSAxel Dörfler}
5040e478f5aSAxel Dörfler
5050e478f5aSAxel Dörfler
5060e478f5aSAxel Dörflerstatus_t
5070e478f5aSAxel DörflerBSecureSocket::WaitForReadable(bigtime_t timeout) const
5080e478f5aSAxel Dörfler{
5090e478f5aSAxel Dörfler	if (fInitStatus != B_OK)
5100e478f5aSAxel Dörfler		return fInitStatus;
5110e478f5aSAxel Dörfler	if (!IsConnected())
5120e478f5aSAxel Dörfler		return B_ERROR;
5130e478f5aSAxel Dörfler
5140e478f5aSAxel Dörfler	if (SSL_pending(fPrivate->fSSL) > 0)
5150e478f5aSAxel Dörfler		return B_OK;
5160e478f5aSAxel Dörfler
5170e478f5aSAxel Dörfler	return BSocket::WaitForReadable(timeout);
5180e478f5aSAxel Dörfler}
5190e478f5aSAxel Dörfler
5200e478f5aSAxel Dörfler
521c6149613SAdrien Destuguesstatus_t
522c6149613SAdrien DestuguesBSecureSocket::InitCheck()
523c6149613SAdrien Destugues{
524c6149613SAdrien Destugues	if (fPrivate == NULL)
525c6149613SAdrien Destugues		return B_NO_MEMORY;
526c6149613SAdrien Destugues
527c6149613SAdrien Destugues	status_t state = fPrivate->InitCheck();
528c6149613SAdrien Destugues	return state;
529c6149613SAdrien Destugues}
530c6149613SAdrien Destugues
531c6149613SAdrien Destugues
5325ebdc799SAdrien Destuguesbool
533c86ad7f9SAdrien DestuguesBSecureSocket::CertificateVerificationFailed(BCertificate&, const char*)
5345ebdc799SAdrien Destugues{
535a830ec9aSAugustin Cavalier	return false;
5365ebdc799SAdrien Destugues}
5375ebdc799SAdrien Destugues
5385ebdc799SAdrien Destugues
5390e478f5aSAxel Dörfler//	#pragma mark - BDataIO implementation
5400e478f5aSAxel Dörfler
5410e478f5aSAxel Dörfler
5420e478f5aSAxel Dörflerssize_t
5430e478f5aSAxel DörflerBSecureSocket::Read(void* buffer, size_t size)
5440e478f5aSAxel Dörfler{
5450e478f5aSAxel Dörfler	if (!IsConnected())
5460e478f5aSAxel Dörfler		return B_ERROR;
5470e478f5aSAxel Dörfler
5480e478f5aSAxel Dörfler	int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
54902deec64SHamish Morrison	if (bytesRead >= 0)
5500e478f5aSAxel Dörfler		return bytesRead;
5510e478f5aSAxel Dörfler
552c500331fSAxel Dörfler	return fPrivate->ErrorCode(bytesRead);
5530e478f5aSAxel Dörfler}
5540e478f5aSAxel Dörfler
5550e478f5aSAxel Dörfler
5560e478f5aSAxel Dörflerssize_t
5570e478f5aSAxel DörflerBSecureSocket::Write(const void* buffer, size_t size)
5580e478f5aSAxel Dörfler{
5590e478f5aSAxel Dörfler	if (!IsConnected())
5600e478f5aSAxel Dörfler		return B_ERROR;
5610e478f5aSAxel Dörfler
5620e478f5aSAxel Dörfler	int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
56302deec64SHamish Morrison	if (bytesWritten >= 0)
5640e478f5aSAxel Dörfler		return bytesWritten;
5650e478f5aSAxel Dörfler
566c500331fSAxel Dörfler	return fPrivate->ErrorCode(bytesWritten);
5670e478f5aSAxel Dörfler}
5680e478f5aSAxel Dörfler
5690e478f5aSAxel Dörfler
570c6149613SAdrien Destuguesstatus_t
571e1c98ceaSMark HellegersBSecureSocket::_SetupCommon(const char* host)
572c6149613SAdrien Destugues{
573c6149613SAdrien Destugues	// Do this only after BSocket::Connect has checked wether we're already
574c6149613SAdrien Destugues	// connected. We don't want to kill an existing SSL session, as that would
575c6149613SAdrien Destugues	// likely crash the protocol loop for it.
576c6149613SAdrien Destugues	if (fPrivate->fSSL != NULL) {
577c6149613SAdrien Destugues		SSL_free(fPrivate->fSSL);
578c6149613SAdrien Destugues	}
579c6149613SAdrien Destugues
580c6149613SAdrien Destugues	fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context());
581c6149613SAdrien Destugues	if (fPrivate->fSSL == NULL) {
582c6149613SAdrien Destugues		BSocket::Disconnect();
583c6149613SAdrien Destugues		return B_NO_MEMORY;
584c6149613SAdrien Destugues	}
585c6149613SAdrien Destugues
586c6149613SAdrien Destugues	BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE);
587c6149613SAdrien Destugues	SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
588c6149613SAdrien Destugues	SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
5898d63a906SAugustin Cavalier	if (host != NULL && host[0] != '\0') {
5908d63a906SAugustin Cavalier		SSL_set_tlsext_host_name(fPrivate->fSSL, host);
5918d63a906SAugustin Cavalier		X509_VERIFY_PARAM_set1_host(SSL_get0_param(fPrivate->fSSL), host, 0);
592e1c98ceaSMark Hellegers	}
593c6149613SAdrien Destugues
594c9dd7d0dSRene Gollent	return B_OK;
595c9dd7d0dSRene Gollent}
596c9dd7d0dSRene Gollent
597c9dd7d0dSRene Gollent
598c9dd7d0dSRene Gollentstatus_t
599e1c98ceaSMark HellegersBSecureSocket::_SetupConnect(const char* host)
600c9dd7d0dSRene Gollent{
601e1c98ceaSMark Hellegers	status_t error = _SetupCommon(host);
602c9dd7d0dSRene Gollent	if (error != B_OK)
603c9dd7d0dSRene Gollent		return error;
604c9dd7d0dSRene Gollent
605c6149613SAdrien Destugues	int returnValue = SSL_connect(fPrivate->fSSL);
606c6149613SAdrien Destugues	if (returnValue <= 0) {
607c6149613SAdrien Destugues		TRACE("SSLConnection can't connect\n");
608c6149613SAdrien Destugues		BSocket::Disconnect();
609c6149613SAdrien Destugues		return fPrivate->ErrorCode(returnValue);
610c6149613SAdrien Destugues	}
611c6149613SAdrien Destugues
612e62e979eSFrançois Revol#ifdef TRACE_SESSION_KEY
613e62e979eSFrançois Revol	fprintf(stderr, "SSL SESSION INFO:\n");
614e62e979eSFrançois Revol	//SSL_SESSION_print_fp(stderr, SSL_get_session(fPrivate->fSSL));
615e62e979eSFrançois Revol	SSL_SESSION_print_keylog(fPrivate->sKeyLogBIO, SSL_get_session(fPrivate->fSSL));
616e62e979eSFrançois Revol	SSL_SESSION_print_client_random(fPrivate->sKeyLogBIO, fPrivate->fSSL);
617e62e979eSFrançois Revol	fprintf(stderr, "\n");
618e62e979eSFrançois Revol#endif
619e62e979eSFrançois Revol
620c6149613SAdrien Destugues	return B_OK;
621c6149613SAdrien Destugues}
622c6149613SAdrien Destugues
623c6149613SAdrien Destugues
624c9dd7d0dSRene Gollentstatus_t
625c9dd7d0dSRene GollentBSecureSocket::_SetupAccept()
626c9dd7d0dSRene Gollent{
627c9dd7d0dSRene Gollent	status_t error = _SetupCommon();
628c9dd7d0dSRene Gollent	if (error != B_OK)
629c9dd7d0dSRene Gollent		return error;
630c9dd7d0dSRene Gollent
631c9dd7d0dSRene Gollent	int returnValue = SSL_accept(fPrivate->fSSL);
632c9dd7d0dSRene Gollent	if (returnValue <= 0) {
633c9dd7d0dSRene Gollent		TRACE("SSLConnection can't accept\n");
634c9dd7d0dSRene Gollent		BSocket::Disconnect();
635c9dd7d0dSRene Gollent		return fPrivate->ErrorCode(returnValue);
636c9dd7d0dSRene Gollent	}
637c9dd7d0dSRene Gollent
638c9dd7d0dSRene Gollent	return B_OK;
639c9dd7d0dSRene Gollent}
640c9dd7d0dSRene Gollent
641c9dd7d0dSRene Gollent
6420e478f5aSAxel Dörfler#else	// OPENSSL_ENABLED
6430e478f5aSAxel Dörfler
6440e478f5aSAxel Dörfler
6450e478f5aSAxel Dörfler// #pragma mark - No-SSL stubs
6460e478f5aSAxel Dörfler
6470e478f5aSAxel Dörfler
6480e478f5aSAxel DörflerBSecureSocket::BSecureSocket()
6490e478f5aSAxel Dörfler{
6500e478f5aSAxel Dörfler}
6510e478f5aSAxel Dörfler
6520e478f5aSAxel Dörfler
6530e478f5aSAxel DörflerBSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
654