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