1 /*
2 * This file is part of nzbget. See <http://nzbget.net>.
3 *
4 * Copyright (C) 2008-2017 Andrey Prygunkov <hugbug@users.sourceforge.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20
21 #include "nzbget.h"
22
23 #ifndef DISABLE_TLS
24
25 #include "TlsSocket.h"
26 #include "Thread.h"
27 #include "Log.h"
28 #include "Util.h"
29 #include "FileSystem.h"
30
31 CString TlsSocket::m_certStore;
32
33 #ifdef HAVE_LIBGNUTLS
34 #ifdef NEED_GCRYPT_LOCKING
35
36 /**
37 * Mutexes for gcryptlib
38 */
39
40 std::vector<std::unique_ptr<Mutex>> g_GCryptLibMutexes;
41
gcry_mutex_init(void ** priv)42 static int gcry_mutex_init(void **priv)
43 {
44 g_GCryptLibMutexes.emplace_back(std::make_unique<Mutex>());
45 *priv = g_GCryptLibMutexes.back().get();
46 return 0;
47 }
48
gcry_mutex_destroy(void ** lock)49 static int gcry_mutex_destroy(void **lock)
50 {
51 Mutex* mutex = ((Mutex*)*lock);
52 g_GCryptLibMutexes.erase(std::find_if(g_GCryptLibMutexes.begin(), g_GCryptLibMutexes.end(),
53 [mutex](std::unique_ptr<Mutex>& itMutex)
54 {
55 return itMutex.get() == mutex;
56 }));
57 return 0;
58 }
59
gcry_mutex_lock(void ** lock)60 static int gcry_mutex_lock(void **lock)
61 {
62 ((Mutex*)*lock)->Lock();
63 return 0;
64 }
65
gcry_mutex_unlock(void ** lock)66 static int gcry_mutex_unlock(void **lock)
67 {
68 ((Mutex*)*lock)->Unlock();
69 return 0;
70 }
71
72 static struct gcry_thread_cbs gcry_threads_Mutex =
73 { GCRY_THREAD_OPTION_USER, nullptr,
74 gcry_mutex_init, gcry_mutex_destroy,
75 gcry_mutex_lock, gcry_mutex_unlock,
76 nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr
77 };
78
79 #endif /* NEED_GCRYPT_LOCKING */
80 #endif /* HAVE_LIBGNUTLS */
81
82
83 #ifdef HAVE_OPENSSL
84
85 #ifndef CRYPTO_set_locking_callback
86 #define NEED_CRYPTO_LOCKING
87 #endif
88
89 #ifdef NEED_CRYPTO_LOCKING
90
91 /**
92 * Mutexes for OpenSSL
93 */
94
95 std::vector<std::unique_ptr<Mutex>> g_OpenSSLMutexes;
96
openssl_locking(int mode,int n,const char * file,int line)97 static void openssl_locking(int mode, int n, const char* file, int line)
98 {
99 Mutex* mutex = g_OpenSSLMutexes[n].get();
100 if (mode & CRYPTO_LOCK)
101 {
102 mutex->Lock();
103 }
104 else
105 {
106 mutex->Unlock();
107 }
108 }
109
openssl_dynlock_create(const char * file,int line)110 static struct CRYPTO_dynlock_value* openssl_dynlock_create(const char *file, int line)
111 {
112 return (CRYPTO_dynlock_value*)new Mutex();
113 }
114
openssl_dynlock_destroy(struct CRYPTO_dynlock_value * l,const char * file,int line)115 static void openssl_dynlock_destroy(struct CRYPTO_dynlock_value *l, const char *file, int line)
116 {
117 Mutex* mutex = (Mutex*)l;
118 delete mutex;
119 }
120
openssl_dynlock_lock(int mode,struct CRYPTO_dynlock_value * l,const char * file,int line)121 static void openssl_dynlock_lock(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
122 {
123 Mutex* mutex = (Mutex*)l;
124 if (mode & CRYPTO_LOCK)
125 {
126 mutex->Lock();
127 }
128 else
129 {
130 mutex->Unlock();
131 }
132 }
133
134 #endif /* NEED_CRYPTO_LOCKING */
135 #endif /* HAVE_OPENSSL */
136
137
Init()138 void TlsSocket::Init()
139 {
140 debug("Initializing TLS library");
141
142 #ifdef HAVE_LIBGNUTLS
143 int error_code;
144
145 #ifdef NEED_GCRYPT_LOCKING
146 error_code = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_Mutex);
147 if (error_code != 0)
148 {
149 error("Could not initialize libcrypt");
150 return;
151 }
152 #endif /* NEED_GCRYPT_LOCKING */
153
154 error_code = gnutls_global_init();
155 if (error_code != 0)
156 {
157 error("Could not initialize libgnutls");
158 return;
159 }
160
161 #endif /* HAVE_LIBGNUTLS */
162
163 #ifdef HAVE_OPENSSL
164
165 #ifdef NEED_CRYPTO_LOCKING
166 for (int i = 0, num = CRYPTO_num_locks(); i < num; i++)
167 {
168 g_OpenSSLMutexes.emplace_back(std::make_unique<Mutex>());
169 }
170
171 CRYPTO_set_locking_callback(openssl_locking);
172 CRYPTO_set_dynlock_create_callback(openssl_dynlock_create);
173 CRYPTO_set_dynlock_destroy_callback(openssl_dynlock_destroy);
174 CRYPTO_set_dynlock_lock_callback(openssl_dynlock_lock);
175 #endif /* NEED_CRYPTO_LOCKING */
176
177 SSL_load_error_strings();
178 SSL_library_init();
179 OpenSSL_add_all_algorithms();
180
181 #endif /* HAVE_OPENSSL */
182 }
183
Final()184 void TlsSocket::Final()
185 {
186 #ifdef HAVE_LIBGNUTLS
187 gnutls_global_deinit();
188 #endif /* HAVE_LIBGNUTLS */
189
190 #ifdef HAVE_OPENSSL
191 #ifndef LIBRESSL_VERSION_NUMBER
192 FIPS_mode_set(0);
193 #endif
194 #ifdef NEED_CRYPTO_LOCKING
195 CRYPTO_set_locking_callback(nullptr);
196 CRYPTO_set_id_callback(nullptr);
197 #endif
198 #if OPENSSL_VERSION_NUMBER < 0x10100000L
199 ERR_remove_state(0);
200 #endif
201 #if OPENSSL_VERSION_NUMBER >= 0x10002000L && ! defined (LIBRESSL_VERSION_NUMBER)
202 SSL_COMP_free_compression_methods();
203 #endif
204 //ENGINE_cleanup();
205 CONF_modules_free();
206 CONF_modules_unload(1);
207 #ifndef OPENSSL_NO_COMP
208 COMP_zlib_cleanup();
209 #endif
210 ERR_free_strings();
211 EVP_cleanup();
212 CRYPTO_cleanup_all_ex_data();
213 #endif /* HAVE_OPENSSL */
214 }
215
~TlsSocket()216 TlsSocket::~TlsSocket()
217 {
218 Close();
219
220 #ifdef HAVE_OPENSSL
221 #if OPENSSL_VERSION_NUMBER < 0x10100000L
222 ERR_remove_state(0);
223 #endif
224 #endif
225 }
226
ReportError(const char * errMsg,bool suppressable)227 void TlsSocket::ReportError(const char* errMsg, bool suppressable)
228 {
229 #ifdef HAVE_LIBGNUTLS
230 const char* errstr = gnutls_strerror(m_retCode);
231 if (suppressable && m_suppressErrors)
232 {
233 debug("%s: %s", errMsg, errstr);
234 }
235 else
236 {
237 PrintError(BString<1024>("%s: %s", errMsg, errstr));
238 }
239 #endif /* HAVE_LIBGNUTLS */
240
241 #ifdef HAVE_OPENSSL
242 int errcode = ERR_get_error();
243 do
244 {
245 char errstr[1024];
246 ERR_error_string_n(errcode, errstr, sizeof(errstr));
247 errstr[1024-1] = '\0';
248
249 if (suppressable && m_suppressErrors)
250 {
251 debug("%s: %s", errMsg, errstr);
252 }
253 else if (errcode != 0)
254 {
255 PrintError(BString<1024>("%s: %s", errMsg, errstr));
256 }
257 else
258 {
259 PrintError(errMsg);
260 }
261
262 errcode = ERR_get_error();
263 } while (errcode);
264 #endif /* HAVE_OPENSSL */
265 }
266
PrintError(const char * errMsg)267 void TlsSocket::PrintError(const char* errMsg)
268 {
269 error("%s", errMsg);
270 }
271
Start()272 bool TlsSocket::Start()
273 {
274 #ifdef HAVE_LIBGNUTLS
275 gnutls_certificate_credentials_t cred;
276 m_retCode = gnutls_certificate_allocate_credentials(&cred);
277 if (m_retCode != 0)
278 {
279 ReportError("Could not create TLS context", false);
280 return false;
281 }
282
283 m_context = cred;
284
285 if (m_certFile && m_keyFile)
286 {
287 m_retCode = gnutls_certificate_set_x509_key_file((gnutls_certificate_credentials_t)m_context,
288 m_certFile, m_keyFile, GNUTLS_X509_FMT_PEM);
289 if (m_retCode != 0)
290 {
291 ReportError("Could not load certificate or key file", false);
292 Close();
293 return false;
294 }
295 }
296
297 gnutls_session_t sess;
298 m_retCode = gnutls_init(&sess, m_isClient ? GNUTLS_CLIENT : GNUTLS_SERVER);
299 if (m_retCode != 0)
300 {
301 ReportError("Could not create TLS session", false);
302 Close();
303 return false;
304 }
305
306 m_session = sess;
307
308 m_initialized = true;
309
310 const char* priority = !m_cipher.Empty() ? m_cipher.Str() :
311 (m_certFile && m_keyFile ? "NORMAL:!VERS-SSL3.0" : "NORMAL");
312
313 m_retCode = gnutls_priority_set_direct((gnutls_session_t)m_session, priority, nullptr);
314 if (m_retCode != 0)
315 {
316 ReportError("Could not select cipher for TLS", false);
317 Close();
318 return false;
319 }
320
321 if (m_host)
322 {
323 m_retCode = gnutls_server_name_set((gnutls_session_t)m_session, GNUTLS_NAME_DNS, m_host, m_host.Length());
324 if (m_retCode != 0)
325 {
326 ReportError("Could not set hostname for TLS");
327 Close();
328 return false;
329 }
330 }
331
332 m_retCode = gnutls_credentials_set((gnutls_session_t)m_session, GNUTLS_CRD_CERTIFICATE,
333 (gnutls_certificate_credentials_t*)m_context);
334 if (m_retCode != 0)
335 {
336 ReportError("Could not initialize TLS session", false);
337 Close();
338 return false;
339 }
340
341 gnutls_transport_set_ptr((gnutls_session_t)m_session, (gnutls_transport_ptr_t)(size_t)m_socket);
342
343 m_retCode = gnutls_handshake((gnutls_session_t)m_session);
344 if (m_retCode != 0)
345 {
346 ReportError(BString<1024>("TLS handshake failed for %s", *m_host));
347 Close();
348 return false;
349 }
350
351 if (m_isClient && !m_certStore.Empty() && !ValidateCert())
352 {
353 Close();
354 return false;
355 }
356
357 m_connected = true;
358 return true;
359 #endif /* HAVE_LIBGNUTLS */
360
361 #ifdef HAVE_OPENSSL
362 m_context = SSL_CTX_new(SSLv23_method());
363
364 if (!m_context)
365 {
366 ReportError("Could not create TLS context", false);
367 return false;
368 }
369
370 if (m_certFile && m_keyFile)
371 {
372 if (SSL_CTX_use_certificate_chain_file((SSL_CTX*)m_context, m_certFile) != 1)
373 {
374 ReportError("Could not load certificate file", false);
375 Close();
376 return false;
377 }
378 if (SSL_CTX_use_PrivateKey_file((SSL_CTX*)m_context, m_keyFile, SSL_FILETYPE_PEM) != 1)
379 {
380 ReportError("Could not load key file", false);
381 Close();
382 return false;
383 }
384 if (!SSL_CTX_set_options((SSL_CTX*)m_context, SSL_OP_NO_SSLv3))
385 {
386 ReportError("Could not select minimum protocol version for TLS", false);
387 Close();
388 return false;
389 }
390
391 // For ECC certificates
392 EC_KEY* ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
393 if (!ecdh)
394 {
395 ReportError("Could not generate ecdh parameters for TLS", false);
396 Close();
397 return false;
398 }
399 if (!SSL_CTX_set_tmp_ecdh((SSL_CTX*)m_context, ecdh))
400 {
401 ReportError("Could not set ecdh parameters for TLS", false);
402 EC_KEY_free(ecdh);
403 Close();
404 return false;
405 }
406 EC_KEY_free(ecdh);
407 }
408
409 if (m_isClient && !m_certStore.Empty())
410 {
411 // Enable certificate validation
412 if (SSL_CTX_load_verify_locations((SSL_CTX*)m_context, m_certStore, nullptr) != 1)
413 {
414 ReportError("Could not set certificate store location", false);
415 Close();
416 return false;
417 }
418
419 SSL_CTX_set_verify((SSL_CTX*)m_context, SSL_VERIFY_PEER, nullptr);
420 }
421
422 m_session = SSL_new((SSL_CTX*)m_context);
423 if (!m_session)
424 {
425 ReportError("Could not create TLS session", false);
426 Close();
427 return false;
428 }
429
430 if (!m_cipher.Empty() && !SSL_set_cipher_list((SSL*)m_session, m_cipher))
431 {
432 ReportError("Could not select cipher for TLS", false);
433 Close();
434 return false;
435 }
436
437 if (m_isClient && m_host && !SSL_set_tlsext_host_name((SSL*)m_session, m_host))
438 {
439 ReportError("Could not set host name for TLS");
440 Close();
441 return false;
442 }
443
444 if (!SSL_set_fd((SSL*)m_session, (int)m_socket))
445 {
446 ReportError("Could not set the file descriptor for TLS");
447 Close();
448 return false;
449 }
450
451 int error_code = m_isClient ? SSL_connect((SSL*)m_session) : SSL_accept((SSL*)m_session);
452 if (error_code < 1)
453 {
454 long verifyRes = SSL_get_verify_result((SSL*)m_session);
455 if (verifyRes != X509_V_OK)
456 {
457 PrintError(BString<1024>("TLS certificate verification failed for %s: %s."
458 " For more info visit http://nzbget.net/certificate-verification",
459 *m_host, X509_verify_cert_error_string(verifyRes)));
460 }
461 else
462 {
463 ReportError(BString<1024>("TLS handshake failed for %s", *m_host));
464 }
465 Close();
466 return false;
467 }
468
469 if (m_isClient && !m_certStore.Empty() && !ValidateCert())
470 {
471 Close();
472 return false;
473 }
474
475 m_connected = true;
476 return true;
477 #endif /* HAVE_OPENSSL */
478 }
479
ValidateCert()480 bool TlsSocket::ValidateCert()
481 {
482 #ifdef HAVE_LIBGNUTLS
483 #if GNUTLS_VERSION_NUMBER >= 0x030104
484 #if GNUTLS_VERSION_NUMBER >= 0x030306
485 if (FileSystem::DirectoryExists(m_certStore))
486 {
487 if (gnutls_certificate_set_x509_trust_dir((gnutls_certificate_credentials_t)m_context, m_certStore, GNUTLS_X509_FMT_PEM) < 0)
488 {
489 ReportError("Could not set certificate store location");
490 return false;
491 }
492 }
493 else
494 #endif
495 {
496 if (gnutls_certificate_set_x509_trust_file((gnutls_certificate_credentials_t)m_context, m_certStore, GNUTLS_X509_FMT_PEM) < 0)
497 {
498 ReportError("Could not set certificate store location");
499 return false;
500 }
501 }
502
503 unsigned int status = 0;
504 if (gnutls_certificate_verify_peers3((gnutls_session_t)m_session, m_host, &status) != 0 ||
505 gnutls_certificate_type_get((gnutls_session_t)m_session) != GNUTLS_CRT_X509)
506 {
507 ReportError("Could not verify TLS certificate");
508 return false;
509 }
510
511 if (status != 0)
512 {
513 if (status & GNUTLS_CERT_UNEXPECTED_OWNER)
514 {
515 // Extracting hostname from the certificate
516 unsigned int cert_list_size = 0;
517 const gnutls_datum_t* cert_list = gnutls_certificate_get_peers((gnutls_session_t)m_session, &cert_list_size);
518 if (cert_list_size > 0)
519 {
520 gnutls_x509_crt_t cert;
521 gnutls_x509_crt_init(&cert);
522 gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
523 char dn[256];
524 size_t size = sizeof(dn);
525 if (gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, dn, &size) == 0)
526 {
527 PrintError(BString<1024>("TLS certificate verification failed for %s: certificate hostname mismatch (%s)."
528 " For more info visit http://nzbget.net/certificate-verification", *m_host, dn));
529 gnutls_x509_crt_deinit(cert);
530 return false;
531 }
532 gnutls_x509_crt_deinit(cert);
533 }
534 }
535
536 gnutls_datum_t msgdata;
537 if (gnutls_certificate_verification_status_print(status, GNUTLS_CRT_X509, &msgdata, 0) == 0)
538 {
539 PrintError(BString<1024>("TLS certificate verification failed for %s: %s."
540 " For more info visit http://nzbget.net/certificate-verification", *m_host, msgdata.data));
541 gnutls_free(&msgdata);
542 }
543 else
544 {
545 ReportError(BString<1024>("TLS certificate verification failed for %s."
546 " For more info visit http://nzbget.net/certificate-verification", *m_host));
547 }
548 return false;
549 }
550 #endif
551 return true;
552 #endif /* HAVE_LIBGNUTLS */
553
554 #ifdef HAVE_OPENSSL
555 // verify a server certificate was presented during the negotiation
556 X509* cert = SSL_get_peer_certificate((SSL*)m_session);
557 if (!cert)
558 {
559 PrintError(BString<1024>("TLS certificate verification failed for %s: no certificate provided by server."
560 " For more info visit http://nzbget.net/certificate-verification", *m_host));
561 return false;
562 }
563
564 #ifdef HAVE_X509_CHECK_HOST
565 // hostname verification
566 if (!m_host.Empty() && X509_check_host(cert, m_host, m_host.Length(), 0, nullptr) != 1)
567 {
568 const unsigned char* certHost = nullptr;
569 // Find the position of the CN field in the Subject field of the certificate
570 int common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name(cert), NID_commonName, -1);
571 if (common_name_loc >= 0)
572 {
573 // Extract the CN field
574 X509_NAME_ENTRY* common_name_entry = X509_NAME_get_entry(X509_get_subject_name(cert), common_name_loc);
575 if (common_name_entry != nullptr)
576 {
577 // Convert the CN field to a C string
578 ASN1_STRING* common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
579 if (common_name_asn1 != nullptr)
580 {
581 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
582 certHost = ASN1_STRING_get0_data(common_name_asn1);
583 #else
584 certHost = ASN1_STRING_data(common_name_asn1);
585 #endif
586 }
587 }
588 }
589
590 PrintError(BString<1024>("TLS certificate verification failed for %s: certificate hostname mismatch (%s)."
591 " For more info visit http://nzbget.net/certificate-verification", *m_host, certHost));
592 X509_free(cert);
593 return false;
594 }
595 #endif
596
597 X509_free(cert);
598 return true;
599 #endif /* HAVE_OPENSSL */
600 }
601
Close()602 void TlsSocket::Close()
603 {
604 if (m_session)
605 {
606 #ifdef HAVE_LIBGNUTLS
607 if (m_connected)
608 {
609 gnutls_bye((gnutls_session_t)m_session, GNUTLS_SHUT_WR);
610 }
611 if (m_initialized)
612 {
613 gnutls_deinit((gnutls_session_t)m_session);
614 }
615 #endif /* HAVE_LIBGNUTLS */
616
617 #ifdef HAVE_OPENSSL
618 if (m_connected)
619 {
620 SSL_shutdown((SSL*)m_session);
621 }
622 SSL_free((SSL*)m_session);
623 #endif /* HAVE_OPENSSL */
624
625 m_session = nullptr;
626 }
627
628 if (m_context)
629 {
630 #ifdef HAVE_LIBGNUTLS
631 gnutls_certificate_free_credentials((gnutls_certificate_credentials_t)m_context);
632 #endif /* HAVE_LIBGNUTLS */
633
634 #ifdef HAVE_OPENSSL
635 SSL_CTX_free((SSL_CTX*)m_context);
636 #endif /* HAVE_OPENSSL */
637
638 m_context = nullptr;
639 }
640 }
641
Send(const char * buffer,int size)642 int TlsSocket::Send(const char* buffer, int size)
643 {
644 #ifdef HAVE_LIBGNUTLS
645 m_retCode = gnutls_record_send((gnutls_session_t)m_session, buffer, size);
646 #endif /* HAVE_LIBGNUTLS */
647
648 #ifdef HAVE_OPENSSL
649 m_retCode = SSL_write((SSL*)m_session, buffer, size);
650 #endif /* HAVE_OPENSSL */
651
652 if (m_retCode < 0)
653 {
654 #ifdef HAVE_OPENSSL
655 if (ERR_peek_error() == 0)
656 {
657 ReportError("Could not write to TLS-Socket: Connection closed by remote host");
658 }
659 else
660 #endif /* HAVE_OPENSSL */
661 ReportError("Could not write to TLS-Socket");
662 return -1;
663 }
664
665 return m_retCode;
666 }
667
Recv(char * buffer,int size)668 int TlsSocket::Recv(char* buffer, int size)
669 {
670 #ifdef HAVE_LIBGNUTLS
671 m_retCode = gnutls_record_recv((gnutls_session_t)m_session, buffer, size);
672 #endif /* HAVE_LIBGNUTLS */
673
674 #ifdef HAVE_OPENSSL
675 m_retCode = SSL_read((SSL*)m_session, buffer, size);
676 #endif /* HAVE_OPENSSL */
677
678 if (m_retCode < 0)
679 {
680 #ifdef HAVE_OPENSSL
681 if (ERR_peek_error() == 0)
682 {
683 ReportError("Could not read from TLS-Socket: Connection closed by remote host");
684 }
685 else
686 #endif /* HAVE_OPENSSL */
687 {
688 ReportError("Could not read from TLS-Socket");
689 }
690 return -1;
691 }
692
693 return m_retCode;
694 }
695
696 #endif
697