Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include "evidence.h"
26 :
27 : #include <string.h>
28 : #include "hal/hash.h"
29 : #include "hal/log.h"
30 : #include <openenclave/corelibc/stdlib.h>
31 : #include <openenclave/attestation/attester.h>
32 : #include <openenclave/attestation/verifier.h>
33 :
34 : static struct { bool initialised; } G_evidence_ctx;
35 :
36 : #define EVIDENCE_CHECK(oe_result, error_msg, statement) \
37 : { \
38 : if (OE_OK != oe_result) { \
39 : LOG("%s: result=%u (%s)\n", \
40 : error_msg, \
41 : result, \
42 : oe_result_str(oe_result)); \
43 : { statement; } \
44 : } \
45 : }
46 :
47 : // ****************************************************** //
48 : // ********** Public interface implemenetation ********** //
49 : // ****************************************************** //
50 :
51 22 : bool evidence_init() {
52 : oe_result_t result;
53 :
54 22 : explicit_bzero(&G_evidence_ctx, sizeof(G_evidence_ctx));
55 :
56 : // Initialize modules
57 22 : result = oe_attester_initialize();
58 22 : EVIDENCE_CHECK(result, "Failed to initialize attester", return false);
59 21 : result = oe_verifier_initialize();
60 21 : EVIDENCE_CHECK(result, "Failed to initialize verifier", return false);
61 :
62 21 : G_evidence_ctx.initialised = true;
63 : LOG("Evidence module initialized\n");
64 21 : return true;
65 : }
66 :
67 37 : void evidence_finalise() {
68 37 : oe_verifier_shutdown();
69 37 : oe_attester_shutdown();
70 37 : explicit_bzero(&G_evidence_ctx, sizeof(G_evidence_ctx));
71 37 : }
72 :
73 12 : bool evidence_get_format_settings(evidence_format_t* format) {
74 : oe_result_t result;
75 :
76 12 : if (!G_evidence_ctx.initialised) {
77 : LOG("Evidence module not initialised\n");
78 2 : return false;
79 : }
80 :
81 10 : if (!format || format->settings || format->settings_size) {
82 : LOG("Invalid format getter spec given\n");
83 2 : return false;
84 : }
85 :
86 8 : result = oe_verifier_get_format_settings(
87 8 : &format->id, &format->settings, &format->settings_size);
88 8 : EVIDENCE_CHECK(result, "Failed to gather format settings", return false);
89 :
90 5 : return true;
91 : }
92 :
93 7 : bool evidence_free_format_settings(uint8_t* settings) {
94 7 : if (!settings)
95 1 : return true;
96 :
97 6 : return oe_verifier_free_format_settings(settings) == OE_OK;
98 : }
99 :
100 4 : bool evidence_supports_format(oe_uuid_t format_id) {
101 4 : evidence_format_t format = {
102 : .id = format_id,
103 : .settings = NULL,
104 : .settings_size = 0,
105 : };
106 : oe_uuid_t selected_format;
107 : oe_result_t result;
108 :
109 : // Make sure we can get format settings
110 4 : if (!evidence_get_format_settings(&format))
111 2 : return false;
112 2 : evidence_free_format_settings(format.settings);
113 :
114 : // Make sure we can select format for attestation
115 2 : result = oe_attester_select_format(&format.id, 1, &selected_format);
116 2 : EVIDENCE_CHECK(result, "Failed to select attestation format", return false);
117 :
118 1 : return true;
119 : }
120 :
121 : // Generates evidence with the given format id and custom claims.
122 8 : bool evidence_generate(evidence_format_t* format,
123 : uint8_t* ccs,
124 : size_t ccs_size,
125 : uint8_t** evidence_buffer,
126 : size_t* evidence_buffer_size) {
127 : oe_result_t result;
128 8 : bool gathered_settings = false;
129 :
130 8 : if (!G_evidence_ctx.initialised) {
131 : LOG("Evidence module not initialised\n");
132 1 : goto generate_evidence_error;
133 : }
134 :
135 7 : if (!format) {
136 : LOG("Invalid evidence format\n");
137 1 : goto generate_evidence_error;
138 : }
139 :
140 6 : if (!evidence_buffer || !evidence_buffer_size) {
141 : LOG("Invalid evidence buffer/size pointers\n");
142 2 : goto generate_evidence_error;
143 : }
144 :
145 : // Gather the corresponding format settings if needed
146 : // Otherwise make sure the format is supported
147 4 : gathered_settings = false;
148 4 : if (!format->settings) {
149 3 : if (!evidence_get_format_settings(format)) {
150 : LOG("Error gathering format settings\n");
151 1 : goto generate_evidence_error;
152 : }
153 2 : gathered_settings = true;
154 : LOG("Gathered settings\n");
155 : }
156 :
157 3 : result = oe_get_evidence(&format->id,
158 : 0,
159 : ccs,
160 : ccs_size,
161 3 : format->settings,
162 : format->settings_size,
163 : evidence_buffer,
164 : evidence_buffer_size,
165 : NULL,
166 : NULL);
167 3 : EVIDENCE_CHECK(
168 : result, "Evidence generation failed", goto generate_evidence_error);
169 :
170 2 : if (gathered_settings) {
171 1 : evidence_free_format_settings(format->settings);
172 1 : format->settings = NULL;
173 1 : format->settings_size = 0;
174 : }
175 :
176 : LOG("Evidence generated successfully\n");
177 :
178 2 : return true;
179 :
180 6 : generate_evidence_error:
181 6 : if (evidence_buffer && *evidence_buffer) {
182 0 : oe_free_evidence(*evidence_buffer);
183 0 : *evidence_buffer = NULL;
184 : }
185 6 : if (evidence_buffer_size) {
186 5 : *evidence_buffer_size = 0;
187 : }
188 6 : if (gathered_settings && format->settings) {
189 1 : evidence_free_format_settings(format->settings);
190 1 : format->settings = NULL;
191 1 : format->settings_size = 0;
192 : }
193 6 : return false;
194 : }
195 :
196 10 : bool evidence_verify_and_extract_claims(oe_uuid_t format_id,
197 : uint8_t* evidence_buffer,
198 : size_t evidence_buffer_size,
199 : oe_claim_t** claims,
200 : size_t* claims_length) {
201 10 : if (!G_evidence_ctx.initialised) {
202 : LOG("Evidence module not initialised\n");
203 1 : return false;
204 : }
205 :
206 9 : if (!evidence_buffer) {
207 : LOG("Invalid evidence buffer pointer\n");
208 0 : return false;
209 : }
210 :
211 9 : if (!claims || !claims_length) {
212 0 : claims = NULL;
213 0 : claims_length = NULL;
214 : }
215 :
216 9 : oe_result_t result = oe_verify_evidence(&format_id,
217 : evidence_buffer,
218 : evidence_buffer_size,
219 : NULL,
220 : 0,
221 : NULL,
222 : 0,
223 : claims,
224 : claims_length);
225 9 : EVIDENCE_CHECK(result, "Evidence verification failed", return false);
226 :
227 : // Make sure claims were succesfully extracted
228 : // if that was the intention
229 8 : if (claims && claims_length && (!*claims || !*claims_length)) {
230 : LOG("Failed to extract claims from evidence\n");
231 0 : return false;
232 : }
233 :
234 : // Verify the custom claims hash is included in the evidence
235 : // and that the extracted custom claims match the custom claims
236 : // in the evidence (just for completeness' sake)
237 : // Hashing of the custom claims based on OpenEnclave's
238 : // common/sgx/verifier.c::oe_sgx_hash_custom_claims_buffer
239 :
240 : // Gather the report body and the custom claims buffer directly from the
241 : // evidence This depends on the evidence format
242 8 : sgx_report_data_t* report_data = NULL;
243 8 : uint8_t* custom_claims_buffer = NULL;
244 8 : size_t custom_claims_buffer_size = 0;
245 8 : if (!memcmp(&format_id, &EVIDENCE_FORMAT_SGX_LOCAL, sizeof(oe_uuid_t))) {
246 4 : if (evidence_buffer_size > sizeof(sgx_report_t)) {
247 2 : custom_claims_buffer = evidence_buffer + sizeof(sgx_report_t);
248 2 : custom_claims_buffer_size =
249 : evidence_buffer_size - sizeof(sgx_report_t);
250 : }
251 4 : report_data = &((sgx_report_t*)evidence_buffer)->body.report_data;
252 4 : } else if (!memcmp(
253 4 : &format_id, &EVIDENCE_FORMAT_SGX_ECDSA, sizeof(oe_uuid_t))) {
254 4 : sgx_quote_t* quote = (sgx_quote_t*)evidence_buffer;
255 4 : size_t report_body_size = sizeof(*quote) + quote->signature_len;
256 :
257 4 : if (evidence_buffer_size > report_body_size) {
258 2 : custom_claims_buffer = evidence_buffer + report_body_size;
259 2 : custom_claims_buffer_size = evidence_buffer_size - report_body_size;
260 : }
261 4 : report_data = &((sgx_quote_t*)evidence_buffer)->report_body.report_data;
262 : } else {
263 : LOG("Unexpected evidence format encountered\n");
264 0 : goto evidence_verify_and_extract_claims_fail;
265 : }
266 :
267 8 : if (claims && *claims) {
268 : // Extract the custom claims buffer from the extracted claims
269 : oe_claim_t* custom_claim =
270 8 : evidence_get_custom_claim(*claims, *claims_length);
271 :
272 : // Make sure the extracted custom claim value and the custom claims
273 : // buffer match
274 8 : if (custom_claim && custom_claims_buffer && custom_claims_buffer_size) {
275 4 : if (custom_claim->value_size != custom_claims_buffer_size ||
276 4 : memcmp(custom_claim->value,
277 : custom_claims_buffer,
278 : custom_claims_buffer_size)) {
279 : LOG("Custom claims buffer and extracted custom claims do not "
280 : "match\n");
281 0 : goto evidence_verify_and_extract_claims_fail;
282 : }
283 4 : } else if (!(!custom_claim && !custom_claims_buffer &&
284 : !custom_claims_buffer_size)) {
285 : LOG("Inconsistent custom claims detected\n");
286 0 : goto evidence_verify_and_extract_claims_fail;
287 : }
288 : }
289 :
290 : // Hash the custom claims buffer, setting to the default value if empty
291 : uint8_t custom_claims_hash[32];
292 : // Default hash for empty string
293 : static const uint8_t sha256_for_empty_string[] = {
294 : 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
295 : 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
296 : 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
297 :
298 8 : if (!custom_claims_buffer || !custom_claims_buffer_size) {
299 4 : memcpy(custom_claims_hash,
300 : sha256_for_empty_string,
301 : sizeof(sha256_for_empty_string));
302 : } else {
303 : hash_sha256_ctx_t hash_ctx;
304 4 : if (!hash_sha256_init(&hash_ctx))
305 0 : goto evidence_verify_and_extract_claims_fail;
306 4 : if (!hash_sha256_update(
307 : &hash_ctx, custom_claims_buffer, custom_claims_buffer_size))
308 0 : goto evidence_verify_and_extract_claims_fail;
309 4 : if (!hash_sha256_final(&hash_ctx, custom_claims_hash))
310 0 : goto evidence_verify_and_extract_claims_fail;
311 : }
312 :
313 8 : if (sizeof(report_data->field) < sizeof(custom_claims_hash) ||
314 8 : memcmp(report_data->field,
315 : custom_claims_hash,
316 : sizeof(custom_claims_hash))) {
317 : LOG("Custom claims hash not contained within the evidence\n");
318 4 : goto evidence_verify_and_extract_claims_fail;
319 : }
320 :
321 : LOG("Evidence verified successfully\n");
322 :
323 4 : return true;
324 4 : evidence_verify_and_extract_claims_fail:
325 4 : if (claims && *claims) {
326 4 : oe_free_claims(*claims, *claims_length);
327 4 : *claims = NULL;
328 4 : *claims_length = 0;
329 : }
330 4 : return false;
331 : }
332 :
333 5 : bool evidence_free_claims(oe_claim_t* claims, size_t claims_length) {
334 5 : if (claims) {
335 3 : if (oe_free_claims(claims, claims_length) != OE_OK)
336 1 : return false;
337 : }
338 4 : return true;
339 : }
340 :
341 34 : oe_claim_t* evidence_get_claim(oe_claim_t* claims,
342 : size_t claims_size,
343 : const char* claim_name) {
344 34 : if (!claims || !claims_size || !claim_name)
345 5 : return NULL;
346 :
347 73 : for (size_t i = 0; i < claims_size; i++) {
348 61 : if (strcmp(claims[i].name, claim_name) == 0)
349 17 : return &claims[i];
350 : }
351 12 : return NULL;
352 : }
353 :
354 16 : oe_claim_t* evidence_get_custom_claim(oe_claim_t* claims, size_t claims_size) {
355 16 : return evidence_get_claim(
356 : claims, claims_size, OE_CLAIM_CUSTOM_CLAIMS_BUFFER);
357 : }
358 :
359 2 : void evidence_free(uint8_t* evidence_buffer) {
360 2 : if (evidence_buffer)
361 1 : oe_free_evidence(evidence_buffer);
362 2 : }
|