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