Whitespace.
[libdcp.git] / test / certificates_test.cc
index d355ad5560b973d428f0d3a1bcf16ccab2b8f0a4..1dc1193221f12c3342faa65281c442131c18caef 100644 (file)
@@ -1,33 +1,50 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
 
-    This program is free software; you can redistribute it and/or modify
+    This file is part of libdcp.
+
+    libdcp is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
     the Free Software Foundation; either version 2 of the License, or
     (at your option) any later version.
 
-    This program is distributed in the hope that it will be useful,
+    libdcp is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
 
     You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
+
+    In addition, as a special exception, the copyright holders give
+    permission to link the code of portions of this program with the
+    OpenSSL library under certain conditions as described in each
+    individual source file, and distribute linked combinations
+    including the two.
 
+    You must obey the GNU General Public License in all respects
+    for all of the code used other than OpenSSL.  If you modify
+    file(s) with this exception, you may extend this exception to your
+    version of the file(s), but you are not obligated to do so.  If you
+    do not wish to do so, delete this exception statement from your
+    version.  If you delete this exception statement from all source
+    files in the program, then also delete it here.
 */
 
-#include <boost/test/unit_test.hpp>
-#include "certificates.h"
-#include "signer.h"
+#include "certificate.h"
+#include "certificate_chain.h"
 #include "util.h"
+#include "exceptions.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+#include <iostream>
 
 using std::list;
 using std::string;
-using boost::shared_ptr;
+using std::shared_ptr;
 
 /** Check that loading certificates from files via strings works */
-BOOST_AUTO_TEST_CASE (certificates)
+BOOST_AUTO_TEST_CASE (certificates1)
 {
        dcp::CertificateChain c;
 
@@ -41,6 +58,7 @@ BOOST_AUTO_TEST_CASE (certificates)
 
        /* Leaf */
        BOOST_CHECK_EQUAL (*i, c.leaf ());
+       BOOST_CHECK_EQUAL (i->thumbprint(), "EZg5wDcihccWqwdg59Y8D+IJpYM=");
 
        BOOST_CHECK_EQUAL (
                c.leaf().issuer(),
@@ -55,6 +73,7 @@ BOOST_AUTO_TEST_CASE (certificates)
        ++i;
 
        /* Intermediate */
+       BOOST_CHECK_EQUAL (i->thumbprint(), "GwM6ex2UVlWclH8f1uV7W1n0EEU=");
        BOOST_CHECK_EQUAL (
                i->issuer(),
                "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
@@ -69,6 +88,7 @@ BOOST_AUTO_TEST_CASE (certificates)
 
        /* Root */
        BOOST_CHECK_EQUAL (*i, c.root ());
+       BOOST_CHECK_EQUAL (i->thumbprint(), "zU8NVNwI2PYejmSYRntG7c6sdTw=");
        BOOST_CHECK_EQUAL (
                c.root().issuer(),
                "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
@@ -86,51 +106,130 @@ BOOST_AUTO_TEST_CASE (certificates)
        BOOST_CHECK_EQUAL (test.certificate(), c.root().certificate());
 }
 
-/** Check that dcp::CertificateChain::valid() and ::attempt_reorder() basically work */
-BOOST_AUTO_TEST_CASE (certificates_validation)
+/** Check some more certificate-from-strings */
+BOOST_AUTO_TEST_CASE (certificates2)
+{
+       {
+               dcp::Certificate c (dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt"));
+               BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt.reformatted"));
+       }
+
+       {
+               dcp::Certificate c (dcp::file_to_string (private_test / "usl-cert.pem"));
+               BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "usl-cert.pem.trimmed"));
+       }
+
+       {
+               /* This is a chain, not an individual certificate, so it should throw an exception */
+               BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "chain.pem")), dcp::MiscError);
+       }
+
+       BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "no-begin.pem")), dcp::MiscError);
+       BOOST_CHECK_THROW (dcp::Certificate ("foo"), dcp::MiscError);
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation1)
+{
+       dcp::CertificateChain good;
+       good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       BOOST_CHECK (good.chain_valid(good._certificates));
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation2)
+{
+       dcp::CertificateChain good;
+       good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       BOOST_CHECK (good.chain_valid(good._certificates));
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation3)
+{
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation4)
+{
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_NO_THROW (bad.root_to_leaf());
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation5)
+{
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_NO_THROW (bad.root_to_leaf());
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation6)
+{
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_NO_THROW (bad.root_to_leaf());
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation7)
+{
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
+}
+
+/** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
+BOOST_AUTO_TEST_CASE (certificates_validation8)
 {
-       dcp::CertificateChain good1;
-       good1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       good1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       good1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       BOOST_CHECK (good1.valid ());
-
-       dcp::CertificateChain good2;
-       good2.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       BOOST_CHECK (good2.valid ());
-
-       dcp::CertificateChain bad1;
-       bad1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       bad1.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       BOOST_CHECK (!bad1.valid ());
-       BOOST_CHECK (!bad1.attempt_reorder ());
-
-       dcp::CertificateChain bad2;
-       bad2.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       bad2.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       bad2.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       BOOST_CHECK (!bad2.valid ());
-       BOOST_CHECK (bad2.attempt_reorder ());
-
-       dcp::CertificateChain bad3;
-       bad3.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       bad3.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       bad3.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       BOOST_CHECK (!bad3.valid ());
-       BOOST_CHECK (bad3.attempt_reorder ());
-
-       dcp::CertificateChain bad4;
-       bad4.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       bad4.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
-       bad4.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       BOOST_CHECK (!bad4.valid ());
-       BOOST_CHECK (bad4.attempt_reorder ());
-
-       dcp::CertificateChain bad5;
-       bad5.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
-       bad5.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       BOOST_CHECK (!bad5.valid ());
-       BOOST_CHECK (!bad5.attempt_reorder ());
+       dcp::CertificateChain bad;
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
+       bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
+       BOOST_CHECK (!bad.chain_valid(bad._certificates));
+       BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
+}
+
+/** Check that we can create a valid chain */
+BOOST_AUTO_TEST_CASE (certificates_validation9)
+{
+       dcp::CertificateChain good (
+               boost::filesystem::path ("openssl"),
+               "dcpomatic.com",
+               "dcpomatic.com",
+               ".dcpomatic.smpte-430-2.ROOT",
+               ".dcpomatic.smpte-430-2.INTERMEDIATE",
+               "CS.dcpomatic.smpte-430-2.LEAF"
+               );
+
+       BOOST_CHECK_NO_THROW (good.root_to_leaf());
+}
+
+/** Check that we can create a valid chain */
+BOOST_AUTO_TEST_CASE (certificates_validation10)
+{
+       dcp::CertificateChain good (boost::filesystem::path ("openssl"));
+       BOOST_CHECK_NO_THROW (good.root_to_leaf());
 }
 
 /** Check that dcp::Signer::valid() basically works */
