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