xref: /aosp_15_r20/system/security/keystore2/src/crypto/tests/certificate_utils_test.cpp (revision e1997b9af69e3155ead6e072d106a0077849ffba)
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 "certificate_utils.h"
18 #include <gtest/gtest.h>
19 
20 #include <openssl/err.h>
21 #include <openssl/evp.h>
22 #include <openssl/mem.h>
23 
24 #include <iomanip>
25 #include <iostream>
26 #include <sstream>
27 #include <variant>
28 
29 #include "test_keys.h"
30 
31 using namespace keystore;
32 
33 // I leave these here in case they are needed for debugging.
34 namespace debug_utils {
35 
log_ssl_error()36 void log_ssl_error() {
37     unsigned long error = ERR_peek_last_error();
38 
39     char buf[128];
40     ERR_error_string_n(error, buf, sizeof(buf));
41     std::cout << "BoringSslError: " << buf << std::endl;
42 }
43 
hexdump(const std::vector<uint8_t> & data)44 std::string hexdump(const std::vector<uint8_t>& data) {
45     std::stringstream s;
46     size_t column_count = 0;
47     for (auto& c : data) {
48         s << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)c;
49         if (++column_count % 40 == 0) s << "\n";
50     }
51     return s.str();
52 }
53 
54 }  // namespace debug_utils
55 
56 constexpr uint64_t kValidity = 24 * 60 * 60 * 1000;  // 24 hours in milliseconds
57 
getMD(Digest digest)58 const EVP_MD* getMD(Digest digest) {
59     switch (digest) {
60     case Digest::SHA1:
61         return EVP_sha1();
62     case Digest::SHA224:
63         return EVP_sha224();
64     case Digest::SHA256:
65         return EVP_sha256();
66     case Digest::SHA384:
67         return EVP_sha384();
68     case Digest::SHA512:
69         return EVP_sha512();
70     }
71 }
72 
73 std::array<Digest, 5> digests = {
74     Digest::SHA1, Digest::SHA224, Digest::SHA256, Digest::SHA384, Digest::SHA512,
75 };
76 
toString(Digest d)77 static const char* toString(Digest d) {
78     switch (d) {
79     case Digest::SHA1:
80         return "SHA1";
81     case Digest::SHA224:
82         return "SHA224";
83     case Digest::SHA256:
84         return "SHA256";
85     case Digest::SHA384:
86         return "SHA384";
87     case Digest::SHA512:
88         return "SHA512";
89     }
90 }
91 
92 std::array<Padding, 2> rsa_paddings = {
93     Padding::PSS,
94     Padding::PKCS1_5,
95 };
96 
97 enum class EcCurve {
98     P224,
99     P256,
100     P384,
101     P521,
102 };
103 
104 std::array<int, 4> ec_curves = {
105     NID_secp224r1,
106     NID_X9_62_prime256v1,
107     NID_secp384r1,
108     NID_secp521r1,
109 };
110 
curveNidToString(int nid)111 static const char* curveNidToString(int nid) {
112     switch (nid) {
113     case NID_secp224r1:
114         return "P224";
115     case NID_X9_62_prime256v1:
116         return "P256";
117     case NID_secp384r1:
118         return "P384";
119     case NID_secp521r1:
120         return "P521";
121     default:
122         return "Unknown";
123     }
124 }
125 
126 std::array<long, 2> rsa_key_sizes = {
127     2048,
128     4096,
129 };
130 
131 using EcParam = std::tuple<int /* EC curve NID */, Digest>;
132 
133 class CertificateUtilsWithEcCurve : public testing::TestWithParam<EcParam> {};
134 
paramToStringEc(testing::TestParamInfo<EcParam> param)135 static std::string paramToStringEc(testing::TestParamInfo<EcParam> param) {
136     std::stringstream s;
137     auto [curve_nid, digest] = param.param;
138     s << param.index << "_" << curveNidToString(curve_nid) << "_" << toString(digest);
139     return s.str();
140 }
141 
142 INSTANTIATE_TEST_SUITE_P(CertSigningWithCallbackEC, CertificateUtilsWithEcCurve,
143                          testing::Combine(testing::ValuesIn(ec_curves), testing::ValuesIn(digests)),
144                          paramToStringEc);
145 
TEST_P(CertificateUtilsWithEcCurve,CertSigningWithCallbackEC)146 TEST_P(CertificateUtilsWithEcCurve, CertSigningWithCallbackEC) {
147     // Structured decomposition (e.g.: auto [a, b, c] = ...) does not work here because
148     // names bound this way cannot be captured in lambda expressions so we use std::tie instead.
149     int curve_nid;
150     Digest digest;
151     std::tie(curve_nid, digest) = GetParam();
152     EVP_PKEY_CTX_Ptr pkey_ctx(EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL));
153     ASSERT_TRUE((bool)pkey_ctx);
154     ASSERT_TRUE(EVP_PKEY_keygen_init(pkey_ctx.get()));
155     ASSERT_TRUE(EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx.get(), curve_nid));
156 
157     EVP_PKEY* pkey_ptr = nullptr;
158     ASSERT_TRUE(EVP_PKEY_keygen(pkey_ctx.get(), &pkey_ptr));
159     EVP_PKEY_Ptr pkey(pkey_ptr);
160     ASSERT_TRUE(pkey);
161 
162     uint64_t now_ms = (uint64_t)time(nullptr) * 1000;
163 
164     BasicConstraintsExtension bcons{
165         .isCa = true,
166         .pathLength = {},
167     };
168 
169     KeyUsageExtension keyUsage{
170         .isSigningKey = true,
171         .isEncryptionKey = false,
172         .isCertificationKey = true,
173     };
174 
175     auto certV = makeCert(pkey.get(), std::nullopt, std::nullopt, now_ms - kValidity,
176                           now_ms + kValidity, true /* subject key id extension */, keyUsage, bcons);
177     ASSERT_TRUE(std::holds_alternative<X509_Ptr>(certV));
178     auto& cert = std::get<X509_Ptr>(certV);
179     ASSERT_TRUE(!setIssuer(cert.get(), cert.get(), true));
180 
181     ASSERT_TRUE(!signCertWith(
182         cert.get(),
183         [&](const uint8_t* data, size_t len) {
184             bssl::ScopedEVP_MD_CTX sign_ctx;
185             EXPECT_TRUE(
186                 EVP_DigestSignInit(sign_ctx.get(), nullptr, getMD(digest), nullptr, pkey.get()));
187 
188             std::vector<uint8_t> sig_buf(512);
189             size_t sig_len = 512;
190             EVP_DigestSign(sign_ctx.get(), sig_buf.data(), &sig_len, data, len);
191             sig_buf.resize(sig_len);
192             return sig_buf;
193         },
194         Algo::ECDSA, Padding::Ignored, digest));
195 
196     auto encCertV = encodeCert(cert.get());
197     ASSERT_TRUE(std::holds_alternative<std::vector<uint8_t>>(encCertV));
198 
199     auto& encCert = std::get<1>(encCertV);
200     // Uncomment the next line to dump the DER encoded signed certificate as hex string.
201     // You can pipe this dump into  "xxd -r -p | openssl x509 -inform der -text -noout"
202     // to inspect the certificate.
203     // std::cout << "DER encoded cert:\n" << debug_utils::hexdump(encCert) << std::endl;
204 
205     const uint8_t* p = encCert.data();
206     X509_Ptr decoded_cert(d2i_X509(nullptr, &p, (long)encCert.size()));
207     EVP_PKEY_Ptr decoded_pkey(X509_get_pubkey(decoded_cert.get()));
208     ASSERT_TRUE(X509_verify(decoded_cert.get(), decoded_pkey.get()));
209 }
210 
211 using RsaParams = std::tuple<long /* key size */, Padding, Digest>;
212 
213 class CertificateUtilsWithRsa : public testing::TestWithParam<RsaParams> {};
214 
paramsToStringRsa(testing::TestParamInfo<RsaParams> param)215 static std::string paramsToStringRsa(testing::TestParamInfo<RsaParams> param) {
216     std::stringstream s;
217     auto [key_size, padding, digest] = param.param;
218     s << param.index << "_" << key_size << "_";
219     switch (padding) {
220     case Padding::PSS:
221         s << "PSS";
222         break;
223     case Padding::PKCS1_5:
224         s << "PKCS1_5";
225         break;
226     case Padding::Ignored:
227         s << "Ignored";
228     }
229     s << "_" << toString(digest);
230     return s.str();
231 }
232 
EncodeX509Algor(const X509_ALGOR * alg)233 static std::optional<std::vector<uint8_t>> EncodeX509Algor(const X509_ALGOR* alg) {
234     uint8_t* der = nullptr;
235     int der_len = i2d_X509_ALGOR(alg, &der);
236     if (der_len < 0) {
237         return std::nullopt;
238     }
239     std::vector<uint8_t> ret(der, der + der_len);
240     OPENSSL_free(der);
241     return ret;
242 }
243 
244 // `x509_verify` not working with RSA-PSS & SHA1/SHA224 digests. so, manually
245 // verify the certificate with RSA-PSS & SHA1/SHA224 digests.
246 // BoringSSL after https://boringssl-review.googlesource.com/c/boringssl/+/53865
247 // does not support RSA-PSS with SHA1/SHA224 digests.
verifyCertFieldsExplicitly(X509 * cert,Digest digest)248 static void verifyCertFieldsExplicitly(X509* cert, Digest digest) {
249     // RSA-PSS-SHA1 AlgorithmIdentifier DER encoded value
250     const std::vector<uint8_t> expected_rsa_pss_sha1 = {
251         0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30, 0x00,
252     };
253     // RSA-PSS-SHA224 AlgorithmIdentifier DER encoded value
254     const std::vector<uint8_t> expected_rsa_pss_sha224 = {
255         0x30, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a, 0x30,
256         0x34, 0xa0, 0x0f, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
257         0x02, 0x04, 0x05, 0x00, 0xa1, 0x1c, 0x30, 0x1a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
258         0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65,
259         0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0xa2, 0x03, 0x02, 0x01, 0x1c,
260     };
261     const X509_ALGOR* alg;
262     const ASN1_BIT_STRING* sig;
263     const EVP_MD* evp_digest;
264     X509_get0_signature(&sig, &alg, cert);
265     auto encoded = EncodeX509Algor(alg);
266     ASSERT_TRUE(encoded);
267 
268     // Check the AlgorithmIdentifiers.
269     if (digest == Digest::SHA1) {
270         evp_digest = EVP_sha1();
271         EXPECT_EQ(encoded.value(), expected_rsa_pss_sha1);
272     } else if (digest == Digest::SHA224) {
273         evp_digest = EVP_sha224();
274         EXPECT_EQ(encoded.value(), expected_rsa_pss_sha224);
275     } else {
276         GTEST_FAIL()
277             << "Error: This is expected to be used only for RSA-PSS with SHA1/SHA224 as digests";
278     }
279 
280     // Check the signature.
281     EVP_PKEY_Ptr pubkey(X509_get_pubkey(cert));
282     ASSERT_TRUE(pubkey);
283 
284     uint8_t* tbs = nullptr;
285     int tbs_len = i2d_X509_tbs(cert, &tbs);
286     ASSERT_GT(tbs_len, 0);
287 
288     size_t sig_len;
289     ASSERT_TRUE(ASN1_BIT_STRING_num_bytes(sig, &sig_len));
290     EVP_PKEY_CTX* pctx;
291     bssl::ScopedEVP_MD_CTX ctx;
292     ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), &pctx, evp_digest, nullptr, pubkey.get()));
293     ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING));
294     // The salt length should match the digest length.
295     ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1));
296     EXPECT_TRUE(EVP_DigestVerify(ctx.get(), ASN1_STRING_get0_data(sig), sig_len, tbs, tbs_len));
297 }
298 
299 INSTANTIATE_TEST_SUITE_P(CertSigningWithCallbackRsa, CertificateUtilsWithRsa,
300                          testing::Combine(testing::ValuesIn(rsa_key_sizes),
301                                           testing::ValuesIn(rsa_paddings),
302                                           testing::ValuesIn(digests)),
303                          paramsToStringRsa);
304 
TEST_P(CertificateUtilsWithRsa,CertSigningWithCallbackRsa)305 TEST_P(CertificateUtilsWithRsa, CertSigningWithCallbackRsa) {
306     // Structured decomposition (e.g.: auto [a, b, c] = ...) does not work here because
307     // names bound this way cannot be captured in lambda expressions so we use std::tie instead.
308     long key_size;
309     Padding padding;
310     Digest digest;
311     std::tie(key_size, padding, digest) = GetParam();
312 
313     CBS cbs;
314     switch (key_size) {
315     case 2048:
316         CBS_init(&cbs, rsa_key_2k, rsa_key_2k_len);
317         break;
318     case 4096:
319         CBS_init(&cbs, rsa_key_4k, rsa_key_4k_len);
320         break;
321     default:
322         FAIL();
323     }
324     EVP_PKEY_Ptr pkey(EVP_parse_private_key(&cbs));
325     ASSERT_TRUE(pkey);
326 
327     uint64_t now_ms = (uint64_t)time(nullptr) * 1000;
328 
329     BasicConstraintsExtension bcons{
330         .isCa = true,
331         .pathLength = 0,
332     };
333 
334     KeyUsageExtension keyUsage{
335         .isSigningKey = true,
336         .isEncryptionKey = false,
337         .isCertificationKey = true,
338     };
339 
340     auto certV = makeCert(pkey.get(), std::nullopt, std::nullopt, now_ms - kValidity,
341                           now_ms + kValidity, true /* subject key id extension */, keyUsage, bcons);
342     ASSERT_TRUE(std::holds_alternative<X509_Ptr>(certV));
343     auto& cert = std::get<X509_Ptr>(certV);
344     ASSERT_TRUE(!setIssuer(cert.get(), cert.get(), true));
345 
346     ASSERT_TRUE(!signCertWith(
347         cert.get(),
348         [&](const uint8_t* data, size_t len) {
349             bssl::ScopedEVP_MD_CTX sign_ctx;
350             EVP_PKEY_CTX* pkey_sign_ctx_ptr;
351             EXPECT_TRUE(EVP_DigestSignInit(sign_ctx.get(), &pkey_sign_ctx_ptr, getMD(digest),
352                                            nullptr, pkey.get()));
353 
354             if (padding == Padding::PSS) {
355                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_sign_ctx_ptr, RSA_PKCS1_PSS_PADDING));
356                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(pkey_sign_ctx_ptr, -1));
357             } else {
358                 EXPECT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_sign_ctx_ptr, RSA_PKCS1_PADDING));
359             }
360 
361             std::vector<uint8_t> sig_buf(1024);
362             size_t sig_len = 1024;
363             EVP_DigestSign(sign_ctx.get(), sig_buf.data(), &sig_len, data, len);
364             sig_buf.resize(sig_len);
365             return sig_buf;
366         },
367         Algo::RSA, padding, digest));
368 
369     auto encCertV = encodeCert(cert.get());
370     ASSERT_TRUE(std::holds_alternative<std::vector<uint8_t>>(encCertV));
371 
372     auto& encCert = std::get<1>(encCertV);
373     // Uncomment the next line to dump the DER encoded signed certificate as hex string.
374     // You can pipe this dump into  "xxd -r -p | openssl x509 -inform der -text -noout"
375     // to inspect the certificate.
376     // std::cout << "DER encoded cert:\n" << debug_utils::hexdump(encCert) << std::endl;
377 
378     const uint8_t* p = encCert.data();
379     X509_Ptr decoded_cert(d2i_X509(nullptr, &p, (long)encCert.size()));
380     EVP_PKEY_Ptr decoded_pkey(X509_get_pubkey(decoded_cert.get()));
381     if ((padding == Padding::PSS) && (digest == Digest::SHA1 || digest == Digest::SHA224)) {
382         // BoringSSL after https://boringssl-review.googlesource.com/c/boringssl/+/53865
383         // does not support these PSS combinations, so verify these certificates manually.
384         EXPECT_NE(decoded_cert.get(), nullptr);
385         EXPECT_NE(decoded_pkey.get(), nullptr);
386         verifyCertFieldsExplicitly(decoded_cert.get(), digest);
387     } else {
388         ASSERT_TRUE(X509_verify(decoded_cert.get(), decoded_pkey.get()));
389     }
390 }
391 
TEST(TimeStringTests,toTimeStringTest)392 TEST(TimeStringTests, toTimeStringTest) {
393     // Two test vectors that need to result in UTCTime
394     ASSERT_EQ(std::string(toTimeString(1622758591000)->data()), std::string("210603221631Z"));
395     ASSERT_EQ(std::string(toTimeString(0)->data()), std::string("700101000000Z"));
396     // Two test vectors that need to result in GeneralizedTime.
397     ASSERT_EQ(std::string(toTimeString(16227585910000)->data()), std::string("24840325064510Z"));
398     ASSERT_EQ(std::string(toTimeString(-1622758591000)->data()), std::string("19180731014329Z"));
399 
400     // Highest possible UTCTime
401     ASSERT_EQ(std::string(toTimeString(2524607999999)->data()), "491231235959Z");
402     // And one millisecond later must be GeneralizedTime.
403     ASSERT_EQ(std::string(toTimeString(2524608000000)->data()), "20500101000000Z");
404 
405     // Earliest possible UTCTime
406     ASSERT_EQ(std::string(toTimeString(-631152000000)->data()), "500101000000Z");
407     // And one millisecond earlier must be GeneralizedTime.
408     // This also checks that the rounding direction does not flip when the input is negative.
409     ASSERT_EQ(std::string(toTimeString(-631152000001)->data()), "19491231235959Z");
410 }
411