• 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 // 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