#include "FileZilla.h"
#include "verifycertdialog.h"
#include <wx/tokenzr.h>
#include "dialogex.h"
#include "ipcmutex.h"
CVerifyCertDialog::~CVerifyCertDialog()
{
for (std::list<t_certData>::iterator iter = m_trustedCerts.begin(); iter != m_trustedCerts.end(); iter++)
delete [] iter->data;
for (std::list<t_certData>::iterator iter = m_sessionTrustedCerts.begin(); iter != m_sessionTrustedCerts.end(); iter++)
delete [] iter->data;
}
void CVerifyCertDialog::ShowVerificationDialog(CCertificateNotification* pNotification)
{
LoadTrustedCerts();
wxDialogEx* pDlg = new wxDialogEx;
pDlg->Load(0, _T("ID_VERIFYCERT"));
pDlg->WrapText(pDlg, XRCID("ID_DESC"), 400);
pDlg->SetLabel(XRCID("ID_HOST"), wxString::Format(_T("%s:%d"), pNotification->GetHost().c_str(), pNotification->GetPort()));
bool warning = false;
if (pNotification->GetActivationTime().IsValid())
{
if (pNotification->GetActivationTime() > wxDateTime::Now())
{
pDlg->SetLabel(XRCID("ID_ACTIVATION_TIME"), wxString::Format(_("%s - Not yet valid!"), pNotification->GetActivationTime().FormatDate().c_str()));
warning = true;
}
else
pDlg->SetLabel(XRCID("ID_ACTIVATION_TIME"), pNotification->GetActivationTime().FormatDate());
}
else
{
warning = true;
pDlg->SetLabel(XRCID("ID_ACTIVATION_TIME"), _("Invalid date"));
}
if (pNotification->GetExpirationTime().IsValid())
{
if (pNotification->GetExpirationTime() < wxDateTime::Now())
{
pDlg->SetLabel(XRCID("ID_EXPIRATION_TIME"), wxString::Format(_("%s - Certificate expired!"), pNotification->GetExpirationTime().FormatDate().c_str()));
warning = true;
}
else
pDlg->SetLabel(XRCID("ID_EXPIRATION_TIME"), pNotification->GetExpirationTime().FormatDate());
}
else
{
warning = true;
pDlg->SetLabel(XRCID("ID_EXPIRATION_TIME"), _("Invalid date"));
}
if (pNotification->GetSerial() != _T(""))
pDlg->SetLabel(XRCID("ID_SERIAL"), pNotification->GetSerial());
else
pDlg->SetLabel(XRCID("ID_SERIAL"), _("None"));
pDlg->SetLabel(XRCID("ID_PKALGO"), wxString::Format(_("%s with %d bits"), pNotification->GetPkAlgoName().c_str(), pNotification->GetPkAlgoBits()));
pDlg->SetLabel(XRCID("ID_FINGERPRINT_MD5"), pNotification->GetFingerPrintMD5());
pDlg->SetLabel(XRCID("ID_FINGERPRINT_SHA1"), pNotification->GetFingerPrintSHA1());
wxSizer* pSizer = XRCCTRL(*pDlg, "ID_SUBJECT_DUMMY", wxStaticText)->GetContainingSizer();
ParseDN(pDlg, pNotification->GetSubject(), pSizer);
XRCCTRL(*pDlg, "ID_SUBJECT_DUMMY", wxStaticText)->Destroy();
pSizer = XRCCTRL(*pDlg, "ID_ISSUER_DUMMY", wxStaticText)->GetContainingSizer();
ParseDN(pDlg, pNotification->GetIssuer(), pSizer);
XRCCTRL(*pDlg, "ID_ISSUER_DUMMY", wxStaticText)->Destroy();
if (warning)
{
XRCCTRL(*pDlg, "ID_IMAGE", wxStaticBitmap)->SetBitmap(wxArtProvider::GetBitmap(wxART_WARNING));
XRCCTRL(*pDlg, "ID_ALWAYS", wxCheckBox)->Enable(false);
}
pDlg->GetSizer()->Fit(pDlg);
pDlg->GetSizer()->SetSizeHints(pDlg);
int res = pDlg->ShowModal();
if (res == wxID_OK)
{
wxASSERT(!IsTrusted(pNotification));
pNotification->m_trusted = true;
if (!warning && XRCCTRL(*pDlg, "ID_ALWAYS", wxCheckBox)->GetValue())
SetPermanentlyTrusted(pNotification);
else
{
t_certData cert;
const unsigned char* data = pNotification->GetRawData(cert.len);
cert.data = new unsigned char[cert.len];
memcpy(cert.data, data, cert.len);
m_sessionTrustedCerts.push_back(cert);
}
}
else
pNotification->m_trusted = false;
delete pDlg;
}
void CVerifyCertDialog::ParseDN(wxDialog* pDlg, const wxString& dn, wxSizer* pSizer)
{
wxStringTokenizer tokens(dn, _T(","));
std::list<wxString> tokenlist;
while (tokens.HasMoreTokens())
tokenlist.push_back(tokens.GetNextToken());
ParseDN_by_prefix(pDlg, tokenlist, _T("CN"), _("Common name:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("O"), _("Organization:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("OU"), _("Unit:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("T"), _("Title:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("C"), _("Country:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("ST"), _("State:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("L"), _("Locality:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("STREET"), _("Street:"), pSizer);
ParseDN_by_prefix(pDlg, tokenlist, _T("EMAIL"), _("E-Mail:"), pSizer);
if (!tokenlist.empty())
{
wxString value = tokenlist.front();
for (std::list<wxString>::const_iterator iter = ++tokenlist.begin(); iter != tokenlist.end(); iter++)
value += _T(",") + *iter;
pSizer->Add(new wxStaticText(pDlg, wxID_ANY, _("Other:")));
pSizer->Add(new wxStaticText(pDlg, wxID_ANY, value));
}
}
void CVerifyCertDialog::ParseDN_by_prefix(wxDialog* pDlg, std::list<wxString>& tokens, wxString prefix, const wxString& name, wxSizer* pSizer)
{
prefix += _T("=");
const int len = prefix.Length();
wxString value;
bool append = false;
std::list<wxString>::iterator iter = tokens.begin();
while (iter != tokens.end())
{
if (!append)
{
if (iter->Left(len) != prefix)
{
iter++;
continue;
}
if (value != _T(""))
value += _T("\n");
}
else
{
append = false;
value += _T(",");
}
value += iter->Mid(len);
if (iter->Last() == '\\')
{
value.RemoveLast();
append = true;
}
std::list<wxString>::iterator remove = iter++;
tokens.erase(remove);
}
if (value != _T(""))
{
pSizer->Add(new wxStaticText(pDlg, wxID_ANY, name));
pSizer->Add(new wxStaticText(pDlg, wxID_ANY, value));
}
}
bool CVerifyCertDialog::IsTrusted(CCertificateNotification* pNotification)
{
LoadTrustedCerts();
wxASSERT(pNotification);
unsigned int len;
const unsigned char* data = pNotification->GetRawData(len);
return IsTrusted(data, len, false);
}
bool CVerifyCertDialog::IsTrusted(const unsigned char* data, unsigned int len, bool permanentOnly)
{
for (std::list<t_certData>::const_iterator iter = m_trustedCerts.begin(); iter != m_trustedCerts.end(); iter++)
{
if (iter->len != len)
continue;
if (!memcmp(iter->data, data, len))
return true;
}
if (permanentOnly)
return false;
for (std::list<t_certData>::const_iterator iter = m_sessionTrustedCerts.begin(); iter != m_sessionTrustedCerts.end(); iter++)
{
if (iter->len != len)
continue;
if (!memcmp(iter->data, data, len))
return true;
}
return false;
}
wxString CVerifyCertDialog::ConvertHexToString(const unsigned char* data, unsigned int len)
{
wxString str;
for (unsigned int i = 0; i < len; i++)
{
const unsigned char& c = data[i];
const unsigned char low = c & 0x0F;
const unsigned char high = (c & 0xF0) >> 4;
if (high < 10)
str += '0' + high;
else
str += 'A' + high - 10;
if (low < 10)
str += '0' + low;
else
str += 'A' + low - 10;
}
return str;
}
unsigned char* CVerifyCertDialog::ConvertStringToHex(const wxString& str, unsigned int &len)
{
len = str.Length() / 2;
unsigned char* data = new unsigned char[len];
unsigned int j = 0;
for (unsigned int i = 0; i < str.Length(); i++, j++)
{
wxChar high = str[i++];
wxChar low = str[i];
if (high >= '0' && high <= '9')
high -= '0';
else if (high >= 'A' && high <= 'F')
high -= 'A' - 10;
else
{
delete [] data;
return 0;
}
if (low >= '0' && low <= '9')
low -= '0';
else if (low >= 'A' && low <= 'F')
low -= 'A' - 10;
else
{
delete [] data;
return 0;
}
data[j] = ((unsigned char)high << 4) + (unsigned char)low;
}
return data;
}
void CVerifyCertDialog::LoadTrustedCerts(bool close /*=true*/)
{
CReentrantInterProcessMutexLocker mutex(MUTEX_TRUSTEDCERTS);
if (!m_xmlFile.HasFileName() || m_xmlFile.Modified())
m_xmlFile.Load(_T("trustedcerts"));
else
return;
TiXmlElement* pElement = m_xmlFile.GetElement();
if (!pElement)
{
if (close)
m_xmlFile.Close();
return;
}
m_trustedCerts.clear();
if (!(pElement = pElement->FirstChildElement("TrustedCerts")))
return;
bool modified = false;
TiXmlElement* pCert = pElement->FirstChildElement("Certificate");
while (pCert)
{
wxString value = GetTextElement(pCert, "Data");
TiXmlElement* pRemove = 0;
t_certData data;
if (value == _T("") || !(data.data = ConvertStringToHex(value, data.len)))
pRemove = pCert;
wxLongLong activationTime = GetTextElementLongLong(pCert, "ActivationTime", 0);
if (activationTime == 0 || activationTime > wxDateTime::GetTimeNow())
pRemove = pCert;
wxLongLong expirationTime = GetTextElementLongLong(pCert, "ExpirationTime", 0);
if (expirationTime == 0 || expirationTime < wxDateTime::GetTimeNow())
pRemove = pCert;
if (IsTrusted(data.data, data.len, true))
pRemove = pCert;
if (!pRemove)
m_trustedCerts.push_back(data);
else
delete [] data.data;
pCert = pCert->NextSiblingElement("Certificate");
if (pRemove)
{
modified = true;
pElement->RemoveChild(pRemove);
}
}
if (modified)
m_xmlFile.Save();
if (close)
m_xmlFile.Close();
}
void CVerifyCertDialog::SetPermanentlyTrusted(const CCertificateNotification* const pNotification)
{
unsigned int len;
const unsigned char* const data = pNotification->GetRawData(len);
CReentrantInterProcessMutexLocker mutex(MUTEX_TRUSTEDCERTS);
LoadTrustedCerts(false);
if (IsTrusted(data, len, true))
{
m_xmlFile.Close();
return;
}
t_certData cert;
cert.len = len;
cert.data = new unsigned char[len];
memcpy(cert.data, data, len);
m_trustedCerts.push_back(cert);
TiXmlElement* pElement = m_xmlFile.GetElement();
if (!pElement)
{
m_xmlFile.Load();
pElement = m_xmlFile.GetElement();
}
if (!pElement)
{
m_xmlFile.Close();
return;
}
TiXmlElement* pCerts = pElement->FirstChildElement("TrustedCerts");
if (!pCerts)
pCerts = pElement->InsertEndChild(TiXmlElement("TrustedCerts"))->ToElement();
TiXmlElement* pCert = pCerts->InsertEndChild(TiXmlElement("Certificate"))->ToElement();
AddTextElement(pCert, "Data", ConvertHexToString(data, len));
wxLongLong time = pNotification->GetActivationTime().GetTicks();
AddTextElement(pCert, "ActivationTime", time.ToString());
time = pNotification->GetExpirationTime().GetTicks();
AddTextElement(pCert, "ExpirationTime", time.ToString());
m_xmlFile.Save();
m_xmlFile.Close();
}
syntax highlighted by Code2HTML, v. 0.9.1