@@ -141,11 +240,41 @@ BOOST_AUTO_TEST_CASE (signer_validation)
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
        chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
-       dcp::Signer signer (chain, dcp::file_to_string ("test/ref/crypt/leaf.key"));
-       BOOST_CHECK (signer.valid ());
+       chain.set_key (dcp::file_to_string ("test/ref/crypt/leaf.key"));
+       BOOST_CHECK (chain.valid ());
 
        /* Put in an unrelated key and the signer should no longer be valid */
-       dcp::Signer another_signer ("openssl");
-       signer.set_key (another_signer.key ());
-       BOOST_CHECK (!signer.valid ());
+       dcp::CertificateChain another_chain (boost::filesystem::path ("openssl"));
+       chain.set_key (another_chain.key().get ());
+       BOOST_CHECK (!chain.valid ());
+}
+
+/** Check reading of a certificate chain from a string */
+BOOST_AUTO_TEST_CASE (certificate_chain_from_string)
+{
+       dcp::CertificateChain a (dcp::file_to_string (private_test / "chain.pem"));
+       BOOST_CHECK_EQUAL (a.root_to_leaf().size(), 3);
+
+       dcp::CertificateChain b (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem"));
+       BOOST_CHECK_EQUAL (b.root_to_leaf().size(), 1);
+}
+
+/** Check not_before and not_after */
+BOOST_AUTO_TEST_CASE (certificate_not_before_after)
+{
+       dcp::Certificate c (dcp::file_to_string("test/ref/crypt/ca.self-signed.pem"));
+       struct tm not_before = c.not_before();
+       BOOST_CHECK_EQUAL (not_before.tm_sec, 8);
+       BOOST_CHECK_EQUAL (not_before.tm_min, 20);
+       BOOST_CHECK_EQUAL (not_before.tm_hour, 13);
+       BOOST_CHECK_EQUAL (not_before.tm_mday, 5);
+       BOOST_CHECK_EQUAL (not_before.tm_mon, 5);
+       BOOST_CHECK_EQUAL (not_before.tm_year, 115);
+       struct tm not_after = c.not_after();
+       BOOST_CHECK_EQUAL (not_after.tm_sec, 8);
+       BOOST_CHECK_EQUAL (not_after.tm_min, 20);
+       BOOST_CHECK_EQUAL (not_after.tm_hour, 13);
+       BOOST_CHECK_EQUAL (not_after.tm_mday, 2);
+       BOOST_CHECK_EQUAL (not_after.tm_mon, 5);
+       BOOST_CHECK_EQUAL (not_after.tm_year, 125);
 }