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 // This is a DiceGenerateCertificate implementation that uses boringssl for
16 // crypto and certificate generation. The algorithms used are SHA512,
17 // HKDF-SHA512, and Ed25519-SHA512.
18
19 #include <stdint.h>
20
21 #include "dice/dice.h"
22 #include "dice/ops.h"
23 #include "dice/utils.h"
24 #include "openssl/asn1.h"
25 #include "openssl/asn1t.h"
26 #include "openssl/bn.h"
27 #include "openssl/curve25519.h"
28 #include "openssl/evp.h"
29 #include "openssl/is_boringssl.h"
30 #include "openssl/objects.h"
31 #include "openssl/x509.h"
32 #include "openssl/x509v3.h"
33
34 #define DICE_MAX_EXTENSION_SIZE 2048
35
36 typedef struct DiceExtensionAsn1 {
37 ASN1_OCTET_STRING* code_hash;
38 ASN1_OCTET_STRING* code_descriptor;
39 ASN1_OCTET_STRING* config_hash;
40 ASN1_OCTET_STRING* config_descriptor;
41 ASN1_OCTET_STRING* authority_hash;
42 ASN1_OCTET_STRING* authority_descriptor;
43 ASN1_ENUMERATED* mode;
44 } DiceExtensionAsn1;
45
46 // clang-format off
47 ASN1_SEQUENCE(DiceExtensionAsn1) = {
48 ASN1_EXP_OPT(DiceExtensionAsn1, code_hash, ASN1_OCTET_STRING, 0),
49 ASN1_EXP_OPT(DiceExtensionAsn1, code_descriptor, ASN1_OCTET_STRING, 1),
50 ASN1_EXP_OPT(DiceExtensionAsn1, config_hash, ASN1_OCTET_STRING, 2),
51 ASN1_EXP_OPT(DiceExtensionAsn1, config_descriptor, ASN1_OCTET_STRING, 3),
52 ASN1_EXP_OPT(DiceExtensionAsn1, authority_hash, ASN1_OCTET_STRING, 4),
53 ASN1_EXP_OPT(DiceExtensionAsn1, authority_descriptor, ASN1_OCTET_STRING, 5),
54 ASN1_EXP_OPT(DiceExtensionAsn1, mode, ASN1_ENUMERATED, 6),
55 } ASN1_SEQUENCE_END(DiceExtensionAsn1)
56 DECLARE_ASN1_FUNCTIONS(DiceExtensionAsn1)
57 IMPLEMENT_ASN1_FUNCTIONS(DiceExtensionAsn1)
58
59 static DiceResult AddStandardFields(X509* x509, const uint8_t subject_id[DICE_ID_SIZE],
60 const uint8_t authority_id[DICE_ID_SIZE]) {
61 // clang-format on
62 DiceResult result = kDiceResultOk;
63
64 // Initialize variables that are cleaned up on 'goto out'.
65 ASN1_INTEGER* serial = NULL;
66 BIGNUM* serial_bn = NULL;
67 X509_NAME* issuer_name = NULL;
68 X509_NAME* subject_name = NULL;
69 ASN1_TIME* not_before = NULL;
70 ASN1_TIME* not_after = NULL;
71
72 serial = ASN1_INTEGER_new();
73 if (!serial) {
74 result = kDiceResultPlatformError;
75 goto out;
76 }
77 issuer_name = X509_NAME_new();
78 if (!issuer_name) {
79 result = kDiceResultPlatformError;
80 goto out;
81 }
82 subject_name = X509_NAME_new();
83 if (!subject_name) {
84 result = kDiceResultPlatformError;
85 goto out;
86 }
87 not_before = ASN1_TIME_new();
88 if (!not_before) {
89 result = kDiceResultPlatformError;
90 goto out;
91 }
92 not_after = ASN1_TIME_new();
93 if (!not_after) {
94 result = kDiceResultPlatformError;
95 goto out;
96 }
97
98 if (!X509_set_version(x509, 2)) {
99 result = kDiceResultPlatformError;
100 goto out;
101 }
102
103 serial_bn = BN_bin2bn(subject_id, DICE_ID_SIZE, NULL);
104 if (!serial_bn) {
105 result = kDiceResultPlatformError;
106 goto out;
107 }
108 BN_to_ASN1_INTEGER(serial_bn, serial);
109 if (!X509_set_serialNumber(x509, serial)) {
110 result = kDiceResultPlatformError;
111 goto out;
112 }
113
114 uint8_t id_hex[40];
115 DiceHexEncode(authority_id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
116 if (!X509_NAME_add_entry_by_NID(issuer_name, NID_serialNumber, MBSTRING_UTF8,
117 id_hex, sizeof(id_hex), 0, 0)) {
118 result = kDiceResultPlatformError;
119 goto out;
120 }
121 if (!X509_set_issuer_name(x509, issuer_name)) {
122 result = kDiceResultPlatformError;
123 goto out;
124 }
125
126 DiceHexEncode(subject_id, DICE_ID_SIZE, id_hex, sizeof(id_hex));
127 if (!X509_NAME_add_entry_by_NID(subject_name, NID_serialNumber, MBSTRING_UTF8,
128 id_hex, sizeof(id_hex), 0, 0)) {
129 result = kDiceResultPlatformError;
130 goto out;
131 }
132 if (!X509_set_subject_name(x509, subject_name)) {
133 result = kDiceResultPlatformError;
134 goto out;
135 }
136
137 // '180322235959Z' is the date of publication of the DICE specification. Here
138 // it's used as a somewhat arbitrary backstop.
139 if (!ASN1_TIME_set_string(not_before, "180322235959Z")) {
140 result = kDiceResultPlatformError;
141 goto out;
142 }
143 if (!X509_set_notBefore(x509, not_before)) {
144 result = kDiceResultPlatformError;
145 goto out;
146 }
147 // '99991231235959Z' is suggested by RFC 5280 in cases where expiry is not
148 // meaningful. Basically, the certificate never expires.
149 if (!ASN1_TIME_set_string(not_after, "99991231235959Z")) {
150 result = kDiceResultPlatformError;
151 goto out;
152 }
153 if (!X509_set_notAfter(x509, not_after)) {
154 result = kDiceResultPlatformError;
155 goto out;
156 }
157 out:
158 if (serial) {
159 ASN1_INTEGER_free(serial);
160 }
161 if (serial_bn) {
162 BN_free(serial_bn);
163 }
164 if (issuer_name) {
165 X509_NAME_free(issuer_name);
166 }
167 if (subject_name) {
168 X509_NAME_free(subject_name);
169 }
170 if (not_before) {
171 ASN1_TIME_free(not_before);
172 }
173 if (not_after) {
174 ASN1_TIME_free(not_after);
175 }
176 return result;
177 }
178
AddStandardExtensions(X509 * x509,const uint8_t subject_id[DICE_ID_SIZE],const uint8_t authority_id[DICE_ID_SIZE])179 static DiceResult AddStandardExtensions(
180 X509* x509, const uint8_t subject_id[DICE_ID_SIZE],
181 const uint8_t authority_id[DICE_ID_SIZE]) {
182 DiceResult result = kDiceResultOk;
183
184 // Initialize variables that are cleaned up on 'goto out'.
185 AUTHORITY_KEYID* authority_key_id = NULL;
186 ASN1_OCTET_STRING* subject_key_id = NULL;
187 ASN1_BIT_STRING* key_usage = NULL;
188 BASIC_CONSTRAINTS* basic_constraints = NULL;
189 X509_EXTENSION* authority_key_id_ext = NULL;
190 X509_EXTENSION* subject_key_id_ext = NULL;
191 X509_EXTENSION* key_usage_ext = NULL;
192 X509_EXTENSION* basic_constraints_ext = NULL;
193
194 // The authority key identifier extension contains the same raw authority id
195 // that appears in the issuer name.
196 authority_key_id = AUTHORITY_KEYID_new();
197 if (!authority_key_id) {
198 result = kDiceResultPlatformError;
199 goto out;
200 }
201 authority_key_id->keyid = ASN1_OCTET_STRING_new();
202 if (!authority_key_id->keyid) {
203 result = kDiceResultPlatformError;
204 goto out;
205 }
206 if (!ASN1_OCTET_STRING_set(authority_key_id->keyid, authority_id,
207 DICE_ID_SIZE)) {
208 result = kDiceResultPlatformError;
209 goto out;
210 }
211
212 // The subject key identifier extension contains the same raw subject id that
213 // appears in the serial number and the subject name.
214 subject_key_id = ASN1_OCTET_STRING_new();
215 if (!subject_key_id) {
216 result = kDiceResultPlatformError;
217 goto out;
218 }
219 if (!ASN1_OCTET_STRING_set(subject_key_id, subject_id, DICE_ID_SIZE)) {
220 result = kDiceResultPlatformError;
221 goto out;
222 }
223
224 // The key usage extension contains only "keyCertSign".
225 key_usage = ASN1_BIT_STRING_new();
226 if (!key_usage) {
227 result = kDiceResultPlatformError;
228 goto out;
229 }
230 ASN1_BIT_STRING_set_bit(key_usage, 5 /*keyCertSign*/, 1);
231
232 // The basic constraints specify this is a CA with unspecified pathlen.
233 basic_constraints = BASIC_CONSTRAINTS_new();
234 if (!basic_constraints) {
235 result = kDiceResultPlatformError;
236 goto out;
237 }
238 basic_constraints->ca = 1;
239
240 // Encode all the extension objects.
241 authority_key_id_ext = X509V3_EXT_i2d(NID_authority_key_identifier,
242 /*crit=*/0, authority_key_id);
243 if (!authority_key_id_ext) {
244 result = kDiceResultPlatformError;
245 goto out;
246 }
247 subject_key_id_ext = X509V3_EXT_i2d(NID_subject_key_identifier,
248 /*crit=*/0, subject_key_id);
249 if (!subject_key_id_ext) {
250 result = kDiceResultPlatformError;
251 goto out;
252 }
253 key_usage_ext = X509V3_EXT_i2d(NID_key_usage, /*crit=*/1, key_usage);
254 if (!key_usage_ext) {
255 result = kDiceResultPlatformError;
256 goto out;
257 }
258 basic_constraints_ext = X509V3_EXT_i2d(NID_basic_constraints,
259 /*crit=*/1, basic_constraints);
260 if (!basic_constraints_ext) {
261 result = kDiceResultPlatformError;
262 goto out;
263 }
264
265 // Add all the extensions to the given X509 object.
266 if (!X509_add_ext(x509, authority_key_id_ext, -1)) {
267 result = kDiceResultPlatformError;
268 goto out;
269 }
270 if (!X509_add_ext(x509, subject_key_id_ext, -1)) {
271 result = kDiceResultPlatformError;
272 goto out;
273 }
274 if (!X509_add_ext(x509, key_usage_ext, -1)) {
275 result = kDiceResultPlatformError;
276 goto out;
277 }
278 if (!X509_add_ext(x509, basic_constraints_ext, -1)) {
279 result = kDiceResultPlatformError;
280 goto out;
281 }
282 out:
283 if (authority_key_id) {
284 AUTHORITY_KEYID_free(authority_key_id);
285 }
286 if (subject_key_id) {
287 ASN1_OCTET_STRING_free(subject_key_id);
288 }
289 if (key_usage) {
290 ASN1_BIT_STRING_free(key_usage);
291 }
292 if (basic_constraints) {
293 BASIC_CONSTRAINTS_free(basic_constraints);
294 }
295 if (authority_key_id_ext) {
296 X509_EXTENSION_free(authority_key_id_ext);
297 }
298 if (subject_key_id_ext) {
299 X509_EXTENSION_free(subject_key_id_ext);
300 }
301 if (key_usage_ext) {
302 X509_EXTENSION_free(key_usage_ext);
303 }
304 if (basic_constraints_ext) {
305 X509_EXTENSION_free(basic_constraints_ext);
306 }
307 return result;
308 }
309
GetDiceExtensionData(const DiceInputValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * actual_size)310 static DiceResult GetDiceExtensionData(const DiceInputValues* input_values,
311 size_t buffer_size, uint8_t* buffer,
312 size_t* actual_size) {
313 DiceResult result = kDiceResultOk;
314
315 DiceExtensionAsn1* asn1 = DiceExtensionAsn1_new();
316 if (!asn1) {
317 result = kDiceResultPlatformError;
318 goto out;
319 }
320
321 // Allocate required fields. Optional fields will be allocated as needed.
322 asn1->code_hash = ASN1_OCTET_STRING_new();
323 if (!asn1->code_hash) {
324 result = kDiceResultPlatformError;
325 goto out;
326 }
327 asn1->config_descriptor = ASN1_OCTET_STRING_new();
328 if (!asn1->config_descriptor) {
329 result = kDiceResultPlatformError;
330 goto out;
331 }
332 asn1->authority_hash = ASN1_OCTET_STRING_new();
333 if (!asn1->authority_hash) {
334 result = kDiceResultPlatformError;
335 goto out;
336 }
337 asn1->mode = ASN1_ENUMERATED_new();
338 if (!asn1->mode) {
339 result = kDiceResultPlatformError;
340 goto out;
341 }
342
343 // Encode code input.
344 if (!ASN1_OCTET_STRING_set(asn1->code_hash, input_values->code_hash,
345 DICE_HASH_SIZE)) {
346 result = kDiceResultPlatformError;
347 goto out;
348 }
349 if (input_values->code_descriptor_size > 0) {
350 asn1->code_descriptor = ASN1_OCTET_STRING_new();
351 if (!asn1->code_descriptor) {
352 result = kDiceResultPlatformError;
353 goto out;
354 }
355 if (!ASN1_OCTET_STRING_set(asn1->code_descriptor,
356 input_values->code_descriptor,
357 input_values->code_descriptor_size)) {
358 result = kDiceResultPlatformError;
359 goto out;
360 }
361 }
362
363 // Encode configuration inputs.
364 if (input_values->config_type == kDiceConfigTypeDescriptor) {
365 // The 'descriptor' type means the configuration input is in the descriptor
366 // field and the hash of this was used as the DICE input. In the extension
367 // both are stored.
368 uint8_t hash_buffer[DICE_HASH_SIZE];
369 asn1->config_hash = ASN1_OCTET_STRING_new();
370 if (!asn1->config_hash) {
371 result = kDiceResultPlatformError;
372 goto out;
373 }
374 if (!ASN1_OCTET_STRING_set(asn1->config_descriptor,
375 input_values->config_descriptor,
376 input_values->config_descriptor_size)) {
377 result = kDiceResultPlatformError;
378 goto out;
379 }
380 if (!ASN1_OCTET_STRING_set(
381 asn1->config_hash,
382 SHA512(input_values->config_descriptor,
383 input_values->config_descriptor_size, hash_buffer),
384 DICE_HASH_SIZE)) {
385 result = kDiceResultPlatformError;
386 goto out;
387 }
388 } else if (input_values->config_type == kDiceConfigTypeInline) {
389 // The 'inline' type means the configuration value is 64 bytes and was used
390 // directly as the DICE input. In the extension this value is stored in the
391 // descriptor and the hash is omitted.
392 if (!ASN1_OCTET_STRING_set(asn1->config_descriptor,
393 input_values->config_value,
394 DICE_INLINE_CONFIG_SIZE)) {
395 result = kDiceResultPlatformError;
396 goto out;
397 }
398 } else {
399 result = kDiceResultInvalidInput;
400 goto out;
401 }
402
403 // Encode authority input.
404 if (!ASN1_OCTET_STRING_set(asn1->authority_hash, input_values->authority_hash,
405 DICE_HASH_SIZE)) {
406 result = kDiceResultPlatformError;
407 goto out;
408 }
409 if (input_values->authority_descriptor_size > 0) {
410 asn1->authority_descriptor = ASN1_OCTET_STRING_new();
411 if (!asn1->authority_descriptor) {
412 result = kDiceResultPlatformError;
413 goto out;
414 }
415 if (!ASN1_OCTET_STRING_set(asn1->authority_descriptor,
416 input_values->authority_descriptor,
417 input_values->authority_descriptor_size)) {
418 result = kDiceResultPlatformError;
419 goto out;
420 }
421 }
422
423 // Encode mode input.
424 if (!ASN1_ENUMERATED_set(asn1->mode, input_values->mode)) {
425 result = kDiceResultPlatformError;
426 goto out;
427 }
428
429 *actual_size = i2d_DiceExtensionAsn1(asn1, NULL);
430 if (buffer_size < *actual_size) {
431 result = kDiceResultBufferTooSmall;
432 goto out;
433 }
434 i2d_DiceExtensionAsn1(asn1, &buffer);
435
436 out:
437 if (asn1) {
438 DiceExtensionAsn1_free(asn1);
439 }
440 return result;
441 }
442
AddDiceExtension(const DiceInputValues * input_values,X509 * x509)443 static DiceResult AddDiceExtension(const DiceInputValues* input_values,
444 X509* x509) {
445 const char* kDiceExtensionOid = "1.3.6.1.4.1.11129.2.1.24";
446
447 // Initialize variables that are cleaned up on 'goto out'.
448 ASN1_OBJECT* oid = NULL;
449 ASN1_OCTET_STRING* octets = NULL;
450 X509_EXTENSION* extension = NULL;
451
452 uint8_t extension_buffer[DICE_MAX_EXTENSION_SIZE];
453 size_t extension_size = 0;
454 DiceResult result =
455 GetDiceExtensionData(input_values, sizeof(extension_buffer),
456 extension_buffer, &extension_size);
457 if (result != kDiceResultOk) {
458 goto out;
459 }
460
461 oid = OBJ_txt2obj(kDiceExtensionOid, 1);
462 if (!oid) {
463 result = kDiceResultPlatformError;
464 goto out;
465 }
466
467 octets = ASN1_OCTET_STRING_new();
468 if (!octets) {
469 result = kDiceResultPlatformError;
470 goto out;
471 }
472 if (!ASN1_OCTET_STRING_set(octets, extension_buffer, extension_size)) {
473 result = kDiceResultPlatformError;
474 goto out;
475 }
476
477 extension =
478 X509_EXTENSION_create_by_OBJ(/*ex=*/NULL, oid, /*crit=*/1, octets);
479 if (!extension) {
480 result = kDiceResultPlatformError;
481 goto out;
482 }
483
484 if (!X509_add_ext(x509, extension, -1)) {
485 result = kDiceResultPlatformError;
486 goto out;
487 }
488 out:
489 if (oid) {
490 ASN1_OBJECT_free(oid);
491 }
492 if (octets) {
493 ASN1_OCTET_STRING_free(octets);
494 }
495 if (extension) {
496 X509_EXTENSION_free(extension);
497 }
498 return result;
499 }
500
GetIdFromKey(void * context,const EVP_PKEY * key,uint8_t id[DICE_ID_SIZE])501 static DiceResult GetIdFromKey(void* context, const EVP_PKEY* key,
502 uint8_t id[DICE_ID_SIZE]) {
503 uint8_t raw_public_key[32];
504 size_t raw_public_key_size = sizeof(raw_public_key);
505 if (!EVP_PKEY_get_raw_public_key(key, raw_public_key, &raw_public_key_size)) {
506 return kDiceResultPlatformError;
507 }
508 return DiceDeriveCdiCertificateId(context, raw_public_key,
509 raw_public_key_size, id);
510 }
511
DiceGenerateCertificate(void * context,const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],const DiceInputValues * input_values,size_t certificate_buffer_size,uint8_t * certificate,size_t * certificate_actual_size)512 DiceResult DiceGenerateCertificate(
513 void* context,
514 const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
515 const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
516 const DiceInputValues* input_values, size_t certificate_buffer_size,
517 uint8_t* certificate, size_t* certificate_actual_size) {
518 DiceResult result = kDiceResultOk;
519
520 // Initialize variables that are cleaned up on 'goto out'.
521 X509* x509 = NULL;
522 EVP_PKEY* authority_key = NULL;
523 EVP_PKEY* subject_key = NULL;
524
525 x509 = X509_new();
526 if (!x509) {
527 result = kDiceResultPlatformError;
528 goto out;
529 }
530 authority_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
531 authority_private_key_seed,
532 DICE_PRIVATE_KEY_SEED_SIZE);
533 if (!authority_key) {
534 result = kDiceResultPlatformError;
535 goto out;
536 }
537 subject_key = EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, NULL,
538 subject_private_key_seed,
539 DICE_PRIVATE_KEY_SEED_SIZE);
540 if (!subject_key) {
541 result = kDiceResultPlatformError;
542 goto out;
543 }
544 if (!X509_set_pubkey(x509, subject_key)) {
545 result = kDiceResultPlatformError;
546 goto out;
547 }
548
549 uint8_t authority_id[DICE_ID_SIZE];
550 result = GetIdFromKey(context, authority_key, authority_id);
551 if (result != kDiceResultOk) {
552 goto out;
553 }
554 uint8_t subject_id[DICE_ID_SIZE];
555 result = GetIdFromKey(context, subject_key, subject_id);
556 if (result != kDiceResultOk) {
557 goto out;
558 }
559
560 result = AddStandardFields(x509, subject_id, authority_id);
561 if (result != kDiceResultOk) {
562 goto out;
563 }
564 result = AddStandardExtensions(x509, subject_id, authority_id);
565 if (result != kDiceResultOk) {
566 goto out;
567 }
568 result = AddDiceExtension(input_values, x509);
569 if (result != kDiceResultOk) {
570 goto out;
571 }
572 if (!X509_sign(x509, authority_key, NULL /*ED25519 always uses SHA-512*/)) {
573 result = kDiceResultPlatformError;
574 goto out;
575 }
576 *certificate_actual_size = i2d_X509(x509, NULL);
577 if (*certificate_actual_size > certificate_buffer_size) {
578 result = kDiceResultBufferTooSmall;
579 goto out;
580 }
581 *certificate_actual_size = i2d_X509(x509, &certificate);
582 out:
583 if (x509) {
584 X509_free(x509);
585 }
586 if (authority_key) {
587 EVP_PKEY_free(authority_key);
588 }
589 if (subject_key) {
590 EVP_PKEY_free(subject_key);
591 }
592 return result;
593 }
594