xref: /aosp_15_r20/external/open-dice/src/template_cbor_cert_op.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 // If no variable length descriptors are used in a DICE certificate, the
16 // certificate can be constructed from a template instead of using a CBOR
17 // library. This implementation includes only hashes and inline configuration in
18 // the DICE extension. For convenience this uses only the lower level curve25519
19 // implementation in boringssl. This approach may be especially useful in very
20 // low level components where simplicity is paramount.
21 
22 // This is an implementation of the DiceGenerateCertificate that generates a
23 // CWT-style CBOR certificate based on a template using the ED25519-SHA512
24 // signature scheme.
25 //
26 // If no variable length descriptors are used in a DICE certificate, the
27 // certificate can be constructed from a template instead of using a CBOR /
28 // COSE library. This implementation includes only hashes and inline
29 // configuration in the certificate fields. This approach may be especially
30 // useful in very low level components where simplicity is paramount.
31 //
32 // This function will return kDiceResultInvalidInput if 'input_values' specifies
33 // any variable length descriptors. In particular:
34 //   * code_descriptor_size must be zero
35 //   * authority_descriptor_size must be zero
36 //   * config_type must be kDiceConfigTypeInline
37 
38 #include <stdint.h>
39 #include <string.h>
40 
41 #include "dice/dice.h"
42 #include "dice/ops.h"
43 #include "dice/utils.h"
44 
45 #if DICE_PUBLIC_KEY_BUFFER_SIZE != 32
46 #error "Only Ed25519 is supported; 32 bytes needed to store the public key."
47 #endif
48 #if DICE_SIGNATURE_BUFFER_SIZE != 64
49 #error "Only Ed25519 is supported; 64 bytes needed to store the signature."
50 #endif
51 
52 // 20 bytes of header, 366 bytes of payload.
53 #define DICE_TBS_SIZE 386
54 
55 // A well-formed certificate, but with zeros in all fields to be filled.
56 static const uint8_t kTemplate[441] = {
57     // Constant encoding.
58     0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x59, 0x01, 0x6e,
59     // Offset 9: Payload starts here, 366 bytes.
60     0xa8, 0x01, 0x78, 0x28,
61     // Offset 13: CWT issuer, 40 bytes.
62     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
63     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
64     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
65     0x00, 0x00, 0x00, 0x00,
66     // Constant encoding.
67     0x02, 0x78, 0x28,
68     // Offset 56: CWT subject, 40 bytes.
69     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
71     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72     0x00, 0x00, 0x00, 0x00,
73     // Constant encoding.
74     0x3a, 0x00, 0x47, 0x44, 0x50, 0x58, 0x40,
75     // Offset 103: Code hash, 64 bytes.
76     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
80     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
81     0x00, 0x00, 0x00, 0x00,
82     // Constant encoding.
83     0x3a, 0x00, 0x47, 0x44, 0x53, 0x58, 0x40,
84     // Offset 174: Configuration value, 64 bytes.
85     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
88     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
89     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
90     0x00, 0x00, 0x00, 0x00,
91     // Constant encoding.
92     0x3a, 0x00, 0x47, 0x44, 0x54, 0x58, 0x40,
93     // Offset 245: Authority hash, 64 bytes.
94     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99     0x00, 0x00, 0x00, 0x00,
100     // Constant encoding.
101     0x3a, 0x00, 0x47, 0x44, 0x56, 0x41,
102     // Offset 315: Mode, 1 byte.
103     0x00,
104     // Constant encoding.
105     0x3a, 0x00, 0x47, 0x44, 0x57, 0x58, 0x2d, 0xa5, 0x01, 0x01, 0x03, 0x27,
106     0x04, 0x81, 0x02, 0x20, 0x06, 0x21, 0x58, 0x20,
107     // Offset 336: Public key, 32 bytes.
108     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111     // Constant encoding (key usage).
112     0x3a, 0x00, 0x47, 0x44, 0x58, 0x41, 0x20,
113     // Offset 375: Payload ends here.
114     // Constant encoding.
115     0x58, 0x40,
116     // Offset 377: Signature, 64 bytes.
117     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
120     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
121     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
122     0x00, 0x00, 0x00, 0x00};
123 
124 // The data to be signed is not the certificate, but the payload appended to
125 // this header. This is the 'Sig_structure' for COSE_Sign1, per RFC 8152.
126 static const uint8_t kTbsHeader[20] = {0x84, 0x6a, 0x53, 0x69, 0x67, 0x6e, 0x61,
127                                        0x74, 0x75, 0x72, 0x65, 0x31, 0x43, 0xa1,
128                                        0x01, 0x27, 0x40, 0x59, 0x01, 0x6e};
129 
130 static const struct {
131   size_t offset;
132   size_t length;
133 } kFieldTable[] = {{13, 40},   // Issuer
134                    {56, 40},   // Subject
135                    {103, 64},  // Code hash
136                    {174, 64},  // Config descriptor
137                    {245, 64},  // Authority hash
138                    {315, 1},   // Mode
139                    {336, 32},  // Public key
140                    {377, 64},  // Signature
141                    {9, 366}};  // Payload
142 
143 static const size_t kFieldIndexIssuer = 0;
144 static const size_t kFieldIndexSubject = 1;
145 static const size_t kFieldIndexCodeHash = 2;
146 static const size_t kFieldIndexConfigDescriptor = 3;
147 static const size_t kFieldIndexAuthorityHash = 4;
148 static const size_t kFieldIndexMode = 5;
149 static const size_t kFieldIndexSubjectPublicKey = 6;
150 static const size_t kFieldIndexSignature = 7;
151 static const size_t kFieldIndexPayload = 8;
152 
153 // |buffer| must point to the beginning of the template buffer and |src| must
154 // point to at least <field-length> bytes.
CopyField(const uint8_t * src,size_t index,uint8_t * buffer)155 static void CopyField(const uint8_t* src, size_t index, uint8_t* buffer) {
156   memcpy(&buffer[kFieldTable[index].offset], src, kFieldTable[index].length);
157 }
158 
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)159 DiceResult DiceGenerateCertificate(
160     void* context,
161     const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
162     const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
163     const DiceInputValues* input_values, size_t certificate_buffer_size,
164     uint8_t* certificate, size_t* certificate_actual_size) {
165   DiceResult result = kDiceResultOk;
166 
167   DiceKeyParam key_param;
168   result = DiceGetKeyParam(context, kDicePrincipalSubject, &key_param);
169   if (result != kDiceResultOk) {
170     goto out;
171   }
172 
173   // Variable length descriptors are not supported.
174   if (input_values->code_descriptor_size > 0 ||
175       input_values->config_type != kDiceConfigTypeInline ||
176       input_values->authority_descriptor_size > 0 || key_param.profile_name) {
177     return kDiceResultInvalidInput;
178   }
179 
180   // We know the certificate size upfront so we can do the buffer size check.
181   *certificate_actual_size = sizeof(kTemplate);
182   if (certificate_buffer_size < sizeof(kTemplate)) {
183     return kDiceResultBufferTooSmall;
184   }
185 
186   // Declare buffers which are cleared on 'goto out'.
187   uint8_t subject_private_key[DICE_PRIVATE_KEY_BUFFER_SIZE];
188   uint8_t authority_private_key[DICE_PRIVATE_KEY_BUFFER_SIZE];
189 
190   // Derive keys and IDs from the private key seeds.
191   uint8_t subject_public_key[DICE_PUBLIC_KEY_BUFFER_SIZE];
192   result = DiceKeypairFromSeed(context, kDicePrincipalSubject,
193                                subject_private_key_seed, subject_public_key,
194                                subject_private_key);
195   if (result != kDiceResultOk) {
196     goto out;
197   }
198 
199   uint8_t subject_id[DICE_ID_SIZE];
200   result = DiceDeriveCdiCertificateId(context, subject_public_key,
201                                       DICE_PUBLIC_KEY_BUFFER_SIZE, subject_id);
202   if (result != kDiceResultOk) {
203     goto out;
204   }
205   uint8_t subject_id_hex[40];
206   DiceHexEncode(subject_id, sizeof(subject_id), subject_id_hex,
207                 sizeof(subject_id_hex));
208 
209   uint8_t authority_public_key[DICE_PUBLIC_KEY_BUFFER_SIZE];
210   result = DiceKeypairFromSeed(context, kDicePrincipalAuthority,
211                                authority_private_key_seed, authority_public_key,
212                                authority_private_key);
213   if (result != kDiceResultOk) {
214     goto out;
215   }
216 
217   uint8_t authority_id[DICE_ID_SIZE];
218   result = DiceDeriveCdiCertificateId(
219       context, authority_public_key, DICE_PUBLIC_KEY_BUFFER_SIZE, authority_id);
220   if (result != kDiceResultOk) {
221     goto out;
222   }
223   uint8_t authority_id_hex[40];
224   DiceHexEncode(authority_id, sizeof(authority_id), authority_id_hex,
225                 sizeof(authority_id_hex));
226 
227   // First copy in the entire template, then fill in the fields.
228   memcpy(certificate, kTemplate, sizeof(kTemplate));
229   CopyField(authority_id_hex, kFieldIndexIssuer, certificate);
230   CopyField(subject_id_hex, kFieldIndexSubject, certificate);
231   CopyField(subject_public_key, kFieldIndexSubjectPublicKey, certificate);
232   CopyField(input_values->code_hash, kFieldIndexCodeHash, certificate);
233   CopyField(input_values->config_value, kFieldIndexConfigDescriptor,
234             certificate);
235   CopyField(input_values->authority_hash, kFieldIndexAuthorityHash,
236             certificate);
237   certificate[kFieldTable[kFieldIndexMode].offset] = input_values->mode;
238 
239   // Fill the TBS structure using the payload from the certificate.
240   uint8_t tbs[DICE_TBS_SIZE];
241   memcpy(tbs, kTbsHeader, sizeof(kTbsHeader));
242   memcpy(&tbs[sizeof(kTbsHeader)],
243          &certificate[kFieldTable[kFieldIndexPayload].offset],
244          kFieldTable[kFieldIndexPayload].length);
245 
246   uint8_t signature[DICE_SIGNATURE_BUFFER_SIZE];
247   result =
248       DiceSign(context, tbs, sizeof(tbs), authority_private_key, signature);
249   if (result != kDiceResultOk) {
250     goto out;
251   }
252   result =
253       DiceVerify(context, tbs, sizeof(tbs), signature, authority_public_key);
254   if (result != kDiceResultOk) {
255     goto out;
256   }
257   CopyField(signature, kFieldIndexSignature, certificate);
258 
259 out:
260   DiceClearMemory(context, sizeof(subject_private_key), subject_private_key);
261   DiceClearMemory(context, sizeof(authority_private_key),
262                   authority_private_key);
263   return result;
264 }
265