source: filezilla/trunk/fuentes/src/engine/tlssocket.cpp @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

File size: 31.4 KB
Line 
1#include <filezilla.h>
2#include "engineprivate.h"
3#include "tlssocket.h"
4#include "ControlSocket.h"
5
6#include <libfilezilla/iputils.hpp>
7
8#include <gnutls/x509.h>
9
10#if FZ_USE_GNUTLS_SYSTEM_CIPHERS
11char const ciphers[] = "@SYSTEM";
12#else
13char const ciphers[] = "SECURE256:+SECURE128:-ARCFOUR-128:-3DES-CBC:-MD5:+SIGN-ALL:-SIGN-RSA-MD5:+CTYPE-X509:-CTYPE-OPENPGP:-VERS-SSL3.0";
14#endif
15
16#define TLSDEBUG 0
17#if TLSDEBUG
18// This is quite ugly
19CControlSocket* pLoggingControlSocket;
20void log_func(int level, const char* msg)
21{
22        if (!msg || !pLoggingControlSocket)
23                return;
24        wxString s(msg, wxConvLocal);
25        s.Trim();
26        pLoggingControlSocket->LogMessage(MessageType::Debug_Debug, _T("tls: %d %s"), level, s);
27}
28#endif
29
30CTlsSocket::CTlsSocket(event_handler* pEvtHandler, CSocket& socket, CControlSocket* pOwner)
31        : event_handler(pOwner->event_loop_)
32        , CBackend(pEvtHandler)
33        , m_pOwner(pOwner)
34        , m_socket(socket)
35{
36        m_pSocketBackend = new CSocketBackend(this, m_socket, m_pOwner->GetEngine().GetRateLimiter());
37
38        m_implicitTrustedCert.data = 0;
39        m_implicitTrustedCert.size = 0;
40}
41
42CTlsSocket::~CTlsSocket()
43{
44        remove_handler();
45
46        Uninit();
47        delete m_pSocketBackend;
48}
49
50bool CTlsSocket::Init()
51{
52        // This function initializes GnuTLS
53        m_initialized = true;
54        int res = gnutls_global_init();
55        if (res) {
56                LogError(res, _T("gnutls_global_init"));
57                Uninit();
58                return false;
59        }
60
61#if TLSDEBUG
62        if (!pLoggingControlSocket) {
63                pLoggingControlSocket = m_pOwner;
64                gnutls_global_set_log_function(log_func);
65                gnutls_global_set_log_level(99);
66        }
67#endif
68        res = gnutls_certificate_allocate_credentials(&m_certCredentials);
69        if (res < 0) {
70                LogError(res, _T("gnutls_certificate_allocate_credentials"));
71                Uninit();
72                return false;
73        }
74
75        if (!InitSession())
76                return false;
77
78        m_shutdown_requested = false;
79
80        // At this point, we can start shaking hands.
81
82        return true;
83}
84
85bool CTlsSocket::SetClientCertificate(fz::native_string const& keyfile, fz::native_string const& certs, fz::native_string const& password)
86{
87        if (!m_certCredentials) {
88                return false;
89        }
90
91        int res = gnutls_certificate_set_x509_key_file2(m_certCredentials, fz::to_string(certs).c_str(),
92                fz::to_string(keyfile).c_str(), GNUTLS_X509_FMT_PEM, password.empty() ? 0 : fz::to_utf8(password).c_str(), 0);
93        if (res < 0) {
94                LogError(res, _T("gnutls_certificate_set_x509_key_file2"));
95                Uninit();
96                return false;
97        }
98
99        return true;
100}
101
102bool CTlsSocket::InitSession()
103{
104        if (!m_certCredentials) {
105                Uninit();
106                return false;
107        }
108
109        int res = gnutls_init(&m_session, GNUTLS_CLIENT);
110        if (res) {
111                LogError(res, _T("gnutls_init"));
112                Uninit();
113                return false;
114        }
115
116        // Even though the name gnutls_db_set_cache_expiration
117        // implies expiration of some cache, it also governs
118        // the actual session lifetime, independend whether the
119        // session is cached or not.
120        gnutls_db_set_cache_expiration(m_session, 100000000);
121
122        res = gnutls_priority_set_direct(m_session, ciphers, 0);
123        if (res) {
124                LogError(res, _T("gnutls_priority_set_direct"));
125                Uninit();
126                return false;
127        }
128
129        gnutls_dh_set_prime_bits(m_session, 1024);
130
131        gnutls_credentials_set(m_session, GNUTLS_CRD_CERTIFICATE, m_certCredentials);
132
133        // Setup transport functions
134        gnutls_transport_set_push_function(m_session, PushFunction);
135        gnutls_transport_set_pull_function(m_session, PullFunction);
136        gnutls_transport_set_ptr(m_session, (gnutls_transport_ptr_t)this);
137
138        return true;
139}
140
141void CTlsSocket::Uninit()
142{
143        UninitSession();
144
145        if (m_certCredentials) {
146                gnutls_certificate_free_credentials(m_certCredentials);
147                m_certCredentials = 0;
148        }
149
150        if (m_initialized) {
151                m_initialized = false;
152                gnutls_global_deinit();
153        }
154
155        m_tlsState = TlsState::noconn;
156
157        delete [] m_peekData;
158        m_peekData = 0;
159        m_peekDataLen = 0;
160
161        delete [] m_implicitTrustedCert.data;
162        m_implicitTrustedCert.data = 0;
163
164#if TLSDEBUG
165        if (pLoggingControlSocket == m_pOwner)
166                pLoggingControlSocket = 0;
167#endif
168}
169
170
171void CTlsSocket::UninitSession()
172{
173        if (m_session) {
174                gnutls_deinit(m_session);
175                m_session = 0;
176        }
177}
178
179
180void CTlsSocket::LogError(int code, const wxString& function, MessageType logLevel)
181{
182        if (code == GNUTLS_E_WARNING_ALERT_RECEIVED || code == GNUTLS_E_FATAL_ALERT_RECEIVED) {
183                PrintAlert(logLevel);
184        }
185        else if (code == GNUTLS_E_PULL_ERROR) {
186                if (function.empty()) {
187                        m_pOwner->LogMessage(MessageType::Debug_Warning, _T("GnuTLS could not read from socket: %s"), CSocket::GetErrorDescription(m_socket_error));
188                }
189                else {
190                        m_pOwner->LogMessage(MessageType::Debug_Warning, _T("GnuTLS could not read from socket in %s: %s"), function, CSocket::GetErrorDescription(m_socket_error));
191                }
192        }
193        else if (code == GNUTLS_E_PUSH_ERROR) {
194                if (function.empty()) {
195                        m_pOwner->LogMessage(MessageType::Debug_Warning, _T("GnuTLS could not write to socket: %s"), CSocket::GetErrorDescription(m_socket_error));
196                }
197                else {
198                        m_pOwner->LogMessage(MessageType::Debug_Warning, _T("GnuTLS could not write to socket in %s: %s"), function, CSocket::GetErrorDescription(m_socket_error));
199                }
200        }
201        else {
202                const char* error = gnutls_strerror(code);
203                if (error) {
204                        wxString str(error, wxConvLocal);
205                        if (function.empty())
206                                m_pOwner->LogMessage(logLevel, _("GnuTLS error %d: %s"), code, str);
207                        else
208                                m_pOwner->LogMessage(logLevel, _("GnuTLS error %d in %s: %s"), code, function, str);
209                }
210                else {
211                        if (function.empty())
212                                m_pOwner->LogMessage(logLevel, _("GnuTLS error %d"), code);
213                        else
214                                m_pOwner->LogMessage(logLevel, _("GnuTLS error %d in %s"), code, function);
215                }
216        }
217}
218
219void CTlsSocket::PrintAlert(MessageType logLevel)
220{
221        gnutls_alert_description_t last_alert = gnutls_alert_get(m_session);
222        const char* alert = gnutls_alert_get_name(last_alert);
223        if (alert) {
224                wxString str(alert, wxConvLocal);
225                m_pOwner->LogMessage(logLevel, _("Received TLS alert from the server: %s (%d)"), str, last_alert);
226        }
227        else
228                m_pOwner->LogMessage(logLevel, _("Received unknown TLS alert %d from the server"), last_alert);
229}
230
231ssize_t CTlsSocket::PushFunction(gnutls_transport_ptr_t ptr, const void* data, size_t len)
232{
233        return ((CTlsSocket*)ptr)->PushFunction(data, len);
234}
235
236ssize_t CTlsSocket::PullFunction(gnutls_transport_ptr_t ptr, void* data, size_t len)
237{
238        return ((CTlsSocket*)ptr)->PullFunction(data, len);
239}
240
241ssize_t CTlsSocket::PushFunction(const void* data, size_t len)
242{
243#if TLSDEBUG
244        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::PushFunction(%d)"), len);
245#endif
246        if (!m_canWriteToSocket) {
247                gnutls_transport_set_errno(m_session, EAGAIN);
248                return -1;
249        }
250
251        if (!m_pSocketBackend) {
252                gnutls_transport_set_errno(m_session, 0);
253                return -1;
254        }
255
256        int error;
257        int written = m_pSocketBackend->Write(data, len, error);
258
259        if (written < 0) {
260                m_canWriteToSocket = false;
261                if (error == EAGAIN) {
262                        m_socket_error = error;
263                }
264                gnutls_transport_set_errno(m_session, error);
265#if TLSDEBUG
266                m_pOwner->LogMessage(MessageType::Debug_Debug, _T("  returning -1 due to %d"), error);
267#endif
268                return -1;
269        }
270
271#if TLSDEBUG
272        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("  returning %d"), written);
273#endif
274
275        return written;
276}
277
278ssize_t CTlsSocket::PullFunction(void* data, size_t len)
279{
280#if TLSDEBUG
281        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::PullFunction(%d)"),  (int)len);
282#endif
283        if (!m_pSocketBackend) {
284                gnutls_transport_set_errno(m_session, 0);
285                return -1;
286        }
287
288        if (m_socketClosed)
289                return 0;
290
291        if (!m_canReadFromSocket) {
292                gnutls_transport_set_errno(m_session, EAGAIN);
293                return -1;
294        }
295
296        int error;
297        int read = m_pSocketBackend->Read(data, len, error);
298        if (read < 0) {
299                m_canReadFromSocket = false;
300                if (error == EAGAIN) {
301                        if (m_canCheckCloseSocket && !m_pSocketBackend->IsWaiting(CRateLimiter::inbound)) {
302                                send_event<CSocketEvent>(m_pSocketBackend, SocketEventType::close, 0);
303                        }
304                }
305                else {
306                        m_socket_error = error;
307                }
308                gnutls_transport_set_errno(m_session, error);
309#if TLSDEBUG
310                m_pOwner->LogMessage(MessageType::Debug_Debug, _T("  returning -1 due to %d"), error);
311#endif
312                return -1;
313        }
314
315        if (m_canCheckCloseSocket) {
316                send_event<CSocketEvent>(m_pSocketBackend, SocketEventType::close, 0);
317        }
318
319        if (!read) {
320                m_socket_eof = true;
321        }
322
323#if TLSDEBUG
324        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("  returning %d"), read);
325#endif
326
327        return read;
328}
329
330void CTlsSocket::operator()(fz::event_base const& ev)
331{
332        fz::dispatch<CSocketEvent>(ev, this, &CTlsSocket::OnSocketEvent);
333}
334
335void CTlsSocket::OnSocketEvent(CSocketEventSource*, SocketEventType t, int error)
336{
337        if (!m_session)
338                return;
339
340        switch (t)
341        {
342        case SocketEventType::read:
343                OnRead();
344                break;
345        case SocketEventType::write:
346                OnSend();
347                break;
348        case SocketEventType::close:
349                {
350                        m_canCheckCloseSocket = true;
351                        char tmp[100];
352                        int peeked = m_pSocketBackend->Peek(&tmp, 100, error);
353                        if (peeked >= 0) {
354                                if (peeked > 0)
355                                        m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::OnSocketEvent(): pending data, postponing close event"));
356                                else {
357                                        m_socket_eof = true;
358                                        m_socketClosed = true;
359                                }
360                                OnRead();
361
362                                if (peeked)
363                                        return;
364                        }
365
366                        m_pOwner->LogMessage(MessageType::Debug_Info, _T("CTlsSocket::OnSocketEvent(): close event received"));
367
368                        //Uninit();
369                        m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, 0);
370                }
371                break;
372        default:
373                break;
374        }
375}
376
377void CTlsSocket::OnRead()
378{
379        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::OnRead()"));
380
381        m_canReadFromSocket = true;
382
383        if (!m_session)
384                return;
385
386        const int direction = gnutls_record_get_direction(m_session);
387        if (direction && !m_lastReadFailed) {
388                m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::Postponing read"));
389                return;
390        }
391
392        if (m_tlsState == TlsState::handshake)
393                ContinueHandshake();
394        if (m_tlsState == TlsState::closing)
395                ContinueShutdown();
396        else if (m_tlsState == TlsState::conn) {
397                CheckResumeFailedReadWrite();
398                TriggerEvents();
399        }
400}
401
402void CTlsSocket::OnSend()
403{
404        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::OnSend()"));
405
406        m_canWriteToSocket = true;
407
408        if (!m_session)
409                return;
410
411        const int direction = gnutls_record_get_direction(m_session);
412        if (!direction && !m_lastWriteFailed)
413                return;
414
415        if (m_tlsState == TlsState::handshake)
416                ContinueHandshake();
417        else if (m_tlsState == TlsState::closing)
418                ContinueShutdown();
419        else if (m_tlsState == TlsState::conn) {
420                CheckResumeFailedReadWrite();
421                TriggerEvents();
422        }
423}
424
425bool CTlsSocket::CopySessionData(const CTlsSocket* pPrimarySocket)
426{
427        gnutls_datum_t d;
428        int res = gnutls_session_get_data2(pPrimarySocket->m_session, &d);
429        if (res) {
430                m_pOwner->LogMessage(MessageType::Debug_Warning, _T("gnutls_session_get_data2 on primary socket failed: %d"), res);
431                return true;
432        }
433
434        // Set session data
435        res = gnutls_session_set_data(m_session, d.data, d.size );
436        gnutls_free(d.data);
437        if (res) {
438                m_pOwner->LogMessage(MessageType::Debug_Info, _T("gnutls_session_set_data failed: %d. Going to reinitialize session."), res);
439                UninitSession();
440                if (!InitSession())
441                        return false;
442        }
443        else
444                m_pOwner->LogMessage(MessageType::Debug_Info, _T("Trying to resume existing TLS session."));
445
446        return true;
447}
448
449bool CTlsSocket::ResumedSession() const
450{
451        return gnutls_session_is_resumed(m_session) != 0;
452}
453
454int CTlsSocket::Handshake(const CTlsSocket* pPrimarySocket, bool try_resume)
455{
456        m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::Handshake()"));
457        wxASSERT(m_session);
458
459        m_tlsState = TlsState::handshake;
460
461        wxString hostname;
462
463        if (pPrimarySocket) {
464                // Implicitly trust certificate of primary socket
465                unsigned int cert_list_size;
466                const gnutls_datum_t* const cert_list = gnutls_certificate_get_peers(pPrimarySocket->m_session, &cert_list_size);
467                if (cert_list && cert_list_size) {
468                        delete [] m_implicitTrustedCert.data;
469                        m_implicitTrustedCert.data = new unsigned char[cert_list[0].size];
470                        memcpy(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size);
471                        m_implicitTrustedCert.size = cert_list[0].size;
472                }
473
474                if (try_resume) {
475                        if (!CopySessionData(pPrimarySocket))
476                                return FZ_REPLY_ERROR;
477                }
478
479                hostname = pPrimarySocket->m_socket.GetPeerHost();
480        }
481        else {
482                hostname = m_socket.GetPeerHost();
483        }
484
485        if (!hostname.empty() && fz::get_address_type(hostname.ToStdWstring()) == fz::address_type::unknown) {
486                const wxWX2MBbuf utf8 = hostname.mb_str(wxConvUTF8);
487                if (utf8) {
488                        int res = gnutls_server_name_set( m_session, GNUTLS_NAME_DNS, utf8, strlen(utf8) );
489                        if (res) {
490                                LogError(res, _T("gnutls_server_name_set"), MessageType::Debug_Warning );
491                        }
492                }
493        }
494
495        return ContinueHandshake();
496}
497
498int CTlsSocket::ContinueHandshake()
499{
500        m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::ContinueHandshake()"));
501        wxASSERT(m_session);
502        wxASSERT(m_tlsState == TlsState::handshake);
503
504        int res = gnutls_handshake(m_session);
505        while (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) {
506                if (!(gnutls_record_get_direction(m_session) ? m_canWriteToSocket : m_canReadFromSocket)) {
507                        break;
508                }
509                res = gnutls_handshake(m_session);
510        }
511        if (!res) {
512                m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Handshake successful"));
513
514                if (ResumedSession())
515                        m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Session resumed"));
516
517                const wxString protocol = GetProtocolName();
518                const wxString keyExchange = GetKeyExchange();
519                const wxString cipherName = GetCipherName();
520                const wxString macName = GetMacName();
521
522                m_pOwner->LogMessage(MessageType::Debug_Info, _T("Protocol: %s, Key exchange: %s, Cipher: %s, MAC: %s"), protocol, keyExchange, cipherName, macName);
523
524                res = VerifyCertificate();
525                if (res != FZ_REPLY_OK)
526                        return res;
527
528                if (m_shutdown_requested) {
529                        int error = Shutdown();
530                        if (!error || error != EAGAIN) {
531                                m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, 0);
532                        }
533                }
534
535                return FZ_REPLY_OK;
536        }
537        else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED)
538                return FZ_REPLY_WOULDBLOCK;
539
540        Failure(res, true);
541
542        return FZ_REPLY_ERROR;
543}
544
545int CTlsSocket::Read(void *buffer, unsigned int len, int& error)
546{
547        if (m_tlsState == TlsState::handshake || m_tlsState == TlsState::verifycert) {
548                error = EAGAIN;
549                return -1;
550        }
551        else if (m_tlsState != TlsState::conn) {
552                error = ENOTCONN;
553                return -1;
554        }
555        else if (m_lastReadFailed) {
556                error = EAGAIN;
557                return -1;
558        }
559
560        if (m_peekDataLen) {
561                unsigned int min = wxMin(len, m_peekDataLen);
562                memcpy(buffer, m_peekData, min);
563
564                if (min == m_peekDataLen) {
565                        m_peekDataLen = 0;
566                        delete [] m_peekData;
567                        m_peekData = 0;
568                }
569                else {
570                        memmove(m_peekData, m_peekData + min, m_peekDataLen - min);
571                        m_peekDataLen -= min;
572                }
573
574                TriggerEvents();
575
576                error = 0;
577                return min;
578        }
579
580        int res = DoCallGnutlsRecordRecv(buffer, len);
581        if (res >= 0) {
582                if (res > 0)
583                        TriggerEvents();
584                else {
585                        // Peer did already initiate a shutdown, reply to it
586                        gnutls_bye(m_session, GNUTLS_SHUT_WR);
587                        // Note: Theoretically this could return a write error.
588                        // But we ignore it, since it is perfectly valid for peer
589                        // to close the connection after sending its shutdown
590                        // notification.
591                }
592
593                error = 0;
594                return res;
595        }
596
597        if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) {
598                error = EAGAIN;
599                m_lastReadFailed = true;
600        }
601        else {
602                Failure(res, false, _T("gnutls_record_recv"));
603                error = m_socket_error;
604        }
605
606        return -1;
607}
608
609int CTlsSocket::Write(const void *buffer, unsigned int len, int& error)
610{
611        if (m_tlsState == TlsState::handshake || m_tlsState == TlsState::verifycert) {
612                error = EAGAIN;
613                return -1;
614        }
615        else if (m_tlsState != TlsState::conn) {
616                error = ENOTCONN;
617                return -1;
618        }
619
620        if (m_lastWriteFailed) {
621                error = EAGAIN;
622                return -1;
623        }
624
625        if (m_writeSkip >= len) {
626                m_writeSkip -= len;
627                return len;
628        }
629
630        len -= m_writeSkip;
631        buffer = (char*)buffer + m_writeSkip;
632
633        int res = gnutls_record_send(m_session, buffer, len);
634
635        while ((res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) && m_canWriteToSocket)
636                res = gnutls_record_send(m_session, 0, 0);
637
638        if (res >= 0) {
639                error = 0;
640                int written = res + m_writeSkip;
641                m_writeSkip = 0;
642
643                TriggerEvents();
644                return written;
645        }
646
647        if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) {
648                if (m_writeSkip) {
649                        error = 0;
650                        int written = m_writeSkip;
651                        m_writeSkip = 0;
652                        return written;
653                }
654                else {
655                        error = EAGAIN;
656                        m_lastWriteFailed = true;
657                        return -1;
658                }
659        }
660        else {
661                Failure(res, false, _T("gnutls_record_send"));
662                error = m_socket_error;
663                return -1;
664        }
665}
666
667void CTlsSocket::TriggerEvents()
668{
669        if (m_tlsState != TlsState::conn)
670                return;
671
672        if (m_canTriggerRead) {
673                m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::read, 0);
674                m_canTriggerRead = false;
675        }
676
677        if (m_canTriggerWrite) {
678                m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::write, 0);
679                m_canTriggerWrite = false;
680        }
681}
682
683void CTlsSocket::CheckResumeFailedReadWrite()
684{
685        if (m_lastWriteFailed) {
686                int res = GNUTLS_E_AGAIN;
687                while ((res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) && m_canWriteToSocket)
688                        res = gnutls_record_send(m_session, 0, 0);
689
690                if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN)
691                        return;
692
693                if (res < 0) {
694                        Failure(res, true);
695                        return;
696                }
697
698                m_writeSkip += res;
699                m_lastWriteFailed = false;
700                m_canTriggerWrite = true;
701        }
702        if (m_lastReadFailed) {
703                wxASSERT(!m_peekData);
704
705                m_peekDataLen = 65536;
706                m_peekData = new char[m_peekDataLen];
707
708                int res = DoCallGnutlsRecordRecv(m_peekData, m_peekDataLen);
709                if (res < 0) {
710                        m_peekDataLen = 0;
711                        delete [] m_peekData;
712                        m_peekData = 0;
713                        if (res != GNUTLS_E_INTERRUPTED && res != GNUTLS_E_AGAIN)
714                                Failure(res, true);
715                        return;
716                }
717
718                if (!res) {
719                        m_peekDataLen = 0;
720                        delete [] m_peekData;
721                        m_peekData = 0;
722                }
723                else
724                        m_peekDataLen = res;
725
726                m_lastReadFailed = false;
727                m_canTriggerRead = true;
728        }
729}
730
731void CTlsSocket::Failure(int code, bool send_close, const wxString& function)
732{
733        m_pOwner->LogMessage(MessageType::Debug_Debug, _T("CTlsSocket::Failure(%d)"), code);
734        if (code) {
735                LogError(code, function);
736                if (m_socket_eof) {
737                        if (code == GNUTLS_E_UNEXPECTED_PACKET_LENGTH
738#ifdef GNUTLS_E_PREMATURE_TERMINATION
739                                || code == GNUTLS_E_PREMATURE_TERMINATION
740#endif
741                                )
742                        {
743                                m_pOwner->LogMessage(MessageType::Status, _("Server did not properly shut down TLS connection"));
744                        }
745                }
746        }
747        Uninit();
748
749        if (send_close) {
750                m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, m_socket_error);
751        }
752}
753
754int CTlsSocket::Peek(void *buffer, unsigned int len, int& error)
755{
756        if (m_peekData) {
757                int min = wxMin(len, m_peekDataLen);
758                memcpy(buffer, m_peekData, min);
759
760                error = 0;
761                return min;
762        }
763
764        int read = Read(buffer, len, error);
765        if (read <= 0)
766                return read;
767
768        m_peekDataLen = read;
769        m_peekData = new char[m_peekDataLen];
770        memcpy(m_peekData, buffer, m_peekDataLen);
771
772        return read;
773}
774
775int CTlsSocket::Shutdown()
776{
777        m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::Shutdown()"));
778
779        if (m_tlsState == TlsState::closed)
780                return 0;
781
782        if (m_tlsState == TlsState::closing)
783                return EAGAIN;
784
785        if (m_tlsState == TlsState::handshake || m_tlsState == TlsState::verifycert) {
786                // Shutdown during handshake is not a good idea.
787                m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("Shutdown during handshake, postponing"));
788                m_shutdown_requested = true;
789                return EAGAIN;
790        }
791
792        if (m_tlsState != TlsState::conn)
793                return ECONNABORTED;
794
795        m_tlsState = TlsState::closing;
796
797        int res = gnutls_bye(m_session, GNUTLS_SHUT_WR);
798        while ((res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) && m_canWriteToSocket)
799                res = gnutls_bye(m_session, GNUTLS_SHUT_WR);
800        if (!res) {
801                m_tlsState = TlsState::closed;
802                return 0;
803        }
804
805        if (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN)
806                return EAGAIN;
807
808        Failure(res, false);
809        return m_socket_error;
810}
811
812void CTlsSocket::ContinueShutdown()
813{
814        m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::ContinueShutdown()"));
815
816        int res = gnutls_bye(m_session, GNUTLS_SHUT_WR);
817        while ((res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) && m_canWriteToSocket)
818                res = gnutls_bye(m_session, GNUTLS_SHUT_WR);
819        if (!res) {
820                m_tlsState = TlsState::closed;
821
822                m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, 0);
823
824                return;
825        }
826
827        if (res != GNUTLS_E_INTERRUPTED && res != GNUTLS_E_AGAIN)
828                Failure(res, true);
829}
830
831void CTlsSocket::TrustCurrentCert(bool trusted)
832{
833        if (m_tlsState != TlsState::verifycert) {
834                m_pOwner->LogMessage(MessageType::Debug_Warning, _T("TrustCurrentCert called at wrong time."));
835                return;
836        }
837
838        if (trusted) {
839                m_tlsState = TlsState::conn;
840
841                if (m_lastWriteFailed)
842                        m_lastWriteFailed = false;
843                CheckResumeFailedReadWrite();
844
845                if (m_tlsState == TlsState::conn) {
846                        m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::connection, 0);
847                }
848
849                TriggerEvents();
850
851                return;
852        }
853
854        m_pOwner->LogMessage(MessageType::Error, _("Remote certificate not trusted."));
855        Failure(0, true);
856}
857
858static wxString bin2hex(const unsigned char* in, size_t size)
859{
860        wxString str;
861        for (size_t i = 0; i < size; i++)
862        {
863                if (i)
864                        str += _T(":");
865                str += wxString::Format(_T("%.2x"), (int)in[i]);
866        }
867
868        return str;
869}
870
871
872bool CTlsSocket::ExtractCert(gnutls_datum_t const* datum, CCertificate& out)
873{
874        gnutls_x509_crt_t cert;
875        if (gnutls_x509_crt_init(&cert)) {
876                m_pOwner->LogMessage(MessageType::Error, _("Could not initialize structure for peer certificates, gnutls_x509_crt_init failed"));
877                return false;
878        }
879
880        if (gnutls_x509_crt_import(cert, datum, GNUTLS_X509_FMT_DER)) {
881                m_pOwner->LogMessage(MessageType::Error, _("Could not import peer certificates, gnutls_x509_crt_import failed"));
882                gnutls_x509_crt_deinit(cert);
883                return false;
884        }
885
886        fz::datetime expirationTime(gnutls_x509_crt_get_expiration_time(cert), fz::datetime::seconds);
887        fz::datetime activationTime(gnutls_x509_crt_get_activation_time(cert), fz::datetime::seconds);
888
889        // Get the serial number of the certificate
890        unsigned char buffer[40];
891        size_t size = sizeof(buffer);
892        int res = gnutls_x509_crt_get_serial(cert, buffer, &size);
893        if( res != 0 ) {
894                size = 0;
895        }
896
897        wxString serial = bin2hex(buffer, size);
898
899        unsigned int pkBits;
900        int pkAlgo = gnutls_x509_crt_get_pk_algorithm(cert, &pkBits);
901        wxString pkAlgoName;
902        if (pkAlgo >= 0) {
903                const char* pAlgo = gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)pkAlgo);
904                if (pAlgo)
905                        pkAlgoName = wxString(pAlgo, wxConvUTF8);
906        }
907
908        int signAlgo = gnutls_x509_crt_get_signature_algorithm(cert);
909        wxString signAlgoName;
910        if (signAlgo >= 0) {
911                const char* pAlgo = gnutls_sign_algorithm_get_name((gnutls_sign_algorithm_t)signAlgo);
912                if (pAlgo)
913                        signAlgoName = wxString(pAlgo, wxConvUTF8);
914        }
915
916        wxString subject, issuer;
917
918        size = 0;
919        res = gnutls_x509_crt_get_dn(cert, 0, &size);
920        if (size) {
921                char* dn = new char[size + 1];
922                dn[size] = 0;
923                if (!(res = gnutls_x509_crt_get_dn(cert, dn, &size)))
924                {
925                        dn[size] = 0;
926                        subject = wxString(dn, wxConvUTF8);
927                }
928                else
929                        LogError(res, _T("gnutls_x509_crt_get_dn"));
930                delete [] dn;
931        }
932        else
933                LogError(res, _T("gnutls_x509_crt_get_dn"));
934        if (subject.empty()) {
935                m_pOwner->LogMessage(MessageType::Error, _("Could not get distinguished name of certificate subject, gnutls_x509_get_dn failed"));
936                gnutls_x509_crt_deinit(cert);
937                return false;
938        }
939
940        std::vector<wxString> alt_subject_names = GetCertSubjectAltNames(cert);
941
942        size = 0;
943        res = gnutls_x509_crt_get_issuer_dn(cert, 0, &size);
944        if (size) {
945                char* dn = new char[++size + 1];
946                dn[size] = 0;
947                if (!(res = gnutls_x509_crt_get_issuer_dn(cert, dn, &size))) {
948                        dn[size] = 0;
949                        issuer = wxString(dn, wxConvUTF8);
950                }
951                else
952                        LogError(res, _T("gnutls_x509_crt_get_issuer_dn"));
953                delete [] dn;
954        }
955        else
956                LogError(res, _T("gnutls_x509_crt_get_issuer_dn"));
957        if (issuer.empty() ) {
958                m_pOwner->LogMessage(MessageType::Error, _("Could not get distinguished name of certificate issuer, gnutls_x509_get_issuer_dn failed"));
959                gnutls_x509_crt_deinit(cert);
960                return false;
961        }
962
963        wxString fingerprint_sha256;
964        wxString fingerprint_sha1;
965
966        unsigned char digest[100];
967        size = sizeof(digest) - 1;
968        if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA256, digest, &size)) {
969                digest[size] = 0;
970                fingerprint_sha256 = bin2hex(digest, size);
971        }
972        size = sizeof(digest) - 1;
973        if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &size)) {
974                digest[size] = 0;
975                fingerprint_sha1 = bin2hex(digest, size);
976        }
977
978        gnutls_x509_crt_deinit(cert);
979
980        out = CCertificate(
981                datum->data, datum->size,
982                activationTime, expirationTime,
983                serial,
984                pkAlgoName, pkBits,
985                signAlgoName,
986                fingerprint_sha256,
987                fingerprint_sha1,
988                issuer,
989                subject,
990                alt_subject_names);
991
992        return true;
993}
994
995
996std::vector<wxString> CTlsSocket::GetCertSubjectAltNames(gnutls_x509_crt_t cert)
997{
998        std::vector<wxString> ret;
999
1000        char san[4096];
1001        for (unsigned int i = 0; i < 10000; ++i) { // I assume this is a sane limit
1002                size_t san_size = sizeof(san) - 1;
1003                int const type_or_error = gnutls_x509_crt_get_subject_alt_name(cert, i, san, &san_size, 0);
1004                if (type_or_error == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1005                        continue;
1006                }
1007                else if (type_or_error < 0) {
1008                        break;
1009                }
1010
1011                if (type_or_error == GNUTLS_SAN_DNSNAME || type_or_error == GNUTLS_SAN_RFC822NAME) {
1012                        wxString dns = wxString(san, wxConvUTF8);
1013                        if (!dns.empty()) {
1014                                ret.push_back(dns);
1015                        }
1016                }
1017                else if (type_or_error == GNUTLS_SAN_IPADDRESS) {
1018                        wxString ip = CSocket::AddressToString(san, san_size);
1019                        if (!ip.empty()) {
1020                                ret.push_back(ip);
1021                        }
1022                }
1023        }
1024
1025        return ret;
1026}
1027
1028bool CTlsSocket::CertificateIsBlacklisted(std::vector<CCertificate> const&)
1029{
1030        return false;
1031}
1032
1033
1034int CTlsSocket::GetAlgorithmWarnings()
1035{
1036        int algorithmWarnings{};
1037
1038        switch (gnutls_protocol_get_version(m_session))
1039        {
1040                case GNUTLS_SSL3:
1041                case GNUTLS_VERSION_UNKNOWN:
1042                        algorithmWarnings |= CCertificateNotification::tlsver;
1043                        break;
1044                default:
1045                        break;
1046        }
1047
1048        switch (gnutls_cipher_get(m_session)) {
1049                case GNUTLS_CIPHER_UNKNOWN:
1050                case GNUTLS_CIPHER_NULL:
1051                case GNUTLS_CIPHER_ARCFOUR_128:
1052                case GNUTLS_CIPHER_3DES_CBC:
1053                case GNUTLS_CIPHER_ARCFOUR_40:
1054                case GNUTLS_CIPHER_RC2_40_CBC:
1055                case GNUTLS_CIPHER_DES_CBC:
1056                        algorithmWarnings |= CCertificateNotification::cipher;
1057                        break;
1058                default:
1059                        break;
1060        }
1061
1062        switch (gnutls_mac_get(m_session)) {
1063                case GNUTLS_MAC_UNKNOWN:
1064                case GNUTLS_MAC_NULL:
1065                case GNUTLS_MAC_MD5:
1066                case GNUTLS_MAC_MD2:
1067                case GNUTLS_MAC_UMAC_96:
1068                        algorithmWarnings |= CCertificateNotification::mac;
1069                        break;
1070                default:
1071                        break;
1072        }
1073
1074        switch (gnutls_kx_get(m_session)) {
1075                case GNUTLS_KX_UNKNOWN:
1076                case GNUTLS_KX_ANON_DH:
1077                case GNUTLS_KX_RSA_EXPORT:
1078                case GNUTLS_KX_ANON_ECDH:
1079                        algorithmWarnings |= CCertificateNotification::kex;
1080                default:
1081                        break;
1082        }
1083
1084        return algorithmWarnings;
1085}
1086
1087
1088int CTlsSocket::VerifyCertificate()
1089{
1090        if (m_tlsState != TlsState::handshake) {
1091                m_pOwner->LogMessage(MessageType::Debug_Warning, _T("VerifyCertificate called at wrong time"));
1092                return FZ_REPLY_ERROR;
1093        }
1094
1095        m_tlsState = TlsState::verifycert;
1096
1097        if (gnutls_certificate_type_get(m_session) != GNUTLS_CRT_X509) {
1098                m_pOwner->LogMessage(MessageType::Error, _("Unsupported certificate type"));
1099                Failure(0, true);
1100                return FZ_REPLY_ERROR;
1101        }
1102
1103        unsigned int status = 0;
1104        int const verifyResult = gnutls_certificate_verify_peers2(m_session, &status);
1105        if (verifyResult < 0) {
1106                m_pOwner->LogMessage(MessageType::Debug_Warning, _T("gnutls_certificate_verify_peers2 returned %d with status %u"), verifyResult, status);
1107                m_pOwner->LogMessage(MessageType::Error, _("Failed to verify peer certificate"));
1108                Failure(0, true);
1109                return FZ_REPLY_ERROR;
1110        }
1111
1112        if (status & GNUTLS_CERT_REVOKED) {
1113                m_pOwner->LogMessage(MessageType::Error, _("Beware! Certificate has been revoked"));
1114                Failure(0, true);
1115                return FZ_REPLY_ERROR;
1116        }
1117
1118        if (status & GNUTLS_CERT_SIGNER_NOT_CA) {
1119                m_pOwner->LogMessage(MessageType::Error, _("Incomplete chain, top certificate is not self-signed certificate authority certificate"));
1120                Failure(0, true);
1121                return FZ_REPLY_ERROR;
1122        }
1123
1124        unsigned int cert_list_size;
1125        const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(m_session, &cert_list_size);
1126        if (!cert_list || !cert_list_size) {
1127                m_pOwner->LogMessage(MessageType::Error, _("gnutls_certificate_get_peers returned no certificates"));
1128                Failure(0, true);
1129                return FZ_REPLY_ERROR;
1130        }
1131
1132        if (m_implicitTrustedCert.data) {
1133                if (m_implicitTrustedCert.size != cert_list[0].size ||
1134                        memcmp(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size))
1135                {
1136                        m_pOwner->LogMessage(MessageType::Error, _("Primary connection and data connection certificates don't match."));
1137                        Failure(0, true);
1138                        return FZ_REPLY_ERROR;
1139                }
1140
1141                TrustCurrentCert(true);
1142
1143                if (m_tlsState != TlsState::conn)
1144                        return FZ_REPLY_ERROR;
1145                return FZ_REPLY_OK;
1146        }
1147
1148        m_pOwner->LogMessage(MessageType::Status, _("Verifying certificate..."));
1149
1150        std::vector<CCertificate> certificates;
1151        for (unsigned int i = 0; i < cert_list_size; ++i) {
1152                CCertificate cert;
1153                if (ExtractCert(cert_list, cert))
1154                        certificates.push_back(cert);
1155                else {
1156                        Failure(0, true);
1157                        return FZ_REPLY_ERROR;
1158                }
1159
1160                ++cert_list;
1161        }
1162
1163        if (CertificateIsBlacklisted(certificates)) {
1164                Failure(0, true);
1165                return FZ_REPLY_ERROR;
1166        }
1167
1168        int const algorithmWarnings = GetAlgorithmWarnings();
1169
1170        CCertificateNotification *pNotification = new CCertificateNotification(
1171                m_pOwner->GetCurrentServer()->GetHost(),
1172                m_pOwner->GetCurrentServer()->GetPort(),
1173                GetProtocolName(),
1174                GetKeyExchange(),
1175                GetCipherName(),
1176                GetMacName(),
1177                algorithmWarnings,
1178                certificates);
1179
1180        m_pOwner->SendAsyncRequest(pNotification);
1181
1182        return FZ_REPLY_WOULDBLOCK;
1183}
1184
1185void CTlsSocket::OnRateAvailable(CRateLimiter::rate_direction)
1186{
1187}
1188
1189wxString CTlsSocket::GetProtocolName()
1190{
1191        wxString protocol = _("unknown");
1192
1193        const char* s = gnutls_protocol_get_name( gnutls_protocol_get_version( m_session ) );
1194        if (s && *s)
1195                protocol = wxString(s, wxConvUTF8);
1196
1197        return protocol;
1198}
1199
1200wxString CTlsSocket::GetKeyExchange()
1201{
1202        wxString keyExchange = _("unknown");
1203
1204        const char* s = gnutls_kx_get_name( gnutls_kx_get( m_session ) );
1205        if (s && *s)
1206                keyExchange = wxString(s, wxConvUTF8);
1207
1208        return keyExchange;
1209}
1210
1211wxString CTlsSocket::GetCipherName()
1212{
1213        const char* cipher = gnutls_cipher_get_name(gnutls_cipher_get(m_session));
1214        if (cipher && *cipher)
1215                return wxString(cipher, wxConvUTF8);
1216        else
1217                return _("unknown");
1218}
1219
1220wxString CTlsSocket::GetMacName()
1221{
1222        const char* mac = gnutls_mac_get_name(gnutls_mac_get(m_session));
1223        if (mac && *mac)
1224                return wxString(mac, wxConvUTF8);
1225        else
1226                return _T("unknown");
1227}
1228
1229wxString CTlsSocket::ListTlsCiphers(wxString priority)
1230{
1231        if (priority.empty())
1232                priority = wxString::FromUTF8(ciphers);
1233
1234        wxString list = wxString::Format(_T("Ciphers for %s:\n"), priority);
1235
1236        gnutls_priority_t pcache;
1237        const char *err = 0;
1238        int ret = gnutls_priority_init(&pcache, priority.mb_str(), &err);
1239        if (ret < 0) {
1240                list += wxString::Format(_T("gnutls_priority_init failed with code %d: %s"), ret, err ? wxString::FromUTF8(err) : _T("Unknown error"));
1241                return list;
1242        }
1243        else {
1244                for (size_t i = 0; ; i++) {
1245                        unsigned int idx;
1246                        ret = gnutls_priority_get_cipher_suite_index(pcache, i, &idx);
1247                        if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1248                                break;
1249                        if (ret == GNUTLS_E_UNKNOWN_CIPHER_SUITE)
1250                                continue;
1251
1252                        gnutls_protocol_t version;
1253                        unsigned char id[2];
1254                        const char* name = gnutls_cipher_suite_info(idx, id, NULL, NULL, NULL, &version);
1255
1256                        if (name != 0)
1257                        {
1258                                list += wxString::Format(
1259                                        _T("%-50s    0x%02x, 0x%02x    %s\n"),
1260                                        wxString::FromUTF8(name),
1261                                        (unsigned char)id[0],
1262                                        (unsigned char)id[1],
1263                                        wxString::FromUTF8(gnutls_protocol_get_name(version)));
1264                        }
1265                }
1266        }
1267
1268        return list;
1269}
1270
1271int CTlsSocket::DoCallGnutlsRecordRecv(void* data, size_t len)
1272{
1273        int res = gnutls_record_recv(m_session, data, len);
1274        while( (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) && m_canReadFromSocket && !gnutls_record_get_direction(m_session)) {
1275                // Spurious EAGAIN. Can happen if GnuTLS gets a partial
1276                // record and the socket got closed.
1277                // The unexpected close is being ignored in this case, unless
1278                // gnutls_record_recv is being called again.
1279                // Manually call gnutls_record_recv as in case of eof on the socket,
1280                // we are not getting another receive event.
1281                m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("gnutls_record_recv returned spurious EAGAIN"));
1282                res = gnutls_record_recv(m_session, data, len);
1283        }
1284
1285        return res;
1286}
Note: See TracBrowser for help on using the repository browser.