• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <memory>
22 
23 #include "cose/cose.h"
24 #include "dice/dice.h"
25 #include "dice/utils.h"
26 #include "openssl/asn1.h"
27 #include "openssl/bn.h"
28 #include "openssl/curve25519.h"
29 #include "openssl/evp.h"
30 #include "openssl/hmac.h"
31 #include "openssl/is_boringssl.h"
32 #include "openssl/mem.h"
33 #include "openssl/sha.h"
34 #include "openssl/x509.h"
35 #include "openssl/x509_vfy.h"
36 #include "openssl/x509v3.h"
37 #include "pw_string/format.h"
38 
39 namespace {
40 
41 // A scoped pointer for cn_cbor.
42 struct CborDeleter {
operator ()__anon25808a3b0111::CborDeleter43   void operator()(cn_cbor* c) { cn_cbor_free(c); }
44 };
45 using ScopedCbor = std::unique_ptr<cn_cbor, CborDeleter>;
46 
GetCertTypeStr(dice::test::CertificateType cert_type)47 const char* GetCertTypeStr(dice::test::CertificateType cert_type) {
48   switch (cert_type) {
49     case dice::test::CertificateType_Cbor:
50       return "CBOR";
51     case dice::test::CertificateType_X509:
52       return "X509";
53   }
54   return "";
55 }
56 
GetKeyTypeStr(dice::test::KeyType key_type)57 const char* GetKeyTypeStr(dice::test::KeyType key_type) {
58   switch (key_type) {
59     case dice::test::KeyType_Ed25519:
60       return "Ed25519";
61     case dice::test::KeyType_P256:
62       return "P256";
63   }
64   return "";
65 }
66 
ParseX509Certificate(const uint8_t * certificate,size_t certificate_size)67 bssl::UniquePtr<X509> ParseX509Certificate(const uint8_t* certificate,
68                                            size_t certificate_size) {
69   const uint8_t* asn1 = certificate;
70   return bssl::UniquePtr<X509>(
71       d2i_X509(/*X509=*/nullptr, &asn1, certificate_size));
72 }
73 
DumpToFile(const char * filename,const uint8_t * data,size_t size)74 void DumpToFile(const char* filename, const uint8_t* data, size_t size) {
75   FILE* fp = fopen(filename, "w");
76   if (fp) {
77     fwrite(data, size, 1, fp);
78     fclose(fp);
79   } else {
80     printf("WARNING: Failed to dump to file.\n");
81   }
82 }
83 
84 // A simple hmac-drbg to help with deterministic ecdsa.
85 class HmacSha512Drbg {
86  public:
HmacSha512Drbg(const uint8_t seed[32])87   HmacSha512Drbg(const uint8_t seed[32]) {
88     Init();
89     Update(seed, 32);
90   }
~HmacSha512Drbg()91   ~HmacSha512Drbg() { HMAC_CTX_cleanup(&ctx_); }
92 
93   // Populates |num_bytes| random bytes into |buffer|.
GetBytes(size_t num_bytes,uint8_t * buffer)94   void GetBytes(size_t num_bytes, uint8_t* buffer) {
95     size_t bytes_written = 0;
96     while (bytes_written < num_bytes) {
97       size_t bytes_to_copy = num_bytes - bytes_written;
98       if (bytes_to_copy > 64) {
99         bytes_to_copy = 64;
100       }
101       Hmac(v_, v_);
102       memcpy(&buffer[bytes_written], v_, bytes_to_copy);
103       bytes_written += bytes_to_copy;
104     }
105     Update0();
106   }
107 
108  private:
Init()109   void Init() {
110     memset(k_, 0, 64);
111     memset(v_, 1, 64);
112     HMAC_CTX_init(&ctx_);
113   }
114 
Hmac(uint8_t in[64],uint8_t out[64])115   void Hmac(uint8_t in[64], uint8_t out[64]) {
116     HmacStart();
117     HmacUpdate(in, 64);
118     HmacFinish(out);
119   }
120 
HmacStart()121   void HmacStart() {
122     HMAC_Init_ex(&ctx_, k_, 64, EVP_sha512(), nullptr /* impl */);
123   }
124 
HmacUpdate(const uint8_t * data,size_t data_size)125   void HmacUpdate(const uint8_t* data, size_t data_size) {
126     HMAC_Update(&ctx_, data, data_size);
127   }
128 
HmacUpdateByte(uint8_t byte)129   void HmacUpdateByte(uint8_t byte) { HmacUpdate(&byte, 1); }
130 
HmacFinish(uint8_t out[64])131   void HmacFinish(uint8_t out[64]) {
132     unsigned int out_len = 64;
133     HMAC_Final(&ctx_, out, &out_len);
134   }
135 
Update(const uint8_t * data,size_t data_size)136   void Update(const uint8_t* data, size_t data_size) {
137     HmacStart();
138     HmacUpdate(v_, 64);
139     HmacUpdateByte(0x00);
140     if (data_size > 0) {
141       HmacUpdate(data, data_size);
142     }
143     HmacFinish(k_);
144     Hmac(v_, v_);
145     if (data_size > 0) {
146       HmacStart();
147       HmacUpdate(v_, 64);
148       HmacUpdateByte(0x01);
149       HmacUpdate(data, data_size);
150       HmacFinish(k_);
151       Hmac(v_, v_);
152     }
153   }
154 
Update0()155   void Update0() { Update(nullptr, 0); }
156 
157   uint8_t k_[64];
158   uint8_t v_[64];
159   HMAC_CTX ctx_;
160 };
161 
KeyFromRawKey(const uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE],dice::test::KeyType key_type,uint8_t raw_public_key[33],size_t * raw_public_key_size)162 bssl::UniquePtr<EVP_PKEY> KeyFromRawKey(
163     const uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE],
164     dice::test::KeyType key_type, uint8_t raw_public_key[33],
165     size_t* raw_public_key_size) {
166   if (key_type == dice::test::KeyType_Ed25519) {
167     bssl::UniquePtr<EVP_PKEY> key(
168         EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, /*unused=*/nullptr,
169                                      raw_key, DICE_PRIVATE_KEY_SEED_SIZE));
170     *raw_public_key_size = 32;
171     EVP_PKEY_get_raw_public_key(key.get(), raw_public_key, raw_public_key_size);
172     return key;
173   } else if (key_type == dice::test::KeyType_P256) {
174     bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
175     const EC_GROUP* group = EC_KEY_get0_group(key.get());
176     bssl::UniquePtr<EC_POINT> pub(EC_POINT_new(group));
177     // Match the algorithm described in RFC6979 and seed with the raw key.
178     HmacSha512Drbg drbg(raw_key);
179     while (true) {
180       uint8_t tmp[32];
181       drbg.GetBytes(32, tmp);
182       bssl::UniquePtr<BIGNUM> candidate(BN_bin2bn(tmp, 32, /*ret=*/nullptr));
183       if (BN_cmp(candidate.get(), EC_GROUP_get0_order(group)) < 0 &&
184           !BN_is_zero(candidate.get())) {
185         // Candidate is suitable.
186         EC_POINT_mul(group, pub.get(), candidate.get(), /*q=*/nullptr,
187                      /*m=*/nullptr,
188                      /*ctx=*/nullptr);
189         EC_KEY_set_public_key(key.get(), pub.get());
190         EC_KEY_set_private_key(key.get(), candidate.get());
191         break;
192       }
193     }
194     bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
195     EVP_PKEY_set1_EC_KEY(pkey.get(), key.get());
196     *raw_public_key_size =
197         EC_POINT_point2oct(group, pub.get(), POINT_CONVERSION_COMPRESSED,
198                            raw_public_key, 33, /*ctx=*/nullptr);
199     return pkey;
200   }
201   printf("ERROR: Unsupported key type.\n");
202   return nullptr;
203 }
204 
CreateX509UdsCertificate(EVP_PKEY * key,const uint8_t id[DICE_ID_SIZE],uint8_t certificate[dice::test::kTestCertSize],size_t * certificate_size)205 void CreateX509UdsCertificate(EVP_PKEY* key, const uint8_t id[DICE_ID_SIZE],
206                               uint8_t certificate[dice::test::kTestCertSize],
207                               size_t* certificate_size) {
208   bssl::UniquePtr<X509> x509(X509_new());
209   X509_set_version(x509.get(), 2);
210 
211   bssl::UniquePtr<ASN1_INTEGER> serial(ASN1_INTEGER_new());
212   ASN1_INTEGER_set_uint64(serial.get(), 1);
213   X509_set_serialNumber(x509.get(), serial.get());
214 
215   uint8_t id_hex[40];
216   DiceHexEncode(id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
217   bssl::UniquePtr<X509_NAME> issuer_name(X509_NAME_new());
218   X509_NAME_add_entry_by_NID(issuer_name.get(), NID_serialNumber, MBSTRING_UTF8,
219                              id_hex, sizeof(id_hex), 0, 0);
220   X509_set_issuer_name(x509.get(), issuer_name.get());
221   X509_set_subject_name(x509.get(), issuer_name.get());
222 
223   bssl::UniquePtr<ASN1_TIME> not_before(ASN1_TIME_new());
224   ASN1_TIME_set_string(not_before.get(), "180322235959Z");
225   X509_set_notBefore(x509.get(), not_before.get());
226   bssl::UniquePtr<ASN1_TIME> not_after(ASN1_TIME_new());
227   ASN1_TIME_set_string(not_after.get(), "99991231235959Z");
228   X509_set_notAfter(x509.get(), not_after.get());
229 
230   bssl::UniquePtr<ASN1_OCTET_STRING> subject_key_id(ASN1_OCTET_STRING_new());
231   ASN1_OCTET_STRING_set(subject_key_id.get(), id, DICE_ID_SIZE);
232   bssl::UniquePtr<X509_EXTENSION> subject_key_id_ext(X509V3_EXT_i2d(
233       NID_subject_key_identifier, /*crit=*/0, subject_key_id.get()));
234   X509_add_ext(x509.get(), subject_key_id_ext.get(), /*loc=*/-1);
235 
236   bssl::UniquePtr<AUTHORITY_KEYID> authority_key_id(AUTHORITY_KEYID_new());
237   authority_key_id->keyid = ASN1_OCTET_STRING_dup(subject_key_id.get());
238   bssl::UniquePtr<X509_EXTENSION> authority_key_id_ext(X509V3_EXT_i2d(
239       NID_authority_key_identifier, /*crit=*/0, authority_key_id.get()));
240   X509_add_ext(x509.get(), authority_key_id_ext.get(), /*loc=*/-1);
241 
242   bssl::UniquePtr<ASN1_BIT_STRING> key_usage(ASN1_BIT_STRING_new());
243   ASN1_BIT_STRING_set_bit(key_usage.get(), 5 /*keyCertSign*/, 1);
244   bssl::UniquePtr<X509_EXTENSION> key_usage_ext(
245       X509V3_EXT_i2d(NID_key_usage, /*crit=*/1, key_usage.get()));
246   X509_add_ext(x509.get(), key_usage_ext.get(), /*loc=*/-1);
247 
248   bssl::UniquePtr<BASIC_CONSTRAINTS> basic_constraints(BASIC_CONSTRAINTS_new());
249   basic_constraints->ca = 1;
250   bssl::UniquePtr<X509_EXTENSION> basic_constraints_ext(X509V3_EXT_i2d(
251       NID_basic_constraints, /*crit=*/1, basic_constraints.get()));
252   X509_add_ext(x509.get(), basic_constraints_ext.get(), /*loc=*/-1);
253 
254   X509_set_pubkey(x509.get(), key);
255   // ED25519 always uses SHA-512 so md must be NULL.
256   const EVP_MD* md =
257       (EVP_PKEY_id(key) == EVP_PKEY_ED25519) ? nullptr : EVP_sha512();
258   X509_sign(x509.get(), key, md);
259   if (i2d_X509(x509.get(), /*out=*/nullptr) <=
260       static_cast<int>(dice::test::kTestCertSize)) {
261     uint8_t* p = certificate;
262     *certificate_size = i2d_X509(x509.get(), &p);
263   } else {
264     *certificate_size = 0;
265   }
266 }
267 
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)268 bool VerifyX509CertificateChain(const uint8_t* root_certificate,
269                                 size_t root_certificate_size,
270                                 const dice::test::DiceStateForTest states[],
271                                 size_t num_dice_states, bool is_partial_chain) {
272   bssl::UniquePtr<STACK_OF(X509)> trusted_certs(sk_X509_new_null());
273   bssl::PushToStack(trusted_certs.get(),
274                     bssl::UpRef(ParseX509Certificate(root_certificate,
275                                                      root_certificate_size)));
276   bssl::UniquePtr<STACK_OF(X509)> untrusted_certs(sk_X509_new_null());
277   for (size_t i = 0; i < num_dice_states - 1; ++i) {
278     bssl::PushToStack(untrusted_certs.get(),
279                       bssl::UpRef(ParseX509Certificate(
280                           states[i].certificate, states[i].certificate_size)));
281   }
282   bssl::UniquePtr<X509> leaf_cert(
283       ParseX509Certificate(states[num_dice_states - 1].certificate,
284                            states[num_dice_states - 1].certificate_size));
285   bssl::UniquePtr<X509_STORE> x509_store(X509_STORE_new());
286   bssl::UniquePtr<X509_STORE_CTX> x509_store_ctx(X509_STORE_CTX_new());
287   X509_STORE_CTX_init(x509_store_ctx.get(), x509_store.get(), leaf_cert.get(),
288                       untrusted_certs.get());
289   X509_STORE_CTX_trusted_stack(x509_store_ctx.get(), trusted_certs.get());
290   X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new();
291   X509_VERIFY_PARAM_set_time(param, 1577923199 /*1/1/2020*/);
292   X509_VERIFY_PARAM_set_depth(param, 10);
293   if (is_partial_chain) {
294     X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_PARTIAL_CHAIN);
295   }
296   X509_STORE_CTX_set0_param(x509_store_ctx.get(), param);
297   return (1 == X509_verify_cert(x509_store_ctx.get()));
298 }
299 
CreateCborUdsCertificate(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)300 void CreateCborUdsCertificate(
301     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
302     const uint8_t id[DICE_ID_SIZE],
303     uint8_t certificate[dice::test::kTestCertSize], size_t* certificate_size) {
304   const uint8_t kProtectedAttributesCbor[3] = {
305       0xa1 /* map(1) */, 0x01 /* alg(1) */, 0x27 /* EdDSA(-8) */};
306   const int64_t kCwtIssuerLabel = 1;
307   const int64_t kCwtSubjectLabel = 2;
308   const int64_t kUdsPublicKeyLabel = -4670552;
309   const int64_t kUdsKeyUsageLabel = -4670553;
310   const uint8_t kKeyUsageCertSign = 32;  // Bit 5.
311 
312   // Public key encoded as a COSE_Key.
313   uint8_t public_key[32];
314   uint8_t bssl_private_key[64];
315   ED25519_keypair_from_seed(public_key, bssl_private_key, private_key_seed);
316   cn_cbor_errback error;
317   ScopedCbor public_key_cbor(cn_cbor_map_create(&error));
318   // kty = okp
319   cn_cbor_mapput_int(public_key_cbor.get(), 1, cn_cbor_int_create(1, &error),
320                      &error);
321   // crv = ed25519
322   cn_cbor_mapput_int(public_key_cbor.get(), -1, cn_cbor_int_create(6, &error),
323                      &error);
324   // x = public_key
325   cn_cbor_mapput_int(public_key_cbor.get(), -2,
326                      cn_cbor_data_create(public_key, 32, &error), &error);
327   uint8_t encoded_public_key[100];
328   size_t encoded_public_key_size =
329       cn_cbor_encoder_write(encoded_public_key, 0, 100, public_key_cbor.get());
330 
331   // Simple CWT payload with issuer, subject, and use the same subject public
332   // key field as a CDI certificate to make verification easy.
333   char id_hex[41];
334   DiceHexEncode(id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
335   id_hex[40] = '\0';
336   ScopedCbor cwt(cn_cbor_map_create(&error));
337   cn_cbor_mapput_int(cwt.get(), kCwtIssuerLabel,
338                      cn_cbor_string_create(id_hex, &error), &error);
339   cn_cbor_mapput_int(cwt.get(), kCwtSubjectLabel,
340                      cn_cbor_string_create(id_hex, &error), &error);
341   cn_cbor_mapput_int(
342       cwt.get(), kUdsPublicKeyLabel,
343       cn_cbor_data_create(encoded_public_key, encoded_public_key_size, &error),
344       &error);
345   uint8_t key_usage_byte = kKeyUsageCertSign;
346   cn_cbor_mapput_int(cwt.get(), kUdsKeyUsageLabel,
347                      cn_cbor_data_create(&key_usage_byte, 1, &error), &error);
348   uint8_t payload[dice::test::kTestCertSize];
349   size_t payload_size =
350       cn_cbor_encoder_write(payload, 0, dice::test::kTestCertSize, cwt.get());
351 
352   // Signature over COSE Sign1 TBS.
353   ScopedCbor tbs_cbor(cn_cbor_array_create(&error));
354   cn_cbor_array_append(tbs_cbor.get(),
355                        cn_cbor_string_create("Signature1", &error), &error);
356   cn_cbor_array_append(tbs_cbor.get(),
357                        cn_cbor_data_create(kProtectedAttributesCbor, 3, &error),
358                        &error);
359   cn_cbor_array_append(tbs_cbor.get(), cn_cbor_data_create(NULL, 0, &error),
360                        &error);
361   cn_cbor_array_append(tbs_cbor.get(),
362                        cn_cbor_data_create(payload, payload_size, &error),
363                        &error);
364   uint8_t tbs[dice::test::kTestCertSize];
365   size_t tbs_size =
366       cn_cbor_encoder_write(tbs, 0, dice::test::kTestCertSize, tbs_cbor.get());
367   uint8_t signature[64];
368   ED25519_sign(signature, tbs, tbs_size, bssl_private_key);
369 
370   // COSE Sign1.
371   ScopedCbor sign1(cn_cbor_array_create(&error));
372   cn_cbor_array_append(sign1.get(),
373                        cn_cbor_data_create(kProtectedAttributesCbor, 3, &error),
374                        &error);
375   cn_cbor_array_append(sign1.get(), cn_cbor_map_create(&error), &error);
376   cn_cbor_array_append(
377       sign1.get(), cn_cbor_data_create(payload, payload_size, &error), &error);
378   cn_cbor_array_append(sign1.get(), cn_cbor_data_create(signature, 64, &error),
379                        &error);
380   *certificate_size = cn_cbor_encoder_write(
381       certificate, 0, dice::test::kTestCertSize, sign1.get());
382 }
383 
ExtractCwtFromCborCertificate(const uint8_t * certificate,size_t certificate_size)384 ScopedCbor ExtractCwtFromCborCertificate(const uint8_t* certificate,
385                                          size_t certificate_size) {
386   cn_cbor_errback error;
387   ScopedCbor sign1(cn_cbor_decode(certificate, certificate_size, &error));
388   if (!sign1 || sign1->type != CN_CBOR_ARRAY || sign1->length != 4) {
389     return nullptr;
390   }
391   cn_cbor* payload = cn_cbor_index(sign1.get(), 2);
392   if (!payload || payload->type != CN_CBOR_BYTES) {
393     return nullptr;
394   }
395   ScopedCbor cwt(cn_cbor_decode(payload->v.bytes, payload->length, &error));
396   if (cwt && cwt->type != CN_CBOR_MAP) {
397     return nullptr;
398   }
399   return cwt;
400 }
401 
ExtractPublicKeyFromCwt(const cn_cbor * cwt)402 ScopedCbor ExtractPublicKeyFromCwt(const cn_cbor* cwt) {
403   cn_cbor_errback error;
404   cn_cbor* key_bytes = cn_cbor_mapget_int(cwt, -4670552);
405   if (!key_bytes || key_bytes->type != CN_CBOR_BYTES) {
406     return nullptr;
407   }
408   ScopedCbor key(cn_cbor_decode(key_bytes->v.bytes, key_bytes->length, &error));
409   if (key && key->type != CN_CBOR_MAP) {
410     return nullptr;
411   }
412   return key;
413 }
414 
ExtractIdsFromCwt(const cn_cbor * cwt,char authority_id_hex[40],char subject_id_hex[40])415 bool ExtractIdsFromCwt(const cn_cbor* cwt, char authority_id_hex[40],
416                        char subject_id_hex[40]) {
417   cn_cbor* authority_id_cbor = cn_cbor_mapget_int(cwt, 1);
418   cn_cbor* subject_id_cbor = cn_cbor_mapget_int(cwt, 2);
419   if (!authority_id_cbor || !subject_id_cbor) {
420     return false;
421   }
422   if (authority_id_cbor->type != CN_CBOR_TEXT ||
423       authority_id_cbor->length != 40 ||
424       subject_id_cbor->type != CN_CBOR_TEXT || subject_id_cbor->length != 40) {
425     return false;
426   }
427   memcpy(authority_id_hex, authority_id_cbor->v.str, 40);
428   memcpy(subject_id_hex, subject_id_cbor->v.str, 40);
429   return true;
430 }
431 
ExtractKeyUsageFromCwt(const cn_cbor * cwt,uint64_t * key_usage)432 bool ExtractKeyUsageFromCwt(const cn_cbor* cwt, uint64_t* key_usage) {
433   cn_cbor* key_usage_bytes = cn_cbor_mapget_int(cwt, -4670553);
434   if (!key_usage_bytes || key_usage_bytes->type != CN_CBOR_BYTES) {
435     return false;
436   }
437   // The highest key usage bit defined in RFC 5280 is 8.
438   if (key_usage_bytes->length > 2) {
439     return false;
440   }
441   if (key_usage_bytes->length == 0) {
442     *key_usage = 0;
443     return true;
444   }
445   *key_usage = key_usage_bytes->v.bytes[0];
446   if (key_usage_bytes->length == 2) {
447     uint64_t tmp = key_usage_bytes->v.bytes[1];
448     *key_usage += tmp >> 8;
449   }
450   return true;
451 }
452 
ValidateCborCertificateCdiFields(const cn_cbor * cwt,bool expect_cdi_certificate)453 bool ValidateCborCertificateCdiFields(const cn_cbor* cwt,
454                                       bool expect_cdi_certificate) {
455   cn_cbor* code_hash_bytes = cn_cbor_mapget_int(cwt, -4670545);
456   cn_cbor* code_desc_bytes = cn_cbor_mapget_int(cwt, -4670546);
457   cn_cbor* conf_hash_bytes = cn_cbor_mapget_int(cwt, -4670547);
458   cn_cbor* conf_desc_bytes = cn_cbor_mapget_int(cwt, -4670548);
459   cn_cbor* auth_hash_bytes = cn_cbor_mapget_int(cwt, -4670549);
460   cn_cbor* auth_desc_bytes = cn_cbor_mapget_int(cwt, -4670550);
461   cn_cbor* mode_bytes = cn_cbor_mapget_int(cwt, -4670551);
462   if (!expect_cdi_certificate) {
463     return (!code_hash_bytes && !code_desc_bytes && !conf_hash_bytes &&
464             !conf_desc_bytes && !auth_hash_bytes && !auth_desc_bytes &&
465             !mode_bytes);
466   }
467   if (!code_hash_bytes || !conf_desc_bytes || !auth_hash_bytes || !mode_bytes) {
468     return false;
469   }
470   if (code_hash_bytes->length != 64) {
471     return false;
472   }
473   if (conf_hash_bytes) {
474     if (conf_hash_bytes->length != 64) {
475       return false;
476     }
477   } else if (conf_desc_bytes->length != 64) {
478     return false;
479   }
480   if (auth_hash_bytes->length != 64) {
481     return false;
482   }
483   if (mode_bytes->length != 1) {
484     return false;
485   }
486   return true;
487 }
488 
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])489 bool VerifySingleCborCertificate(const uint8_t* certificate,
490                                  size_t certificate_size,
491                                  const cn_cbor* authority_public_key,
492                                  const char authority_id_hex[40],
493                                  bool expect_cdi_certificate,
494                                  ScopedCbor* subject_public_key,
495                                  char subject_id_hex[40]) {
496   // Use the COSE-C library to decode and validate.
497   cose_errback error;
498   int struct_type = 0;
499   HCOSE_SIGN1 sign1 = (HCOSE_SIGN1)COSE_Decode(
500       certificate, certificate_size, &struct_type, COSE_sign1_object, &error);
501   if (!sign1) {
502     return false;
503   }
504   (void)authority_public_key;
505   bool result = COSE_Sign1_validate(sign1, authority_public_key, &error);
506   COSE_Sign1_Free(sign1);
507   if (!result) {
508     return false;
509   }
510 
511   ScopedCbor cwt(ExtractCwtFromCborCertificate(certificate, certificate_size));
512   if (!cwt) {
513     return false;
514   }
515   char actual_authority_id[40];
516   char tmp_subject_id_hex[40];
517   if (!ExtractIdsFromCwt(cwt.get(), actual_authority_id, tmp_subject_id_hex)) {
518     return false;
519   }
520   if (0 != memcmp(authority_id_hex, actual_authority_id, 40)) {
521     return false;
522   }
523   memcpy(subject_id_hex, tmp_subject_id_hex, 40);
524   *subject_public_key = ExtractPublicKeyFromCwt(cwt.get());
525   if (!subject_public_key) {
526     return false;
527   }
528   uint64_t key_usage = 0;
529   const uint64_t kKeyUsageCertSign = 1 << 5;  // Bit 5.
530   if (!ExtractKeyUsageFromCwt(cwt.get(), &key_usage)) {
531     return false;
532   }
533   if (key_usage != kKeyUsageCertSign) {
534     return false;
535   }
536   if (!ValidateCborCertificateCdiFields(cwt.get(), expect_cdi_certificate)) {
537     return false;
538   }
539   return true;
540 }
541 
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)542 bool VerifyCborCertificateChain(const uint8_t* root_certificate,
543                                 size_t root_certificate_size,
544                                 const dice::test::DiceStateForTest states[],
545                                 size_t num_dice_states, bool is_partial_chain) {
546   ScopedCbor root_cwt =
547       ExtractCwtFromCborCertificate(root_certificate, root_certificate_size);
548   if (!root_cwt) {
549     return false;
550   }
551   ScopedCbor authority_public_key = ExtractPublicKeyFromCwt(root_cwt.get());
552   if (!authority_public_key) {
553     return false;
554   }
555   char expected_authority_id_hex[40];
556   char not_used[40];
557   if (!ExtractIdsFromCwt(root_cwt.get(), not_used, expected_authority_id_hex)) {
558     return false;
559   }
560   if (!is_partial_chain) {
561     // We can't verify the root certificate in a partial chain, we can only
562     // check that its public key certifies the other certificates. But with a
563     // full chain, we can expect the root to be self-signed.
564     if (!VerifySingleCborCertificate(
565             root_certificate, root_certificate_size, authority_public_key.get(),
566             expected_authority_id_hex, /*expect_cdi_certificate=*/false,
567             &authority_public_key, expected_authority_id_hex)) {
568       return false;
569     }
570   }
571   for (size_t i = 0; i < num_dice_states; ++i) {
572     if (!VerifySingleCborCertificate(
573             states[i].certificate, states[i].certificate_size,
574             authority_public_key.get(), expected_authority_id_hex,
575             /*expect_cdi_certificate=*/true, &authority_public_key,
576             expected_authority_id_hex)) {
577       return false;
578     }
579   }
580   return true;
581 }
582 
583 }  // namespace
584 
585 namespace dice {
586 namespace test {
587 
DumpState(CertificateType cert_type,KeyType key_type,const char * suffix,const DiceStateForTest & state)588 void DumpState(CertificateType cert_type, KeyType key_type, const char* suffix,
589                const DiceStateForTest& state) {
590   char filename[100];
591   pw::string::Format(filename, "_attest_cdi_%s.bin", suffix);
592   DumpToFile(filename, state.cdi_attest, DICE_CDI_SIZE);
593   pw::string::Format(filename, "_seal_cdi_%s.bin", suffix);
594   DumpToFile(filename, state.cdi_seal, DICE_CDI_SIZE);
595   pw::string::Format(filename, "_%s_%s_cert_%s.cert", GetCertTypeStr(cert_type),
596                      GetKeyTypeStr(key_type), suffix);
597   DumpToFile(filename, state.certificate, state.certificate_size);
598 }
599 
DeriveFakeInputValue(const char * seed,size_t length,uint8_t * output)600 void DeriveFakeInputValue(const char* seed, size_t length, uint8_t* output) {
601   union {
602     uint8_t buffer[64];
603     uint64_t counter;
604   } context;
605   SHA512(reinterpret_cast<const uint8_t*>(seed), strlen(seed), context.buffer);
606   size_t output_pos = 0;
607   while (output_pos < length) {
608     uint8_t tmp[64];
609     SHA512(context.buffer, 64, tmp);
610     context.counter++;
611     size_t remaining = length - output_pos;
612     size_t to_copy = remaining < 64 ? remaining : 64;
613     memcpy(&output[output_pos], tmp, to_copy);
614     output_pos += to_copy;
615   }
616 }
617 
CreateFakeUdsCertificate(void * context,const uint8_t uds[32],CertificateType cert_type,KeyType key_type,uint8_t certificate[kTestCertSize],size_t * certificate_size)618 void CreateFakeUdsCertificate(void* context, const uint8_t uds[32],
619                               CertificateType cert_type, KeyType key_type,
620                               uint8_t certificate[kTestCertSize],
621                               size_t* certificate_size) {
622   uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE];
623   DiceDeriveCdiPrivateKeySeed(context, uds, raw_key);
624 
625   uint8_t raw_public_key[33];
626   size_t raw_public_key_size = 0;
627   bssl::UniquePtr<EVP_PKEY> key(
628       KeyFromRawKey(raw_key, key_type, raw_public_key, &raw_public_key_size));
629 
630   uint8_t id[DICE_ID_SIZE];
631   DiceDeriveCdiCertificateId(context, raw_public_key, raw_public_key_size, id);
632 
633   if (cert_type == CertificateType_X509) {
634     CreateX509UdsCertificate(key.get(), id, certificate, certificate_size);
635   } else {
636     CreateCborUdsCertificate(raw_key, id, certificate, certificate_size);
637   }
638 
639   char filename[100];
640   pw::string::Format(filename, "_%s_%s_uds_cert.cert",
641                      GetCertTypeStr(cert_type), GetKeyTypeStr(key_type));
642   DumpToFile(filename, certificate, *certificate_size);
643 }
644 
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)645 bool VerifyCertificateChain(CertificateType cert_type,
646                             const uint8_t* root_certificate,
647                             size_t root_certificate_size,
648                             const DiceStateForTest states[],
649                             size_t num_dice_states, bool is_partial_chain) {
650   switch (cert_type) {
651     case CertificateType_Cbor:
652       return VerifyCborCertificateChain(root_certificate, root_certificate_size,
653                                         states, num_dice_states,
654                                         is_partial_chain);
655     case CertificateType_X509:
656       return VerifyX509CertificateChain(root_certificate, root_certificate_size,
657                                         states, num_dice_states,
658                                         is_partial_chain);
659   }
660   return false;
661 }
662 }  // namespace test
663 }  // namespace dice
664