• 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 #include "dice/android/bcc.h"
16 
17 #include <string.h>
18 
19 #include "dice/cbor_reader.h"
20 #include "dice/cbor_writer.h"
21 #include "dice/ops/trait/cose.h"
22 #include "dice/dice.h"
23 #include "dice/ops.h"
24 
25 // Completely gratuitous bit twiddling.
PopulationCount(uint32_t n)26 static size_t PopulationCount(uint32_t n) {
27   n = n - ((n >> 1) & 0x55555555);
28   n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
29   return (((n + (n >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
30 }
31 
BccFormatConfigDescriptor(const BccConfigValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * actual_size)32 DiceResult BccFormatConfigDescriptor(const BccConfigValues* input_values,
33                                      size_t buffer_size, uint8_t* buffer,
34                                      size_t* actual_size) {
35   static const int64_t kComponentNameLabel = -70002;
36   static const int64_t kComponentVersionLabel = -70003;
37   static const int64_t kResettableLabel = -70004;
38 
39   // BccConfigDescriptor = {
40   //   ? -70002 : tstr,     ; Component name
41   //   ? -70003 : int,      ; Component version
42   //   ? -70004 : null,     ; Resettable
43   // }
44   struct CborOut out;
45   CborOutInit(buffer, buffer_size, &out);
46   CborWriteMap(PopulationCount(input_values->inputs), &out);
47   if (input_values->inputs & BCC_INPUT_COMPONENT_NAME &&
48       input_values->component_name) {
49     CborWriteInt(kComponentNameLabel, &out);
50     CborWriteTstr(input_values->component_name, &out);
51   }
52   if (input_values->inputs & BCC_INPUT_COMPONENT_VERSION) {
53     CborWriteInt(kComponentVersionLabel, &out);
54     CborWriteUint(input_values->component_version, &out);
55   }
56   if (input_values->inputs & BCC_INPUT_RESETTABLE) {
57     CborWriteInt(kResettableLabel, &out);
58     CborWriteNull(&out);
59   }
60   if (CborOutOverflowed(&out)) {
61     return kDiceResultBufferTooSmall;
62   }
63   *actual_size = CborOutSize(&out);
64   return kDiceResultOk;
65 }
66 
BccMainFlow(void * context,const uint8_t current_cdi_attest[DICE_CDI_SIZE],const uint8_t current_cdi_seal[DICE_CDI_SIZE],const uint8_t * bcc,size_t bcc_size,const DiceInputValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * actual_size,uint8_t next_cdi_attest[DICE_CDI_SIZE],uint8_t next_cdi_seal[DICE_CDI_SIZE])67 DiceResult BccMainFlow(void* context,
68                        const uint8_t current_cdi_attest[DICE_CDI_SIZE],
69                        const uint8_t current_cdi_seal[DICE_CDI_SIZE],
70                        const uint8_t* bcc, size_t bcc_size,
71                        const DiceInputValues* input_values, size_t buffer_size,
72                        uint8_t* buffer, size_t* actual_size,
73                        uint8_t next_cdi_attest[DICE_CDI_SIZE],
74                        uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
75   DiceResult result;
76   enum CborReadResult res;
77   struct CborIn in;
78   size_t bcc_item_count;
79 
80   // The BCC has a more detailed internal structure, but those details aren't
81   // relevant to the work of this function.
82   //
83   // Bcc = [
84   //   COSE_Key,         ; Root public key
85   //   + COSE_Sign1,     ; Bcc entries
86   // ]
87   CborInInit(bcc, bcc_size, &in);
88   res = CborReadArray(&in, &bcc_item_count);
89   if (res != CBOR_READ_RESULT_OK) {
90     return kDiceResultInvalidInput;
91   }
92 
93   if (bcc_item_count < 2 || bcc_item_count == SIZE_MAX) {
94     // There should at least be the public key and one entry.
95     return kDiceResultInvalidInput;
96   }
97 
98   // Measure the existing BCC entries.
99   size_t bcc_items_offset = CborInOffset(&in);
100   for (size_t bcc_pos = 0; bcc_pos < bcc_item_count; ++bcc_pos) {
101     res = CborReadSkip(&in);
102     if (res != CBOR_READ_RESULT_OK) {
103       return kDiceResultInvalidInput;
104     }
105   }
106   size_t bcc_items_size = CborInOffset(&in) - bcc_items_offset;
107 
108   // Copy to the new buffer, with space in the BCC for one more entry.
109   struct CborOut out;
110   CborOutInit(buffer, buffer_size, &out);
111   CborWriteArray(bcc_item_count + 1, &out);
112   if (CborOutOverflowed(&out) ||
113       bcc_items_size > buffer_size - CborOutSize(&out)) {
114     return kDiceResultBufferTooSmall;
115   }
116   memcpy(buffer + CborOutSize(&out), bcc + bcc_items_offset, bcc_items_size);
117 
118   size_t certificate_size;
119   result =
120       DiceMainFlow(context, current_cdi_attest, current_cdi_seal, input_values,
121                    buffer_size - (CborOutSize(&out) + bcc_items_size),
122                    buffer + CborOutSize(&out) + bcc_items_size,
123                    &certificate_size, next_cdi_attest, next_cdi_seal);
124   if (result != kDiceResultOk) {
125     return result;
126   }
127 
128   *actual_size = CborOutSize(&out) + bcc_items_size + certificate_size;
129   return kDiceResultOk;
130 }
131 
BccMainFlowWithNewBcc(void * context,const uint8_t current_cdi_attest[DICE_CDI_SIZE],const uint8_t current_cdi_seal[DICE_CDI_SIZE],const DiceInputValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * bcc_size,uint8_t next_cdi_attest[DICE_CDI_SIZE],uint8_t next_cdi_seal[DICE_CDI_SIZE])132 static DiceResult BccMainFlowWithNewBcc(
133     void* context, const uint8_t current_cdi_attest[DICE_CDI_SIZE],
134     const uint8_t current_cdi_seal[DICE_CDI_SIZE],
135     const DiceInputValues* input_values, size_t buffer_size, uint8_t* buffer,
136     size_t* bcc_size, uint8_t next_cdi_attest[DICE_CDI_SIZE],
137     uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
138   uint8_t current_cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
139   uint8_t attestation_public_key[DICE_PUBLIC_KEY_SIZE];
140   uint8_t attestation_private_key[DICE_PRIVATE_KEY_SIZE];
141   // Derive an asymmetric private key seed from the current attestation CDI
142   // value.
143   DiceResult result = DiceDeriveCdiPrivateKeySeed(context, current_cdi_attest,
144                                                   current_cdi_private_key_seed);
145   if (result != kDiceResultOk) {
146     goto out;
147   }
148   // Derive attestation key pair.
149   result = DiceKeypairFromSeed(context, current_cdi_private_key_seed,
150                                attestation_public_key, attestation_private_key);
151   if (result != kDiceResultOk) {
152     goto out;
153   }
154 
155   // Consruct the BCC from the attestation public key and the next CDI
156   // certificate.
157   struct CborOut out;
158   CborOutInit(buffer, buffer_size, &out);
159   CborWriteArray(2, &out);
160   if (CborOutOverflowed(&out)) {
161     result = kDiceResultBufferTooSmall;
162     goto out;
163   }
164   size_t encoded_size_used = CborOutSize(&out);
165   buffer += encoded_size_used;
166   buffer_size -= encoded_size_used;
167 
168   size_t encoded_pub_key_size = 0;
169   result = DiceCoseEncodePublicKey(context, attestation_public_key, buffer_size,
170                                    buffer, &encoded_pub_key_size);
171   if (result != kDiceResultOk) {
172     goto out;
173   }
174 
175   buffer += encoded_pub_key_size;
176   buffer_size -= encoded_pub_key_size;
177 
178   result = DiceMainFlow(context, current_cdi_attest, current_cdi_seal,
179                         input_values, buffer_size, buffer, bcc_size,
180                         next_cdi_attest, next_cdi_seal);
181   if (result != kDiceResultOk) {
182     return result;
183   }
184   *bcc_size += encoded_size_used + encoded_pub_key_size;
185 
186 out:
187   DiceClearMemory(context, sizeof(current_cdi_private_key_seed),
188                   current_cdi_private_key_seed);
189   DiceClearMemory(context, sizeof(attestation_private_key),
190                   attestation_private_key);
191 
192   return result;
193 }
194 
BccHandoverMainFlow(void * context,const uint8_t * bcc_handover,size_t bcc_handover_size,const DiceInputValues * input_values,size_t buffer_size,uint8_t * buffer,size_t * actual_size)195 DiceResult BccHandoverMainFlow(void* context, const uint8_t* bcc_handover,
196                                size_t bcc_handover_size,
197                                const DiceInputValues* input_values,
198                                size_t buffer_size, uint8_t* buffer,
199                                size_t* actual_size) {
200   static const int64_t kCdiAttestLabel = 1;
201   static const int64_t kCdiSealLabel = 2;
202   static const int64_t kBccLabel = 3;
203 
204   DiceResult result;
205   const uint8_t* current_cdi_attest;
206   const uint8_t* current_cdi_seal;
207   const uint8_t* bcc;
208 
209   // Extract details from the handover data.
210   //
211   // BccHandover = {
212   //   1 : bstr .size 32,     ; CDI_Attest
213   //   2 : bstr .size 32,     ; CDI_Seal
214   //   ? 3 : Bcc,             ; Certificate chain
215   // }
216   struct CborIn in;
217   int64_t label;
218   size_t item_size;
219   CborInInit(bcc_handover, bcc_handover_size, &in);
220   if (CborReadMap(&in, &item_size) != CBOR_READ_RESULT_OK || item_size < 2 ||
221       // Read the attestation CDI.
222       CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
223       label != kCdiAttestLabel ||
224       CborReadBstr(&in, &item_size, &current_cdi_attest) !=
225           CBOR_READ_RESULT_OK ||
226       item_size != DICE_CDI_SIZE ||
227       // Read the sealing CDI.
228       CborReadInt(&in, &label) != CBOR_READ_RESULT_OK ||
229       label != kCdiSealLabel ||
230       CborReadBstr(&in, &item_size, &current_cdi_seal) != CBOR_READ_RESULT_OK ||
231       item_size != DICE_CDI_SIZE) {
232     return kDiceResultInvalidInput;
233   }
234 
235   size_t bcc_size = 0;
236   // Calculate the BCC size, if the BCC is present in the BccHandover.
237   if (CborReadInt(&in, &label) == CBOR_READ_RESULT_OK) {
238     if (label != kBccLabel) {
239       return kDiceResultInvalidInput;
240     }
241     size_t bcc_start = CborInOffset(&in);
242     bcc = bcc_handover + bcc_start;
243     if (CborReadSkip(&in) != CBOR_READ_RESULT_OK) {
244       return kDiceResultInvalidInput;
245     }
246     bcc_size = CborInOffset(&in) - bcc_start;
247   }
248 
249   // Write the new handover data.
250   struct CborOut out;
251   CborOutInit(buffer, buffer_size, &out);
252   CborWriteMap(/*num_pairs=*/3, &out);
253   CborWriteInt(kCdiAttestLabel, &out);
254   uint8_t* next_cdi_attest = CborAllocBstr(DICE_CDI_SIZE, &out);
255   CborWriteInt(kCdiSealLabel, &out);
256   uint8_t* next_cdi_seal = CborAllocBstr(DICE_CDI_SIZE, &out);
257   CborWriteInt(kBccLabel, &out);
258 
259   if (CborOutOverflowed(&out) || !next_cdi_attest || !next_cdi_seal) {
260     return kDiceResultBufferTooSmall;
261   }
262 
263   if (bcc_size != 0) {
264     // If BCC is present in the bcc_handover, append the next certificate to the
265     // existing BCC.
266     result = BccMainFlow(context, current_cdi_attest, current_cdi_seal, bcc,
267                          bcc_size, input_values, buffer_size - CborOutSize(&out),
268                          buffer + CborOutSize(&out), &bcc_size, next_cdi_attest,
269                          next_cdi_seal);
270   } else {
271     // If BCC is not present in the bcc_handover, construct BCC from the public key
272     // derived from the current CDI attest and the next CDI certificate.
273     result = BccMainFlowWithNewBcc(
274         context, current_cdi_attest, current_cdi_seal, input_values,
275         buffer_size - CborOutSize(&out), buffer + CborOutSize(&out), &bcc_size,
276         next_cdi_attest, next_cdi_seal);
277   }
278   if (result != kDiceResultOk) {
279       return result;
280   }
281   *actual_size = CborOutSize(&out) + bcc_size;
282   return kDiceResultOk;
283 }
284