Software APIs
perso_tlv_data.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/silicon_creator/manuf/base/perso_tlv_data.h"
6 
7 #include "sw/device/silicon_creator/lib/cert/cert.h"
8 #include "sw/device/silicon_creator/lib/error.h"
9 
10 rom_error_t perso_tlv_get_cert_obj(uint8_t *buf, size_t ltv_buf_size,
11  perso_tlv_cert_obj_t *obj) {
12  perso_tlv_object_header_t objh;
13  perso_tlv_object_type_t obj_type;
14  uint16_t obj_size;
15 
16  // Extract LTV object header, including: size and type.
17  if (ltv_buf_size < sizeof(perso_tlv_object_header_t)) {
18  return kErrorPersoTlvInternal;
19  }
20  obj->obj_p = buf;
21  memcpy(&objh, buf, sizeof(perso_tlv_object_header_t));
22  // Extract LTV object size.
23  PERSO_TLV_GET_FIELD(Objh, Size, objh, &obj_size);
24  if (obj_size == 0)
25  return kErrorPersoTlvCertObjNotFound; // Object is empty.
26  if (obj_size > ltv_buf_size)
27  return kErrorPersoTlvInternal; // Object exceeds the size of host buffer.
28  obj->obj_size = obj_size;
29  // Extract LTV object type.
30  PERSO_TLV_GET_FIELD(Objh, Type, objh, &obj_type);
31  obj->obj_type = obj_type;
32  if (obj_type != kPersoObjectTypeX509Cert &&
33  obj_type != kPersoObjectTypeCwtCert) {
34  return kErrorPersoTlvCertObjNotFound;
35  }
36  buf += sizeof(perso_tlv_object_header_t);
37  ltv_buf_size -= sizeof(perso_tlv_object_header_t);
38 
39  // If we made it this far, we found a certificate LTV object, so we will parse
40  // the object's header and metadata next.
41 
42  perso_tlv_cert_header_t crth;
43  uint16_t wrapped_cert_size;
44  uint16_t name_len;
45 
46  // Extract the certificate object header, including: certificate object and
47  // nameksizes, certificate name string, and pointer to the certificate body.
48  if (ltv_buf_size < sizeof(perso_tlv_cert_header_t)) {
49  return kErrorPersoTlvInternal;
50  }
51  memcpy(&crth, buf, sizeof(perso_tlv_cert_header_t));
52  // Extract certificate name size.
53  PERSO_TLV_GET_FIELD(Crth, NameSize, crth, &name_len);
54  // Extract wrapped certificate object size.
55  PERSO_TLV_GET_FIELD(Crth, Size, crth, &wrapped_cert_size);
56  // There are at least 4 bytes in an X.509 ASN.1 DER certificate: two bytes of
57  // header and two bytes of size data.
58  if ((wrapped_cert_size < (sizeof(perso_tlv_cert_header_t) + name_len + 4)) ||
59  (wrapped_cert_size > ltv_buf_size))
60  return kErrorPersoTlvInternal; // Something is really screwed up.
61  buf += sizeof(perso_tlv_cert_header_t);
62  ltv_buf_size -= sizeof(perso_tlv_cert_header_t);
63  // Extract certificate name string.
64  if (ltv_buf_size < name_len) {
65  return kErrorPersoTlvInternal;
66  }
67  memcpy(obj->name, buf, name_len);
68  obj->name[name_len] = '\0';
69  buf += name_len;
70  ltv_buf_size -= name_len;
71  // Set pointer to certificate body.
72  obj->cert_body_size =
73  wrapped_cert_size - sizeof(perso_tlv_cert_header_t) - name_len;
74  obj->cert_body_p = buf;
75 
76  // Sanity check on the certificate body size.
77  // TODO(24281): add sanity check on CWT certificate body size.
78  if (obj_type == kPersoObjectTypeX509Cert) {
79  size_t decoded_cert_size =
80  cert_x509_asn1_decode_size_header(obj->cert_body_p);
81  if (decoded_cert_size != obj->cert_body_size) {
82  return kErrorPersoTlvInternal;
83  }
84  }
85 
86  return kErrorOk;
87 }
88 
89 rom_error_t perso_tlv_cert_obj_build(const char *name,
90  const perso_tlv_object_type_t obj_type,
91  const uint8_t *cert, size_t cert_size,
92  uint8_t *buf, size_t *buf_size) {
93  perso_tlv_object_header_t obj_header = 0;
94  perso_tlv_cert_header_t cert_header = 0;
95  size_t obj_size;
96  size_t wrapped_cert_size;
97 
98  // Compute the name length (strlen() is not available).
99  size_t name_len = 0;
100  while (name[name_len])
101  name_len++;
102  if (name_len > kCrthNameSizeFieldMask)
103  return kErrorPersoTlvCertNameTooLong;
104 
105  // Compute the wrapped certificate object (cert header + cert data) and perso
106  // LTV object sizes.
107  wrapped_cert_size = sizeof(perso_tlv_cert_header_t) + name_len + cert_size;
108  obj_size = wrapped_cert_size + sizeof(perso_tlv_object_header_t);
109 
110  // Check there is enough room in the buffer to store the perso LTV object.
111  if (obj_size > *buf_size)
112  return kErrorPersoTlvOutputBufTooSmall;
113 
114  // Setup the perso LTV object header.
115  PERSO_TLV_SET_FIELD(Objh, Type, obj_header, obj_type);
116  PERSO_TLV_SET_FIELD(Objh, Size, obj_header, obj_size);
117 
118  // Setup the cert object header.
119  PERSO_TLV_SET_FIELD(Crth, Size, cert_header, wrapped_cert_size);
120  PERSO_TLV_SET_FIELD(Crth, NameSize, cert_header, name_len);
121 
122  // Push the cert perso LTV object to the buffer.
123  // Return the size of the buffer that was used up by this perso LTV object.
124  *buf_size = 0;
125  memcpy(buf + *buf_size, &obj_header, sizeof(perso_tlv_object_header_t));
126  *buf_size += sizeof(perso_tlv_object_header_t);
127  memcpy(buf + *buf_size, &cert_header, sizeof(perso_tlv_cert_header_t));
128  *buf_size += sizeof(perso_tlv_cert_header_t);
129  memcpy(buf + *buf_size, name, name_len);
130  *buf_size += name_len;
131  memcpy(buf + *buf_size, cert, cert_size);
132  *buf_size += cert_size;
133 
134  return kErrorOk;
135 }
136 
137 rom_error_t perso_tlv_push_cert_to_perso_blob(
138  const char *name, bool needs_endorsement,
139  const dice_cert_format_t dice_format, const uint8_t *cert, size_t cert_size,
140  perso_blob_t *pb) {
141  if (pb->next_free > sizeof(pb->body)) {
142  return kErrorPersoTlvInternal;
143  }
144  // Build the perso TLV cert object and push it to the perso blob.
145  size_t obj_size = sizeof(pb->body) - pb->next_free;
146  perso_tlv_object_type_t obj_type = kPersoObjectTypeCwtCert;
147  if (dice_format == kDiceCertFormatX509TcbInfo) {
148  if (needs_endorsement) {
149  obj_type = kPersoObjectTypeX509Tbs;
150  } else {
151  obj_type = kPersoObjectTypeX509Cert;
152  }
153  }
154  HARDENED_RETURN_IF_ERROR(perso_tlv_cert_obj_build(
155  name, obj_type, cert, cert_size, pb->body + pb->next_free, &obj_size));
156 
157  // Update the perso blob offset and object count.
158  pb->next_free += obj_size;
159  pb->num_objs++;
160 
161  return kErrorOk;
162 }
163 
164 rom_error_t perso_tlv_push_to_perso_blob(const void *data, size_t size,
165  perso_blob_t *perso_blob) {
166  if (perso_blob->next_free > sizeof(perso_blob->body)) {
167  return kErrorPersoTlvInternal;
168  }
169  size_t room = sizeof(perso_blob->body) - perso_blob->next_free;
170  if (room < size)
171  return kErrorPersoTlvOutputBufTooSmall;
172  memcpy(perso_blob->body + perso_blob->next_free, data, size);
173  perso_blob->next_free += size;
174  return kErrorOk;
175 }