LCOV - code coverage report
Current view: top level - hal/sgx/src/trusted - evidence.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 127 139 91.4 %
Date: 2025-10-30 06:27:42 Functions: 11 11 100.0 %

          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 : }

Generated by: LCOV version 1.16