int CTlsSocket::ContinueHandshake() { m_pOwner->LogMessage(Debug_Verbose, _T("CTlsSocket::ContinueHandshake()")); wxASSERT(m_session); wxASSERT(m_tlsState == handshake); int res = gnutls_handshake(m_session); while (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) { if ( gnutls_record_get_direction(m_session) != 1 || !m_canWriteToSocket ) break; res = gnutls_handshake(m_session); } if (!res) { m_pOwner->LogMessage(Debug_Info, _T("TLS Handshake successful")); if (ResumedSession()) m_pOwner->LogMessage(Debug_Info, _T("TLS Session resumed")); const wxString protocol = GetProtocolName(); const wxString keyExchange = GetKeyExchange(); const wxString cipherName = GetCipherName(); const wxString macName = GetMacName(); m_pOwner->LogMessage(Debug_Info, _T("Protocol: %s, Key exchange: %s, Cipher: %s, MAC: %s"), protocol.c_str(), keyExchange.c_str(), cipherName.c_str(), macName.c_str()); res = VerifyCertificate(); if (res != FZ_REPLY_OK) return res; if (m_shutdown_requested) { int error = Shutdown(); if (!error || error != EAGAIN) { CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close); CSocketEventDispatcher::Get().SendEvent(evt); } } return FZ_REPLY_OK; } else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) return FZ_REPLY_WOULDBLOCK; Failure(res, ECONNABORTED); return FZ_REPLY_ERROR; }
int CTlsSocket::ContinueHandshake() { m_pOwner->LogMessage(MessageType::Debug_Verbose, _T("CTlsSocket::ContinueHandshake()")); wxASSERT(m_session); wxASSERT(m_tlsState == TlsState::handshake); int res = gnutls_handshake(m_session); while (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) { if (!(gnutls_record_get_direction(m_session) ? m_canWriteToSocket : m_canReadFromSocket)) { break; } res = gnutls_handshake(m_session); } if (!res) { m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Handshake successful")); if (ResumedSession()) m_pOwner->LogMessage(MessageType::Debug_Info, _T("TLS Session resumed")); const wxString protocol = GetProtocolName(); const wxString keyExchange = GetKeyExchange(); const wxString cipherName = GetCipherName(); const wxString macName = GetMacName(); m_pOwner->LogMessage(MessageType::Debug_Info, _T("Protocol: %s, Key exchange: %s, Cipher: %s, MAC: %s"), protocol, keyExchange, cipherName, macName); res = VerifyCertificate(); if (res != FZ_REPLY_OK) return res; if (m_shutdown_requested) { int error = Shutdown(); if (!error || error != EAGAIN) { m_pEvtHandler->send_event<CSocketEvent>(this, SocketEventType::close, 0); } } return FZ_REPLY_OK; } else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) return FZ_REPLY_WOULDBLOCK; Failure(res, true); return FZ_REPLY_ERROR; }
int CTlsSocket::ContinueHandshake() { m_pOwner->LogMessage(Debug_Verbose, _T("CTlsSocket::ContinueHandshake()")); wxASSERT(m_session); wxASSERT(m_tlsState == handshake); int res = gnutls_handshake(m_session); if (!res) { m_pOwner->LogMessage(Debug_Info, _T("Handshake successful")); if (ResumedSession()) m_pOwner->LogMessage(Debug_Info, _T("Session resumed")); const wxString& cipherName = GetCipherName(); const wxString& macName = GetMacName(); m_pOwner->LogMessage(Debug_Info, _T("Cipher: %s, MAC: %s"), cipherName.c_str(), macName.c_str()); res = VerifyCertificate(); if (res != FZ_REPLY_OK) return res; if (m_shutdown_requested) { int error = Shutdown(); if (!error || error != EAGAIN) { CSocketEvent *evt = new CSocketEvent(m_pEvtHandler, this, CSocketEvent::close); CSocketEventDispatcher::Get().SendEvent(evt); } } return FZ_REPLY_OK; } else if (res == GNUTLS_E_AGAIN || res == GNUTLS_E_INTERRUPTED) return FZ_REPLY_WOULDBLOCK; Failure(res, ECONNABORTED); return FZ_REPLY_ERROR; }
int CTlsSocket::VerifyCertificate() { if (m_tlsState != handshake) { m_pOwner->LogMessage(::Debug_Warning, _T("VerifyCertificate called at wrong time")); return FZ_REPLY_ERROR; } m_tlsState = verifycert; if (gnutls_certificate_type_get(m_session) != GNUTLS_CRT_X509) { m_pOwner->LogMessage(::Error, _("Unsupported certificate type")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int status = 0; if (gnutls_certificate_verify_peers2(m_session, &status) < 0) { m_pOwner->LogMessage(::Error, _("Failed to verify peer certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_REVOKED) { m_pOwner->LogMessage(::Error, _("Beware! Certificate has been revoked")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_SIGNER_NOT_CA) { m_pOwner->LogMessage(::Error, _("Incomplete chain, top certificate is not self-signed certificate authority certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_require_root_trust && status & GNUTLS_CERT_SIGNER_NOT_FOUND) { m_pOwner->LogMessage(::Error, _("Root certificate is not trusted")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int cert_list_size; const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(m_session, &cert_list_size); if (!cert_list || !cert_list_size) { m_pOwner->LogMessage(::Error, _("gnutls_certificate_get_peers returned no certificates")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_implicitTrustedCert.data) { if (m_implicitTrustedCert.size != cert_list[0].size || memcmp(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size)) { m_pOwner->LogMessage(::Error, _("Primary connection and data connection certificates don't match.")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } TrustCurrentCert(true); if (m_tlsState != conn) return FZ_REPLY_ERROR; return FZ_REPLY_OK; } std::vector<CCertificate> certificates; for (unsigned int i = 0; i < cert_list_size; i++) { CCertificate cert; if (ExtractCert(cert_list, cert)) certificates.push_back(cert); else { Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } ++cert_list; } CCertificateNotification *pNotification = new CCertificateNotification( m_pOwner->GetCurrentServer()->GetHost(), m_pOwner->GetCurrentServer()->GetPort(), GetProtocolName(), GetKeyExchange(), GetCipherName(), GetMacName(), certificates); m_pOwner->SendAsyncRequest(pNotification); m_pOwner->LogMessage(Status, _("Verifying certificate...")); return FZ_REPLY_WOULDBLOCK; }
int CTlsSocket::VerifyCertificate() { if (m_tlsState != handshake) { m_pOwner->LogMessage(::Debug_Warning, _T("VerifyCertificate called at wrong time")); return FZ_REPLY_ERROR; } m_tlsState = verifycert; if (gnutls_certificate_type_get(m_session) != GNUTLS_CRT_X509) { m_pOwner->LogMessage(::Error, _("Unsupported certificate type")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int status = 0; if (gnutls_certificate_verify_peers2(m_session, &status) < 0) { m_pOwner->LogMessage(::Error, _("Failed to verify peer certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_REVOKED) { m_pOwner->LogMessage(::Error, _("Beware! Certificate has been revoked")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (status & GNUTLS_CERT_SIGNER_NOT_CA) { m_pOwner->LogMessage(::Error, _("Incomplete chain, top certificate is not self-signed certificate authority certificate")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_require_root_trust && status & GNUTLS_CERT_SIGNER_NOT_FOUND) { m_pOwner->LogMessage(::Error, _("Root certificate is not trusted")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } unsigned int cert_list_size; const gnutls_datum_t* cert_list = gnutls_certificate_get_peers(m_session, &cert_list_size); if (!cert_list || !cert_list_size) { m_pOwner->LogMessage(::Error, _("gnutls_certificate_get_peers returned no certificates")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (m_implicitTrustedCert.data) { if (m_implicitTrustedCert.size != cert_list[0].size || memcmp(m_implicitTrustedCert.data, cert_list[0].data, cert_list[0].size)) { m_pOwner->LogMessage(::Error, _("Primary connection and data connection certificates don't match.")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } TrustCurrentCert(true); if (m_tlsState != conn) return FZ_REPLY_ERROR; return FZ_REPLY_OK; } std::vector<CCertificate> certificates; for (unsigned int i = 0; i < cert_list_size; i++) { gnutls_x509_crt_t cert; if (gnutls_x509_crt_init(&cert)) { m_pOwner->LogMessage(::Error, _("Could not initialize structure for peer certificates, gnutls_x509_crt_init failed")); Failure(0, ECONNABORTED); return FZ_REPLY_ERROR; } if (gnutls_x509_crt_import(cert, cert_list, GNUTLS_X509_FMT_DER)) { m_pOwner->LogMessage(::Error, _("Could not import peer certificates, gnutls_x509_crt_import failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } wxDateTime expirationTime = gnutls_x509_crt_get_expiration_time(cert); wxDateTime activationTime = gnutls_x509_crt_get_activation_time(cert); // Get the serial number of the certificate unsigned char buffer[40]; size_t size = sizeof(buffer); int res = gnutls_x509_crt_get_serial(cert, buffer, &size); wxString serial = bin2hex(buffer, size); unsigned int bits; int algo = gnutls_x509_crt_get_pk_algorithm(cert, &bits); wxString algoName; const char* pAlgo = gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo); if (pAlgo) algoName = wxString(pAlgo, wxConvUTF8); //int version = gnutls_x509_crt_get_version(cert); wxString subject, issuer; size = 0; res = gnutls_x509_crt_get_dn(cert, 0, &size); if (size) { char* dn = new char[size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_dn(cert, dn, &size))) { dn[size] = 0; subject = wxString(dn, wxConvUTF8); } else LogError(res); delete [] dn; } else LogError(res); if (subject == _T("")) { m_pOwner->LogMessage(::Error, _("Could not get distinguished name of certificate subject, gnutls_x509_get_dn failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } size = 0; res = gnutls_x509_crt_get_issuer_dn(cert, 0, &size); if (size) { char* dn = new char[++size + 1]; dn[size] = 0; if (!(res = gnutls_x509_crt_get_issuer_dn(cert, dn, &size))) { dn[size] = 0; issuer = wxString(dn, wxConvUTF8); } else LogError(res); delete [] dn; } else LogError(res); if (issuer == _T("")) { m_pOwner->LogMessage(::Error, _("Could not get distinguished name of certificate issuer, gnutls_x509_get_issuer_dn failed")); Failure(0, ECONNABORTED); gnutls_x509_crt_deinit(cert); return FZ_REPLY_ERROR; } wxString fingerprint_md5; wxString fingerprint_sha1; unsigned char digest[100]; size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_MD5, digest, &size)) { digest[size] = 0; fingerprint_md5 = bin2hex(digest, size); } size = sizeof(digest) - 1; if (!gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &size)) { digest[size] = 0; fingerprint_sha1 = bin2hex(digest, size); } certificates.push_back(CCertificate( cert_list->data, cert_list->size, activationTime, expirationTime, serial, algoName, bits, fingerprint_md5, fingerprint_sha1, subject, issuer)); cert_list++; } CCertificateNotification *pNotification = new CCertificateNotification( m_pOwner->GetCurrentServer()->GetHost(), m_pOwner->GetCurrentServer()->GetPort(), GetCipherName(), GetMacName(), certificates); m_pOwner->SendAsyncRequest(pNotification); m_pOwner->LogMessage(Status, _("Verifying certificate...")); return FZ_REPLY_WOULDBLOCK; }