xref: /haiku/src/kits/network/libnetapi/SecureSocket.cpp (revision 44d19f4d32b8f7e9c01f00294c87ca5cc2e057f7)
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 #endif
15 
16 #include <pthread.h>
17 
18 #include <Certificate.h>
19 #include <FindDirectory.h>
20 #include <Path.h>
21 
22 #include <AutoDeleter.h>
23 
24 #include "CertificatePrivate.h"
25 
26 
27 //#define TRACE_SOCKET
28 #ifdef TRACE_SOCKET
29 #	define TRACE(x...) printf(x)
30 #else
31 #	define TRACE(x...) ;
32 #endif
33 
34 
35 #ifdef OPENSSL_ENABLED
36 
37 
38 class BSecureSocket::Private {
39 public:
40 								Private();
41 								~Private();
42 
43 			status_t			InitCheck();
44 			status_t			ErrorCode(int returnValue);
45 
46 	static	SSL_CTX*			Context();
47 	static	int					VerifyCallback(int ok, X509_STORE_CTX* ctx);
48 
49 private:
50 	static	void				_CreateContext();
51 
52 public:
53 			SSL*				fSSL;
54 			BIO*				fBIO;
55 	static	int					sDataIndex;
56 
57 private:
58 	static	SSL_CTX*			sContext;
59 		// FIXME When do we SSL_CTX_free it?
60 	static	pthread_once_t		sInitOnce;
61 };
62 
63 
64 /* static */ SSL_CTX* BSecureSocket::Private::sContext = NULL;
65 /* static */ int BSecureSocket::Private::sDataIndex;
66 /* static */ pthread_once_t BSecureSocket::Private::sInitOnce
67 	= PTHREAD_ONCE_INIT;
68 
69 
70 BSecureSocket::Private::Private()
71 	:
72 	fSSL(NULL),
73 	fBIO(BIO_new(BIO_s_socket()))
74 {
75 }
76 
77 
78 BSecureSocket::Private::~Private()
79 {
80 	// SSL_free also frees the underlying BIO.
81 	if (fSSL != NULL)
82 		SSL_free(fSSL);
83 	else {
84 		// The SSL session was never created (Connect() was not called or
85 		// failed). We must free the BIO we created in the constructor.
86 		BIO_free(fBIO);
87 	}
88 }
89 
90 
91 status_t
92 BSecureSocket::Private::InitCheck()
93 {
94 	if (fBIO == NULL)
95 		return B_NO_MEMORY;
96 	return B_OK;
97 }
98 
99 
100 status_t
101 BSecureSocket::Private::ErrorCode(int returnValue)
102 {
103 	int error = SSL_get_error(fSSL, returnValue);
104 	switch (error) {
105 		case SSL_ERROR_NONE:
106 			// Shouldn't happen...
107 			return B_NO_ERROR;
108 		case SSL_ERROR_ZERO_RETURN:
109 			// Socket is closed
110 			return B_CANCELED;
111 		case SSL_ERROR_SSL:
112 			// Probably no certificate
113 			return B_NOT_ALLOWED;
114 
115 		case SSL_ERROR_WANT_READ:
116 		case SSL_ERROR_WANT_WRITE:
117 		case SSL_ERROR_WANT_CONNECT:
118 		case SSL_ERROR_WANT_ACCEPT:
119 		case SSL_ERROR_WANT_X509_LOOKUP:
120 		case SSL_ERROR_SYSCALL:
121 		default:
122 			// TODO: translate SSL error codes!
123 			fprintf(stderr, "SSL error: %d\n", error);
124 			return B_ERROR;
125 	}
126 }
127 
128 
129 /* static */ SSL_CTX*
130 BSecureSocket::Private::Context()
131 {
132 	// We use lazy initialisation here, because reading certificates from disk
133 	// and parsing them is a relatively long operation and uses some memory.
134 	// We don't want programs that don't use SSL to waste resources with that.
135 	pthread_once(&sInitOnce, _CreateContext);
136 
137 	return sContext;
138 }
139 
140 
141 /*!	This is called each time a certificate verification occurs. It allows us to
142 	catch failures and report them.
143 */
144 /* static */ int
145 BSecureSocket::Private::VerifyCallback(int ok, X509_STORE_CTX* ctx)
146 {
147 	// OpenSSL already checked the certificate again the certificate store for
148 	// us, and tells the result of that in the ok parameter.
149 
150 	// If the verification succeeded, no need for any further checks. Let's
151 	// proceed with the connection.
152 	if (ok)
153 		return ok;
154 
155 	// The certificate verification failed. Signal this to the BSecureSocket.
156 
157 	// First of all, get the affected BSecureSocket
158 	SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx,
159 		SSL_get_ex_data_X509_STORE_CTX_idx());
160 	BSecureSocket* socket = (BSecureSocket*)SSL_get_ex_data(ssl, sDataIndex);
161 
162 	// Get the certificate that we could not validate (this may not be the one
163 	// we got from the server, but something higher up in the certificate
164 	// chain)
165 	X509* x509 = X509_STORE_CTX_get_current_cert(ctx);
166 	BCertificate::Private* certificate
167 		= new(std::nothrow) BCertificate::Private(x509);
168 
169 	if (certificate == NULL)
170 		return 0;
171 
172 	int error = X509_STORE_CTX_get_error(ctx);
173 	const char* message = X509_verify_cert_error_string(error);
174 
175 	// Let the BSecureSocket (or subclass) decide if we should continue anyway.
176 	BCertificate failedCertificate(certificate);
177 	return socket->CertificateVerificationFailed(failedCertificate, message);
178 }
179 
180 
181 /* static */ void
182 BSecureSocket::Private::_CreateContext()
183 {
184 	sContext = SSL_CTX_new(SSLv23_method());
185 
186 	// Disable legacy protocols. They have known vulnerabilities.
187 	SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
188 
189 	// Don't bother us with ERROR_WANT_READ.
190 	SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY);
191 
192 	// Setup certificate verification
193 	BPath certificateStore;
194 	find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore);
195 	certificateStore.Append("ssl/CARootCertificates.pem");
196 	// TODO we may want to add a non-packaged certificate directory?
197 	// (would make it possible to store user-added certificate exceptions
198 	// there)
199 	SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL);
200 	SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback);
201 
202 	// OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to validate certificate
203 	// chains. This makes the validation stop as soon as a recognized certificate is found in the
204 	// chain, instead of validating the whole chain, then seeing if the root certificate is known.
205 #ifdef X509_V_FLAG_TRUSTED_FIRST
206 	X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new();
207 	X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST);
208 	SSL_CTX_set1_param(sContext, verifyParam);
209 
210 	// TODO we need to free this after freeing the SSL context (which we currently never do)
211 	// X509_VERIFY_PARAM_free(verifyParam);
212 #endif
213 
214 	// Get an unique index number for storing application data in SSL
215 	// structs. We will store a pointer to the BSecureSocket class there.
216 	sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
217 }
218 
219 
220 // # pragma mark - BSecureSocket
221 
222 
223 BSecureSocket::BSecureSocket()
224 	:
225 	fPrivate(new(std::nothrow) BSecureSocket::Private())
226 {
227 	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
228 }
229 
230 
231 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
232 	:
233 	fPrivate(new(std::nothrow) BSecureSocket::Private())
234 {
235 	fInitStatus = fPrivate != NULL ? fPrivate->InitCheck() : B_NO_MEMORY;
236 	Connect(peer, timeout);
237 }
238 
239 
240 BSecureSocket::BSecureSocket(const BSecureSocket& other)
241 	:
242 	BSocket(other)
243 {
244 	fPrivate = new(std::nothrow) BSecureSocket::Private(*other.fPrivate);
245 		// TODO: this won't work this way! - write working copy constructor for
246 		// Private.
247 
248 	if (fPrivate != NULL)
249 		SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
250 	else
251 		fInitStatus = B_NO_MEMORY;
252 
253 }
254 
255 
256 BSecureSocket::~BSecureSocket()
257 {
258 	delete fPrivate;
259 }
260 
261 
262 status_t
263 BSecureSocket::Accept(BAbstractSocket*& _socket)
264 {
265 	int fd = -1;
266 	BNetworkAddress peer;
267 	status_t error = AcceptNext(fd, peer);
268 	if (error != B_OK)
269 		return error;
270 	BSecureSocket* socket = new(std::nothrow) BSecureSocket();
271 	ObjectDeleter<BSecureSocket> socketDeleter(socket);
272 	if (socket == NULL || socket->InitCheck() != B_OK) {
273 		close(fd);
274 		return B_NO_MEMORY;
275 	}
276 
277 	socket->_SetTo(fd, fLocal, peer);
278 	error = socket->_SetupAccept();
279 	if (error != B_OK)
280 		return error;
281 
282 	_socket = socket;
283 	socketDeleter.Detach();
284 
285 	return B_OK;
286 }
287 
288 
289 status_t
290 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
291 {
292 	status_t status = InitCheck();
293 	if (status != B_OK)
294 		return status;
295 
296 	status = BSocket::Connect(peer, timeout);
297 	if (status != B_OK)
298 		return status;
299 
300 	return _SetupConnect();
301 }
302 
303 
304 void
305 BSecureSocket::Disconnect()
306 {
307 	if (IsConnected()) {
308 		if (fPrivate->fSSL != NULL)
309 			SSL_shutdown(fPrivate->fSSL);
310 
311 		BSocket::Disconnect();
312 	}
313 }
314 
315 
316 status_t
317 BSecureSocket::WaitForReadable(bigtime_t timeout) const
318 {
319 	if (fInitStatus != B_OK)
320 		return fInitStatus;
321 	if (!IsConnected())
322 		return B_ERROR;
323 
324 	if (SSL_pending(fPrivate->fSSL) > 0)
325 		return B_OK;
326 
327 	return BSocket::WaitForReadable(timeout);
328 }
329 
330 
331 status_t
332 BSecureSocket::InitCheck()
333 {
334 	if (fPrivate == NULL)
335 		return B_NO_MEMORY;
336 
337 	status_t state = fPrivate->InitCheck();
338 	return state;
339 }
340 
341 
342 bool
343 BSecureSocket::CertificateVerificationFailed(BCertificate&, const char*)
344 {
345 	// Until apps actually make use of the certificate API, let's keep the old
346 	// behavior and accept all connections, even if the certificate validation
347 	// didn't work.
348 	return true;
349 }
350 
351 
352 //	#pragma mark - BDataIO implementation
353 
354 
355 ssize_t
356 BSecureSocket::Read(void* buffer, size_t size)
357 {
358 	if (!IsConnected())
359 		return B_ERROR;
360 
361 	int bytesRead = SSL_read(fPrivate->fSSL, buffer, size);
362 	if (bytesRead >= 0)
363 		return bytesRead;
364 
365 	return fPrivate->ErrorCode(bytesRead);
366 }
367 
368 
369 ssize_t
370 BSecureSocket::Write(const void* buffer, size_t size)
371 {
372 	if (!IsConnected())
373 		return B_ERROR;
374 
375 	int bytesWritten = SSL_write(fPrivate->fSSL, buffer, size);
376 	if (bytesWritten >= 0)
377 		return bytesWritten;
378 
379 	return fPrivate->ErrorCode(bytesWritten);
380 }
381 
382 
383 status_t
384 BSecureSocket::_SetupCommon()
385 {
386 	// Do this only after BSocket::Connect has checked wether we're already
387 	// connected. We don't want to kill an existing SSL session, as that would
388 	// likely crash the protocol loop for it.
389 	if (fPrivate->fSSL != NULL) {
390 		SSL_free(fPrivate->fSSL);
391 	}
392 
393 	fPrivate->fSSL = SSL_new(BSecureSocket::Private::Context());
394 	if (fPrivate->fSSL == NULL) {
395 		BSocket::Disconnect();
396 		return B_NO_MEMORY;
397 	}
398 
399 	BIO_set_fd(fPrivate->fBIO, fSocket, BIO_NOCLOSE);
400 	SSL_set_bio(fPrivate->fSSL, fPrivate->fBIO, fPrivate->fBIO);
401 	SSL_set_ex_data(fPrivate->fSSL, Private::sDataIndex, this);
402 
403 	return B_OK;
404 }
405 
406 
407 status_t
408 BSecureSocket::_SetupConnect()
409 {
410 	status_t error = _SetupCommon();
411 	if (error != B_OK)
412 		return error;
413 
414 	int returnValue = SSL_connect(fPrivate->fSSL);
415 	if (returnValue <= 0) {
416 		TRACE("SSLConnection can't connect\n");
417 		BSocket::Disconnect();
418 		return fPrivate->ErrorCode(returnValue);
419 	}
420 
421 	return B_OK;
422 }
423 
424 
425 status_t
426 BSecureSocket::_SetupAccept()
427 {
428 	status_t error = _SetupCommon();
429 	if (error != B_OK)
430 		return error;
431 
432 	int returnValue = SSL_accept(fPrivate->fSSL);
433 	if (returnValue <= 0) {
434 		TRACE("SSLConnection can't accept\n");
435 		BSocket::Disconnect();
436 		return fPrivate->ErrorCode(returnValue);
437 	}
438 
439 	return B_OK;
440 }
441 
442 
443 #else	// OPENSSL_ENABLED
444 
445 
446 // #pragma mark - No-SSL stubs
447 
448 
449 BSecureSocket::BSecureSocket()
450 {
451 }
452 
453 
454 BSecureSocket::BSecureSocket(const BNetworkAddress& peer, bigtime_t timeout)
455 {
456 	fInitStatus = B_UNSUPPORTED;
457 }
458 
459 
460 BSecureSocket::BSecureSocket(const BSecureSocket& other)
461 	:
462 	BSocket(other)
463 {
464 }
465 
466 
467 BSecureSocket::~BSecureSocket()
468 {
469 }
470 
471 
472 bool
473 BSecureSocket::CertificateVerificationFailed(BCertificate& certificate, const char*)
474 {
475 	(void)certificate;
476 	return false;
477 }
478 
479 
480 status_t
481 BSecureSocket::Accept(BAbstractSocket*& _socket)
482 {
483 	return B_UNSUPPORTED;
484 }
485 
486 
487 status_t
488 BSecureSocket::Connect(const BNetworkAddress& peer, bigtime_t timeout)
489 {
490 	return fInitStatus = B_UNSUPPORTED;
491 }
492 
493 
494 void
495 BSecureSocket::Disconnect()
496 {
497 }
498 
499 
500 status_t
501 BSecureSocket::WaitForReadable(bigtime_t timeout) const
502 {
503 	return B_UNSUPPORTED;
504 }
505 
506 
507 //	#pragma mark - BDataIO implementation
508 
509 
510 ssize_t
511 BSecureSocket::Read(void* buffer, size_t size)
512 {
513 	return B_UNSUPPORTED;
514 }
515 
516 
517 ssize_t
518 BSecureSocket::Write(const void* buffer, size_t size)
519 {
520 	return B_UNSUPPORTED;
521 }
522 
523 
524 status_t
525 BSecureSocket::InitCheck()
526 {
527 	return B_UNSUPPORTED;
528 }
529 
530 
531 status_t
532 BSecureSocket::_SetupCommon()
533 {
534 	return B_UNSUPPORTED;
535 }
536 
537 
538 status_t
539 BSecureSocket::_SetupConnect()
540 {
541 	return B_UNSUPPORTED;
542 }
543 
544 
545 status_t
546 BSecureSocket::_SetupAccept()
547 {
548 	return B_UNSUPPORTED;
549 }
550 
551 
552 #endif	// !OPENSSL_ENABLED
553