Software APIs
perso_tlv_data.h
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 #ifndef OPENTITAN_SW_DEVICE_SILICON_CREATOR_MANUF_BASE_PERSO_TLV_DATA_H_
6 #define OPENTITAN_SW_DEVICE_SILICON_CREATOR_MANUF_BASE_PERSO_TLV_DATA_H_
7 
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdint.h>
11 
12 #include "sw/device/lib/testing/json/provisioning_data.h"
13 #include "sw/device/silicon_creator/lib/cert/cert.h"
14 #include "sw/device/silicon_creator/lib/error.h"
15 
16 /**
17  * Personalization data is sent between the device and the host during the
18  * device provisioning. Personalization data is laid out as a sequence of
19  * concatenated LTV objects. The length and type field of the objects are packed
20  * in a 16 bit integer:
21  * d15 d0
22  * +-------------+--------------------------------+
23  * | 4 bit type | 12 bits total object size |
24  * +-------------+--------------------------------+
25  *
26  * The following object types have been defined so far:
27  */
28 typedef enum perso_tlv_object_type {
29  kPersoObjectTypeX509Tbs = 0,
30  kPersoObjectTypeX509Cert = 1,
31  kPersoObjectTypeDevSeed = 2,
32  kPersoObjectTypeCwtCert = 3,
33 } perso_tlv_object_type_t;
34 
35 typedef uint16_t perso_tlv_object_header_t;
36 typedef uint16_t perso_tlv_cert_header_t;
37 typedef uint16_t perso_tlv_dev_seed_header_t;
38 
39 typedef enum perso_tlv_obj_header_fields {
40  // Object size, total size, this header included.
41  kObjhSizeFieldShift = 0,
42  kObjhSizeFieldWidth = 12,
43  kObjhSizeFieldMask = (1 << kObjhSizeFieldWidth) - 1,
44 
45  // Object type, one of perso_tlv_object_type_t.
46  kObjhTypeFieldShift = kObjhSizeFieldWidth,
47  kObjhTypeFieldWidth =
48  sizeof(perso_tlv_object_header_t) * 8 - kObjhSizeFieldWidth,
49  kObjhTypeFieldMask = (1 << kObjhTypeFieldWidth) - 1,
50 } perso_tlv_obj_header_fields_t;
51 
53  uint32_t el[8];
55 
56 typedef struct perso_tlv_dev_seed {
60 
61 typedef struct perso_tlv_dev_seed_set {
62  perso_tlv_dev_seed_t seeds[2];
64 
65 /**
66  * The x509 certificate is prepended by a 16 bits header followed by the ASCII
67  * characters of the certificate name, followed by the certificate body.
68  *
69  * The certificate header includes 4 bits for the certificate name length then
70  * the full size of the certificate object (header size + name length +
71  * certificate size).
72  *
73  * d15 d0
74  * +-------------+--------------------------------+
75  * | 4 bit length| 12 bits total size |
76  * +-------------+--------------------------------+
77  */
78 typedef enum perso_tlv_cert_header_fields {
79  // Certificate size, total size, this header and name length included.
80  kCrthSizeFieldShift = 0,
81  kCrthSizeFieldWidth = 12,
82  kCrthSizeFieldMask = (1 << kCrthSizeFieldWidth) - 1,
83 
84  // Length of the certificate name immediately following the header.
85  kCrthNameSizeFieldShift = kCrthSizeFieldWidth,
86  kCrthNameSizeFieldWidth =
87  sizeof(perso_tlv_cert_header_t) * 8 - kCrthSizeFieldWidth,
88  kCrthNameSizeFieldMask = (1 << kCrthNameSizeFieldWidth) - 1,
89 } perso_tlv_cert_header_fields_t;
90 
91 // Helper macros allowing set or get various object and certificate header
92 // fields. Operate on objects in big endian representation, as they are
93 // transferred over wire.
94 #define PERSO_TLV_SET_FIELD(type_name, field_name, full_value, field_value) \
95  { \
96  uint16_t mask = k##type_name##field_name##FieldMask; \
97  uint16_t shift = k##type_name##field_name##FieldShift; \
98  uint16_t fieldv = (uint16_t)(field_value)&mask; \
99  uint16_t fullv = __builtin_bswap16((uint16_t)(full_value)); \
100  mask = (uint16_t)(mask << shift); \
101  (full_value) = __builtin_bswap16( \
102  (uint16_t)((fullv & ~mask) | (((uint16_t)fieldv) << shift))); \
103  }
104 
105 #define PERSO_TLV_GET_FIELD(type_name, field_name, full_value, field_value) \
106  { \
107  uint16_t mask = k##type_name##field_name##FieldMask; \
108  uint16_t shift = k##type_name##field_name##FieldShift; \
109  *(field_value) = (__builtin_bswap16(full_value) >> shift) & mask; \
110  }
111 
112 /**
113  * A helper structure for quick access to a certificate stored as a perso LTV
114  * object.
115  */
116 typedef struct perso_tlv_cert_obj {
117  /**
118  * Pointer to the start of the perso LTV object.
119  */
120  uint8_t *obj_p;
121  /**
122  * LTV object size (in bytes).
123  */
124  size_t obj_size;
125  /**
126  * LTV object type.
127  */
128  uint32_t obj_type;
129  /**
130  * Pointer to the start of the certificate body (i.e., ASN.1 object for X.509
131  * certificates, or CBOR object for CWT certificates).
132  */
133  uint8_t *cert_body_p;
134  /**
135  * Certificate (ASN.1 or CBOR) body size (in bytes).
136  *
137  * Equal to: obj_size - obj_hdr_size - cert_hdr_size - cert_name_len
138  */
140  /**
141  * Certificate name string.
142  */
143  char name[kCrthNameSizeFieldMask + 1];
145 
146 /**
147  * Given the pointer to an LTV object, in case this is an endorsed certificate
148  * set up the perso_tlv_cert_obj_t structure for it.
149  *
150  * @param buf Pointer to the LTV object buffer storing the certificate object.
151  * @param ltv_buf_size Total number of bytes until the end of the LTV buffer
152  * (cert LTV object must be <= the buffer size).
153  * @param[out] obj Pointer to the certificate perso LTV object to populate.
154  *
155  * @return OK_STATUS on success, NOT_FOUND if the object is not an endorsed
156  * certificate, or the error condition encountered.
157  */
159 rom_error_t perso_tlv_get_cert_obj(uint8_t *buf, size_t ltv_buf_size,
160  perso_tlv_cert_obj_t *obj);
161 
162 /**
163  * Wraps the passed certificate in a perso LTV object and copies it to an output
164  * buffer.
165  *
166  * The certificate perso LTV object is laid out as follows:
167  * - 16 bit LTV object header
168  * - 16 bit cert header
169  * - Certificate name string
170  * - Cerificate data
171  *
172  * Note that both certificate and object headers' are 16 bit integers in big
173  * endian format.
174  *
175  * d15 d0
176  * +-------------+--------------------------------+
177  * | 4 bit type | 12 bits total object size | <-- Object Header
178  * +-------------+--------------------------------+
179  * | name length |12 bits total cert payload size | <-- Cert Header
180  * +-------------+--------------------------------+
181  * | cert name string |
182  * +----------------------------------------------+
183  * | cert |
184  * +----------------------------------------------+
185  *
186  * @param name The name of the certificate.
187  * @param obj_type The object type that needs to encoded.
188  * @param cert The binary certificate blob.
189  * @param cert_size Size of the certificate blob in bytes.
190  * @param[out] buf Output buffer to copy the data into.
191  * @param[inout] buf_size Input is size of the output buffer in bytes; output is
192  * space of buffer that was consumed by the LTV object.
193  * @return status of the operation.
194  */
196 rom_error_t perso_tlv_cert_obj_build(const char *name,
197  const perso_tlv_object_type_t obj_type,
198  const uint8_t *cert, size_t cert_size,
199  uint8_t *buf, size_t *buf_size);
200 
201 /**
202  * Constructs an certificate perso LTV object (shown above) by invoking
203  * `perso_tlv_cert_obj_build()` and pushes it to a `perso_blob_t` object used
204  * for shuffling data between the host and device during personalization.
205  *
206  * @param name The name of the certificate.
207  * @param needs_endorsement Defines the type of the LTV object the certificate
208  * is wrapped into (TBS or fully formed).
209  * @param cert_format The format of the certificate.
210  * @param cert The binary certificate blob.
211  * @param cert_size Size of the certificate blob in bytes.
212  * @param perso_blob Pointer to the `perso_blob_t` to copy the object to.
213  * @return status of the operation.
214  */
216 rom_error_t perso_tlv_push_cert_to_perso_blob(
217  const char *name, bool needs_endorsement,
218  const dice_cert_format_t cert_format, const uint8_t *cert, size_t cert_size,
219  perso_blob_t *pb);
220 
221 /**
222  * Pushes arbitrary data to the perso blob that is sent between host and device.
223  *
224  * @param data Pointer to the data to add to the blob.
225  * @param size Size of the data to add in bytes.
226  * @param perso_blob Pointer to the perso blob to add the data to.
227  * @return status of the operation.
228  */
230 rom_error_t perso_tlv_push_to_perso_blob(const void *data, size_t size,
231  perso_blob_t *perso_blob);
232 
233 #endif // OPENTITAN_SW_DEVICE_SILICON_CREATOR_MANUF_BASE_PERSO_TLV_DATA_H_