xref: /aosp_15_r20/external/open-dice/src/mbedtls_ops.c (revision 60b67249c2e226f42f35cc6cfe66c6048e0bae6b)
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 an implementation of DiceGenerateCertificate and the crypto
16 // operations that uses mbedtls. The algorithms used are SHA512, HKDF-SHA512,
17 // and deterministic ECDSA-P256-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 "mbedtls/asn1.h"
26 #include "mbedtls/asn1write.h"
27 #include "mbedtls/bignum.h"
28 #include "mbedtls/ecdsa.h"
29 #include "mbedtls/ecp.h"
30 #include "mbedtls/hkdf.h"
31 #include "mbedtls/hmac_drbg.h"
32 #include "mbedtls/md.h"
33 #include "mbedtls/oid.h"
34 #include "mbedtls/pk.h"
35 #include "mbedtls/x509.h"
36 #include "mbedtls/x509_crt.h"
37 
38 #define DICE_MAX_CERTIFICATE_SIZE 2048
39 #define DICE_MAX_EXTENSION_SIZE 2048
40 #define DICE_MAX_KEY_ID_SIZE 40
41 
SetupKeyPair(const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],mbedtls_pk_context * context)42 static DiceResult SetupKeyPair(
43     const uint8_t private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
44     mbedtls_pk_context* context) {
45   if (0 !=
46       mbedtls_pk_setup(context, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))) {
47     return kDiceResultPlatformError;
48   }
49   // Use the |private_key_seed| directly to seed a PRNG which is then in turn
50   // used to generate the private key. This implementation uses HMAC_DRBG in a
51   // loop with no reduction, like RFC6979.
52   DiceResult result = kDiceResultOk;
53   mbedtls_hmac_drbg_context rng_context;
54   mbedtls_hmac_drbg_init(&rng_context);
55   if (0 != mbedtls_hmac_drbg_seed_buf(
56                &rng_context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
57                private_key_seed, DICE_PRIVATE_KEY_SEED_SIZE)) {
58     result = kDiceResultPlatformError;
59     goto out;
60   }
61   if (0 != mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1,
62                                mbedtls_pk_ec(*context),
63                                mbedtls_hmac_drbg_random, &rng_context)) {
64     result = kDiceResultPlatformError;
65     goto out;
66   }
67 
68 out:
69   mbedtls_hmac_drbg_free(&rng_context);
70   return result;
71 }
72 
GetIdFromKey(void * context,const mbedtls_pk_context * pk_context,uint8_t id[DICE_ID_SIZE])73 static DiceResult GetIdFromKey(void* context,
74                                const mbedtls_pk_context* pk_context,
75                                uint8_t id[DICE_ID_SIZE]) {
76   uint8_t raw_public_key[33];
77   size_t raw_public_key_size = 0;
78   mbedtls_ecp_keypair* key = mbedtls_pk_ec(*pk_context);
79 
80   if (0 != mbedtls_ecp_point_write_binary(
81                &key->grp, &key->Q, MBEDTLS_ECP_PF_COMPRESSED,
82                &raw_public_key_size, raw_public_key, sizeof(raw_public_key))) {
83     return kDiceResultPlatformError;
84   }
85   return DiceDeriveCdiCertificateId(context, raw_public_key,
86                                     raw_public_key_size, id);
87 }
88 
89 // 54 byte name is prefix (13), hex id (40), and a null terminator.
GetNameFromId(const uint8_t id[DICE_ID_SIZE],char name[54])90 static void GetNameFromId(const uint8_t id[DICE_ID_SIZE], char name[54]) {
91   strcpy(name, "serialNumber=");
92   DiceHexEncode(id, /*num_bytes=*/DICE_ID_SIZE, (uint8_t*)&name[13],
93                 /*out_size=*/40);
94   name[53] = '\0';
95 }
96 
GetSubjectKeyIdFromId(const uint8_t id[DICE_ID_SIZE],size_t buffer_size,uint8_t * buffer,size_t * actual_size)97 static DiceResult GetSubjectKeyIdFromId(const uint8_t id[DICE_ID_SIZE],
98                                         size_t buffer_size, uint8_t* buffer,
99                                         size_t* actual_size) {
100   uint8_t* pos = buffer + buffer_size;
101   int length_or_error =
102       mbedtls_asn1_write_octet_string(&pos, buffer, id, DICE_ID_SIZE);
103   if (length_or_error < 0) {
104     return kDiceResultPlatformError;
105   }
106   *actual_size = length_or_error;
107   memmove(buffer, pos, *actual_size);
108   return kDiceResultOk;
109 }
110 
AddAuthorityKeyIdEncoding(uint8_t ** pos,uint8_t * start,int length)111 static int AddAuthorityKeyIdEncoding(uint8_t** pos, uint8_t* start,
112                                      int length) {
113   // From RFC 5280 4.2.1.1.
114   const int kKeyIdentifierTag = 0;
115 
116   int ret = 0;  // Used by MBEDTLS_ASN1_CHK_ADD.
117   MBEDTLS_ASN1_CHK_ADD(length, mbedtls_asn1_write_len(pos, start, length));
118   MBEDTLS_ASN1_CHK_ADD(
119       length,
120       mbedtls_asn1_write_tag(
121           pos, start, MBEDTLS_ASN1_CONTEXT_SPECIFIC | kKeyIdentifierTag));
122 
123   MBEDTLS_ASN1_CHK_ADD(length, mbedtls_asn1_write_len(pos, start, length));
124   MBEDTLS_ASN1_CHK_ADD(
125       length,
126       mbedtls_asn1_write_tag(pos, start,
127                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
128   return length;
129 }
130 
GetAuthorityKeyIdFromId(const uint8_t id[DICE_ID_SIZE],size_t buffer_size,uint8_t * buffer,size_t * actual_size)131 static DiceResult GetAuthorityKeyIdFromId(const uint8_t id[DICE_ID_SIZE],
132                                           size_t buffer_size, uint8_t* buffer,
133                                           size_t* actual_size) {
134   uint8_t* pos = buffer + buffer_size;
135   int length_or_error =
136       mbedtls_asn1_write_raw_buffer(&pos, buffer, id, DICE_ID_SIZE);
137   if (length_or_error < 0) {
138     return kDiceResultPlatformError;
139   }
140   length_or_error = AddAuthorityKeyIdEncoding(&pos, buffer, length_or_error);
141   if (length_or_error < 0) {
142     return kDiceResultPlatformError;
143   }
144   *actual_size = length_or_error;
145   memmove(buffer, pos, *actual_size);
146   return kDiceResultOk;
147 }
148 
GetFieldTag(uint8_t tag)149 static uint8_t GetFieldTag(uint8_t tag) {
150   return MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag;
151 }
152 
153 // Can be used with MBEDTLS_ASN1_CHK_ADD.
WriteExplicitModeField(uint8_t tag,int value,uint8_t ** pos,uint8_t * start)154 static int WriteExplicitModeField(uint8_t tag, int value, uint8_t** pos,
155                                   uint8_t* start) {
156   // ASN.1 constants not defined by mbedtls.
157   const uint8_t kEnumTypeTag = 10;
158 
159   int ret = 0;  // Used by MBEDTLS_ASN1_CHK_ADD.
160   int field_length = 0;
161   MBEDTLS_ASN1_CHK_ADD(field_length, mbedtls_asn1_write_int(pos, start, value));
162   // Overwrite the 'int' type.
163   ++(*pos);
164   --field_length;
165   MBEDTLS_ASN1_CHK_ADD(field_length,
166                        mbedtls_asn1_write_tag(pos, start, kEnumTypeTag));
167 
168   // Explicitly tagged, so add the field tag too.
169   MBEDTLS_ASN1_CHK_ADD(field_length,
170                        mbedtls_asn1_write_len(pos, start, field_length));
171   MBEDTLS_ASN1_CHK_ADD(field_length,
172                        mbedtls_asn1_write_tag(pos, start, GetFieldTag(tag)));
173   return field_length;
174 }
175 
176 // Can be used with MBEDTLS_ASN1_CHK_ADD.
WriteExplicitUtf8StringField(uint8_t tag,const void * value,size_t value_size,uint8_t ** pos,uint8_t * start)177 static int WriteExplicitUtf8StringField(uint8_t tag, const void* value,
178                                         size_t value_size, uint8_t** pos,
179                                         uint8_t* start) {
180   int ret = 0;  // Used by MBEDTLS_ASN1_CHK_ADD.
181   int field_length = 0;
182   MBEDTLS_ASN1_CHK_ADD(field_length, mbedtls_asn1_write_utf8_string(
183                                          pos, start, value, value_size));
184   // Explicitly tagged, so add the field tag too.
185   MBEDTLS_ASN1_CHK_ADD(field_length,
186                        mbedtls_asn1_write_len(pos, start, field_length));
187   MBEDTLS_ASN1_CHK_ADD(field_length,
188                        mbedtls_asn1_write_tag(pos, start, GetFieldTag(tag)));
189   return field_length;
190 }
191 
192 // Can be used with MBEDTLS_ASN1_CHK_ADD.
WriteExplicitOctetStringField(uint8_t tag,const uint8_t * value,size_t value_size,uint8_t ** pos,uint8_t * start)193 static int WriteExplicitOctetStringField(uint8_t tag, const uint8_t* value,
194                                          size_t value_size, uint8_t** pos,
195                                          uint8_t* start) {
196   int ret = 0;  // Used by MBEDTLS_ASN1_CHK_ADD.
197   int field_length = 0;
198   MBEDTLS_ASN1_CHK_ADD(field_length, mbedtls_asn1_write_octet_string(
199                                          pos, start, value, value_size));
200   // Explicitly tagged, so add the field tag too.
201   MBEDTLS_ASN1_CHK_ADD(field_length,
202                        mbedtls_asn1_write_len(pos, start, field_length));
203   MBEDTLS_ASN1_CHK_ADD(field_length,
204                        mbedtls_asn1_write_tag(pos, start, GetFieldTag(tag)));
205   return field_length;
206 }
207 
GetDiceExtensionDataHelper(const DiceInputValues * input_values,uint8_t ** pos,uint8_t * start)208 static int GetDiceExtensionDataHelper(const DiceInputValues* input_values,
209                                       uint8_t** pos, uint8_t* start) {
210   // ASN.1 tags for extension fields.
211   const uint8_t kDiceFieldCodeHash = 0;
212   const uint8_t kDiceFieldCodeDescriptor = 1;
213   const uint8_t kDiceFieldConfigHash = 2;
214   const uint8_t kDiceFieldConfigDescriptor = 3;
215   const uint8_t kDiceFieldAuthorityHash = 4;
216   const uint8_t kDiceFieldAuthorityDescriptor = 5;
217   const uint8_t kDiceFieldMode = 6;
218   const uint8_t kDiceFieldProfileName = 7;
219 
220   // Build up the extension ASN.1 in reverse order.
221   int ret = 0;  // Used by MBEDTLS_ASN1_CHK_ADD.
222   int length = 0;
223 
224   // Add the profile name field.
225   if (DICE_PROFILE_NAME) {
226     MBEDTLS_ASN1_CHK_ADD(length, WriteExplicitUtf8StringField(
227                                      kDiceFieldProfileName, DICE_PROFILE_NAME,
228                                      strlen(DICE_PROFILE_NAME), pos, start));
229   }
230 
231   // Add the mode field.
232   MBEDTLS_ASN1_CHK_ADD(
233       length,
234       WriteExplicitModeField(kDiceFieldMode, input_values->mode, pos, start));
235 
236   // Add the authorityDescriptor field, if applicable.
237   if (input_values->authority_descriptor_size > 0) {
238     MBEDTLS_ASN1_CHK_ADD(
239         length,
240         WriteExplicitOctetStringField(
241             kDiceFieldAuthorityDescriptor, input_values->authority_descriptor,
242             input_values->authority_descriptor_size, pos, start));
243   }
244 
245   // Add the authorityHash field.
246   MBEDTLS_ASN1_CHK_ADD(
247       length, WriteExplicitOctetStringField(kDiceFieldAuthorityHash,
248                                             input_values->authority_hash,
249                                             DICE_HASH_SIZE, pos, start));
250 
251   // Add the configurationDescriptor field (and configurationHash field, if
252   // applicable).
253   if (input_values->config_type == kDiceConfigTypeDescriptor) {
254     uint8_t hash[DICE_HASH_SIZE];
255     int result = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
256                             input_values->config_descriptor,
257                             input_values->config_descriptor_size, hash);
258     if (result) {
259       return result;
260     }
261     MBEDTLS_ASN1_CHK_ADD(
262         length, WriteExplicitOctetStringField(
263                     kDiceFieldConfigDescriptor, input_values->config_descriptor,
264                     input_values->config_descriptor_size, pos, start));
265     MBEDTLS_ASN1_CHK_ADD(
266         length, WriteExplicitOctetStringField(kDiceFieldConfigHash, hash,
267                                               DICE_HASH_SIZE, pos, start));
268   } else if (input_values->config_type == kDiceConfigTypeInline) {
269     MBEDTLS_ASN1_CHK_ADD(
270         length, WriteExplicitOctetStringField(
271                     kDiceFieldConfigDescriptor, input_values->config_value,
272                     DICE_INLINE_CONFIG_SIZE, pos, start));
273   }
274 
275   // Add the code descriptor field, if applicable.
276   if (input_values->code_descriptor_size > 0) {
277     MBEDTLS_ASN1_CHK_ADD(
278         length, WriteExplicitOctetStringField(
279                     kDiceFieldCodeDescriptor, input_values->code_descriptor,
280                     input_values->code_descriptor_size, pos, start));
281   }
282 
283   // Add the code hash field.
284   MBEDTLS_ASN1_CHK_ADD(length, WriteExplicitOctetStringField(
285                                    kDiceFieldCodeHash, input_values->code_hash,
286                                    DICE_HASH_SIZE, pos, start));
287 
288   // Add the sequence length and tag.
289   MBEDTLS_ASN1_CHK_ADD(length, mbedtls_asn1_write_len(pos, start, length));
290   MBEDTLS_ASN1_CHK_ADD(
291       length,
292       mbedtls_asn1_write_tag(pos, start,
293                              MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
294   return length;
295 }
296 
GetDiceExtensionData(const DiceInputValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * actual_size)297 static DiceResult GetDiceExtensionData(const DiceInputValues* input_values,
298                                        size_t buffer_size, uint8_t* buffer,
299                                        size_t* actual_size) {
300   uint8_t* pos = buffer + buffer_size;
301   int length_or_error = GetDiceExtensionDataHelper(input_values, &pos, buffer);
302   if (length_or_error == MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) {
303     return kDiceResultBufferTooSmall;
304   } else if (length_or_error < 0) {
305     return kDiceResultPlatformError;
306   }
307   *actual_size = length_or_error;
308   memmove(buffer, pos, *actual_size);
309   return kDiceResultOk;
310 }
311 
DiceHash(void * context_not_used,const uint8_t * input,size_t input_size,uint8_t output[DICE_HASH_SIZE])312 DiceResult DiceHash(void* context_not_used, const uint8_t* input,
313                     size_t input_size, uint8_t output[DICE_HASH_SIZE]) {
314   (void)context_not_used;
315   if (0 != mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), input,
316                       input_size, output)) {
317     return kDiceResultPlatformError;
318   }
319   return kDiceResultOk;
320 }
321 
DiceKdf(void * context_not_used,size_t length,const uint8_t * ikm,size_t ikm_size,const uint8_t * salt,size_t salt_size,const uint8_t * info,size_t info_size,uint8_t * output)322 DiceResult DiceKdf(void* context_not_used, size_t length, const uint8_t* ikm,
323                    size_t ikm_size, const uint8_t* salt, size_t salt_size,
324                    const uint8_t* info, size_t info_size, uint8_t* output) {
325   (void)context_not_used;
326   if (0 != mbedtls_hkdf(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), salt,
327                         salt_size, ikm, ikm_size, info, info_size, output,
328                         length)) {
329     return kDiceResultPlatformError;
330   }
331   return kDiceResultOk;
332 }
333 
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)334 DiceResult DiceGenerateCertificate(
335     void* context,
336     const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
337     const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
338     const DiceInputValues* input_values, size_t certificate_buffer_size,
339     uint8_t* certificate, size_t* certificate_actual_size) {
340   // 1.3.6.1.4.1.11129.2.1.24
341   // iso.org.dod.internet.private.enterprise.
342   //   google.googleSecurity.certificateExtensions.diceAttestationData
343   const char* kDiceExtensionOid =
344       MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD
345       "\x01\x04\x01\xd6\x79\x02\x01\x18";
346   const size_t kDiceExtensionOidLength = 10;
347 
348   DiceResult result = kDiceResultOk;
349 
350   // Initialize variables cleaned up on 'goto out'.
351   mbedtls_pk_context authority_key_context;
352   mbedtls_pk_init(&authority_key_context);
353   mbedtls_pk_context subject_key_context;
354   mbedtls_pk_init(&subject_key_context);
355   mbedtls_x509write_cert cert_context;
356   mbedtls_x509write_crt_init(&cert_context);
357   mbedtls_mpi serial_number;
358   mbedtls_mpi_init(&serial_number);
359 
360   // Derive key pairs and IDs.
361   result = SetupKeyPair(authority_private_key_seed, &authority_key_context);
362   if (result != kDiceResultOk) {
363     goto out;
364   }
365 
366   uint8_t authority_id[DICE_ID_SIZE];
367   result = GetIdFromKey(context, &authority_key_context, authority_id);
368   if (result != kDiceResultOk) {
369     goto out;
370   }
371 
372   char authority_name[54];
373   GetNameFromId(authority_id, authority_name);
374 
375   uint8_t authority_key_id[DICE_MAX_KEY_ID_SIZE];
376   size_t authority_key_id_size = 0;
377   result = GetAuthorityKeyIdFromId(authority_id, sizeof(authority_key_id),
378                                    authority_key_id, &authority_key_id_size);
379   if (result != kDiceResultOk) {
380     goto out;
381   }
382   result = SetupKeyPair(subject_private_key_seed, &subject_key_context);
383   if (result != kDiceResultOk) {
384     goto out;
385   }
386 
387   uint8_t subject_id[DICE_ID_SIZE];
388   result = GetIdFromKey(context, &subject_key_context, subject_id);
389   if (result != kDiceResultOk) {
390     goto out;
391   }
392 
393   char subject_name[54];
394   GetNameFromId(subject_id, subject_name);
395 
396   uint8_t subject_key_id[DICE_MAX_KEY_ID_SIZE];
397   size_t subject_key_id_size = 0;
398   result = GetSubjectKeyIdFromId(subject_id, sizeof(subject_key_id),
399                                  subject_key_id, &subject_key_id_size);
400   if (result != kDiceResultOk) {
401     goto out;
402   }
403 
404   uint8_t dice_extension[DICE_MAX_EXTENSION_SIZE];
405   size_t dice_extension_size = 0;
406   result = GetDiceExtensionData(input_values, sizeof(dice_extension),
407                                 dice_extension, &dice_extension_size);
408   if (result != kDiceResultOk) {
409     goto out;
410   }
411 
412   // Construct the certificate.
413   mbedtls_x509write_crt_set_version(&cert_context, MBEDTLS_X509_CRT_VERSION_3);
414   if (0 !=
415       mbedtls_mpi_read_binary(&serial_number, subject_id, sizeof(subject_id))) {
416     result = kDiceResultPlatformError;
417     goto out;
418   }
419   if (0 != mbedtls_x509write_crt_set_serial(&cert_context, &serial_number)) {
420     result = kDiceResultPlatformError;
421     goto out;
422   }
423   // '20180322235959' is the date of publication of the DICE specification. Here
424   // it's used as a somewhat arbitrary backstop. '99991231235959' is suggested
425   // by RFC 5280 in cases where expiry is not meaningful. Basically, the
426   // certificate never expires.
427   if (0 != mbedtls_x509write_crt_set_validity(&cert_context, "20180322235959",
428                                               "99991231235959")) {
429     result = kDiceResultPlatformError;
430     goto out;
431   }
432   if (0 !=
433       mbedtls_x509write_crt_set_issuer_name(&cert_context, authority_name)) {
434     result = kDiceResultPlatformError;
435     goto out;
436   }
437   if (0 !=
438       mbedtls_x509write_crt_set_subject_name(&cert_context, subject_name)) {
439     result = kDiceResultPlatformError;
440     goto out;
441   }
442   mbedtls_x509write_crt_set_subject_key(&cert_context, &subject_key_context);
443   mbedtls_x509write_crt_set_issuer_key(&cert_context, &authority_key_context);
444   mbedtls_x509write_crt_set_md_alg(&cert_context, MBEDTLS_MD_SHA512);
445   if (0 != mbedtls_x509write_crt_set_extension(
446                &cert_context, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
447                MBEDTLS_OID_SIZE(MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER),
448                /*critical=*/0, authority_key_id, authority_key_id_size)) {
449     result = kDiceResultPlatformError;
450     goto out;
451   }
452   if (0 != mbedtls_x509write_crt_set_extension(
453                &cert_context, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
454                MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER),
455                /*critical=*/0, subject_key_id, subject_key_id_size)) {
456     result = kDiceResultPlatformError;
457     goto out;
458   }
459   if (0 != mbedtls_x509write_crt_set_key_usage(&cert_context,
460                                                MBEDTLS_X509_KU_KEY_CERT_SIGN)) {
461     result = kDiceResultPlatformError;
462     goto out;
463   }
464   if (0 != mbedtls_x509write_crt_set_basic_constraints(&cert_context,
465                                                        /*is_ca=*/1,
466                                                        /*max_pathlen=*/-1)) {
467     result = kDiceResultPlatformError;
468     goto out;
469   }
470   if (0 != mbedtls_x509write_crt_set_extension(
471                &cert_context, kDiceExtensionOid, kDiceExtensionOidLength,
472                /*critical=*/1, dice_extension, dice_extension_size)) {
473     result = kDiceResultPlatformError;
474     goto out;
475   }
476   // This implementation is deterministic and assumes entropy is not available.
477   // If this code is run where entropy is available, however, f_rng and p_rng
478   // should be set to use that entropy. As is, we'll provide a DRBG for blinding
479   // but it will be ineffective.
480   mbedtls_hmac_drbg_context drbg;
481   mbedtls_hmac_drbg_init(&drbg);
482   mbedtls_hmac_drbg_seed_buf(&drbg,
483                              mbedtls_md_info_from_type(MBEDTLS_MD_SHA512),
484                              subject_key_id, subject_key_id_size);
485   uint8_t tmp_buffer[DICE_MAX_CERTIFICATE_SIZE];
486   int length_or_error =
487       mbedtls_x509write_crt_der(&cert_context, tmp_buffer, sizeof(tmp_buffer),
488                                 mbedtls_hmac_drbg_random, &drbg);
489   mbedtls_hmac_drbg_free(&drbg);
490   if (length_or_error < 0) {
491     result = kDiceResultPlatformError;
492     goto out;
493   }
494   *certificate_actual_size = length_or_error;
495   if (*certificate_actual_size > certificate_buffer_size) {
496     result = kDiceResultBufferTooSmall;
497     goto out;
498   }
499   // The certificate has been written to the end of tmp_buffer. Skip unused
500   // buffer when copying.
501   memcpy(certificate,
502          &tmp_buffer[sizeof(tmp_buffer) - *certificate_actual_size],
503          *certificate_actual_size);
504 
505 out:
506   mbedtls_mpi_free(&serial_number);
507   mbedtls_x509write_crt_free(&cert_context);
508   mbedtls_pk_free(&authority_key_context);
509   mbedtls_pk_free(&subject_key_context);
510   return result;
511 }
512