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 ()__anona73747a30111::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
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)631 bool VerifyCoseSign1Signature(const uint8_t* certificate,
632 size_t certificate_size,
633 const uint8_t* external_aad,
634 size_t external_aad_size,
635 const cn_cbor* authority_public_key) {
636 // Use the COSE-C library to decode and validate.
637 cose_errback error;
638 int struct_type = 0;
639 HCOSE_SIGN1 sign1 = (HCOSE_SIGN1)COSE_Decode(
640 certificate, certificate_size, &struct_type, COSE_sign1_object, &error);
641 if (!sign1) {
642 return false;
643 }
644 COSE_Sign1_SetExternal(sign1, external_aad, external_aad_size, &error);
645 bool result = COSE_Sign1_validate(sign1, authority_public_key, &error);
646 COSE_Sign1_Free(sign1);
647 if (!result) {
648 return false;
649 }
650 return true;
651 }
652
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])653 bool VerifySingleCborCertificate(const uint8_t* certificate,
654 size_t certificate_size,
655 const cn_cbor* authority_public_key,
656 const char authority_id_hex[40],
657 bool expect_cdi_certificate,
658 ScopedCbor* subject_public_key,
659 char subject_id_hex[40]) {
660 if (!VerifyCoseSign1Signature(certificate, certificate_size, /*aad=*/NULL,
661 /*aad_size=*/0, authority_public_key)) {
662 return false;
663 }
664
665 ScopedCbor cwt(ExtractCwtFromCborCertificate(certificate, certificate_size));
666 if (!cwt) {
667 return false;
668 }
669 char actual_authority_id[40];
670 char tmp_subject_id_hex[40];
671 if (!ExtractIdsFromCwt(cwt.get(), actual_authority_id, tmp_subject_id_hex)) {
672 return false;
673 }
674 if (0 != memcmp(authority_id_hex, actual_authority_id, 40)) {
675 return false;
676 }
677 memcpy(subject_id_hex, tmp_subject_id_hex, 40);
678 *subject_public_key = ExtractPublicKeyFromCwt(cwt.get());
679 if (!subject_public_key) {
680 return false;
681 }
682 uint64_t key_usage = 0;
683 const uint64_t kKeyUsageCertSign = 1 << 5; // Bit 5.
684 if (!ExtractKeyUsageFromCwt(cwt.get(), &key_usage)) {
685 return false;
686 }
687 if (key_usage != kKeyUsageCertSign) {
688 return false;
689 }
690 if (!ValidateCborCertificateCdiFields(cwt.get(), expect_cdi_certificate)) {
691 return false;
692 }
693 return true;
694 }
695
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)696 bool VerifyCborCertificateChain(const uint8_t* root_certificate,
697 size_t root_certificate_size,
698 const dice::test::DiceStateForTest states[],
699 size_t num_dice_states, bool is_partial_chain) {
700 ScopedCbor root_cwt =
701 ExtractCwtFromCborCertificate(root_certificate, root_certificate_size);
702 if (!root_cwt) {
703 return false;
704 }
705 ScopedCbor authority_public_key = ExtractPublicKeyFromCwt(root_cwt.get());
706 if (!authority_public_key) {
707 return false;
708 }
709 char expected_authority_id_hex[40];
710 char not_used[40];
711 if (!ExtractIdsFromCwt(root_cwt.get(), not_used, expected_authority_id_hex)) {
712 return false;
713 }
714 if (!is_partial_chain) {
715 // We can't verify the root certificate in a partial chain, we can only
716 // check that its public key certifies the other certificates. But with a
717 // full chain, we can expect the root to be self-signed.
718 if (!VerifySingleCborCertificate(
719 root_certificate, root_certificate_size, authority_public_key.get(),
720 expected_authority_id_hex, /*expect_cdi_certificate=*/false,
721 &authority_public_key, expected_authority_id_hex)) {
722 return false;
723 }
724 }
725 for (size_t i = 0; i < num_dice_states; ++i) {
726 if (!VerifySingleCborCertificate(
727 states[i].certificate, states[i].certificate_size,
728 authority_public_key.get(), expected_authority_id_hex,
729 /*expect_cdi_certificate=*/true, &authority_public_key,
730 expected_authority_id_hex)) {
731 return false;
732 }
733 }
734 return true;
735 }
736
737 } // namespace
738
739 namespace dice {
740 namespace test {
741
DumpState(CertificateType cert_type,KeyType key_type,const char * suffix,const DiceStateForTest & state)742 void DumpState(CertificateType cert_type, KeyType key_type, const char* suffix,
743 const DiceStateForTest& state) {
744 char filename[100];
745 pw::string::Format(filename, "_attest_cdi_%s.bin", suffix);
746 DumpToFile(filename, state.cdi_attest, DICE_CDI_SIZE);
747 pw::string::Format(filename, "_seal_cdi_%s.bin", suffix);
748 DumpToFile(filename, state.cdi_seal, DICE_CDI_SIZE);
749 pw::string::Format(filename, "_%s_%s_cert_%s.cert", GetCertTypeStr(cert_type),
750 GetKeyTypeStr(key_type), suffix);
751 DumpToFile(filename, state.certificate, state.certificate_size);
752 }
753
DeriveFakeInputValue(const char * seed,size_t length,uint8_t * output)754 void DeriveFakeInputValue(const char* seed, size_t length, uint8_t* output) {
755 union {
756 uint8_t buffer[64];
757 uint64_t counter;
758 } context;
759 SHA512(reinterpret_cast<const uint8_t*>(seed), strlen(seed), context.buffer);
760 size_t output_pos = 0;
761 while (output_pos < length) {
762 uint8_t tmp[64];
763 SHA512(context.buffer, 64, tmp);
764 context.counter++;
765 size_t remaining = length - output_pos;
766 size_t to_copy = remaining < 64 ? remaining : 64;
767 memcpy(&output[output_pos], tmp, to_copy);
768 output_pos += to_copy;
769 }
770 }
771
CreateFakeUdsCertificate(void * context,const uint8_t uds[32],CertificateType cert_type,KeyType key_type,uint8_t certificate[kTestCertSize],size_t * certificate_size)772 void CreateFakeUdsCertificate(void* context, const uint8_t uds[32],
773 CertificateType cert_type, KeyType key_type,
774 uint8_t certificate[kTestCertSize],
775 size_t* certificate_size) {
776 uint8_t raw_key[DICE_PRIVATE_KEY_SEED_SIZE];
777 DiceDeriveCdiPrivateKeySeed(context, uds, raw_key);
778
779 uint8_t raw_public_key[MAX_PUBLIC_KEY_SIZE];
780 size_t raw_public_key_size = 0;
781 bssl::UniquePtr<EVP_PKEY> key(
782 KeyFromRawKey(raw_key, key_type, raw_public_key, &raw_public_key_size));
783
784 uint8_t id[DICE_ID_SIZE];
785 DiceDeriveCdiCertificateId(context, raw_public_key, raw_public_key_size, id);
786
787 if (cert_type == CertificateType_X509) {
788 CreateX509UdsCertificate(key.get(), id, certificate, certificate_size);
789 } else {
790 CreateCborUdsCertificate(raw_key, key_type, id, certificate,
791 certificate_size);
792 }
793
794 char filename[100];
795 pw::string::Format(filename, "_%s_%s_uds_cert.cert",
796 GetCertTypeStr(cert_type), GetKeyTypeStr(key_type));
797 DumpToFile(filename, certificate, *certificate_size);
798 }
799
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)800 [[maybe_unused]] bool VerifyCoseSign1(
801 const uint8_t* certificate, size_t certificate_size,
802 const uint8_t* external_aad, size_t external_aad_size,
803 const uint8_t* encoded_public_key, size_t encoded_public_key_size,
804 const uint8_t* expected_cwt, size_t expected_cwt_size) {
805 cn_cbor_errback error;
806 ScopedCbor public_key(
807 cn_cbor_decode(encoded_public_key, encoded_public_key_size, &error));
808 if (!public_key) {
809 return false;
810 }
811
812 if (!VerifyCoseSign1Signature(certificate, certificate_size, external_aad,
813 external_aad_size, public_key.get())) {
814 return false;
815 }
816
817 ScopedCbor sign1(cn_cbor_decode(certificate, certificate_size, &error));
818 if (!sign1 || sign1->type != CN_CBOR_ARRAY || sign1->length != 4) {
819 return false;
820 }
821 cn_cbor* payload = cn_cbor_index(sign1.get(), 2);
822 if (!payload || payload->type != CN_CBOR_BYTES) {
823 return false;
824 }
825
826 if (payload->length != expected_cwt_size) {
827 return false;
828 }
829
830 if (memcmp(payload->v.bytes, expected_cwt, expected_cwt_size) != 0) {
831 return false;
832 }
833 return true;
834 }
835
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)836 bool VerifyCertificateChain(CertificateType cert_type,
837 const uint8_t* root_certificate,
838 size_t root_certificate_size,
839 const DiceStateForTest states[],
840 size_t num_dice_states, bool is_partial_chain) {
841 switch (cert_type) {
842 case CertificateType_Cbor:
843 return VerifyCborCertificateChain(root_certificate, root_certificate_size,
844 states, num_dice_states,
845 is_partial_chain);
846 case CertificateType_X509:
847 return VerifyX509CertificateChain(root_certificate, root_certificate_size,
848 states, num_dice_states,
849 is_partial_chain);
850 }
851 return false;
852 }
853 } // namespace test
854 } // namespace dice
855