Complain on startup if signer or decryption chains are inconsistent (#1520).
authorCarl Hetherington <cth@carlh.net>
Sun, 31 Mar 2019 23:31:22 +0000 (00:31 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 10 May 2019 22:43:42 +0000 (23:43 +0100)
src/lib/config.cc
src/lib/config.h
src/tools/dcpomatic.cc
src/wx/recreate_chain_dialog.cc
src/wx/recreate_chain_dialog.h

index 4ce4517f8088fbac0e89087925f5d300a3969942..ea2a579398b918531f57f3e674cac8fe0859e78d 100644 (file)
@@ -69,7 +69,7 @@ Config* Config::_instance = 0;
 int const Config::_current_version = 3;
 boost::signals2::signal<void ()> Config::FailedToLoad;
 boost::signals2::signal<void (string)> Config::Warning;
-boost::signals2::signal<bool (void)> Config::BadSignerChain;
+boost::signals2::signal<bool (Config::BadReason)> Config::Bad;
 
 /** Construct default configuration */
 Config::Config ()
@@ -441,30 +441,6 @@ try
        }
 #endif
 
-       /* These must be done before we call BadSignerChain as that might set one
-          of the nags.
-       */
-       BOOST_FOREACH (cxml::NodePtr i, f.node_children("Nagged")) {
-               int const id = i->number_attribute<int>("Id");
-               if (id >= 0 && id < NAG_COUNT) {
-                       _nagged[id] = raw_convert<int>(i->content());
-               }
-       }
-
-       bool bad_signer_chain = false;
-       BOOST_FOREACH (dcp::Certificate const & i, _signer_chain->unordered()) {
-               if (i.has_utf8_strings()) {
-                       bad_signer_chain = true;
-               }
-       }
-
-       if (bad_signer_chain) {
-               optional<bool> const remake = BadSignerChain();
-               if (remake && *remake) {
-                       _signer_chain = create_certificate_chain ();
-               }
-       }
-
        cxml::NodePtr decryption = f.optional_node_child ("Decryption");
 #ifdef DCPOMATIC_VARIANT_SWAROOP
        if (decryption && decryption->node_children().size() == 1) {
@@ -492,6 +468,48 @@ try
                _decryption_chain = create_certificate_chain ();
        }
 #endif
+
+       /* These must be done before we call Bad as that might set one
+          of the nags.
+       */
+       BOOST_FOREACH (cxml::NodePtr i, f.node_children("Nagged")) {
+               int const id = i->number_attribute<int>("Id");
+               if (id >= 0 && id < NAG_COUNT) {
+                       _nagged[id] = raw_convert<int>(i->content());
+               }
+       }
+
+       optional<BadReason> bad;
+
+       BOOST_FOREACH (dcp::Certificate const & i, _signer_chain->unordered()) {
+               if (i.has_utf8_strings()) {
+                       bad = BAD_SIGNER_UTF8_STRINGS;
+               }
+       }
+
+       if (!_signer_chain->private_key_valid() || !_signer_chain->chain_valid()) {
+               bad = BAD_SIGNER_INCONSISTENT;
+       }
+
+       if (!_decryption_chain->private_key_valid() || !_decryption_chain->chain_valid()) {
+               bad = BAD_DECRYPTION_INCONSISTENT;
+       }
+
+       if (bad) {
+               optional<bool> const remake = Bad(*bad);
+               if (remake && *remake) {
+                       switch (*bad) {
+                       case BAD_SIGNER_UTF8_STRINGS:
+                       case BAD_SIGNER_INCONSISTENT:
+                               _signer_chain = create_certificate_chain ();
+                               break;
+                       case BAD_DECRYPTION_INCONSISTENT:
+                               _decryption_chain = create_certificate_chain ();
+                               break;
+                       }
+               }
+       }
+
        if (f.optional_node_child("DKDMGroup")) {
                /* New-style: all DKDMs in a group */
                _dkdms = dynamic_pointer_cast<DKDMGroup> (DKDMBase::read (f.node_child("DKDMGroup")));
index 1d0501ce4d7487d1b61a9ec980f2bcd312c1d0de..a8427663dd6c2fa4cd648842420437dfe365a617 100644 (file)
@@ -1072,10 +1072,16 @@ public:
        static boost::signals2::signal<void ()> FailedToLoad;
        /** Emitted if read() issued a warning which the user might want to know about */
        static boost::signals2::signal<void (std::string)> Warning;
-       /** Emitted if there is a bad certificate in the signer chain.  Handler can call
-        *  true to ask Config to re-create the chain.
+       /** Emitted if there is a something wrong the contents of our config.  Handler can call
+        *  true to ask Config to solve the problem (by discarding and recreating the bad thing)
         */
-       static boost::signals2::signal<bool (void)> BadSignerChain;
+       enum BadReason {
+               BAD_SIGNER_UTF8_STRINGS,     ///< signer chain contains UTF-8 strings (not PRINTABLESTRING)
+               BAD_SIGNER_INCONSISTENT,     ///< signer chain is somehow inconsistent
+               BAD_DECRYPTION_INCONSISTENT, ///< KDM decryption chain is somehow inconsistent
+       };
+
+       static boost::signals2::signal<bool (BadReason)> Bad;
 
        void write () const;
        void write_config () const;
index 5bd22041edd975ad25dcb6d957ba177bf25a269e..7cac8e7f0ce30156364efd0ed3f67920f71410ac 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -1455,20 +1455,20 @@ public:
        App ()
                : wxApp ()
                , _frame (0)
+               , _splash (0)
        {}
 
 private:
 
        bool OnInit ()
        {
-               wxSplashScreen* splash = 0;
                try {
                        wxInitAllImageHandlers ();
 
                        Config::FailedToLoad.connect (boost::bind (&App::config_failed_to_load, this));
                        Config::Warning.connect (boost::bind (&App::config_warning, this, _1));
 
-                       splash = maybe_show_splash ();
+                       _splash = maybe_show_splash ();
 
                        SetAppName (_("DCP-o-matic"));
 
@@ -1506,14 +1506,14 @@ private:
                        */
                        Config::drop ();
 
-                       Config::BadSignerChain.connect (boost::bind (&App::config_bad_signer_chain, this));
+                       Config::Bad.connect (boost::bind(&App::config_bad, this, _1));
 
                        _frame = new DOMFrame (_("DCP-o-matic"));
                        SetTopWindow (_frame);
                        _frame->Maximize ();
-                       if (splash) {
-                               splash->Destroy ();
-                               splash = 0;
+                       if (_splash) {
+                               _splash->Destroy ();
+                               _splash = 0;
                        }
 
                        if (!Config::instance()->nagged(Config::NAG_INITIAL_SETUP)) {
@@ -1558,8 +1558,9 @@ private:
                }
                catch (exception& e)
                {
-                       if (splash) {
-                               splash->Destroy ();
+                       if (_splash) {
+                               _splash->Destroy ();
+                               _splash = 0;
                        }
                        error_dialog (0, wxString::Format ("DCP-o-matic could not start."), std_to_wx(e.what()));
                }
@@ -1659,19 +1660,73 @@ private:
                message_dialog (_frame, std_to_wx (m));
        }
 
-       bool config_bad_signer_chain ()
+       bool config_bad (Config::BadReason reason)
        {
-               if (Config::instance()->nagged(Config::NAG_BAD_SIGNER_CHAIN)) {
-                       return false;
-               }
+               /* Destroy the splash screen here, as otherwise bad things seem to happen (for reasons unknown)
+                  when we open our recreate dialog, close it, *then* try to Destroy the splash (the Destroy fails).
+               */
+               _splash->Destroy ();
+               _splash = 0;
 
-               RecreateChainDialog* d = new RecreateChainDialog (_frame);
-               int const r = d->ShowModal ();
-               d->Destroy ();
-               return r == wxID_OK;
+               Config* config = Config::instance();
+               switch (reason) {
+               case Config::BAD_SIGNER_UTF8_STRINGS:
+               {
+                       if (config->nagged(Config::NAG_BAD_SIGNER_CHAIN)) {
+                               return false;
+                       }
+                       RecreateChainDialog* d = new RecreateChainDialog (
+                               _frame, _("Recreate signing certificates"),
+                               _("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs contains a small error\n"
+                                 "which will prevent DCPs from being validated correctly on some systems.  Do you want to re-create\n"
+                                 "the certificate chain for signing DCPs and KDMs?"),
+                               _("Do nothing"),
+                               Config::NAG_BAD_SIGNER_CHAIN
+                               );
+                       int const r = d->ShowModal ();
+                       d->Destroy ();
+                       return r == wxID_OK;
+               }
+               case Config::BAD_SIGNER_INCONSISTENT:
+               {
+                       RecreateChainDialog* d = new RecreateChainDialog (
+                               _frame, _("Recreate signing certificates"),
+                               _("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs is inconsistent and\n"
+                                 "cannot be used.  DCP-o-matic cannot start unless you re-create it.  Do you want to re-create\n"
+                                 "the certificate chain for signing DCPs and KDMs?"),
+                               _("Close DCP-o-matic")
+                               );
+                       int const r = d->ShowModal ();
+                       d->Destroy ();
+                       if (r != wxID_OK) {
+                               exit (EXIT_FAILURE);
+                       }
+                       return true;
+               }
+               case Config::BAD_DECRYPTION_INCONSISTENT:
+               {
+                       RecreateChainDialog* d = new RecreateChainDialog (
+                               _frame, _("Recreate KDM decryption chain"),
+                               _("The certificate chain that DCP-o-matic uses for decrypting KDMs is inconsistent and\n"
+                                 "cannot be used.  DCP-o-matic cannot start unless you re-create it.  Do you want to re-create\n"
+                                 "the certificate chain for decrypting KDMs?  You may want to say \"No\" here and back up your\n"
+                                 "configuration before continuing."),
+                               _("Close DCP-o-matic")
+                               );
+                       int const r = d->ShowModal ();
+                       d->Destroy ();
+                       if (r != wxID_OK) {
+                               exit (EXIT_FAILURE);
+                       }
+                       return true;
+               }
+               default:
+                       DCPOMATIC_ASSERT (false);
+               }
        }
 
        DOMFrame* _frame;
+       wxSplashScreen* _splash;
        shared_ptr<wxTimer> _timer;
        string _film_to_load;
        string _film_to_create;
index 1dd14e0c8da4a87494418ff130783500abde8c0b..e477cdc1f1e19cb1799c5dd79e1974d90b33e184 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 
 using std::list;
 using std::string;
+using boost::optional;
 
-RecreateChainDialog::RecreateChainDialog (wxWindow* parent)
-       : QuestionDialog (parent, _("Certificate chain"), _("Recreate signing certificates"), _("Do nothing"))
+RecreateChainDialog::RecreateChainDialog (wxWindow* parent, wxString title, wxString message, wxString cancel, optional<Config::Nag> nag)
+       : QuestionDialog (parent, _("Certificate chain"), title, cancel)
+       , _nag (nag)
 {
-       wxString const message = _("The certificate chain that DCP-o-matic uses for signing DCPs and KDMs contains a small error\n"
-                                  "which will prevent DCPs from being validated correctly on some systems.  Do you want to re-create\n"
-                                  "the certificate chain for signing DCPs and KDMs?");
-
        _sizer->Add (new StaticText (this, message), 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
 
-       wxCheckBox* shut_up = new CheckBox (this, _("Don't ask this again"));
-       _sizer->Add (shut_up, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
-
-       shut_up->Bind (wxEVT_CHECKBOX, bind (&RecreateChainDialog::shut_up, this, _1));
+       if (nag) {
+               wxCheckBox* shut_up = new CheckBox (this, _("Don't ask this again"));
+               _sizer->Add (shut_up, 0, wxALL, DCPOMATIC_DIALOG_BORDER);
+               shut_up->Bind (wxEVT_CHECKBOX, bind (&RecreateChainDialog::shut_up, this, _1));
+       }
 
        layout ();
 }
@@ -49,5 +48,5 @@ RecreateChainDialog::RecreateChainDialog (wxWindow* parent)
 void
 RecreateChainDialog::shut_up (wxCommandEvent& ev)
 {
-       Config::instance()->set_nagged (Config::NAG_BAD_SIGNER_CHAIN, ev.IsChecked());
+       Config::instance()->set_nagged(*_nag, ev.IsChecked());
 }
index 287e657670408a14fbc52540218ceb320652a046..10086be865a2166fe472242011c740e47db2ca3c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 */
 
 #include "question_dialog.h"
+#include "lib/config.h"
 #include <wx/wx.h>
 #include <list>
 
 class RecreateChainDialog : public QuestionDialog
 {
 public:
-       RecreateChainDialog (wxWindow* parent);
+       RecreateChainDialog (wxWindow* parent, wxString title, wxString message, wxString cancel, boost::optional<Config::Nag> nag = boost::optional<Config::Nag>());
 
 private:
        void shut_up (wxCommandEvent& ev);
+       boost::optional<Config::Nag> _nag;
 };