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