xref: /aosp_15_r20/external/open-dice/src/test_utils.cc (revision 60b67249c2e226f42f35cc6cfe66c6048e0bae6b)
1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "dice/test_utils.h"
16 
17 #include <stddef.h>
18 #include <stdint.h>
19 #include <string.h>
20 
21 #include <functional>
22 #include <memory>
23 #include <span>
24 #include <vector>
25 
26 #include "cose/cose.h"
27 #include "dice/boringssl_ecdsa_utils.h"
28 #include "dice/dice.h"
29 #include "dice/utils.h"
30 #include "openssl/asn1.h"
31 #include "openssl/bn.h"
32 #include "openssl/curve25519.h"
33 #include "openssl/evp.h"
34 #include "openssl/is_boringssl.h"
35 #include "openssl/mem.h"
36 #include "openssl/sha.h"
37 #include "openssl/x509.h"
38 #include "openssl/x509_vfy.h"
39 #include "openssl/x509v3.h"
40 #include "pw_string/format.h"
41 
42 // The largest possible public key size among ECDSA P-384, P-256, and ED25519
43 #define MAX_PUBLIC_KEY_SIZE 96
44 
45 namespace {
46 
47 // A scoped pointer for cn_cbor.
48 struct CborDeleter {
operator ()__anonad3d27450111::CborDeleter49   void operator()(cn_cbor* c) { cn_cbor_free(c); }
50 };
51 using ScopedCbor = std::unique_ptr<cn_cbor, CborDeleter>;
52 
GetCertTypeStr(dice::test::CertificateType cert_type)53 const char* GetCertTypeStr(dice::test::CertificateType cert_type) {
54   switch (cert_type) {
55     case dice::test::CertificateType_Cbor:
56       return "CBOR";
57     case dice::test::CertificateType_X509:
58       return "X509";
59   }
60   return "";
61 }
62 
GetKeyTypeStr(dice::test::KeyType key_type)63 const char* GetKeyTypeStr(dice::test::KeyType key_type) {
64   switch (key_type) {
65     case dice::test::KeyType_Ed25519:
66       return "Ed25519";
67     case dice::test::KeyType_P256:
68     case dice::test::KeyType_P256_COMPRESSED:
69       return "P256";
70     case dice::test::KeyType_P384:
71       return "P384";
72   }
73   return "";
74 }
75 
ParseX509Certificate(const uint8_t * certificate,size_t certificate_size)76 bssl::UniquePtr<X509> ParseX509Certificate(const uint8_t* certificate,
77                                            size_t certificate_size) {
78   const uint8_t* asn1 = certificate;
79   return bssl::UniquePtr<X509>(
80       d2i_X509(/*X509=*/nullptr, &asn1, certificate_size));
81 }
82 
DumpToFile(const char * filename,const uint8_t * data,size_t size)83 void DumpToFile(const char* filename, const uint8_t* data, size_t size) {
84   FILE* fp = fopen(filename, "w");
85   if (fp) {
86     fwrite(data, size, 1, fp);
87     fclose(fp);
88   } else {
89     printf("WARNING: Failed to dump to file.\n");
90   }
91 }
92 
EcKeyFromCoords(int nid,uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE],size_t public_key_size)93 bssl::UniquePtr<EVP_PKEY> EcKeyFromCoords(
94     int nid, uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE],
95     size_t public_key_size) {
96   bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
97   BIGNUM* x = BN_new();
98   BN_bin2bn(&raw_public_key[0], public_key_size / 2, x);
99   BIGNUM* y = BN_new();
100   BN_bin2bn(&raw_public_key[public_key_size / 2], public_key_size / 2, y);
101   EC_KEY_set_public_key_affine_coordinates(key.get(), x, y);
102   BN_clear_free(y);
103   BN_clear_free(x);
104   bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
105   EVP_PKEY_set1_EC_KEY(pkey.get(), key.get());
106   return pkey;
107 }
108 
KeyFromRawKey(const uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE],dice::test::KeyType key_type,uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE],size_t * raw_public_key_size)109 bssl::UniquePtr<EVP_PKEY> KeyFromRawKey(
110     const uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE],
111     dice::test::KeyType key_type, uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE],
112     size_t* raw_public_key_size) {
113   if (key_type == dice::test::KeyType_Ed25519) {
114     bssl::UniquePtr<EVP_PKEY> key(
115         EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, /*unused=*/nullptr,
116                                      raw_key, DICE_PRIVATE_KEY_SEED_SIZE));
117     *raw_public_key_size = 32;
118     EVP_PKEY_get_raw_public_key(key.get(), raw_public_key, raw_public_key_size);
119     return key;
120   } else if (key_type == dice::test::KeyType_P256 ||
121              key_type == dice::test::KeyType_P256_COMPRESSED) {
122     const size_t kPublicKeySize = 64;
123     const size_t kPrivateKeySize = 32;
124     uint8_t pk[kPrivateKeySize];
125     P256KeypairFromSeed(raw_public_key, pk, raw_key);
126     bssl::UniquePtr<EVP_PKEY> pkey =
127         EcKeyFromCoords(NID_X9_62_prime256v1, raw_public_key, kPublicKeySize);
128     if (key_type == dice::test::KeyType_P256_COMPRESSED) {
129       const EC_KEY* key = EVP_PKEY_get0_EC_KEY(pkey.get());
130       const EC_GROUP* group = EC_KEY_get0_group(key);
131       const EC_POINT* pub = EC_KEY_get0_public_key(key);
132       *raw_public_key_size = EC_POINT_point2oct(
133           group, pub, POINT_CONVERSION_COMPRESSED, raw_public_key,
134           MAX_PUBLIC_KEY_SIZE, /*ctx=*/nullptr);
135     } else {
136       *raw_public_key_size = kPublicKeySize;
137     }
138     return pkey;
139   } else if (key_type == dice::test::KeyType_P384) {
140     const size_t kPublicKeySize = 96;
141     const size_t kPrivateKeySize = 48;
142     uint8_t pk[kPrivateKeySize];
143     P384KeypairFromSeed(raw_public_key, pk, raw_key);
144     *raw_public_key_size = kPublicKeySize;
145     return EcKeyFromCoords(NID_secp384r1, raw_public_key, kPublicKeySize);
146   }
147 
148   printf("ERROR: Unsupported key type.\n");
149   return nullptr;
150 }
151 
CreateX509UdsCertificate(EVP_PKEY * key,const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)152 void CreateX509UdsCertificate(EVP_PKEY* key, const uint8_t id[DICE_ID_SIZE],
153                               uint8_t certificate[dice::test::kTestCertSize],
154                               size_t* certificate_size) {
155   bssl::UniquePtr<X509> x509(X509_new());
156   X509_set_version(x509.get(), 2);
157 
158   bssl::UniquePtr<ASN1_INTEGER> serial(ASN1_INTEGER_new());
159   ASN1_INTEGER_set_uint64(serial.get(), 1);
160   X509_set_serialNumber(x509.get(), serial.get());
161 
162   uint8_t id_hex[40];
163   DiceHexEncode(id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
164   bssl::UniquePtr<X509_NAME> issuer_name(X509_NAME_new());
165   X509_NAME_add_entry_by_NID(issuer_name.get(), NID_serialNumber, MBSTRING_UTF8,
166                              id_hex, sizeof(id_hex), 0, 0);
167   X509_set_issuer_name(x509.get(), issuer_name.get());
168   X509_set_subject_name(x509.get(), issuer_name.get());
169 
170   bssl::UniquePtr<ASN1_TIME> not_before(ASN1_TIME_new());
171   ASN1_TIME_set_string(not_before.get(), "180322235959Z");
172   X509_set_notBefore(x509.get(), not_before.get());
173   bssl::UniquePtr<ASN1_TIME> not_after(ASN1_TIME_new());
174   ASN1_TIME_set_string(not_after.get(), "99991231235959Z");
175   X509_set_notAfter(x509.get(), not_after.get());
176 
177   bssl::UniquePtr<ASN1_OCTET_STRING> subject_key_id(ASN1_OCTET_STRING_new());
178   ASN1_OCTET_STRING_set(subject_key_id.get(), id, DICE_ID_SIZE);
179   bssl::UniquePtr<X509_EXTENSION> subject_key_id_ext(X509V3_EXT_i2d(
180       NID_subject_key_identifier, /*crit=*/0, subject_key_id.get()));
181   X509_add_ext(x509.get(), subject_key_id_ext.get(), /*loc=*/-1);
182 
183   bssl::UniquePtr<AUTHORITY_KEYID> authority_key_id(AUTHORITY_KEYID_new());
184   authority_key_id->keyid = ASN1_OCTET_STRING_dup(subject_key_id.get());
185   bssl::UniquePtr<X509_EXTENSION> authority_key_id_ext(X509V3_EXT_i2d(
186       NID_authority_key_identifier, /*crit=*/0, authority_key_id.get()));
187   X509_add_ext(x509.get(), authority_key_id_ext.get(), /*loc=*/-1);
188 
189   bssl::UniquePtr<ASN1_BIT_STRING> key_usage(ASN1_BIT_STRING_new());
190   ASN1_BIT_STRING_set_bit(key_usage.get(), 5 /*keyCertSign*/, 1);
191   bssl::UniquePtr<X509_EXTENSION> key_usage_ext(
192       X509V3_EXT_i2d(NID_key_usage, /*crit=*/1, key_usage.get()));
193   X509_add_ext(x509.get(), key_usage_ext.get(), /*loc=*/-1);
194 
195   bssl::UniquePtr<BASIC_CONSTRAINTS> basic_constraints(BASIC_CONSTRAINTS_new());
196   basic_constraints->ca = 1;
197   bssl::UniquePtr<X509_EXTENSION> basic_constraints_ext(X509V3_EXT_i2d(
198       NID_basic_constraints, /*crit=*/1, basic_constraints.get()));
199   X509_add_ext(x509.get(), basic_constraints_ext.get(), /*loc=*/-1);
200 
201   X509_set_pubkey(x509.get(), key);
202   // ED25519 always uses SHA-512 so md must be NULL.
203   const EVP_MD* md =
204       (EVP_PKEY_id(key) == EVP_PKEY_ED25519) ? nullptr : EVP_sha512();
205   X509_sign(x509.get(), key, md);
206   if (i2d_X509(x509.get(), /*out=*/nullptr) <=
207       static_cast<int>(dice::test::kTestCertSize)) {
208     uint8_t* p = certificate;
209     *certificate_size = i2d_X509(x509.get(), &p);
210   } else {
211     *certificate_size = 0;
212   }
213 }
214 
VerifyX509CertificateChain(const uint8_t * root_certificate,size_t root_certificate_size,const dice::test::DiceStateForTest states[],size_t num_dice_states,bool is_partial_chain)215 bool VerifyX509CertificateChain(const uint8_t* root_certificate,
216                                 size_t root_certificate_size,
217                                 const dice::test::DiceStateForTest states[],
218                                 size_t num_dice_states, bool is_partial_chain) {
219   bssl::UniquePtr<STACK_OF(X509)> trusted_certs(sk_X509_new_null());
220   bssl::PushToStack(trusted_certs.get(),
221                     bssl::UpRef(ParseX509Certificate(root_certificate,
222                                                      root_certificate_size)));
223   bssl::UniquePtr<STACK_OF(X509)> untrusted_certs(sk_X509_new_null());
224   for (size_t i = 0; i < num_dice_states - 1; ++i) {
225     bssl::PushToStack(untrusted_certs.get(),
226                       bssl::UpRef(ParseX509Certificate(
227                           states[i].certificate, states[i].certificate_size)));
228   }
229   bssl::UniquePtr<X509> leaf_cert(
230       ParseX509Certificate(states[num_dice_states - 1].certificate,
231                            states[num_dice_states - 1].certificate_size));
232   bssl::UniquePtr<X509_STORE> x509_store(X509_STORE_new());
233   bssl::UniquePtr<X509_STORE_CTX> x509_store_ctx(X509_STORE_CTX_new());
234   X509_STORE_CTX_init(x509_store_ctx.get(), x509_store.get(), leaf_cert.get(),
235                       untrusted_certs.get());
236   X509_STORE_CTX_trusted_stack(x509_store_ctx.get(), trusted_certs.get());
237   X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
238   X509_VERIFY_PARAM_set_time(param, 1577923199 /*1/1/2020*/);
239   X509_VERIFY_PARAM_set_depth(param, 10);
240   if (is_partial_chain) {
241     X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_PARTIAL_CHAIN);
242   }
243   // Boringssl doesn't support custom extensions, so ignore them.
244   X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_IGNORE_CRITICAL);
245   X509_STORE_CTX_set0_param(x509_store_ctx.get(), param);
246   return (1 == X509_verify_cert(x509_store_ctx.get()));
247 }
248 
CreateEd25519CborUdsCertificate(const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)249 void CreateEd25519CborUdsCertificate(
250     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
251     const uint8_t id[DICE_ID_SIZE],
252     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
253   const uint8_t kProtectedAttributesCbor[3] = {
254       0xa1 /* map(1) */, 0x01 /* alg(1) */, 0x27 /* EdDSA(-8) */};
255   const int64_t kCwtIssuerLabel = 1;
256   const int64_t kCwtSubjectLabel = 2;
257   const int64_t kUdsPublicKeyLabel = -4670552;
258   const int64_t kUdsKeyUsageLabel = -4670553;
259   const uint8_t kKeyUsageCertSign = 32;  // Bit 5.
260 
261   // Public key encoded as a COSE_Key.
262   uint8_t public_key[32];
263   uint8_t bssl_private_key[64];
264   ED25519_keypair_from_seed(public_key, bssl_private_key, private_key_seed);
265   cn_cbor_errback error;
266   ScopedCbor public_key_cbor(cn_cbor_map_create(&error));
267   // kty = okp
268   cn_cbor_mapput_int(public_key_cbor.get(), 1, cn_cbor_int_create(1, &error),
269                      &error);
270   // crv = ed25519
271   cn_cbor_mapput_int(public_key_cbor.get(), -1, cn_cbor_int_create(6, &error),
272                      &error);
273   // x = public_key
274   cn_cbor_mapput_int(public_key_cbor.get(), -2,
275                      cn_cbor_data_create(public_key, 32, &error), &error);
276   uint8_t encoded_public_key[100];
277   size_t encoded_public_key_size =
278       cn_cbor_encoder_write(encoded_public_key, 0, 100, public_key_cbor.get());
279 
280   // Simple CWT payload with issuer, subject, and use the same subject public
281   // key field as a CDI certificate to make verification easy.
282   char id_hex[41];
283   DiceHexEncode(id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
284   id_hex[40] = '\0';
285   ScopedCbor cwt(cn_cbor_map_create(&error));
286   cn_cbor_mapput_int(cwt.get(), kCwtIssuerLabel,
287                      cn_cbor_string_create(id_hex, &error), &error);
288   cn_cbor_mapput_int(cwt.get(), kCwtSubjectLabel,
289                      cn_cbor_string_create(id_hex, &error), &error);
290   cn_cbor_mapput_int(
291       cwt.get(), kUdsPublicKeyLabel,
292       cn_cbor_data_create(encoded_public_key, encoded_public_key_size, &error),
293       &error);
294   uint8_t key_usage_byte = kKeyUsageCertSign;
295   cn_cbor_mapput_int(cwt.get(), kUdsKeyUsageLabel,
296                      cn_cbor_data_create(&key_usage_byte, 1, &error), &error);
297   uint8_t payload[dice::test::kTestCertSize];
298   size_t payload_size =
299       cn_cbor_encoder_write(payload, 0, dice::test::kTestCertSize, cwt.get());
300 
301   // Signature over COSE Sign1 TBS.
302   ScopedCbor tbs_cbor(cn_cbor_array_create(&error));
303   cn_cbor_array_append(tbs_cbor.get(),
304                        cn_cbor_string_create("Signature1", &error), &error);
305   cn_cbor_array_append(tbs_cbor.get(),
306                        cn_cbor_data_create(kProtectedAttributesCbor, 3, &error),
307                        &error);
308   cn_cbor_array_append(tbs_cbor.get(), cn_cbor_data_create(NULL, 0, &error),
309                        &error);
310   cn_cbor_array_append(tbs_cbor.get(),
311                        cn_cbor_data_create(payload, payload_size, &error),
312                        &error);
313   uint8_t tbs[dice::test::kTestCertSize];
314   size_t tbs_size =
315       cn_cbor_encoder_write(tbs, 0, dice::test::kTestCertSize, tbs_cbor.get());
316   uint8_t signature[64];
317   ED25519_sign(signature, tbs, tbs_size, bssl_private_key);
318 
319   // COSE Sign1.
320   ScopedCbor sign1(cn_cbor_array_create(&error));
321   cn_cbor_array_append(sign1.get(),
322                        cn_cbor_data_create(kProtectedAttributesCbor, 3, &error),
323                        &error);
324   cn_cbor_array_append(sign1.get(), cn_cbor_map_create(&error), &error);
325   cn_cbor_array_append(
326       sign1.get(), cn_cbor_data_create(payload, payload_size, &error), &error);
327   cn_cbor_array_append(sign1.get(), cn_cbor_data_create(signature, 64, &error),
328                        &error);
329   *certificate_size = cn_cbor_encoder_write(
330       certificate, 0, dice::test::kTestCertSize, sign1.get());
331 }
332 
CreateEcdsaCborUdsCertificate(std::span<uint8_t> public_key,std::function<std::vector<uint8_t> (std::span<uint8_t>)> sign,const uint8_t id[DICE_ID_SIZE],int8_t alg,uint8_t crv,uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)333 void CreateEcdsaCborUdsCertificate(
334     std::span<uint8_t> public_key,
335     std::function<std::vector<uint8_t>(std::span<uint8_t>)> sign,
336     const uint8_t id[DICE_ID_SIZE], int8_t alg, uint8_t crv,
337     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
338   const int64_t kCwtIssuerLabel = 1;
339   const int64_t kCwtSubjectLabel = 2;
340   const int64_t kUdsPublicKeyLabel = -4670552;
341   const int64_t kUdsKeyUsageLabel = -4670553;
342   const uint8_t kKeyUsageCertSign = 32;  // Bit 5.
343   const uint8_t kProtectedAttributesCbor[4] = {0xa1 /* map(1) */,
344                                                0x01 /* alg(1) */, 0x38,
345                                                static_cast<uint8_t>(-alg - 1)};
346 
347   cn_cbor_errback error;
348   ScopedCbor public_key_cbor(cn_cbor_map_create(&error));
349   // kty = ec2
350   cn_cbor_mapput_int(public_key_cbor.get(), 1, cn_cbor_int_create(2, &error),
351                      &error);
352   // crv
353   cn_cbor_mapput_int(public_key_cbor.get(), -1, cn_cbor_int_create(crv, &error),
354                      &error);
355   // x = public_key X
356   size_t coord_size = public_key.size() / 2;
357   cn_cbor_mapput_int(public_key_cbor.get(), -2,
358                      cn_cbor_data_create(&public_key[0], coord_size, &error),
359                      &error);
360   // y = public_key Y
361   cn_cbor_mapput_int(
362       public_key_cbor.get(), -3,
363       cn_cbor_data_create(&public_key[coord_size], coord_size, &error), &error);
364   uint8_t encoded_public_key[200];
365   size_t encoded_public_key_size =
366       cn_cbor_encoder_write(encoded_public_key, 0, 200, public_key_cbor.get());
367 
368   // Simple CWT payload with issuer, subject, and use the same subject public
369   // key field as a CDI certificate to make verification easy.
370   char id_hex[41];
371   DiceHexEncode(id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
372   id_hex[40] = '\0';
373   ScopedCbor cwt(cn_cbor_map_create(&error));
374   cn_cbor_mapput_int(cwt.get(), kCwtIssuerLabel,
375                      cn_cbor_string_create(id_hex, &error), &error);
376   cn_cbor_mapput_int(cwt.get(), kCwtSubjectLabel,
377                      cn_cbor_string_create(id_hex, &error), &error);
378   cn_cbor_mapput_int(
379       cwt.get(), kUdsPublicKeyLabel,
380       cn_cbor_data_create(encoded_public_key, encoded_public_key_size, &error),
381       &error);
382   uint8_t key_usage_byte = kKeyUsageCertSign;
383   cn_cbor_mapput_int(cwt.get(), kUdsKeyUsageLabel,
384                      cn_cbor_data_create(&key_usage_byte, 1, &error), &error);
385   uint8_t payload[dice::test::kTestCertSize];
386   size_t payload_size =
387       cn_cbor_encoder_write(payload, 0, dice::test::kTestCertSize, cwt.get());
388 
389   // Signature over COSE Sign1 TBS.
390   ScopedCbor tbs_cbor(cn_cbor_array_create(&error));
391   cn_cbor_array_append(tbs_cbor.get(),
392                        cn_cbor_string_create("Signature1", &error), &error);
393   cn_cbor_array_append(tbs_cbor.get(),
394                        cn_cbor_data_create(kProtectedAttributesCbor, 4, &error),
395                        &error);
396   cn_cbor_array_append(tbs_cbor.get(), cn_cbor_data_create(NULL, 0, &error),
397                        &error);
398   cn_cbor_array_append(tbs_cbor.get(),
399                        cn_cbor_data_create(payload, payload_size, &error),
400                        &error);
401   uint8_t tbs[dice::test::kTestCertSize];
402   size_t tbs_size =
403       cn_cbor_encoder_write(tbs, 0, dice::test::kTestCertSize, tbs_cbor.get());
404   std::vector signature = sign({tbs, tbs_size});
405 
406   // COSE Sign1.
407   ScopedCbor sign1(cn_cbor_array_create(&error));
408   cn_cbor_array_append(sign1.get(),
409                        cn_cbor_data_create(kProtectedAttributesCbor, 4, &error),
410                        &error);
411   cn_cbor_array_append(sign1.get(), cn_cbor_map_create(&error), &error);
412   cn_cbor_array_append(
413       sign1.get(), cn_cbor_data_create(payload, payload_size, &error), &error);
414   cn_cbor_array_append(
415       sign1.get(),
416       cn_cbor_data_create(signature.data(), signature.size(), &error), &error);
417   *certificate_size = cn_cbor_encoder_write(
418       certificate, 0, dice::test::kTestCertSize, sign1.get());
419 }
420 
CreateP256CborUdsCertificate(const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)421 void CreateP256CborUdsCertificate(
422     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
423     const uint8_t id[DICE_ID_SIZE],
424     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
425   const int8_t kAlgEs256 = -7;
426   const uint8_t kCrvP256 = 1;
427   const size_t kPublicKeySize = 64;
428   const size_t kPrivateKeySize = 32;
429   const size_t kSignatureSize = 64;
430 
431   // Public key encoded as a COSE_Key.
432   uint8_t public_key[kPublicKeySize];
433   uint8_t private_key[kPrivateKeySize];
434   P256KeypairFromSeed(public_key, private_key, private_key_seed);
435 
436   auto sign = [&](std::span<uint8_t> tbs) {
437     std::vector<uint8_t> signature(kSignatureSize);
438     P256Sign(signature.data(), tbs.data(), tbs.size(), private_key);
439     return signature;
440   };
441 
442   CreateEcdsaCborUdsCertificate(public_key, sign, id, kAlgEs256, kCrvP256,
443                                 certificate, certificate_size);
444 }
445 
CreateP384CborUdsCertificate(const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)446 void CreateP384CborUdsCertificate(
447     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
448     const uint8_t id[DICE_ID_SIZE],
449     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
450   const int8_t kAlgEs384 = -35;
451   const uint8_t kCrvP384 = 2;
452   const size_t kPublicKeySize = 96;
453   const size_t kPrivateKeySize = 48;
454   const size_t kSignatureSize = 96;
455 
456   // Public key encoded as a COSE_Key.
457   uint8_t public_key[kPublicKeySize];
458   uint8_t private_key[kPrivateKeySize];
459   P384KeypairFromSeed(public_key, private_key, private_key_seed);
460 
461   auto sign = [&](std::span<uint8_t> tbs) {
462     std::vector<uint8_t> signature(kSignatureSize);
463     P384Sign(signature.data(), tbs.data(), tbs.size(), private_key);
464     return signature;
465   };
466 
467   CreateEcdsaCborUdsCertificate(public_key, sign, id, kAlgEs384, kCrvP384,
468                                 certificate, certificate_size);
469 }
470 
CreateCborUdsCertificate(const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],dice::test::KeyType key_type,const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)471 void CreateCborUdsCertificate(
472     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
473     dice::test::KeyType key_type, const uint8_t id[DICE_ID_SIZE],
474     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
475   switch (key_type) {
476     case dice::test::KeyType_Ed25519:
477       CreateEd25519CborUdsCertificate(private_key_seed, id, certificate,
478                                       certificate_size);
479       break;
480     case dice::test::KeyType_P256:
481       CreateP256CborUdsCertificate(private_key_seed, id, certificate,
482                                    certificate_size);
483       break;
484     case dice::test::KeyType_P256_COMPRESSED:
485       fprintf(stderr, "ERROR: Unsupported key type.\n");
486       abort();
487     case dice::test::KeyType_P384:
488       CreateP384CborUdsCertificate(private_key_seed, id, certificate,
489                                    certificate_size);
490       break;
491   }
492 }
493 
ExtractCwtFromCborCertificate(const uint8_t * certificate,size_t certificate_size)494 ScopedCbor ExtractCwtFromCborCertificate(const uint8_t* certificate,
495                                          size_t certificate_size) {
496   cn_cbor_errback error;
497   ScopedCbor sign1(cn_cbor_decode(certificate, certificate_size, &error));
498   if (!sign1 || sign1->type != CN_CBOR_ARRAY || sign1->length != 4) {
499     return nullptr;
500   }
501   cn_cbor* payload = cn_cbor_index(sign1.get(), 2);
502   if (!payload || payload->type != CN_CBOR_BYTES) {
503     return nullptr;
504   }
505   ScopedCbor cwt(cn_cbor_decode(payload->v.bytes, payload->length, &error));
506   if (!cwt || cwt->type != CN_CBOR_MAP) {
507     return nullptr;
508   }
509   return cwt;
510 }
511 
ExtractPublicKeyFromCwt(const cn_cbor * cwt)512 ScopedCbor ExtractPublicKeyFromCwt(const cn_cbor* cwt) {
513   cn_cbor_errback error;
514   cn_cbor* key_bytes = cn_cbor_mapget_int(cwt, -4670552);
515   if (!key_bytes || key_bytes->type != CN_CBOR_BYTES) {
516     return nullptr;
517   }
518   ScopedCbor key(cn_cbor_decode(key_bytes->v.bytes, key_bytes->length, &error));
519   if (key && key->type != CN_CBOR_MAP) {
520     return nullptr;
521   }
522   return key;
523 }
524 
ExtractIdsFromCwt(const cn_cbor * cwt,char authority_id_hex[40],char subject_id_hex[40])525 bool ExtractIdsFromCwt(const cn_cbor* cwt, char authority_id_hex[40],
526                        char subject_id_hex[40]) {
527   cn_cbor* authority_id_cbor = cn_cbor_mapget_int(cwt, 1);
528   cn_cbor* subject_id_cbor = cn_cbor_mapget_int(cwt, 2);
529   if (!authority_id_cbor || !subject_id_cbor) {
530     return false;
531   }
532   if (authority_id_cbor->type != CN_CBOR_TEXT ||
533       authority_id_cbor->length != 40 ||
534       subject_id_cbor->type != CN_CBOR_TEXT || subject_id_cbor->length != 40) {
535     return false;
536   }
537   memcpy(authority_id_hex, authority_id_cbor->v.str, 40);
538   memcpy(subject_id_hex, subject_id_cbor->v.str, 40);
539   return true;
540 }
541 
ExtractKeyUsageFromCwt(const cn_cbor * cwt,uint64_t * key_usage)542 bool ExtractKeyUsageFromCwt(const cn_cbor* cwt, uint64_t* key_usage) {
543   cn_cbor* key_usage_bytes = cn_cbor_mapget_int(cwt, -4670553);
544   if (!key_usage_bytes || key_usage_bytes->type != CN_CBOR_BYTES) {
545     return false;
546   }
547   // The highest key usage bit defined in RFC 5280 is 8.
548   if (key_usage_bytes->length > 2) {
549     return false;
550   }
551   if (key_usage_bytes->length == 0) {
552     *key_usage = 0;
553     return true;
554   }
555   *key_usage = key_usage_bytes->v.bytes[0];
556   if (key_usage_bytes->length == 2) {
557     uint64_t tmp = key_usage_bytes->v.bytes[1];
558     *key_usage += tmp >> 8;
559   }
560   return true;
561 }
562 
ValidateCborCertificateCdiFields(const cn_cbor * cwt,bool expect_cdi_certificate)563 bool ValidateCborCertificateCdiFields(const cn_cbor* cwt,
564                                       bool expect_cdi_certificate) {
565   cn_cbor* code_hash_bytes = cn_cbor_mapget_int(cwt, -4670545);
566   cn_cbor* code_desc_bytes = cn_cbor_mapget_int(cwt, -4670546);
567   cn_cbor* conf_hash_bytes = cn_cbor_mapget_int(cwt, -4670547);
568   cn_cbor* conf_desc_bytes = cn_cbor_mapget_int(cwt, -4670548);
569   cn_cbor* auth_hash_bytes = cn_cbor_mapget_int(cwt, -4670549);
570   cn_cbor* auth_desc_bytes = cn_cbor_mapget_int(cwt, -4670550);
571   cn_cbor* mode_bytes = cn_cbor_mapget_int(cwt, -4670551);
572   if (!expect_cdi_certificate) {
573     return (!code_hash_bytes && !code_desc_bytes && !conf_hash_bytes &&
574             !conf_desc_bytes && !auth_hash_bytes && !auth_desc_bytes &&
575             !mode_bytes);
576   }
577   if (!code_hash_bytes || !conf_desc_bytes || !auth_hash_bytes || !mode_bytes) {
578     return false;
579   }
580   if (code_hash_bytes->length != 64) {
581     return false;
582   }
583   if (conf_hash_bytes) {
584     if (conf_hash_bytes->length != 64) {
585       return false;
586     }
587   } else if (conf_desc_bytes->length != 64) {
588     return false;
589   }
590   if (auth_hash_bytes->length != 64) {
591     return false;
592   }
593   if (mode_bytes->length != 1) {
594     return false;
595   }
596   return true;
597 }
598 
VerifyCoseSign1Signature(const uint8_t * certificate,size_t certificate_size,const uint8_t * external_aad,size_t external_aad_size,const cn_cbor * authority_public_key)599 bool VerifyCoseSign1Signature(const uint8_t* certificate,
600                               size_t certificate_size,
601                               const uint8_t* external_aad,
602                               size_t external_aad_size,
603                               const cn_cbor* authority_public_key) {
604   // Use the COSE-C library to decode and validate.
605   cose_errback error;
606   int struct_type = 0;
607   HCOSE_SIGN1 sign1 = (HCOSE_SIGN1)COSE_Decode(
608       certificate, certificate_size, &struct_type, COSE_sign1_object, &error);
609   if (!sign1) {
610     return false;
611   }
612   COSE_Sign1_SetExternal(sign1, external_aad, external_aad_size, &error);
613   bool result = COSE_Sign1_validate(sign1, authority_public_key, &error);
614   COSE_Sign1_Free(sign1);
615   if (!result) {
616     return false;
617   }
618   return true;
619 }
620 
VerifySingleCborCertificate(const uint8_t * certificate,size_t certificate_size,const cn_cbor * authority_public_key,const char authority_id_hex[40],bool expect_cdi_certificate,ScopedCbor * subject_public_key,char subject_id_hex[40])621 bool VerifySingleCborCertificate(const uint8_t* certificate,
622                                  size_t certificate_size,
623                                  const cn_cbor* authority_public_key,
624                                  const char authority_id_hex[40],
625                                  bool expect_cdi_certificate,
626                                  ScopedCbor* subject_public_key,
627                                  char subject_id_hex[40]) {
628   if (!VerifyCoseSign1Signature(certificate, certificate_size, /*aad=*/NULL,
629                                 /*aad_size=*/0, authority_public_key)) {
630     return false;
631   }
632 
633   ScopedCbor cwt(ExtractCwtFromCborCertificate(certificate, certificate_size));
634   if (!cwt) {
635     return false;
636   }
637   char actual_authority_id[40];
638   char tmp_subject_id_hex[40];
639   if (!ExtractIdsFromCwt(cwt.get(), actual_authority_id, tmp_subject_id_hex)) {
640     return false;
641   }
642   if (0 != memcmp(authority_id_hex, actual_authority_id, 40)) {
643     return false;
644   }
645   memcpy(subject_id_hex, tmp_subject_id_hex, 40);
646   *subject_public_key = ExtractPublicKeyFromCwt(cwt.get());
647   if (!subject_public_key) {
648     return false;
649   }
650   uint64_t key_usage = 0;
651   const uint64_t kKeyUsageCertSign = 1 << 5;  // Bit 5.
652   if (!ExtractKeyUsageFromCwt(cwt.get(), &key_usage)) {
653     return false;
654   }
655   if (key_usage != kKeyUsageCertSign) {
656     return false;
657   }
658   if (!ValidateCborCertificateCdiFields(cwt.get(), expect_cdi_certificate)) {
659     return false;
660   }
661   return true;
662 }
663 
VerifyCborCertificateChain(const uint8_t * root_certificate,size_t root_certificate_size,const dice::test::DiceStateForTest states[],size_t num_dice_states,bool is_partial_chain)664 bool VerifyCborCertificateChain(const uint8_t* root_certificate,
665                                 size_t root_certificate_size,
666                                 const dice::test::DiceStateForTest states[],
667                                 size_t num_dice_states, bool is_partial_chain) {
668   ScopedCbor root_cwt =
669       ExtractCwtFromCborCertificate(root_certificate, root_certificate_size);
670   if (!root_cwt) {
671     return false;
672   }
673   ScopedCbor authority_public_key = ExtractPublicKeyFromCwt(root_cwt.get());
674   if (!authority_public_key) {
675     return false;
676   }
677   char expected_authority_id_hex[40];
678   char not_used[40];
679   if (!ExtractIdsFromCwt(root_cwt.get(), not_used, expected_authority_id_hex)) {
680     return false;
681   }
682   if (!is_partial_chain) {
683     // We can't verify the root certificate in a partial chain, we can only
684     // check that its public key certifies the other certificates. But with a
685     // full chain, we can expect the root to be self-signed.
686     if (!VerifySingleCborCertificate(
687             root_certificate, root_certificate_size, authority_public_key.get(),
688             expected_authority_id_hex, /*expect_cdi_certificate=*/false,
689             &authority_public_key, expected_authority_id_hex)) {
690       return false;
691     }
692   }
693   for (size_t i = 0; i < num_dice_states; ++i) {
694     if (!VerifySingleCborCertificate(
695             states[i].certificate, states[i].certificate_size,
696             authority_public_key.get(), expected_authority_id_hex,
697             /*expect_cdi_certificate=*/true, &authority_public_key,
698             expected_authority_id_hex)) {
699       return false;
700     }
701   }
702   return true;
703 }
704 
705 }  // namespace
706 
707 namespace dice {
708 namespace test {
709 
DumpState(CertificateType cert_type,KeyType key_type,const char * suffix,const DiceStateForTest & state)710 void DumpState(CertificateType cert_type, KeyType key_type, const char* suffix,
711                const DiceStateForTest& state) {
712   char filename[100];
713   pw::string::Format(filename, "_attest_cdi_%s.bin", suffix);
714   DumpToFile(filename, state.cdi_attest, DICE_CDI_SIZE);
715   pw::string::Format(filename, "_seal_cdi_%s.bin", suffix);
716   DumpToFile(filename, state.cdi_seal, DICE_CDI_SIZE);
717   pw::string::Format(filename, "_%s_%s_cert_%s.cert", GetCertTypeStr(cert_type),
718                      GetKeyTypeStr(key_type), suffix);
719   DumpToFile(filename, state.certificate, state.certificate_size);
720 }
721 
DeriveFakeInputValue(const char * seed,size_t length,uint8_t * output)722 void DeriveFakeInputValue(const char* seed, size_t length, uint8_t* output) {
723   union {
724     uint8_t buffer[64];
725     uint64_t counter;
726   } context;
727   SHA512(reinterpret_cast<const uint8_t*>(seed), strlen(seed), context.buffer);
728   size_t output_pos = 0;
729   while (output_pos < length) {
730     uint8_t tmp[64];
731     SHA512(context.buffer, 64, tmp);
732     context.counter++;
733     size_t remaining = length - output_pos;
734     size_t to_copy = remaining < 64 ? remaining : 64;
735     memcpy(&output[output_pos], tmp, to_copy);
736     output_pos += to_copy;
737   }
738 }
739 
CreateFakeUdsCertificate(void * context,const uint8_t uds[32],CertificateType cert_type,KeyType key_type,uint8_t certificate[kTestCertSize],size_t * certificate_size)740 void CreateFakeUdsCertificate(void* context, const uint8_t uds[32],
741                               CertificateType cert_type, KeyType key_type,
742                               uint8_t certificate[kTestCertSize],
743                               size_t* certificate_size) {
744   uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE];
745   DiceDeriveCdiPrivateKeySeed(context, uds, raw_key);
746 
747   uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE];
748   size_t raw_public_key_size = 0;
749   bssl::UniquePtr<EVP_PKEY> key(
750       KeyFromRawKey(raw_key, key_type, raw_public_key, &raw_public_key_size));
751 
752   uint8_t id[DICE_ID_SIZE];
753   DiceDeriveCdiCertificateId(context, raw_public_key, raw_public_key_size, id);
754 
755   if (cert_type == CertificateType_X509) {
756     CreateX509UdsCertificate(key.get(), id, certificate, certificate_size);
757   } else {
758     CreateCborUdsCertificate(raw_key, key_type, id, certificate,
759                              certificate_size);
760   }
761 
762   char filename[100];
763   pw::string::Format(filename, "_%s_%s_uds_cert.cert",
764                      GetCertTypeStr(cert_type), GetKeyTypeStr(key_type));
765   DumpToFile(filename, certificate, *certificate_size);
766 }
767 
VerifyCoseSign1(const uint8_t * certificate,size_t certificate_size,const uint8_t * external_aad,size_t external_aad_size,const uint8_t * encoded_public_key,size_t encoded_public_key_size,const uint8_t * expected_cwt,size_t expected_cwt_size)768 [[maybe_unused]] bool VerifyCoseSign1(
769     const uint8_t* certificate, size_t certificate_size,
770     const uint8_t* external_aad, size_t external_aad_size,
771     const uint8_t* encoded_public_key, size_t encoded_public_key_size,
772     const uint8_t* expected_cwt, size_t expected_cwt_size) {
773   cn_cbor_errback error;
774   ScopedCbor public_key(
775       cn_cbor_decode(encoded_public_key, encoded_public_key_size, &error));
776   if (!public_key) {
777     return false;
778   }
779 
780   if (!VerifyCoseSign1Signature(certificate, certificate_size, external_aad,
781                                 external_aad_size, public_key.get())) {
782     return false;
783   }
784 
785   ScopedCbor sign1(cn_cbor_decode(certificate, certificate_size, &error));
786   if (!sign1 || sign1->type != CN_CBOR_ARRAY || sign1->length != 4) {
787     return false;
788   }
789   cn_cbor* payload = cn_cbor_index(sign1.get(), 2);
790   if (!payload || payload->type != CN_CBOR_BYTES) {
791     return false;
792   }
793 
794   if (payload->length != expected_cwt_size) {
795     return false;
796   }
797 
798   if (memcmp(payload->v.bytes, expected_cwt, expected_cwt_size) != 0) {
799     return false;
800   }
801   return true;
802 }
803 
VerifyCertificateChain(CertificateType cert_type,const uint8_t * root_certificate,size_t root_certificate_size,const DiceStateForTest states[],size_t num_dice_states,bool is_partial_chain)804 bool VerifyCertificateChain(CertificateType cert_type,
805                             const uint8_t* root_certificate,
806                             size_t root_certificate_size,
807                             const DiceStateForTest states[],
808                             size_t num_dice_states, bool is_partial_chain) {
809   switch (cert_type) {
810     case CertificateType_Cbor:
811       return VerifyCborCertificateChain(root_certificate, root_certificate_size,
812                                         states, num_dice_states,
813                                         is_partial_chain);
814     case CertificateType_X509:
815       return VerifyX509CertificateChain(root_certificate, root_certificate_size,
816                                         states, num_dice_states,
817                                         is_partial_chain);
818   }
819   return false;
820 }
821 }  // namespace test
822 }  // namespace dice
823