xref: /aosp_15_r20/external/open-dice/src/dice.c (revision 60b67249c2e226f42f35cc6cfe66c6048e0bae6b)
1*60b67249SAndroid Build Coastguard Worker // Copyright 2020 Google LLC
2*60b67249SAndroid Build Coastguard Worker //
3*60b67249SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*60b67249SAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*60b67249SAndroid Build Coastguard Worker // the License at
6*60b67249SAndroid Build Coastguard Worker //
7*60b67249SAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*60b67249SAndroid Build Coastguard Worker //
9*60b67249SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*60b67249SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*60b67249SAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*60b67249SAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*60b67249SAndroid Build Coastguard Worker // the License.
14*60b67249SAndroid Build Coastguard Worker 
15*60b67249SAndroid Build Coastguard Worker #include "dice/dice.h"
16*60b67249SAndroid Build Coastguard Worker 
17*60b67249SAndroid Build Coastguard Worker #include <string.h>
18*60b67249SAndroid Build Coastguard Worker 
19*60b67249SAndroid Build Coastguard Worker #include "dice/ops.h"
20*60b67249SAndroid Build Coastguard Worker 
21*60b67249SAndroid Build Coastguard Worker #define DICE_CODE_SIZE DICE_HASH_SIZE
22*60b67249SAndroid Build Coastguard Worker #define DICE_CONFIG_SIZE DICE_INLINE_CONFIG_SIZE
23*60b67249SAndroid Build Coastguard Worker #define DICE_AUTHORITY_SIZE DICE_HASH_SIZE
24*60b67249SAndroid Build Coastguard Worker #define DICE_MODE_SIZE 1
25*60b67249SAndroid Build Coastguard Worker 
26*60b67249SAndroid Build Coastguard Worker static const uint8_t kAsymSalt[] = {
27*60b67249SAndroid Build Coastguard Worker     0x63, 0xB6, 0xA0, 0x4D, 0x2C, 0x07, 0x7F, 0xC1, 0x0F, 0x63, 0x9F,
28*60b67249SAndroid Build Coastguard Worker     0x21, 0xDA, 0x79, 0x38, 0x44, 0x35, 0x6C, 0xC2, 0xB0, 0xB4, 0x41,
29*60b67249SAndroid Build Coastguard Worker     0xB3, 0xA7, 0x71, 0x24, 0x03, 0x5C, 0x03, 0xF8, 0xE1, 0xBE, 0x60,
30*60b67249SAndroid Build Coastguard Worker     0x35, 0xD3, 0x1F, 0x28, 0x28, 0x21, 0xA7, 0x45, 0x0A, 0x02, 0x22,
31*60b67249SAndroid Build Coastguard Worker     0x2A, 0xB1, 0xB3, 0xCF, 0xF1, 0x67, 0x9B, 0x05, 0xAB, 0x1C, 0xA5,
32*60b67249SAndroid Build Coastguard Worker     0xD1, 0xAF, 0xFB, 0x78, 0x9C, 0xCD, 0x2B, 0x0B, 0x3B};
33*60b67249SAndroid Build Coastguard Worker static const size_t kAsymSaltSize = 64;
34*60b67249SAndroid Build Coastguard Worker 
35*60b67249SAndroid Build Coastguard Worker static const uint8_t kIdSalt[] = {
36*60b67249SAndroid Build Coastguard Worker     0xDB, 0xDB, 0xAE, 0xBC, 0x80, 0x20, 0xDA, 0x9F, 0xF0, 0xDD, 0x5A,
37*60b67249SAndroid Build Coastguard Worker     0x24, 0xC8, 0x3A, 0xA5, 0xA5, 0x42, 0x86, 0xDF, 0xC2, 0x63, 0x03,
38*60b67249SAndroid Build Coastguard Worker     0x1E, 0x32, 0x9B, 0x4D, 0xA1, 0x48, 0x43, 0x06, 0x59, 0xFE, 0x62,
39*60b67249SAndroid Build Coastguard Worker     0xCD, 0xB5, 0xB7, 0xE1, 0xE0, 0x0F, 0xC6, 0x80, 0x30, 0x67, 0x11,
40*60b67249SAndroid Build Coastguard Worker     0xEB, 0x44, 0x4A, 0xF7, 0x72, 0x09, 0x35, 0x94, 0x96, 0xFC, 0xFF,
41*60b67249SAndroid Build Coastguard Worker     0x1D, 0xB9, 0x52, 0x0B, 0xA5, 0x1C, 0x7B, 0x29, 0xEA};
42*60b67249SAndroid Build Coastguard Worker static const size_t kIdSaltSize = 64;
43*60b67249SAndroid Build Coastguard Worker 
DiceDeriveCdiPrivateKeySeed(void * context,const uint8_t cdi_attest[DICE_CDI_SIZE],uint8_t cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE])44*60b67249SAndroid Build Coastguard Worker DiceResult DiceDeriveCdiPrivateKeySeed(
45*60b67249SAndroid Build Coastguard Worker     void* context, const uint8_t cdi_attest[DICE_CDI_SIZE],
46*60b67249SAndroid Build Coastguard Worker     uint8_t cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE]) {
47*60b67249SAndroid Build Coastguard Worker   // Use the CDI as input key material, with fixed salt and info.
48*60b67249SAndroid Build Coastguard Worker   return DiceKdf(context, /*length=*/DICE_PRIVATE_KEY_SEED_SIZE, cdi_attest,
49*60b67249SAndroid Build Coastguard Worker                  /*ikm_size=*/DICE_CDI_SIZE, kAsymSalt, kAsymSaltSize,
50*60b67249SAndroid Build Coastguard Worker                  /*info=*/(const uint8_t*)"Key Pair", /*info_size=*/8,
51*60b67249SAndroid Build Coastguard Worker                  cdi_private_key_seed);
52*60b67249SAndroid Build Coastguard Worker }
53*60b67249SAndroid Build Coastguard Worker 
DiceDeriveCdiCertificateId(void * context,const uint8_t * cdi_public_key,size_t cdi_public_key_size,uint8_t id[DICE_ID_SIZE])54*60b67249SAndroid Build Coastguard Worker DiceResult DiceDeriveCdiCertificateId(void* context,
55*60b67249SAndroid Build Coastguard Worker                                       const uint8_t* cdi_public_key,
56*60b67249SAndroid Build Coastguard Worker                                       size_t cdi_public_key_size,
57*60b67249SAndroid Build Coastguard Worker                                       uint8_t id[DICE_ID_SIZE]) {
58*60b67249SAndroid Build Coastguard Worker   // Use the public key as input key material, with fixed salt and info.
59*60b67249SAndroid Build Coastguard Worker   DiceResult result =
60*60b67249SAndroid Build Coastguard Worker       DiceKdf(context, /*length=*/20, cdi_public_key, cdi_public_key_size,
61*60b67249SAndroid Build Coastguard Worker               kIdSalt, kIdSaltSize,
62*60b67249SAndroid Build Coastguard Worker               /*info=*/(const uint8_t*)"ID", /*info_size=*/2, id);
63*60b67249SAndroid Build Coastguard Worker   if (result == kDiceResultOk) {
64*60b67249SAndroid Build Coastguard Worker     // Clear the top bit to keep the integer positive.
65*60b67249SAndroid Build Coastguard Worker     id[0] &= ~0x80;
66*60b67249SAndroid Build Coastguard Worker   }
67*60b67249SAndroid Build Coastguard Worker   return result;
68*60b67249SAndroid Build Coastguard Worker }
69*60b67249SAndroid Build Coastguard Worker 
DiceMainFlow(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 next_cdi_certificate_buffer_size,uint8_t * next_cdi_certificate,size_t * next_cdi_certificate_actual_size,uint8_t next_cdi_attest[DICE_CDI_SIZE],uint8_t next_cdi_seal[DICE_CDI_SIZE])70*60b67249SAndroid Build Coastguard Worker DiceResult DiceMainFlow(void* context,
71*60b67249SAndroid Build Coastguard Worker                         const uint8_t current_cdi_attest[DICE_CDI_SIZE],
72*60b67249SAndroid Build Coastguard Worker                         const uint8_t current_cdi_seal[DICE_CDI_SIZE],
73*60b67249SAndroid Build Coastguard Worker                         const DiceInputValues* input_values,
74*60b67249SAndroid Build Coastguard Worker                         size_t next_cdi_certificate_buffer_size,
75*60b67249SAndroid Build Coastguard Worker                         uint8_t* next_cdi_certificate,
76*60b67249SAndroid Build Coastguard Worker                         size_t* next_cdi_certificate_actual_size,
77*60b67249SAndroid Build Coastguard Worker                         uint8_t next_cdi_attest[DICE_CDI_SIZE],
78*60b67249SAndroid Build Coastguard Worker                         uint8_t next_cdi_seal[DICE_CDI_SIZE]) {
79*60b67249SAndroid Build Coastguard Worker   // This implementation serializes the inputs for a one-shot hash. On some
80*60b67249SAndroid Build Coastguard Worker   // platforms, using a multi-part hash operation may be more optimal. The
81*60b67249SAndroid Build Coastguard Worker   // combined input buffer has this layout:
82*60b67249SAndroid Build Coastguard Worker   // ---------------------------------------------------------------------------
83*60b67249SAndroid Build Coastguard Worker   // | Code Input | Config Input | Authority Input | Mode Input | Hidden Input |
84*60b67249SAndroid Build Coastguard Worker   // ---------------------------------------------------------------------------
85*60b67249SAndroid Build Coastguard Worker   const size_t kCodeOffset = 0;
86*60b67249SAndroid Build Coastguard Worker   const size_t kConfigOffset = kCodeOffset + DICE_CODE_SIZE;
87*60b67249SAndroid Build Coastguard Worker   const size_t kAuthorityOffset = kConfigOffset + DICE_CONFIG_SIZE;
88*60b67249SAndroid Build Coastguard Worker   const size_t kModeOffset = kAuthorityOffset + DICE_AUTHORITY_SIZE;
89*60b67249SAndroid Build Coastguard Worker   const size_t kHiddenOffset = kModeOffset + DICE_MODE_SIZE;
90*60b67249SAndroid Build Coastguard Worker 
91*60b67249SAndroid Build Coastguard Worker   DiceResult result = kDiceResultOk;
92*60b67249SAndroid Build Coastguard Worker 
93*60b67249SAndroid Build Coastguard Worker   // Declare buffers that get cleaned up on 'goto out'.
94*60b67249SAndroid Build Coastguard Worker   uint8_t input_buffer[DICE_CODE_SIZE + DICE_CONFIG_SIZE + DICE_AUTHORITY_SIZE +
95*60b67249SAndroid Build Coastguard Worker                        DICE_MODE_SIZE + DICE_HIDDEN_SIZE];
96*60b67249SAndroid Build Coastguard Worker   uint8_t attest_input_hash[DICE_HASH_SIZE];
97*60b67249SAndroid Build Coastguard Worker   uint8_t seal_input_hash[DICE_HASH_SIZE];
98*60b67249SAndroid Build Coastguard Worker   uint8_t current_cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
99*60b67249SAndroid Build Coastguard Worker   uint8_t next_cdi_private_key_seed[DICE_PRIVATE_KEY_SEED_SIZE];
100*60b67249SAndroid Build Coastguard Worker 
101*60b67249SAndroid Build Coastguard Worker   // Assemble the input buffer.
102*60b67249SAndroid Build Coastguard Worker   memcpy(&input_buffer[kCodeOffset], input_values->code_hash, DICE_CODE_SIZE);
103*60b67249SAndroid Build Coastguard Worker   if (input_values->config_type == kDiceConfigTypeInline) {
104*60b67249SAndroid Build Coastguard Worker     memcpy(&input_buffer[kConfigOffset], input_values->config_value,
105*60b67249SAndroid Build Coastguard Worker            DICE_CONFIG_SIZE);
106*60b67249SAndroid Build Coastguard Worker   } else if (!input_values->config_descriptor) {
107*60b67249SAndroid Build Coastguard Worker     result = kDiceResultInvalidInput;
108*60b67249SAndroid Build Coastguard Worker     goto out;
109*60b67249SAndroid Build Coastguard Worker   } else {
110*60b67249SAndroid Build Coastguard Worker     result = DiceHash(context, input_values->config_descriptor,
111*60b67249SAndroid Build Coastguard Worker                       input_values->config_descriptor_size,
112*60b67249SAndroid Build Coastguard Worker                       &input_buffer[kConfigOffset]);
113*60b67249SAndroid Build Coastguard Worker     if (result != kDiceResultOk) {
114*60b67249SAndroid Build Coastguard Worker       goto out;
115*60b67249SAndroid Build Coastguard Worker     }
116*60b67249SAndroid Build Coastguard Worker   }
117*60b67249SAndroid Build Coastguard Worker   memcpy(&input_buffer[kAuthorityOffset], input_values->authority_hash,
118*60b67249SAndroid Build Coastguard Worker          DICE_AUTHORITY_SIZE);
119*60b67249SAndroid Build Coastguard Worker   input_buffer[kModeOffset] = input_values->mode;
120*60b67249SAndroid Build Coastguard Worker   memcpy(&input_buffer[kHiddenOffset], input_values->hidden, DICE_HIDDEN_SIZE);
121*60b67249SAndroid Build Coastguard Worker 
122*60b67249SAndroid Build Coastguard Worker   // Hash the appropriate input values for both attestation and sealing. For
123*60b67249SAndroid Build Coastguard Worker   // attestation all the inputs are used, and for sealing only the authority,
124*60b67249SAndroid Build Coastguard Worker   // mode, and hidden inputs are used.
125*60b67249SAndroid Build Coastguard Worker   result =
126*60b67249SAndroid Build Coastguard Worker       DiceHash(context, input_buffer, sizeof(input_buffer), attest_input_hash);
127*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
128*60b67249SAndroid Build Coastguard Worker     goto out;
129*60b67249SAndroid Build Coastguard Worker   }
130*60b67249SAndroid Build Coastguard Worker   result = DiceHash(context, &input_buffer[kAuthorityOffset],
131*60b67249SAndroid Build Coastguard Worker                     DICE_AUTHORITY_SIZE + DICE_MODE_SIZE + DICE_HIDDEN_SIZE,
132*60b67249SAndroid Build Coastguard Worker                     seal_input_hash);
133*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
134*60b67249SAndroid Build Coastguard Worker     goto out;
135*60b67249SAndroid Build Coastguard Worker   }
136*60b67249SAndroid Build Coastguard Worker 
137*60b67249SAndroid Build Coastguard Worker   // Compute the next CDI values. For each of these the current CDI value is
138*60b67249SAndroid Build Coastguard Worker   // used as input key material and the input hash is used as salt.
139*60b67249SAndroid Build Coastguard Worker   result = DiceKdf(context, /*length=*/DICE_CDI_SIZE, current_cdi_attest,
140*60b67249SAndroid Build Coastguard Worker                    /*ikm_size=*/DICE_CDI_SIZE, attest_input_hash,
141*60b67249SAndroid Build Coastguard Worker                    /*salt_size=*/DICE_HASH_SIZE,
142*60b67249SAndroid Build Coastguard Worker                    /*info=*/(const uint8_t*)"CDI_Attest", /*info_size=*/10,
143*60b67249SAndroid Build Coastguard Worker                    next_cdi_attest);
144*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
145*60b67249SAndroid Build Coastguard Worker     goto out;
146*60b67249SAndroid Build Coastguard Worker   }
147*60b67249SAndroid Build Coastguard Worker   result = DiceKdf(
148*60b67249SAndroid Build Coastguard Worker       context, /*length=*/DICE_CDI_SIZE, current_cdi_seal,
149*60b67249SAndroid Build Coastguard Worker       /*ikm_size=*/DICE_CDI_SIZE, seal_input_hash, /*salt_size=*/DICE_HASH_SIZE,
150*60b67249SAndroid Build Coastguard Worker       /*info=*/(const uint8_t*)"CDI_Seal", /*info_size=*/8, next_cdi_seal);
151*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
152*60b67249SAndroid Build Coastguard Worker     goto out;
153*60b67249SAndroid Build Coastguard Worker   }
154*60b67249SAndroid Build Coastguard Worker 
155*60b67249SAndroid Build Coastguard Worker   // Create the CDI certificate only if it is required (i.e. non-null/non-zero
156*60b67249SAndroid Build Coastguard Worker   // values are provided for the next CDI certificate parameters).
157*60b67249SAndroid Build Coastguard Worker   if (next_cdi_certificate == NULL &&
158*60b67249SAndroid Build Coastguard Worker       next_cdi_certificate_actual_size == NULL &&
159*60b67249SAndroid Build Coastguard Worker       next_cdi_certificate_buffer_size == 0) {
160*60b67249SAndroid Build Coastguard Worker     goto out;
161*60b67249SAndroid Build Coastguard Worker   }
162*60b67249SAndroid Build Coastguard Worker 
163*60b67249SAndroid Build Coastguard Worker   // Derive asymmetric private key seeds from the attestation CDI values.
164*60b67249SAndroid Build Coastguard Worker   result = DiceDeriveCdiPrivateKeySeed(context, current_cdi_attest,
165*60b67249SAndroid Build Coastguard Worker                                        current_cdi_private_key_seed);
166*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
167*60b67249SAndroid Build Coastguard Worker     goto out;
168*60b67249SAndroid Build Coastguard Worker   }
169*60b67249SAndroid Build Coastguard Worker   result = DiceDeriveCdiPrivateKeySeed(context, next_cdi_attest,
170*60b67249SAndroid Build Coastguard Worker                                        next_cdi_private_key_seed);
171*60b67249SAndroid Build Coastguard Worker   if (result != kDiceResultOk) {
172*60b67249SAndroid Build Coastguard Worker     goto out;
173*60b67249SAndroid Build Coastguard Worker   }
174*60b67249SAndroid Build Coastguard Worker 
175*60b67249SAndroid Build Coastguard Worker   // Generate a certificate for |next_cdi_private_key_seed| with
176*60b67249SAndroid Build Coastguard Worker   // |current_cdi_private_key_seed| as the authority.
177*60b67249SAndroid Build Coastguard Worker   result = DiceGenerateCertificate(
178*60b67249SAndroid Build Coastguard Worker       context, next_cdi_private_key_seed, current_cdi_private_key_seed,
179*60b67249SAndroid Build Coastguard Worker       input_values, next_cdi_certificate_buffer_size, next_cdi_certificate,
180*60b67249SAndroid Build Coastguard Worker       next_cdi_certificate_actual_size);
181*60b67249SAndroid Build Coastguard Worker 
182*60b67249SAndroid Build Coastguard Worker out:
183*60b67249SAndroid Build Coastguard Worker   // Clear sensitive memory.
184*60b67249SAndroid Build Coastguard Worker   DiceClearMemory(context, sizeof(input_buffer), input_buffer);
185*60b67249SAndroid Build Coastguard Worker   DiceClearMemory(context, sizeof(attest_input_hash), attest_input_hash);
186*60b67249SAndroid Build Coastguard Worker   DiceClearMemory(context, sizeof(seal_input_hash), seal_input_hash);
187*60b67249SAndroid Build Coastguard Worker   DiceClearMemory(context, sizeof(current_cdi_private_key_seed),
188*60b67249SAndroid Build Coastguard Worker                   current_cdi_private_key_seed);
189*60b67249SAndroid Build Coastguard Worker   DiceClearMemory(context, sizeof(next_cdi_private_key_seed),
190*60b67249SAndroid Build Coastguard Worker                   next_cdi_private_key_seed);
191*60b67249SAndroid Build Coastguard Worker   return result;
192*60b67249SAndroid Build Coastguard Worker }
193