2 Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
6 libdcp is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 libdcp is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with libdcp. If not, see <http://www.gnu.org/licenses/>.
19 In addition, as a special exception, the copyright holders give
20 permission to link the code of portions of this program with the
21 OpenSSL library under certain conditions as described in each
22 individual source file, and distribute linked combinations
25 You must obey the GNU General Public License in all respects
26 for all of the code used other than OpenSSL. If you modify
27 file(s) with this exception, you may extend this exception to your
28 version of the file(s), but you are not obligated to do so. If you
29 do not wish to do so, delete this exception statement from your
30 version. If you delete this exception statement from all source
31 files in the program, then also delete it here.
34 #include "certificate.h"
35 #include "certificate_chain.h"
37 #include "exceptions.h"
39 #include <boost/test/unit_test.hpp>
44 using std::shared_ptr;
46 /** Check that loading certificates from files via strings works */
47 BOOST_AUTO_TEST_CASE (certificates1)
49 dcp::CertificateChain c;
51 c.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
52 c.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
53 c.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
55 dcp::CertificateChain::List leaf_to_root = c.leaf_to_root ();
57 dcp::CertificateChain::List::iterator i = leaf_to_root.begin ();
60 BOOST_CHECK_EQUAL (*i, c.leaf ());
61 BOOST_CHECK_EQUAL (i->thumbprint(), "EZg5wDcihccWqwdg59Y8D+IJpYM=");
65 "dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
70 "dnQualifier=QFVlym7fuql6bPOnY38aaO1ZPW4=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
76 BOOST_CHECK_EQUAL (i->thumbprint(), "GwM6ex2UVlWclH8f1uV7W1n0EEU=");
79 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
84 "dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
90 BOOST_CHECK_EQUAL (*i, c.root ());
91 BOOST_CHECK_EQUAL (i->thumbprint(), "zU8NVNwI2PYejmSYRntG7c6sdTw=");
94 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
97 BOOST_CHECK_EQUAL (c.root().serial(), "5");
101 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
104 /* Check that reconstruction from a string works */
105 dcp::Certificate test (c.root().certificate (true));
106 BOOST_CHECK_EQUAL (test.certificate(), c.root().certificate());
109 /** Check some more certificate-from-strings */
110 BOOST_AUTO_TEST_CASE (certificates2)
113 dcp::Certificate c (dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt"));
114 BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "CA.GDC-TECH.COM_SA2100_A14903.crt.crt.reformatted"));
118 dcp::Certificate c (dcp::file_to_string (private_test / "usl-cert.pem"));
119 BOOST_CHECK_EQUAL (c.certificate(true), dcp::file_to_string (private_test / "usl-cert.pem.trimmed"));
123 /* This is a chain, not an individual certificate, so it should throw an exception */
124 BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "chain.pem")), dcp::MiscError);
127 BOOST_CHECK_THROW (dcp::Certificate (dcp::file_to_string (private_test / "no-begin.pem")), dcp::MiscError);
128 BOOST_CHECK_THROW (dcp::Certificate ("foo"), dcp::MiscError);
131 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
132 BOOST_AUTO_TEST_CASE (certificates_validation1)
134 dcp::CertificateChain good;
135 good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
136 good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
137 good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
138 BOOST_CHECK (good.chain_valid(good._certificates));
141 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
142 BOOST_AUTO_TEST_CASE (certificates_validation2)
144 dcp::CertificateChain good;
145 good.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
146 BOOST_CHECK (good.chain_valid(good._certificates));
149 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
150 BOOST_AUTO_TEST_CASE (certificates_validation3)
152 dcp::CertificateChain bad;
153 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
154 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
155 BOOST_CHECK (!bad.chain_valid(bad._certificates));
156 BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
159 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
160 BOOST_AUTO_TEST_CASE (certificates_validation4)
162 dcp::CertificateChain bad;
163 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
164 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
165 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
166 BOOST_CHECK (!bad.chain_valid(bad._certificates));
167 BOOST_CHECK_NO_THROW (bad.root_to_leaf());
170 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
171 BOOST_AUTO_TEST_CASE (certificates_validation5)
173 dcp::CertificateChain bad;
174 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
175 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
176 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
177 BOOST_CHECK (!bad.chain_valid(bad._certificates));
178 BOOST_CHECK_NO_THROW (bad.root_to_leaf());
181 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
182 BOOST_AUTO_TEST_CASE (certificates_validation6)
184 dcp::CertificateChain bad;
185 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
186 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
187 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
188 BOOST_CHECK (!bad.chain_valid(bad._certificates));
189 BOOST_CHECK_NO_THROW (bad.root_to_leaf());
192 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
193 BOOST_AUTO_TEST_CASE (certificates_validation7)
195 dcp::CertificateChain bad;
196 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
197 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
198 BOOST_CHECK (!bad.chain_valid(bad._certificates));
199 BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
202 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
203 BOOST_AUTO_TEST_CASE (certificates_validation8)
205 dcp::CertificateChain bad;
206 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
207 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
208 bad.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
209 BOOST_CHECK (!bad.chain_valid(bad._certificates));
210 BOOST_CHECK_THROW (bad.root_to_leaf(), dcp::CertificateChainError);
213 /** Check that we can create a valid chain */
214 BOOST_AUTO_TEST_CASE (certificates_validation9)
216 dcp::CertificateChain good (
217 boost::filesystem::path ("openssl"),
220 ".dcpomatic.smpte-430-2.ROOT",
221 ".dcpomatic.smpte-430-2.INTERMEDIATE",
222 "CS.dcpomatic.smpte-430-2.LEAF"
225 BOOST_CHECK_NO_THROW (good.root_to_leaf());
228 /** Check that we can create a valid chain */
229 BOOST_AUTO_TEST_CASE (certificates_validation10)
231 dcp::CertificateChain good (boost::filesystem::path ("openssl"));
232 BOOST_CHECK_NO_THROW (good.root_to_leaf());
235 /** Check that dcp::Signer::valid() basically works */
236 BOOST_AUTO_TEST_CASE (signer_validation)
238 /* Check a valid signer */
239 dcp::CertificateChain chain;
240 chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
241 chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
242 chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
243 chain.set_key (dcp::file_to_string ("test/ref/crypt/leaf.key"));
244 BOOST_CHECK (chain.valid ());
246 /* Put in an unrelated key and the signer should no longer be valid */
247 dcp::CertificateChain another_chain (boost::filesystem::path ("openssl"));
248 chain.set_key (another_chain.key().get ());
249 BOOST_CHECK (!chain.valid ());
252 /** Check reading of a certificate chain from a string */
253 BOOST_AUTO_TEST_CASE (certificate_chain_from_string)
255 dcp::CertificateChain a (dcp::file_to_string (private_test / "chain.pem"));
256 BOOST_CHECK_EQUAL (a.root_to_leaf().size(), 3);
258 dcp::CertificateChain b (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem"));
259 BOOST_CHECK_EQUAL (b.root_to_leaf().size(), 1);
262 /** Check not_before and not_after */
263 BOOST_AUTO_TEST_CASE (certificate_not_before_after)
265 dcp::Certificate c (dcp::file_to_string("test/ref/crypt/ca.self-signed.pem"));
266 struct tm not_before = c.not_before();
267 BOOST_CHECK_EQUAL (not_before.tm_sec, 8);
268 BOOST_CHECK_EQUAL (not_before.tm_min, 20);
269 BOOST_CHECK_EQUAL (not_before.tm_hour, 13);
270 BOOST_CHECK_EQUAL (not_before.tm_mday, 5);
271 BOOST_CHECK_EQUAL (not_before.tm_mon, 5);
272 BOOST_CHECK_EQUAL (not_before.tm_year, 115);
273 struct tm not_after = c.not_after();
274 BOOST_CHECK_EQUAL (not_after.tm_sec, 8);
275 BOOST_CHECK_EQUAL (not_after.tm_min, 20);
276 BOOST_CHECK_EQUAL (not_after.tm_hour, 13);
277 BOOST_CHECK_EQUAL (not_after.tm_mday, 2);
278 BOOST_CHECK_EQUAL (not_after.tm_mon, 5);
279 BOOST_CHECK_EQUAL (not_after.tm_year, 125);