#include "FileZilla.h" #include "verifycertdialog.h" #include #include "dialogex.h" #include "ipcmutex.h" CVerifyCertDialog::~CVerifyCertDialog() { for (std::list::iterator iter = m_trustedCerts.begin(); iter != m_trustedCerts.end(); iter++) delete [] iter->data; for (std::list::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 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::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& tokens, wxString prefix, const wxString& name, wxSizer* pSizer) { prefix += _T("="); const int len = prefix.Length(); wxString value; bool append = false; std::list::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::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::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::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(); }