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