• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 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 generates a CWT-style
16 // CBOR certificate. The function DiceCoseEncodePublicKey depends on the
17 // signature algorithm type, and must be implemented elsewhere.
18 
19 #include <stddef.h>
20 #include <stdint.h>
21 #include <string.h>
22 
23 #include "dice/cbor_writer.h"
24 #include "dice/dice.h"
25 #include "dice/ops.h"
26 #include "dice/ops/trait/cose.h"
27 #include "dice/utils.h"
28 
29 // Max size of COSE_Sign1 including payload.
30 #define DICE_MAX_CERTIFICATE_SIZE 2048
31 // Max size of COSE_Key encoding.
32 #define DICE_MAX_PUBLIC_KEY_SIZE (DICE_PUBLIC_KEY_SIZE + 32)
33 // Max size of the COSE_Sign1 protected attributes.
34 #define DICE_MAX_PROTECTED_ATTRIBUTES_SIZE 16
35 
EncodeProtectedAttributes(size_t buffer_size,uint8_t * buffer,size_t * encoded_size)36 static DiceResult EncodeProtectedAttributes(size_t buffer_size, uint8_t* buffer,
37                                             size_t* encoded_size) {
38   // Constants per RFC 8152.
39   const int64_t kCoseHeaderAlgLabel = 1;
40 
41   struct CborOut out;
42   CborOutInit(buffer, buffer_size, &out);
43   CborWriteMap(/*num_elements=*/1, &out);
44   // Add the algorithm.
45   CborWriteInt(kCoseHeaderAlgLabel, &out);
46   CborWriteInt(DICE_COSE_KEY_ALG_VALUE, &out);
47   if (CborOutOverflowed(&out)) {
48     return kDiceResultBufferTooSmall;
49   }
50   *encoded_size = CborOutSize(&out);
51   return kDiceResultOk;
52 }
53 
EncodeCoseTbs(const uint8_t * protected_attributes,size_t protected_attributes_size,const uint8_t * payload,size_t payload_size,const uint8_t * aad,size_t aad_size,size_t buffer_size,uint8_t * buffer,size_t * encoded_size)54 static DiceResult EncodeCoseTbs(const uint8_t* protected_attributes,
55                                 size_t protected_attributes_size,
56                                 const uint8_t* payload, size_t payload_size,
57                                 const uint8_t* aad, size_t aad_size,
58                                 size_t buffer_size, uint8_t* buffer,
59                                 size_t* encoded_size) {
60   struct CborOut out;
61   CborOutInit(buffer, buffer_size, &out);
62   // TBS is an array of four elements.
63   CborWriteArray(/*num_elements=*/4, &out);
64   // Context string field.
65   CborWriteTstr("Signature1", &out);
66   // Protected attributes from COSE_Sign1.
67   CborWriteBstr(protected_attributes_size, protected_attributes, &out);
68   // Additional authenticated data.
69   CborWriteBstr(aad_size, aad, &out);
70   // Payload from COSE_Sign1.
71   CborWriteBstr(payload_size, payload, &out);
72   if (CborOutOverflowed(&out)) {
73     return kDiceResultBufferTooSmall;
74   }
75   *encoded_size = CborOutSize(&out);
76   return kDiceResultOk;
77 }
78 
EncodeCoseSign1(const uint8_t * protected_attributes,size_t protected_attributes_size,const uint8_t * payload,size_t payload_size,const uint8_t signature[DICE_SIGNATURE_SIZE],size_t buffer_size,uint8_t * buffer,size_t * encoded_size)79 static DiceResult EncodeCoseSign1(const uint8_t* protected_attributes,
80                                   size_t protected_attributes_size,
81                                   const uint8_t* payload, size_t payload_size,
82                                   const uint8_t signature[DICE_SIGNATURE_SIZE],
83                                   size_t buffer_size, uint8_t* buffer,
84                                   size_t* encoded_size) {
85   struct CborOut out;
86   CborOutInit(buffer, buffer_size, &out);
87   // COSE_Sign1 is an array of four elements.
88   CborWriteArray(/*num_elements=*/4, &out);
89   // Protected attributes.
90   CborWriteBstr(protected_attributes_size, protected_attributes, &out);
91   // Empty map for unprotected attributes.
92   CborWriteMap(/*num_pairs=*/0, &out);
93   // Payload.
94   CborWriteBstr(payload_size, payload, &out);
95   // Signature.
96   CborWriteBstr(/*num_elements=*/DICE_SIGNATURE_SIZE, signature, &out);
97   if (CborOutOverflowed(&out)) {
98     return kDiceResultBufferTooSmall;
99   }
100   *encoded_size = CborOutSize(&out);
101   return kDiceResultOk;
102 }
103 
DiceCoseSignAndEncodeSign1(void * context,const uint8_t * payload,size_t payload_size,const uint8_t * aad,size_t aad_size,const uint8_t private_key[DICE_PRIVATE_KEY_SIZE],size_t buffer_size,uint8_t * buffer,size_t * encoded_size)104 DiceResult DiceCoseSignAndEncodeSign1(
105     void* context, const uint8_t* payload, size_t payload_size,
106     const uint8_t* aad, size_t aad_size,
107     const uint8_t private_key[DICE_PRIVATE_KEY_SIZE], size_t buffer_size,
108     uint8_t* buffer, size_t* encoded_size) {
109   DiceResult result;
110 
111   *encoded_size = 0;
112 
113   // The encoded protected attributes are used in the TBS and the final
114   // COSE_Sign1 structure.
115   uint8_t protected_attributes[DICE_MAX_PROTECTED_ATTRIBUTES_SIZE];
116   size_t protected_attributes_size = 0;
117   result = EncodeProtectedAttributes(sizeof(protected_attributes),
118                                      protected_attributes,
119                                      &protected_attributes_size);
120   if (result != kDiceResultOk) {
121     return result;
122   }
123 
124   // Construct a To-Be-Signed (TBS) structure based on the relevant fields of
125   // the COSE_Sign1.
126   result = EncodeCoseTbs(protected_attributes, protected_attributes_size,
127                          payload, payload_size, aad, aad_size, buffer_size,
128                          buffer, encoded_size);
129   if (result != kDiceResultOk) {
130     return result;
131   }
132 
133   // Sign the TBS with the authority key.
134   uint8_t signature[DICE_SIGNATURE_SIZE];
135   result = DiceSign(context, buffer, *encoded_size, private_key, signature);
136   if (result != kDiceResultOk) {
137     return result;
138   }
139 
140   // The final certificate is an untagged COSE_Sign1 structure.
141   return EncodeCoseSign1(protected_attributes, protected_attributes_size,
142                          payload, payload_size, signature, buffer_size, buffer,
143                          encoded_size);
144 }
145 
146 // Encodes a CBOR Web Token (CWT) with an issuer, subject, and additional
147 // fields.
EncodeCwt(void * context,const DiceInputValues * input_values,const char * authority_id_hex,const char * subject_id_hex,const uint8_t * encoded_public_key,size_t encoded_public_key_size,size_t buffer_size,uint8_t * buffer,size_t * encoded_size)148 static DiceResult EncodeCwt(void* context, const DiceInputValues* input_values,
149                             const char* authority_id_hex,
150                             const char* subject_id_hex,
151                             const uint8_t* encoded_public_key,
152                             size_t encoded_public_key_size, size_t buffer_size,
153                             uint8_t* buffer, size_t* encoded_size) {
154   // Constants per RFC 8392.
155   const int64_t kCwtIssuerLabel = 1;
156   const int64_t kCwtSubjectLabel = 2;
157   // Constants per the Open Profile for DICE specification.
158   const int64_t kCodeHashLabel = -4670545;
159   const int64_t kCodeDescriptorLabel = -4670546;
160   const int64_t kConfigHashLabel = -4670547;
161   const int64_t kConfigDescriptorLabel = -4670548;
162   const int64_t kAuthorityHashLabel = -4670549;
163   const int64_t kAuthorityDescriptorLabel = -4670550;
164   const int64_t kModeLabel = -4670551;
165   const int64_t kSubjectPublicKeyLabel = -4670552;
166   const int64_t kKeyUsageLabel = -4670553;
167   // Key usage constant per RFC 5280.
168   const uint8_t kKeyUsageCertSign = 32;
169 
170   // Count the number of entries.
171   uint32_t map_pairs = 7;
172   if (input_values->code_descriptor_size > 0) {
173     map_pairs += 1;
174   }
175   if (input_values->config_type == kDiceConfigTypeDescriptor) {
176     map_pairs += 2;
177   } else {
178     map_pairs += 1;
179   }
180   if (input_values->authority_descriptor_size > 0) {
181     map_pairs += 1;
182   }
183 
184   struct CborOut out;
185   CborOutInit(buffer, buffer_size, &out);
186   CborWriteMap(map_pairs, &out);
187   // Add the issuer.
188   CborWriteInt(kCwtIssuerLabel, &out);
189   CborWriteTstr(authority_id_hex, &out);
190   // Add the subject.
191   CborWriteInt(kCwtSubjectLabel, &out);
192   CborWriteTstr(subject_id_hex, &out);
193   // Add the code hash.
194   CborWriteInt(kCodeHashLabel, &out);
195   CborWriteBstr(DICE_HASH_SIZE, input_values->code_hash, &out);
196   // Add the code descriptor, if provided.
197   if (input_values->code_descriptor_size > 0) {
198     CborWriteInt(kCodeDescriptorLabel, &out);
199     CborWriteBstr(input_values->code_descriptor_size,
200                   input_values->code_descriptor, &out);
201   }
202   // Add the config inputs.
203   if (input_values->config_type == kDiceConfigTypeDescriptor) {
204     uint8_t config_descriptor_hash[DICE_HASH_SIZE];
205     DiceResult result =
206         DiceHash(context, input_values->config_descriptor,
207                  input_values->config_descriptor_size, config_descriptor_hash);
208     if (result != kDiceResultOk) {
209       return result;
210     }
211     // Add the config descriptor.
212     CborWriteInt(kConfigDescriptorLabel, &out);
213     CborWriteBstr(input_values->config_descriptor_size,
214                   input_values->config_descriptor, &out);
215     // Add the Config hash.
216     CborWriteInt(kConfigHashLabel, &out);
217     CborWriteBstr(DICE_HASH_SIZE, config_descriptor_hash, &out);
218   } else if (input_values->config_type == kDiceConfigTypeInline) {
219     // Add the inline config.
220     CborWriteInt(kConfigDescriptorLabel, &out);
221     CborWriteBstr(DICE_INLINE_CONFIG_SIZE, input_values->config_value, &out);
222   }
223   // Add the authority inputs.
224   CborWriteInt(kAuthorityHashLabel, &out);
225   CborWriteBstr(DICE_HASH_SIZE, input_values->authority_hash, &out);
226   if (input_values->authority_descriptor_size > 0) {
227     CborWriteInt(kAuthorityDescriptorLabel, &out);
228     CborWriteBstr(input_values->authority_descriptor_size,
229                   input_values->authority_descriptor, &out);
230   }
231   uint8_t mode_byte = input_values->mode;
232   uint8_t key_usage = kKeyUsageCertSign;
233   // Add the mode input.
234   CborWriteInt(kModeLabel, &out);
235   CborWriteBstr(/*data_sisze=*/1, &mode_byte, &out);
236   // Add the subject public key.
237   CborWriteInt(kSubjectPublicKeyLabel, &out);
238   CborWriteBstr(encoded_public_key_size, encoded_public_key, &out);
239   // Add the key usage.
240   CborWriteInt(kKeyUsageLabel, &out);
241   CborWriteBstr(/*data_size=*/1, &key_usage, &out);
242   if (CborOutOverflowed(&out)) {
243     return kDiceResultBufferTooSmall;
244   }
245   *encoded_size = CborOutSize(&out);
246   return kDiceResultOk;
247 }
248 
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)249 DiceResult DiceGenerateCertificate(
250     void* context,
251     const uint8_t subject_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
252     const uint8_t authority_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE],
253     const DiceInputValues* input_values, size_t certificate_buffer_size,
254     uint8_t* certificate, size_t* certificate_actual_size) {
255   DiceResult result = kDiceResultOk;
256 
257   *certificate_actual_size = 0;
258   if (input_values->config_type != kDiceConfigTypeDescriptor &&
259       input_values->config_type != kDiceConfigTypeInline) {
260     return kDiceResultInvalidInput;
261   }
262 
263   // Declare buffers which are cleared on 'goto out'.
264   uint8_t subject_private_key[DICE_PRIVATE_KEY_SIZE];
265   uint8_t authority_private_key[DICE_PRIVATE_KEY_SIZE];
266 
267   // Derive keys and IDs from the private key seeds.
268   uint8_t subject_public_key[DICE_PUBLIC_KEY_SIZE];
269   result = DiceKeypairFromSeed(context, subject_private_key_seed,
270                                subject_public_key, subject_private_key);
271   if (result != kDiceResultOk) {
272     goto out;
273   }
274 
275   uint8_t subject_id[DICE_ID_SIZE];
276   result = DiceDeriveCdiCertificateId(context, subject_public_key,
277                                       DICE_PUBLIC_KEY_SIZE, subject_id);
278   if (result != kDiceResultOk) {
279     goto out;
280   }
281   char subject_id_hex[41];
282   DiceHexEncode(subject_id, sizeof(subject_id), subject_id_hex,
283                 sizeof(subject_id_hex));
284   subject_id_hex[sizeof(subject_id_hex) - 1] = '\0';
285 
286   uint8_t authority_public_key[DICE_PUBLIC_KEY_SIZE];
287   result = DiceKeypairFromSeed(context, authority_private_key_seed,
288                                authority_public_key, authority_private_key);
289   if (result != kDiceResultOk) {
290     goto out;
291   }
292 
293   uint8_t authority_id[DICE_ID_SIZE];
294   result = DiceDeriveCdiCertificateId(context, authority_public_key,
295                                       DICE_PUBLIC_KEY_SIZE, authority_id);
296   if (result != kDiceResultOk) {
297     goto out;
298   }
299   char authority_id_hex[41];
300   DiceHexEncode(authority_id, sizeof(authority_id), authority_id_hex,
301                 sizeof(authority_id_hex));
302   authority_id_hex[sizeof(authority_id_hex) - 1] = '\0';
303 
304   // The public key encoded as a COSE_Key structure is embedded in the CWT.
305   uint8_t encoded_public_key[DICE_MAX_PUBLIC_KEY_SIZE];
306   size_t encoded_public_key_size = 0;
307   result = DiceCoseEncodePublicKey(
308       context, subject_public_key, sizeof(encoded_public_key),
309       encoded_public_key, &encoded_public_key_size);
310   if (result != kDiceResultOk) {
311     goto out;
312   }
313 
314   // The CWT is the payload in both the TBS and the final COSE_Sign1 structure.
315   uint8_t payload[DICE_MAX_CERTIFICATE_SIZE];
316   size_t payload_size = 0;
317   result = EncodeCwt(context, input_values, authority_id_hex, subject_id_hex,
318                      encoded_public_key, encoded_public_key_size,
319                      sizeof(payload), payload, &payload_size);
320   if (result != kDiceResultOk) {
321     goto out;
322   }
323 
324   result = DiceCoseSignAndEncodeSign1(
325       context, payload, payload_size, /*aad=*/NULL, /*aad_size=*/0,
326       authority_private_key, certificate_buffer_size, certificate,
327       certificate_actual_size);
328 
329 out:
330   DiceClearMemory(context, sizeof(subject_private_key), subject_private_key);
331   DiceClearMemory(context, sizeof(authority_private_key),
332                   authority_private_key);
333 
334   return result;
335 }
336