1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fcntl.h>
6 #include <unistd.h>
7
8 #include "cast/common/certificate/cast_crl.h"
9 #include "cast/common/certificate/testing/test_helpers.h"
10 #include "cast/common/certificate/types.h"
11 #include "platform/test/paths.h"
12 #include "util/crypto/certificate_utils.h"
13 #include "util/crypto/digest_sign.h"
14 #include "util/crypto/pem_helpers.h"
15 #include "util/crypto/sha2.h"
16 #include "util/osp_logging.h"
17
18 namespace openscreen {
19 namespace cast {
20 namespace {
21
AddRevokedPublicKeyHash(TbsCrl * tbs_crl,X509 * cert)22 std::string* AddRevokedPublicKeyHash(TbsCrl* tbs_crl, X509* cert) {
23 std::string* pubkey_hash = tbs_crl->add_revoked_public_key_hashes();
24 std::string pubkey_spki = GetSpkiTlv(cert);
25 *pubkey_hash = SHA256HashString(pubkey_spki).value();
26 return pubkey_hash;
27 }
28
AddSerialNumberRange(TbsCrl * tbs_crl,X509 * issuer,uint64_t first,uint64_t last)29 void AddSerialNumberRange(TbsCrl* tbs_crl,
30 X509* issuer,
31 uint64_t first,
32 uint64_t last) {
33 SerialNumberRange* serial_range = tbs_crl->add_revoked_serial_number_ranges();
34 std::string issuer_spki = GetSpkiTlv(issuer);
35 serial_range->set_issuer_public_key_hash(
36 SHA256HashString(issuer_spki).value());
37 serial_range->set_first_serial_number(first);
38 serial_range->set_last_serial_number(last);
39 }
40
MakeTbsCrl(uint64_t not_before,uint64_t not_after,X509 * device_cert,X509 * inter_cert)41 TbsCrl MakeTbsCrl(uint64_t not_before,
42 uint64_t not_after,
43 X509* device_cert,
44 X509* inter_cert) {
45 TbsCrl tbs_crl;
46 tbs_crl.set_version(0);
47 tbs_crl.set_not_before_seconds(not_before);
48 tbs_crl.set_not_after_seconds(not_after);
49
50 // NOTE: By default, include a hash which should not match any included certs.
51 std::string* pubkey_hash = AddRevokedPublicKeyHash(&tbs_crl, device_cert);
52 (*pubkey_hash)[0] ^= 0xff;
53
54 // NOTE: Include default serial number range at device-level, which should not
55 // include any of our certs.
56 ErrorOr<uint64_t> maybe_serial =
57 ParseDerUint64(X509_get0_serialNumber(device_cert));
58 OSP_DCHECK(maybe_serial);
59 uint64_t serial = maybe_serial.value();
60 OSP_DCHECK_LE(serial, UINT64_MAX - 200);
61 AddSerialNumberRange(&tbs_crl, inter_cert, serial + 100, serial + 200);
62
63 return tbs_crl;
64 }
65
66 // Pack into a CrlBundle and sign with |crl_inter_key|. |crl_inter_der| must be
67 // directly signed by a Cast CRL root CA (possibly distinct from Cast root CA).
PackCrlIntoFile(const std::string & filename,const TbsCrl & tbs_crl,const std::string & crl_inter_der,EVP_PKEY * crl_inter_key)68 void PackCrlIntoFile(const std::string& filename,
69 const TbsCrl& tbs_crl,
70 const std::string& crl_inter_der,
71 EVP_PKEY* crl_inter_key) {
72 CrlBundle crl_bundle;
73 Crl* crl = crl_bundle.add_crls();
74 std::string* tbs_crl_serial = crl->mutable_tbs_crl();
75 tbs_crl.SerializeToString(tbs_crl_serial);
76 crl->set_signer_cert(crl_inter_der);
77 ErrorOr<std::string> signature =
78 SignData(EVP_sha256(), crl_inter_key,
79 absl::Span<const uint8_t>{
80 reinterpret_cast<const uint8_t*>(tbs_crl_serial->data()),
81 tbs_crl_serial->size()});
82 OSP_DCHECK(signature);
83 crl->set_signature(std::move(signature.value()));
84
85 std::string output;
86 crl_bundle.SerializeToString(&output);
87 int fd = open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
88 OSP_DCHECK_GE(fd, 0);
89 OSP_DCHECK_EQ(write(fd, output.data(), output.size()),
90 static_cast<int>(output.size()));
91 close(fd);
92 }
93
CastMain()94 int CastMain() {
95 const std::string data_path = GetTestDataPath() + "cast/receiver/channel/";
96 bssl::UniquePtr<EVP_PKEY> inter_key =
97 ReadKeyFromPemFile(data_path + "inter_key.pem");
98 bssl::UniquePtr<EVP_PKEY> crl_inter_key =
99 ReadKeyFromPemFile(data_path + "crl_inter_key.pem");
100 OSP_DCHECK(inter_key);
101 OSP_DCHECK(crl_inter_key);
102
103 std::vector<std::string> chain_der =
104 ReadCertificatesFromPemFile(data_path + "device_chain.pem");
105 std::vector<std::string> crl_inter_der =
106 ReadCertificatesFromPemFile(data_path + "crl_inter.pem");
107 OSP_DCHECK_EQ(chain_der.size(), 3u);
108 OSP_DCHECK_EQ(crl_inter_der.size(), 1u);
109
110 std::string& device_der = chain_der[0];
111 std::string& inter_der = chain_der[1];
112 std::string& root_der = chain_der[2];
113
114 auto* data = reinterpret_cast<const uint8_t*>(device_der.data());
115 bssl::UniquePtr<X509> device_cert{
116 d2i_X509(nullptr, &data, device_der.size())};
117 data = reinterpret_cast<const uint8_t*>(inter_der.data());
118 bssl::UniquePtr<X509> inter_cert{d2i_X509(nullptr, &data, inter_der.size())};
119 data = reinterpret_cast<const uint8_t*>(root_der.data());
120 bssl::UniquePtr<X509> root_cert{d2i_X509(nullptr, &data, root_der.size())};
121 data = reinterpret_cast<const uint8_t*>(crl_inter_der[0].data());
122 bssl::UniquePtr<X509> crl_inter_cert{
123 d2i_X509(nullptr, &data, crl_inter_der[0].size())};
124 OSP_DCHECK(device_cert);
125 OSP_DCHECK(inter_cert);
126 OSP_DCHECK(root_cert);
127 OSP_DCHECK(crl_inter_cert);
128
129 // NOTE: CRL where everything should pass.
130 DateTime july2019 = {};
131 july2019.month = 7;
132 july2019.year = 2019;
133 july2019.day = 16;
134 DateTime july2020 = {};
135 july2020.month = 7;
136 july2020.year = 2020;
137 july2020.day = 23;
138 std::chrono::seconds not_before = DateTimeToSeconds(july2019);
139 std::chrono::seconds not_after = DateTimeToSeconds(july2020);
140 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
141 device_cert.get(), inter_cert.get());
142 PackCrlIntoFile(data_path + "good_crl.pb", tbs_crl, crl_inter_der[0],
143 crl_inter_key.get());
144
145 // NOTE: CRL used outside its valid time range.
146 {
147 DateTime august2019 = {};
148 august2019.month = 8;
149 august2019.year = 2019;
150 august2019.day = 16;
151 std::chrono::seconds not_after = DateTimeToSeconds(august2019);
152 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
153 device_cert.get(), inter_cert.get());
154 PackCrlIntoFile(data_path + "invalid_time_crl.pb", tbs_crl,
155 crl_inter_der[0], crl_inter_key.get());
156 }
157
158 // NOTE: Device's issuer revoked.
159 {
160 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
161 device_cert.get(), inter_cert.get());
162 AddRevokedPublicKeyHash(&tbs_crl, inter_cert.get());
163 PackCrlIntoFile(data_path + "issuer_revoked_crl.pb", tbs_crl,
164 crl_inter_der[0], crl_inter_key.get());
165 }
166
167 // NOTE: Device revoked.
168 {
169 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
170 device_cert.get(), inter_cert.get());
171 AddRevokedPublicKeyHash(&tbs_crl, device_cert.get());
172 PackCrlIntoFile(data_path + "device_revoked_crl.pb", tbs_crl,
173 crl_inter_der[0], crl_inter_key.get());
174 }
175
176 // NOTE: Issuer serial revoked.
177 {
178 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
179 device_cert.get(), inter_cert.get());
180 ErrorOr<uint64_t> maybe_serial =
181 ParseDerUint64(X509_get0_serialNumber(inter_cert.get()));
182 OSP_DCHECK(maybe_serial);
183 uint64_t serial = maybe_serial.value();
184 OSP_DCHECK_GE(serial, 10);
185 OSP_DCHECK_LE(serial, UINT64_MAX - 20);
186 AddSerialNumberRange(&tbs_crl, root_cert.get(), serial - 10, serial + 20);
187 PackCrlIntoFile(data_path + "issuer_serial_revoked_crl.pb", tbs_crl,
188 crl_inter_der[0], crl_inter_key.get());
189 }
190
191 // NOTE: Device serial revoked.
192 {
193 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
194 device_cert.get(), inter_cert.get());
195 ErrorOr<uint64_t> maybe_serial =
196 ParseDerUint64(X509_get0_serialNumber(device_cert.get()));
197 OSP_DCHECK(maybe_serial);
198 uint64_t serial = maybe_serial.value();
199 OSP_DCHECK_GE(serial, 10);
200 OSP_DCHECK_LE(serial, UINT64_MAX - 20);
201 AddSerialNumberRange(&tbs_crl, inter_cert.get(), serial - 10, serial + 20);
202 PackCrlIntoFile(data_path + "device_serial_revoked_crl.pb", tbs_crl,
203 crl_inter_der[0], crl_inter_key.get());
204 }
205
206 // NOTE: Bad |signer_cert| used for Crl (not issued by Cast CRL root).
207 {
208 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
209 device_cert.get(), inter_cert.get());
210 PackCrlIntoFile(data_path + "bad_signer_cert_crl.pb", tbs_crl, inter_der,
211 inter_key.get());
212 }
213
214 // NOTE: Mismatched key for signature in Crl (just looks like bad signature).
215 {
216 TbsCrl tbs_crl = MakeTbsCrl(not_before.count(), not_after.count(),
217 device_cert.get(), inter_cert.get());
218 PackCrlIntoFile(data_path + "bad_signature_crl.pb", tbs_crl,
219 crl_inter_der[0], inter_key.get());
220 }
221
222 return 0;
223 }
224
225 } // namespace
226 } // namespace cast
227 } // namespace openscreen
228
main()229 int main() {
230 return openscreen::cast::CastMain();
231 }
232