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