Report every frame (with index) that has a JPEG2000 codestream error (DoM #2698).
[libdcp.git] / test / certificates_test.cc
1 /*
2     Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
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.
10
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.
15
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/>.
18
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
23     including the two.
24
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.
32 */
33
34 #include "certificate.h"
35 #include "certificate_chain.h"
36 #include "util.h"
37 #include "exceptions.h"
38 #include "test.h"
39 #include <boost/test/unit_test.hpp>
40 #include <iostream>
41
42 using std::list;
43 using std::string;
44 using std::shared_ptr;
45
46 /** Check that loading certificates from files via strings works */
47 BOOST_AUTO_TEST_CASE (certificates1)
48 {
49         dcp::CertificateChain c;
50
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")));
54
55         dcp::CertificateChain::List leaf_to_root = c.leaf_to_root ();
56
57         dcp::CertificateChain::List::iterator i = leaf_to_root.begin ();
58
59         /* Leaf */
60         BOOST_CHECK_EQUAL (*i, c.leaf ());
61         BOOST_CHECK_EQUAL (i->thumbprint(), "EZg5wDcihccWqwdg59Y8D+IJpYM=");
62
63         BOOST_CHECK_EQUAL (
64                 c.leaf().issuer(),
65                 "dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
66                 );
67
68         BOOST_CHECK_EQUAL (
69                 c.leaf().subject(),
70                 "dnQualifier=QFVlym7fuql6bPOnY38aaO1ZPW4=,CN=CS.smpte-430-2.LEAF.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
71                 );
72
73         ++i;
74
75         /* Intermediate */
76         BOOST_CHECK_EQUAL (i->thumbprint(), "GwM6ex2UVlWclH8f1uV7W1n0EEU=");
77         BOOST_CHECK_EQUAL (
78                 i->issuer(),
79                 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
80                 );
81
82         BOOST_CHECK_EQUAL (
83                 i->subject(),
84                 "dnQualifier=6eat8r33US71avuQEojmH\\+bjk84=,CN=.smpte-430-2.INTERMEDIATE.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
85                 );
86
87         ++i;
88
89         /* Root */
90         BOOST_CHECK_EQUAL (*i, c.root ());
91         BOOST_CHECK_EQUAL (i->thumbprint(), "zU8NVNwI2PYejmSYRntG7c6sdTw=");
92         BOOST_CHECK_EQUAL (
93                 c.root().issuer(),
94                 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
95                 );
96
97         BOOST_CHECK_EQUAL (c.root().serial(), "5");
98
99         BOOST_CHECK_EQUAL (
100                 c.root().subject(),
101                 "dnQualifier=DCnRdHFbcv4ANVUq2\\+wMVALFSec=,CN=.smpte-430-2.ROOT.NOT_FOR_PRODUCTION,OU=example.org,O=example.org"
102                 );
103
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());
107 }
108
109 /** Check some more certificate-from-strings */
110 BOOST_AUTO_TEST_CASE (certificates2)
111 {
112         {
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"));
115         }
116
117         {
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"));
120         }
121
122         {
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);
125         }
126
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);
129 }
130
131 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
132 BOOST_AUTO_TEST_CASE (certificates_validation1)
133 {
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));
139 }
140
141 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
142 BOOST_AUTO_TEST_CASE (certificates_validation2)
143 {
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));
147 }
148
149 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
150 BOOST_AUTO_TEST_CASE (certificates_validation3)
151 {
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);
157 }
158
159 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
160 BOOST_AUTO_TEST_CASE (certificates_validation4)
161 {
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());
168 }
169
170 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
171 BOOST_AUTO_TEST_CASE (certificates_validation5)
172 {
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());
179 }
180
181 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
182 BOOST_AUTO_TEST_CASE (certificates_validation6)
183 {
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());
190 }
191
192 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
193 BOOST_AUTO_TEST_CASE (certificates_validation7)
194 {
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);
200 }
201
202 /** Check that dcp::CertificateChain::chain_valid() and ::root_to_leaf() basically work */
203 BOOST_AUTO_TEST_CASE (certificates_validation8)
204 {
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);
211 }
212
213 /** Check that we can create a valid chain */
214 BOOST_AUTO_TEST_CASE (certificates_validation9)
215 {
216         dcp::CertificateChain good (
217                 boost::filesystem::path ("openssl"),
218                 10 * 365,
219                 "dcpomatic.com",
220                 "dcpomatic.com",
221                 ".dcpomatic.smpte-430-2.ROOT",
222                 ".dcpomatic.smpte-430-2.INTERMEDIATE",
223                 "CS.dcpomatic.smpte-430-2.LEAF"
224                 );
225
226         BOOST_CHECK_NO_THROW (good.root_to_leaf());
227 }
228
229 /** Check that we can create a valid chain */
230 BOOST_AUTO_TEST_CASE (certificates_validation10)
231 {
232         dcp::CertificateChain good (boost::filesystem::path ("openssl"), 10 * 365);
233         BOOST_CHECK_NO_THROW (good.root_to_leaf());
234 }
235
236 /** Check that dcp::Signer::valid() basically works */
237 BOOST_AUTO_TEST_CASE (signer_validation)
238 {
239         /* Check a valid signer */
240         dcp::CertificateChain chain;
241         chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/ca.self-signed.pem")));
242         chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/intermediate.signed.pem")));
243         chain.add (dcp::Certificate (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem")));
244         chain.set_key (dcp::file_to_string ("test/ref/crypt/leaf.key"));
245         BOOST_CHECK (chain.valid ());
246
247         /* Put in an unrelated key and the signer should no longer be valid */
248         dcp::CertificateChain another_chain (boost::filesystem::path ("openssl"), 10 * 365);
249         chain.set_key (another_chain.key().get ());
250         BOOST_CHECK (!chain.valid ());
251 }
252
253 /** Check reading of a certificate chain from a string */
254 BOOST_AUTO_TEST_CASE (certificate_chain_from_string)
255 {
256         dcp::CertificateChain a (dcp::file_to_string (private_test / "chain.pem"));
257         BOOST_CHECK_EQUAL (a.root_to_leaf().size(), 3U);
258
259         dcp::CertificateChain b (dcp::file_to_string ("test/ref/crypt/leaf.signed.pem"));
260         BOOST_CHECK_EQUAL (b.root_to_leaf().size(), 1U);
261 }
262
263 /** Check not_before and not_after */
264 BOOST_AUTO_TEST_CASE (certificate_not_before_after)
265 {
266         dcp::Certificate c (dcp::file_to_string("test/ref/crypt/ca.self-signed.pem"));
267         auto not_before = c.not_before();
268         BOOST_CHECK_EQUAL (not_before.second(), 8);
269         BOOST_CHECK_EQUAL (not_before.minute(), 20);
270         BOOST_CHECK_EQUAL (not_before.hour(), 13);
271         BOOST_CHECK_EQUAL (not_before.day(), 5);
272         BOOST_CHECK_EQUAL (not_before.month(), 6);
273         BOOST_CHECK_EQUAL (not_before.year(), 2015);
274         auto not_after = c.not_after();
275         BOOST_CHECK_EQUAL (not_after.second(), 8);
276         BOOST_CHECK_EQUAL (not_after.minute(), 20);
277         BOOST_CHECK_EQUAL (not_after.hour(), 13);
278         BOOST_CHECK_EQUAL (not_after.day(), 2);
279         BOOST_CHECK_EQUAL (not_after.month(), 6);
280         BOOST_CHECK_EQUAL (not_after.year(), 2025);
281 }