-class CertificateChainEditor : public wxPanel
-{
-public:
- CertificateChainEditor (
- wxWindow* parent,
- wxString title,
- int border,
- function<void (shared_ptr<dcp::CertificateChain>)> set,
- function<shared_ptr<const dcp::CertificateChain> (void)> get,
- function<void (void)> nag_remake
- )
- : wxPanel (parent)
- , _set (set)
- , _get (get)
- , _nag_remake (nag_remake)
- {
- wxFont subheading_font (*wxNORMAL_FONT);
- subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
-
- _sizer = new wxBoxSizer (wxVERTICAL);
-
- {
- wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
- m->SetFont (subheading_font);
- _sizer->Add (m, 0, wxALL, border);
- }
-
- wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
- _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
-
- _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
-
- {
- wxListItem ip;
- ip.SetId (0);
- ip.SetText (_("Type"));
- ip.SetWidth (100);
- _certificates->InsertColumn (0, ip);
- }
-
- {
- wxListItem ip;
- ip.SetId (1);
- ip.SetText (_("Thumbprint"));
- ip.SetWidth (340);
-
- wxFont font = ip.GetFont ();
- font.SetFamily (wxFONTFAMILY_TELETYPE);
- ip.SetFont (font);
-
- _certificates->InsertColumn (1, ip);
- }
-
- certificates_sizer->Add (_certificates, 1, wxEXPAND);
-
- {
- wxSizer* s = new wxBoxSizer (wxVERTICAL);
- _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
- s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
- _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
- s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
- _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
- s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
- certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
- }
-
- wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
- _sizer->Add (table, 1, wxALL | wxEXPAND, border);
- int r = 0;
-
- add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
- _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
- wxFont font = _private_key->GetFont ();
- font.SetFamily (wxFONTFAMILY_TELETYPE);
- _private_key->SetFont (font);
- table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
- _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
- table->Add (_load_private_key, wxGBPosition (r, 2));
- _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
- table->Add (_export_private_key, wxGBPosition (r, 3));
- ++r;
-
- _button_sizer = new wxBoxSizer (wxHORIZONTAL);
- _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
- _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
- table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
- ++r;
-
- _private_key_bad = new wxStaticText (this, wxID_ANY, _("Leaf private key does not match leaf certificate!"));
- font = *wxSMALL_FONT;
- font.SetWeight (wxFONTWEIGHT_BOLD);
- _private_key_bad->SetFont (font);
- table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
- ++r;
-
- _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this));
- _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this));
- _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this));
- _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
- _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
- _remake_certificates->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remake_certificates, this));
- _load_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::load_private_key, this));
- _export_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_private_key, this));
-
- SetSizerAndFit (_sizer);
- }
-
- void config_changed ()
- {
- _chain.reset (new dcp::CertificateChain (*_get().get ()));
-
- update_certificate_list ();
- update_private_key ();
- update_sensitivity ();
- }
-
- void add_button (wxWindow* button)
- {
- _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
- _sizer->Layout ();
- }
-
-private:
- void add_certificate ()
- {
- wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
-
- if (d->ShowModal() == wxID_OK) {
- try {
- dcp::Certificate c;
- string extra;
- try {
- extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
- } catch (boost::filesystem::filesystem_error& e) {
- error_dialog (this, wxString::Format (_("Could not load certificate (%s)"), d->GetPath().data()));
- d->Destroy ();
- return;
- }
-
- if (!extra.empty ()) {
- message_dialog (
- this,
- _("This file contains other certificates (or other data) after its first certificate. "
- "Only the first certificate will be used.")
- );
- }
- _chain->add (c);
- if (!_chain->chain_valid ()) {
- error_dialog (
- this,
- _("Adding this certificate would make the chain inconsistent, so it will not be added. "
- "Add certificates in order from root to intermediate to leaf.")
- );
- _chain->remove (c);
- } else {
- _set (_chain);
- update_certificate_list ();
- }
- } catch (dcp::MiscError& e) {
- error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
- }
- }
-
- d->Destroy ();
-
- update_sensitivity ();
- }
-
- void remove_certificate ()
- {
- int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
- if (i == -1) {
- return;
- }
-
- _certificates->DeleteItem (i);
- _chain->remove (i);
- _set (_chain);
-
- update_sensitivity ();
- }
-
- void export_certificate ()
- {
- int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
- if (i == -1) {
- return;
- }
-
- wxFileDialog* d = new wxFileDialog (
- this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- dcp::CertificateChain::List all = _chain->root_to_leaf ();
- dcp::CertificateChain::List::iterator j = all.begin ();
- for (int k = 0; k < i; ++k) {
- ++j;
- }
-
- if (d->ShowModal () == wxID_OK) {
- FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
- if (!f) {
- throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
- }
-
- string const s = j->certificate (true);
- fwrite (s.c_str(), 1, s.length(), f);
- fclose (f);
- }
- d->Destroy ();
- }
-
- void update_certificate_list ()
- {
- _certificates->DeleteAllItems ();
- size_t n = 0;
- dcp::CertificateChain::List certs = _chain->root_to_leaf ();
- BOOST_FOREACH (dcp::Certificate const & i, certs) {
- wxListItem item;
- item.SetId (n);
- _certificates->InsertItem (item);
- _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
-
- if (n == 0) {
- _certificates->SetItem (n, 0, _("Root"));
- } else if (n == (certs.size() - 1)) {
- _certificates->SetItem (n, 0, _("Leaf"));
- } else {
- _certificates->SetItem (n, 0, _("Intermediate"));
- }
-
- ++n;
- }
-
- static wxColour normal = _private_key_bad->GetForegroundColour ();
-
- if (_chain->private_key_valid ()) {
- _private_key_bad->Hide ();
- _private_key_bad->SetForegroundColour (normal);
- } else {
- _private_key_bad->Show ();
- _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
- }
- }
-
- void remake_certificates ()
- {
- shared_ptr<const dcp::CertificateChain> chain = _get ();
-
- string subject_organization_name;
- string subject_organizational_unit_name;
- string root_common_name;
- string intermediate_common_name;
- string leaf_common_name;
-
- dcp::CertificateChain::List all = chain->root_to_leaf ();
-
- if (all.size() >= 1) {
- /* Have a root */
- subject_organization_name = chain->root().subject_organization_name ();
- subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
- root_common_name = chain->root().subject_common_name ();
- }
-
- if (all.size() >= 2) {
- /* Have a leaf */
- leaf_common_name = chain->leaf().subject_common_name ();
- }
-
- if (all.size() >= 3) {
- /* Have an intermediate */
- dcp::CertificateChain::List::iterator i = all.begin ();
- ++i;
- intermediate_common_name = i->subject_common_name ();
- }
-
- _nag_remake ();
-
- MakeChainDialog* d = new MakeChainDialog (
- this,
- subject_organization_name,
- subject_organizational_unit_name,
- root_common_name,
- intermediate_common_name,
- leaf_common_name
- );
-
- if (d->ShowModal () == wxID_OK) {
- _chain.reset (
- new dcp::CertificateChain (
- openssl_path (),
- d->organisation (),
- d->organisational_unit (),
- d->root_common_name (),
- d->intermediate_common_name (),
- d->leaf_common_name ()
- )
- );
-
- _set (_chain);
- update_certificate_list ();
- update_private_key ();
- }
-
- d->Destroy ();
- }
-
- void update_sensitivity ()
- {
- /* We can only remove the leaf certificate */
- _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
- _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
- }
-
- void update_private_key ()
- {
- checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
- _sizer->Layout ();
- }
-
- void load_private_key ()
- {
- wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
-
- if (d->ShowModal() == wxID_OK) {
- try {
- boost::filesystem::path p (wx_to_std (d->GetPath ()));
- if (boost::filesystem::file_size (p) > 8192) {
- error_dialog (
- this,
- wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
- );
- return;
- }
-
- _chain->set_key (dcp::file_to_string (p));
- _set (_chain);
- update_private_key ();
- } catch (dcp::MiscError& e) {
- error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
- }
- }
-
- d->Destroy ();
-
- update_sensitivity ();
- }
-
- void export_private_key ()
- {
- optional<string> key = _chain->key ();
- if (!key) {
- return;
- }
-
- wxFileDialog* d = new wxFileDialog (
- this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- if (d->ShowModal () == wxID_OK) {
- FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
- if (!f) {
- throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
- }
-
- string const s = _chain->key().get ();
- fwrite (s.c_str(), 1, s.length(), f);
- fclose (f);
- }
- d->Destroy ();
- }
-
- wxListCtrl* _certificates;
- wxButton* _add_certificate;
- wxButton* _export_certificate;
- wxButton* _remove_certificate;
- wxButton* _remake_certificates;
- wxStaticText* _private_key;
- wxButton* _load_private_key;
- wxButton* _export_private_key;
- wxStaticText* _private_key_bad;
- wxSizer* _sizer;
- wxBoxSizer* _button_sizer;
- shared_ptr<dcp::CertificateChain> _chain;
- boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
- boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
- boost::function<void (void)> _nag_remake;
-};
-
-class KeysPage : public StandardPage
-{
-public:
- KeysPage (wxSize panel_size, int border)
- : StandardPage (panel_size, border)
- {}
-
- wxString GetName () const
- {
- return _("Keys");
- }
-
-#ifdef DCPOMATIC_OSX
- wxBitmap GetLargeIcon () const
- {
- return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
- }
-#endif
-
-private:
-
- void setup ()
- {
- _signer = new CertificateChainEditor (
- _panel, _("Signing DCPs and KDMs"), _border,
- boost::bind (&Config::set_signer_chain, Config::instance (), _1),
- boost::bind (&Config::signer_chain, Config::instance ()),
- boost::bind (&do_nothing)
- );
-
- _panel->GetSizer()->Add (_signer);
-
- _decryption = new CertificateChainEditor (
- _panel, _("Decrypting KDMs"), _border,
- boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
- boost::bind (&Config::decryption_chain, Config::instance ()),
- boost::bind (&KeysPage::nag_remake_decryption_chain, this)
- );
-
- _panel->GetSizer()->Add (_decryption);
-
- _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\ncertificate..."));
- _decryption->add_button (_export_decryption_certificate);
- _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\nchain..."));
- _decryption->add_button (_export_decryption_chain);
-
- _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
- _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
- }
-
- void export_decryption_certificate ()
- {
- wxFileDialog* d = new wxFileDialog (
- _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- if (d->ShowModal () == wxID_OK) {
- FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
- if (!f) {
- throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
- }
-
- string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
- fwrite (s.c_str(), 1, s.length(), f);
- fclose (f);
- }
- d->Destroy ();
- }
-
- void export_decryption_chain ()
- {
- wxFileDialog* d = new wxFileDialog (
- _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
-
- if (d->ShowModal () == wxID_OK) {
- FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
- if (!f) {
- throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
- }
-
- string const s = Config::instance()->decryption_chain()->chain();
- fwrite (s.c_str(), 1, s.length(), f);
- fclose (f);
- }
- d->Destroy ();
- }
-
- void config_changed ()
- {
- _signer->config_changed ();
- _decryption->config_changed ();
- }
-
- void nag_remake_decryption_chain ()
- {
- NagDialog::maybe_nag (
- _panel,
- Config::NAG_REMAKE_DECRYPTION_CHAIN,
- _("If you continue with this operation you will no longer be able to use any DKDMs that you have created. Also, any KDMs that have been sent to you will become useless. Proceed with caution!")
- );
- }
-
- CertificateChainEditor* _signer;
- CertificateChainEditor* _decryption;
- wxButton* _export_decryption_certificate;
- wxButton* _export_decryption_chain;
-};
-