1 /*
2  * Copyright 2020, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include "certificate_utils.h"
20 
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 #include <openssl/mem.h>
24 
25 #include <iomanip>
26 #include <iostream>
27 #include <sstream>
28 #include <variant>
29 
30 #include "test_keys.h"
31 
32 using namespace keystore;
33 
34 // I leave these here in case they are needed for debugging.
35 namespace debug_utils {
36 
log_ssl_error()37 void log_ssl_error() {
38     unsigned long error = ERR_peek_last_error();
39 
40     char buf[128];
41     ERR_error_string_n(error, buf, sizeof(buf));
42     std::cout << "BoringSslError: " << buf << std::endl;
43 }
44 
hexdump(const std::vector<uint8_t> & data)45 std::string hexdump(const std::vector<uint8_t>& data) {
46     std::stringstream s;
47     size_t column_count = 0;
48     for (auto& c : data) {
49         s << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)c;
50         if (++column_count % 40 == 0) s << "\n";
51     }
52     return s.str();
53 }
54 
55 }  // namespace debug_utils
56 
57 constexpr uint64_t kValidity = 24 * 60 * 60 * 1000;  // 24 hours in milliseconds
58 
getMD(Digest digest)59 const EVP_MD* getMD(Digest digest) {
60     switch (digest) {
61     case Digest::SHA1:
62         return EVP_sha1();
63     case Digest::SHA224:
64         return EVP_sha224();
65     case Digest::SHA256:
66         return EVP_sha256();
67     case Digest::SHA384:
68         return EVP_sha384();
69     case Digest::SHA512:
70         return EVP_sha512();
71     }
72 }
73 
74 std::array<Digest, 5> digests = {
75     Digest::SHA1, Digest::SHA224, Digest::SHA256, Digest::SHA384, Digest::SHA512,
76 };
77 
toString(Digest d)78 static const char* toString(Digest d) {
79     switch (d) {
80     case Digest::SHA1:
81         return "SHA1";
82     case Digest::SHA224:
83         return "SHA224";
84     case Digest::SHA256:
85         return "SHA256";
86     case Digest::SHA384:
87         return "SHA384";
88     case Digest::SHA512:
89         return "SHA512";
90     }
91 }
92 
93 std::array<Padding, 2> rsa_paddings = {
94     Padding::PSS,
95     Padding::PKCS1_5,
96 };
97 
98 enum class EcCurve {
99     P224,
100     P256,
101     P384,
102     P521,
103 };
104 
105 std::array<int, 4> ec_curves = {
106     NID_secp224r1,
107     NID_X9_62_prime256v1,
108     NID_secp384r1,
109     NID_secp521r1,
110 };
111 
curveNidToString(int nid)112 static const char* curveNidToString(int nid) {
113     switch (nid) {
114     case NID_secp224r1:
115         return "P224";
116     case NID_X9_62_prime256v1:
117         return "P256";
118     case NID_secp384r1:
119         return "P384";
120     case NID_secp521r1:
121         return "P521";
122     default:
123         return "Unknown";
124     }
125 }
126 
127 std::array<long, 2> rsa_key_sizes = {
128     2048,
129     4096,
130 };
131 
132 using EcParam = std::tuple<int /* EC curve NID */, Digest>;
133 
134 class CertificateUtilsWithEcCurve : public testing::TestWithParam<EcParam> {};
135 
paramToStringEc(testing::TestParamInfo<EcParam> param)136 static std::string paramToStringEc(testing::TestParamInfo<EcParam> param) {
137     std::stringstream s;
138     auto [curve_nid, digest] = param.param;
139     s << param.index << "_" << curveNidToString(curve_nid) << "_" << toString(digest);
140     return s.str();
141 }
142 
143 INSTANTIATE_TEST_SUITE_P(CertSigningWithCallbackEC, CertificateUtilsWithEcCurve,
144                          testing::Combine(testing::ValuesIn(ec_curves), testing::ValuesIn(digests)),
145                          paramToStringEc);
146 
TEST_P(CertificateUtilsWithEcCurve,CertSigningWithCallbackEC)147 TEST_P(CertificateUtilsWithEcCurve, CertSigningWithCallbackEC) {
148     // Structured decomposition (e.g.: auto [a, b, c] = ...) does not work here because
149     // names bound this way cannot be captured in lambda expressions so we use std::tie instead.
150     int curve_nid;
151     Digest digest;
152     std::tie(curve_nid, digest) = GetParam();
153     EVP_PKEY_CTX_Ptr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL));
154     ASSERT_TRUE((bool)pkey_ctx);
155     ASSERT_TRUE(EVP_PKEY_keygen_init(pkey_ctx.get()));
156     ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx.get(), curve_nid));
157 
158     EVP_PKEY* pkey_ptr = nullptr;
159     ASSERT_TRUE(EVP_PKEY_keygen(pkey_ctx.get(), &pkey_ptr));
160     EVP_PKEY_Ptr pkey(pkey_ptr);
161     ASSERT_TRUE(pkey);
162 
163     uint64_t now_ms = (uint64_t)time(nullptr) * 1000;
164 
165     BasicConstraintsExtension bcons{
166         .isCa = true,
167         .pathLength = {},
168     };
169 
170     KeyUsageExtension keyUsage{
171         .isSigningKey = true,
172         .isEncryptionKey = false,
173         .isCertificationKey = true,
174     };
175 
176     auto certV = makeCert(pkey.get(), std::nullopt, std::nullopt, now_ms - kValidity,
177                           now_ms + kValidity, true /* subject key id extension */, keyUsage, bcons);
178     ASSERT_TRUE(std::holds_alternative<X509_Ptr>(certV));
179     auto& cert = std::get<X509_Ptr>(certV);
180     ASSERT_TRUE(!setIssuer(cert.get(), cert.get(), true));
181 
182     ASSERT_TRUE(!signCertWith(
183         cert.get(),
184         [&](const uint8_t* data, size_t len) {
185             bssl::ScopedEVP_MD_CTX sign_ctx;
186             EXPECT_TRUE(
187                 EVP_DigestSignInit(sign_ctx.get(), nullptr, getMD(digest), nullptr, pkey.get()));
188 
189             std::vector<uint8_t> sig_buf(512);
190             size_t sig_len = 512;
191             EVP_DigestSign(sign_ctx.get(), sig_buf.data(), &sig_len, data, len);
192             sig_buf.resize(sig_len);
193             return sig_buf;
194         },
195         Algo::ECDSA, Padding::Ignored, digest));
196 
197     auto encCertV = encodeCert(cert.get());
198     ASSERT_TRUE(std::holds_alternative<std::vector<uint8_t>>(encCertV));
199 
200     auto& encCert = std::get<1>(encCertV);
201     // Uncomment the next line to dump the DER encoded signed certificate as hex string.
202     // You can pipe this dump into  "xxd -r -p | openssl x509 -inform der -text -noout"
203     // to inspect the certificate.
204     // std::cout << "DER encoded cert:\n" << debug_utils::hexdump(encCert) << std::endl;
205 
206     const uint8_t* p = encCert.data();
207     X509_Ptr decoded_cert(d2i_X509(nullptr, &p, (long)encCert.size()));
208     EVP_PKEY_Ptr decoded_pkey(X509_get_pubkey(decoded_cert.get()));
209     ASSERT_TRUE(X509_verify(decoded_cert.get(), decoded_pkey.get()));
210 }
211 
212 using RsaParams = std::tuple<long /* key size */, Padding, Digest>;
213 
214 class CertificateUtilsWithRsa : public testing::TestWithParam<RsaParams> {};
215 
paramsToStringRsa(testing::TestParamInfo<RsaParams> param)216 static std::string paramsToStringRsa(testing::TestParamInfo<RsaParams> param) {
217     std::stringstream s;
218     auto [key_size, padding, digest] = param.param;
219     s << param.index << "_" << key_size << "_";
220     switch (padding) {
221     case Padding::PSS:
222         s << "PSS";
223         break;
224     case Padding::PKCS1_5:
225         s << "PKCS1_5";
226         break;
227     case Padding::Ignored:
228         s << "Ignored";
229     }
230     s << "_" << toString(digest);
231     return s.str();
232 }
233 
234 INSTANTIATE_TEST_SUITE_P(CertSigningWithCallbackRsa, CertificateUtilsWithRsa,
235                          testing::Combine(testing::ValuesIn(rsa_key_sizes),
236                                           testing::ValuesIn(rsa_paddings),
237                                           testing::ValuesIn(digests)),
238                          paramsToStringRsa);
239 
TEST_P(CertificateUtilsWithRsa,CertSigningWithCallbackRsa)240 TEST_P(CertificateUtilsWithRsa, CertSigningWithCallbackRsa) {
241     // Structured decomposition (e.g.: auto [a, b, c] = ...) does not work here because
242     // names bound this way cannot be captured in lambda expressions so we use std::tie instead.
243     long key_size;
244     Padding padding;
245     Digest digest;
246     std::tie(key_size, padding, digest) = GetParam();
247 
248     CBS cbs;
249     switch (key_size) {
250     case 2048:
251         CBS_init(&cbs, rsa_key_2k, rsa_key_2k_len);
252         break;
253     case 4096:
254         CBS_init(&cbs, rsa_key_4k, rsa_key_4k_len);
255         break;
256     default:
257         FAIL();
258     }
259     EVP_PKEY_Ptr pkey(EVP_parse_private_key(&cbs));
260     ASSERT_TRUE(pkey);
261 
262     uint64_t now_ms = (uint64_t)time(nullptr) * 1000;
263 
264     BasicConstraintsExtension bcons{
265         .isCa = true,
266         .pathLength = 0,
267     };
268 
269     KeyUsageExtension keyUsage{
270         .isSigningKey = true,
271         .isEncryptionKey = false,
272         .isCertificationKey = true,
273     };
274 
275     auto certV = makeCert(pkey.get(), std::nullopt, std::nullopt, now_ms - kValidity,
276                           now_ms + kValidity, true /* subject key id extension */, keyUsage, bcons);
277     ASSERT_TRUE(std::holds_alternative<X509_Ptr>(certV));
278     auto& cert = std::get<X509_Ptr>(certV);
279     ASSERT_TRUE(!setIssuer(cert.get(), cert.get(), true));
280 
281     ASSERT_TRUE(!signCertWith(
282         cert.get(),
283         [&](const uint8_t* data, size_t len) {
284             bssl::ScopedEVP_MD_CTX sign_ctx;
285             EVP_PKEY_CTX* pkey_sign_ctx_ptr;
286             EXPECT_TRUE(EVP_DigestSignInit(sign_ctx.get(), &pkey_sign_ctx_ptr, getMD(digest),
287                                            nullptr, pkey.get()));
288 
289             if (padding == Padding::PSS) {
290                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_sign_ctx_ptr, RSA_PKCS1_PSS_PADDING));
291                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_sign_ctx_ptr, -1));
292             } else {
293                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_sign_ctx_ptr, RSA_PKCS1_PADDING));
294             }
295 
296             std::vector<uint8_t> sig_buf(1024);
297             size_t sig_len = 1024;
298             EVP_DigestSign(sign_ctx.get(), sig_buf.data(), &sig_len, data, len);
299             sig_buf.resize(sig_len);
300             return sig_buf;
301         },
302         Algo::RSA, padding, digest));
303 
304     auto encCertV = encodeCert(cert.get());
305     ASSERT_TRUE(std::holds_alternative<std::vector<uint8_t>>(encCertV));
306 
307     auto& encCert = std::get<1>(encCertV);
308     // Uncomment the next line to dump the DER encoded signed certificate as hex string.
309     // You can pipe this dump into  "xxd -r -p | openssl x509 -inform der -text -noout"
310     // to inspect the certificate.
311     // std::cout << "DER encoded cert:\n" << debug_utils::hexdump(encCert) << std::endl;
312 
313     const uint8_t* p = encCert.data();
314     X509_Ptr decoded_cert(d2i_X509(nullptr, &p, (long)encCert.size()));
315     EVP_PKEY_Ptr decoded_pkey(X509_get_pubkey(decoded_cert.get()));
316     ASSERT_TRUE(X509_verify(decoded_cert.get(), decoded_pkey.get()));
317 }
318 
TEST(TimeStringTests,toTimeStringTest)319 TEST(TimeStringTests, toTimeStringTest) {
320     // Two test vectors that need to result in UTCTime
321     ASSERT_EQ(std::string(toTimeString(1622758591000)->data()), std::string("210603221631Z"));
322     ASSERT_EQ(std::string(toTimeString(0)->data()), std::string("700101000000Z"));
323     // Two test vectors that need to result in GeneralizedTime.
324     ASSERT_EQ(std::string(toTimeString(16227585910000)->data()), std::string("24840325064510Z"));
325     ASSERT_EQ(std::string(toTimeString(-1622758591000)->data()), std::string("19180731014329Z"));
326 
327     // Highest possible UTCTime
328     ASSERT_EQ(std::string(toTimeString(2524607999999)->data()), "491231235959Z");
329     // And one millisecond later must be GeneralizedTime.
330     ASSERT_EQ(std::string(toTimeString(2524608000000)->data()), "20500101000000Z");
331 
332     // Earliest possible UTCTime
333     ASSERT_EQ(std::string(toTimeString(-631152000000)->data()), "500101000000Z");
334     // And one millisecond earlier must be GeneralizedTime.
335     // This also checks that the rounding direction does not flip when the input is negative.
336     ASSERT_EQ(std::string(toTimeString(-631152000001)->data()), "19491231235959Z");
337 }