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