LCOV - code coverage report
Current view: top level - sgx/src/trusted - upgrade.c (source / functions) Hit Total Coverage
Test: powHSM firmware Lines: 238 278 85.6 %
Date: 2025-07-10 13:49:13 Functions: 9 9 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 "upgrade.h"
      26             : 
      27             : #include <string.h>
      28             : #include <secp256k1.h>
      29             : #include <secp256k1_ecdh.h>
      30             : #include <openenclave/corelibc/stdlib.h>
      31             : 
      32             : #include "hal/exceptions.h"
      33             : #include "hal/log.h"
      34             : #include "hal/seed.h"
      35             : #include "hal/hash.h"
      36             : 
      37             : #include "defs.h"
      38             : #include "apdu.h"
      39             : #include "hsm.h"
      40             : #include "migrate.h"
      41             : #include "eth.h"
      42             : #include "ints.h"
      43             : #include "compiletime.h"
      44             : #include "evidence.h"
      45             : #include "util.h"
      46             : #include "random.h"
      47             : #include "aes_gcm.h"
      48             : 
      49             : // Authorizers' public keys length (uncompressed format)
      50             : #define AUTHORIZED_SIGNER_PUBKEY_LENGTH 65
      51             : 
      52             : // Maximum number of authorizers (increase this if using a greater number)
      53             : #define MAX_AUTHORIZERS 10
      54             : 
      55             : // Maximum size for a peer data packet
      56             : #define MAX_RECV_DATA_SIZE (8 * 1024) // 8Kbytes
      57             : 
      58             : // Authorized signers
      59             : #include "upgrade_signers.h"
      60             : static const uint8_t authorizers_pubkeys[][AUTHORIZED_SIGNER_PUBKEY_LENGTH] =
      61             :     AUTHORIZERS_PUBKEYS;
      62             : 
      63             : // Total number of authorizers
      64             : #define TOTAL_AUTHORIZERS \
      65             :     (sizeof(authorizers_pubkeys) / sizeof(authorizers_pubkeys[0]))
      66             : 
      67             : // Minimum number of authorizers required to authorize a signer
      68             : #define THRESHOLD_AUTHORIZERS (TOTAL_AUTHORIZERS / 2 + 1)
      69             : 
      70             : // SGX upgrade spec message parts
      71             : #define SGX_UPG_SPEC_MSG_P1 "RSK_powHSM_SGX_upgrade_from_"
      72             : #define SGX_UPG_SPEC_MSG_P1_LENGTH (sizeof(SGX_UPG_SPEC_MSG_P1) - sizeof(""))
      73             : 
      74             : #define SGX_UPG_SPEC_MSG_P2 "_to_"
      75             : #define SGX_UPG_SPEC_MSG_P2_LENGTH (sizeof(SGX_UPG_SPEC_MSG_P2) - sizeof(""))
      76             : 
      77             : #define EVIDENCE_FORMAT EVIDENCE_FORMAT_SGX_LOCAL
      78             : 
      79             : // Operation selectors
      80             : typedef enum {
      81             :     OP_UPGRADE_START = 0x01,
      82             :     OP_UPGRADE_SPEC_SIG = 0x02,
      83             :     OP_UPGRADE_IDENTIFY_SELF = 0x03,
      84             :     OP_UPGRADE_IDENTIFY_PEER = 0x04,
      85             :     OP_UPGRADE_PROCESS_DATA = 0x05,
      86             : } op_code_upgrade_t;
      87             : 
      88             : // Error codes
      89             : typedef enum {
      90             :     ERR_UPGRADE_PROTOCOL = 0x6A00,
      91             :     ERR_UPGRADE_SPEC = 0x6A01,
      92             :     ERR_UPGRADE_SIGNATURE = 0x6A02,
      93             :     ERR_UPGRADE_AUTH = 0x6A03,
      94             :     ERR_UPGRADE_DATA_PROCESSING = 0x6A04,
      95             :     ERR_UPGRADE_INTERNAL = 0x6A99,
      96             : } err_code_upgrade_t;
      97             : 
      98             : // MRENCLAVE size
      99             : #define UPGRADE_MRENCLAVE_SIZE HASH_LENGTH
     100             : 
     101             : // SGX upgrade spec
     102             : typedef struct {
     103             :     uint8_t mrenclave_from[UPGRADE_MRENCLAVE_SIZE];
     104             :     uint8_t mrenclave_to[UPGRADE_MRENCLAVE_SIZE];
     105             : } upgrade_spec_t;
     106             : 
     107             : // SGX upgrade operations
     108             : typedef enum {
     109             :     upgrade_operation_none = 0,
     110             :     upgrade_operation_export = 1,
     111             :     upgrade_operation_import = 2,
     112             : } upgrade_operation_t;
     113             : 
     114             : // SGX upgrade SM states
     115             : typedef enum {
     116             :     upgrade_state_await_spec,
     117             :     upgrade_state_await_spec_sigs,
     118             :     upgrade_state_send_self_id,
     119             :     upgrade_state_await_peer_id,
     120             :     upgrade_state_ready_for_xchg,
     121             : } upgrade_state_t;
     122             : 
     123             : // SGX upgrade context
     124             : typedef struct {
     125             :     upgrade_state_t state;
     126             : 
     127             :     upgrade_spec_t spec;
     128             :     upgrade_operation_t operation;
     129             :     uint8_t* my_mrenclave;
     130             :     uint8_t* their_mrenclave;
     131             : 
     132             :     uint8_t expected_message_hash[HASH_LENGTH];
     133             :     bool authorized_signer_verified[MAX_AUTHORIZERS];
     134             : 
     135             :     uint8_t* evidence;
     136             :     size_t evidence_size;
     137             :     bool evidence_external;
     138             : 
     139             :     uint8_t my_privkey[PRIVATE_KEY_LENGTH];
     140             :     uint8_t my_pubkey[PUBKEY_CMP_LENGTH];
     141             :     size_t my_pubkey_len;
     142             :     uint8_t their_pubkey[PUBKEY_CMP_LENGTH];
     143             : 
     144             :     size_t trx_offset;
     145             : } upgrade_ctx_t;
     146             : 
     147             : // SGX upgrade ctx
     148             : static upgrade_ctx_t upgrade_ctx;
     149             : 
     150             : /*
     151             :  * Free current evidence buffer, if any
     152             :  */
     153          88 : static void free_evidence() {
     154          88 :     if (upgrade_ctx.evidence) {
     155          43 :         if (!upgrade_ctx.evidence_external)
     156          34 :             evidence_free(upgrade_ctx.evidence);
     157             :         else
     158           9 :             oe_free(upgrade_ctx.evidence);
     159             :     }
     160          88 :     upgrade_ctx.evidence = NULL;
     161          88 :     upgrade_ctx.evidence_size = 0;
     162          88 : }
     163             : 
     164             : /*
     165             :  * Reset the upgrade context
     166             :  */
     167          56 : static void reset_upgrade() {
     168          56 :     free_evidence();
     169          56 :     explicit_bzero(&upgrade_ctx, sizeof(upgrade_ctx));
     170          56 : }
     171             : 
     172             : /*
     173             :  * Check that the context for the SGX upgrade
     174             :  * matches the expected state and is in a
     175             :  * consistent state.
     176             :  *
     177             :  * Reset the state and throw a protocol error
     178             :  * otherwise.
     179             :  */
     180          89 : static void check_state(upgrade_state_t expected) {
     181             :     // Consistency check
     182          89 :     if (upgrade_ctx.state == upgrade_state_await_spec &&
     183          30 :         upgrade_ctx.operation != upgrade_operation_none) {
     184           0 :         reset_upgrade();
     185           0 :         THROW(ERR_UPGRADE_PROTOCOL);
     186          89 :     } else if (upgrade_ctx.state != upgrade_state_await_spec &&
     187          59 :                upgrade_ctx.operation == upgrade_operation_none) {
     188           0 :         reset_upgrade();
     189           0 :         THROW(ERR_UPGRADE_PROTOCOL);
     190             :     }
     191             :     // Expectation check
     192          89 :     if (upgrade_ctx.state != expected) {
     193           2 :         reset_upgrade();
     194           2 :         THROW(ERR_UPGRADE_PROTOCOL);
     195             :     }
     196          87 : }
     197             : 
     198          17 : static bool generate_message_to_verify() {
     199             :     uint8_t message_size;
     200             :     uint8_t aux_buf[4]; // Hold at most three digits plus a null terminator
     201             :     hash_keccak256_ctx_t hash_ctx;
     202             : 
     203          17 :     if (!hash_keccak256_init(&hash_ctx))
     204           0 :         goto generate_message_to_verify_error;
     205             : 
     206             :     // Hash eth prefix
     207          17 :     if (!hash_keccak256_update(&hash_ctx,
     208             :                                (const uint8_t*)ETHEREUM_MSG_PREFIX,
     209             :                                ETHEREUM_MSG_PREFIX_LENGTH))
     210           0 :         goto generate_message_to_verify_error;
     211             : 
     212             :     // Compute total message size
     213          17 :     message_size = SGX_UPG_SPEC_MSG_P1_LENGTH +
     214             :                    sizeof(upgrade_ctx.spec.mrenclave_from) * 2 + // Hexa
     215             :                    SGX_UPG_SPEC_MSG_P2_LENGTH +
     216             :                    sizeof(upgrade_ctx.spec.mrenclave_to) * 2; // Hexa
     217             : 
     218             :     // Hash message size
     219         119 :     UINT_TO_DECSTR(aux_buf, message_size);
     220          17 :     if (!hash_keccak256_update(&hash_ctx, aux_buf, strlen((char*)aux_buf)))
     221           0 :         goto generate_message_to_verify_error;
     222             : 
     223             :     // Hash message
     224          17 :     if (!hash_keccak256_update(&hash_ctx,
     225             :                                (uint8_t*)SGX_UPG_SPEC_MSG_P1,
     226             :                                SGX_UPG_SPEC_MSG_P1_LENGTH))
     227           0 :         goto generate_message_to_verify_error;
     228             : 
     229         561 :     for (unsigned int i = 0; i < sizeof(upgrade_ctx.spec.mrenclave_from); i++) {
     230         544 :         BYTE_TO_HEXSTR(aux_buf, upgrade_ctx.spec.mrenclave_from[i]);
     231         544 :         if (!hash_keccak256_update(&hash_ctx, aux_buf, 2))
     232           0 :             goto generate_message_to_verify_error;
     233             :     }
     234             : 
     235          17 :     if (!hash_keccak256_update(&hash_ctx,
     236             :                                (uint8_t*)SGX_UPG_SPEC_MSG_P2,
     237             :                                SGX_UPG_SPEC_MSG_P2_LENGTH))
     238           0 :         goto generate_message_to_verify_error;
     239             : 
     240         561 :     for (unsigned int i = 0; i < sizeof(upgrade_ctx.spec.mrenclave_to); i++) {
     241         544 :         BYTE_TO_HEXSTR(aux_buf, upgrade_ctx.spec.mrenclave_to[i]);
     242         544 :         if (!hash_keccak256_update(&hash_ctx, aux_buf, 2))
     243           0 :             goto generate_message_to_verify_error;
     244             :     }
     245             : 
     246             :     // Output hash
     247          17 :     if (!hash_keccak256_final(&hash_ctx, upgrade_ctx.expected_message_hash))
     248           0 :         goto generate_message_to_verify_error;
     249          17 :     return true;
     250             : 
     251           0 : generate_message_to_verify_error:
     252             :     LOG("Error generating message to verify\n");
     253           0 :     return false;
     254             : }
     255             : 
     256          11 : static size_t send_data(uint8_t* src,
     257             :                         size_t src_size,
     258             :                         size_t* src_offset,
     259             :                         bool* more) {
     260          11 :     size_t tx = MIN(APDU_TOTAL_DATA_SIZE_OUT, src_size - *src_offset);
     261          11 :     memcpy(APDU_DATA_PTR, src + *src_offset, tx);
     262          11 :     *src_offset += tx;
     263          11 :     *more = *src_offset < src_size;
     264             :     LOG("Sending %lu bytes of data\n", tx);
     265          11 :     return tx;
     266             : }
     267             : 
     268          13 : static bool receive_data(volatile unsigned int rx,
     269             :                          uint8_t** dest,
     270             :                          size_t* dest_size,
     271             :                          size_t* dest_offset) {
     272          13 :     size_t pl = !*dest ? 2 : 0; // Two bytes for payload length
     273          13 :     if (APDU_DATA_SIZE(rx) <= pl) {
     274           1 :         reset_upgrade();
     275           1 :         THROW(ERR_UPGRADE_PROTOCOL);
     276             :     }
     277          12 :     if (!*dest) {
     278          30 :         VAR_BIGENDIAN_FROM(APDU_DATA_PTR, *dest_size, pl);
     279             :         // We allow a maximum data size due to the nature of data
     280             :         // we need to process
     281          10 :         if (*dest_size > MAX_RECV_DATA_SIZE) {
     282             :             LOG("Data bigger than allowed max\n");
     283           1 :             reset_upgrade();
     284           1 :             THROW(ERR_UPGRADE_PROTOCOL);
     285             :         }
     286           9 :         *dest = oe_malloc(*dest_size);
     287           9 :         *dest_offset = 0;
     288             :         LOG("Expecting %lu bytes of data\n", *dest_size);
     289             :     }
     290          11 :     if (APDU_DATA_SIZE(rx) - pl > *dest_size - *dest_offset) {
     291             :         LOG("Data buffer overflow\n");
     292           1 :         reset_upgrade();
     293           1 :         THROW(ERR_UPGRADE_PROTOCOL);
     294             :     }
     295          10 :     memcpy(*dest + *dest_offset, APDU_DATA_PTR + pl, APDU_DATA_SIZE(rx) - pl);
     296          10 :     *dest_offset += APDU_DATA_SIZE(rx) - pl;
     297             :     LOG("Received %lu bytes of data\n", APDU_DATA_SIZE(rx) - pl);
     298          10 :     return *dest_offset < *dest_size; // More?
     299             : }
     300             : 
     301             : // -----------------------------------------------------------------------
     302             : // Protocol implementation
     303             : // -----------------------------------------------------------------------
     304             : 
     305          30 : void upgrade_init() {
     306             :     // Build should fail when more authorizers than supported are provided
     307             :     COMPILE_TIME_ASSERT(TOTAL_AUTHORIZERS <= MAX_AUTHORIZERS);
     308             :     // Build should fail if hash size size differs from expected key size
     309             :     COMPILE_TIME_ASSERT(HASH_LENGTH == AES_GCM_KEY_SIZE);
     310             : 
     311          30 :     reset_upgrade();
     312             :     LOG("Upgrade module initialized\n");
     313          30 : }
     314             : 
     315           1 : void upgrade_reset() {
     316           1 :     reset_upgrade();
     317           1 : }
     318             : 
     319          90 : unsigned int upgrade_process_apdu(volatile unsigned int rx) {
     320             :     uint8_t key[AES_GCM_KEY_SIZE];
     321          90 :     size_t sz = 0;
     322             :     unsigned int tx;
     323             :     bool baux;
     324             :     int signature_valid;
     325             :     long unsigned valid_count;
     326             :     secp256k1_context* secp_ctx;
     327             :     secp256k1_ecdsa_signature signature;
     328             :     secp256k1_pubkey pubkey;
     329          90 :     oe_claim_t* claims = NULL;
     330             :     size_t claims_size;
     331             :     oe_claim_t* claim;
     332             :     evidence_format_t format;
     333             :     uint16_t error;
     334             : 
     335          90 :     switch (APDU_OP()) {
     336          31 :     case OP_UPGRADE_START:
     337          31 :         check_state(upgrade_state_await_spec);
     338             : 
     339             :         // We expect a from/to upgrade spec plus an operation type byte
     340          30 :         if (APDU_DATA_SIZE(rx) != UPGRADE_MRENCLAVE_SIZE * 2 + 1) {
     341           2 :             reset_upgrade();
     342           2 :             THROW(ERR_UPGRADE_PROTOCOL);
     343             :         }
     344             :         // Operation validations
     345          28 :         switch (APDU_DATA_PTR[0]) {
     346          20 :         case upgrade_operation_export:
     347          20 :             REQUIRE_ONBOARDED();
     348          19 :             REQUIRE_UNLOCKED();
     349          18 :             break;
     350           8 :         case upgrade_operation_import:
     351           8 :             REQUIRE_NOT_ONBOARDED();
     352           7 :             break;
     353           0 :         default:
     354           0 :             reset_upgrade();
     355           0 :             THROW(ERR_UPGRADE_PROTOCOL);
     356             :         }
     357          25 :         upgrade_ctx.operation = APDU_DATA_PTR[0];
     358             :         // Spec
     359          25 :         memcpy(upgrade_ctx.spec.mrenclave_from,
     360          25 :                APDU_DATA_PTR + 1,
     361             :                UPGRADE_MRENCLAVE_SIZE);
     362          25 :         memcpy(upgrade_ctx.spec.mrenclave_to,
     363          25 :                APDU_DATA_PTR + 1 + UPGRADE_MRENCLAVE_SIZE,
     364             :                UPGRADE_MRENCLAVE_SIZE);
     365          25 :         upgrade_ctx.my_mrenclave =
     366          25 :             upgrade_ctx.operation == upgrade_operation_export
     367             :                 ? upgrade_ctx.spec.mrenclave_from
     368          25 :                 : upgrade_ctx.spec.mrenclave_to;
     369          25 :         upgrade_ctx.their_mrenclave =
     370          25 :             upgrade_ctx.operation == upgrade_operation_export
     371             :                 ? upgrade_ctx.spec.mrenclave_to
     372          25 :                 : upgrade_ctx.spec.mrenclave_from;
     373             :         LOG("Spec received\n");
     374             :         LOG_HEX(
     375             :             "From:", upgrade_ctx.spec.mrenclave_from, UPGRADE_MRENCLAVE_SIZE);
     376             :         LOG_HEX("To:", upgrade_ctx.spec.mrenclave_to, UPGRADE_MRENCLAVE_SIZE);
     377             :         LOG("Role: %s\n",
     378             :             upgrade_ctx.operation == upgrade_operation_export ? "exporter"
     379             :                                                               : "importer");
     380             :         // Check this enclave's mrenclave matches the corresponding
     381             :         // value in the spec according to the specified role
     382          25 :         explicit_bzero(&format, sizeof(format));
     383          25 :         format.id = EVIDENCE_FORMAT;
     384          25 :         upgrade_ctx.evidence_external = false;
     385          25 :         if (!evidence_generate(&format,
     386             :                                NULL,
     387             :                                0,
     388             :                                &upgrade_ctx.evidence,
     389             :                                &upgrade_ctx.evidence_size)) {
     390             :             LOG("Unable to generate enclave evidence for self\n");
     391           2 :             error = ERR_UPGRADE_INTERNAL;
     392           2 :             goto upgrade_process_apdu_start_error;
     393             :         }
     394          23 :         if (!evidence_verify_and_extract_claims(EVIDENCE_FORMAT,
     395             :                                                 upgrade_ctx.evidence,
     396             :                                                 upgrade_ctx.evidence_size,
     397             :                                                 &claims,
     398             :                                                 &claims_size)) {
     399             :             LOG("Error verifying this enclave's evidence\n");
     400           2 :             error = ERR_UPGRADE_INTERNAL;
     401           2 :             goto upgrade_process_apdu_start_error;
     402             :         }
     403          21 :         if (!(claim = evidence_get_claim(
     404             :                   claims, claims_size, OE_CLAIM_UNIQUE_ID))) {
     405             :             LOG("Error extracting this enclave's mrenclave\n");
     406           2 :             error = ERR_UPGRADE_INTERNAL;
     407           2 :             goto upgrade_process_apdu_start_error;
     408             :         }
     409             :         LOG_HEX("This enclave's mrenclave:", claim->value, claim->value_size);
     410          19 :         if (claim->value_size != UPGRADE_MRENCLAVE_SIZE ||
     411          19 :             memcmp(claim->value,
     412          19 :                    upgrade_ctx.my_mrenclave,
     413             :                    UPGRADE_MRENCLAVE_SIZE) != 0) {
     414             :             LOG("This enclave's mrenclave does not match the spec's "
     415             :                 "mrenclave\n");
     416           2 :             error = ERR_UPGRADE_SPEC;
     417           2 :             goto upgrade_process_apdu_start_error;
     418             :         }
     419          17 :         generate_message_to_verify();
     420             :         LOG_HEX("Message to verify:",
     421             :                 upgrade_ctx.expected_message_hash,
     422             :                 sizeof(upgrade_ctx.expected_message_hash));
     423          17 :         upgrade_ctx.state = upgrade_state_await_spec_sigs;
     424          17 :         oe_free(claims);
     425          17 :         free_evidence();
     426          17 :         return TX_NO_DATA();
     427           8 :     upgrade_process_apdu_start_error:
     428           8 :         if (claims)
     429           4 :             oe_free(claims);
     430           8 :         reset_upgrade();
     431           8 :         THROW(error);
     432          28 :     case OP_UPGRADE_SPEC_SIG:
     433          28 :         check_state(upgrade_state_await_spec_sigs);
     434             : 
     435          28 :         if (APDU_DATA_SIZE(rx) < 1) {
     436           0 :             reset_upgrade();
     437           0 :             THROW(ERR_UPGRADE_PROTOCOL);
     438             :         }
     439             :         // Check to see whether we find a matching authorized signer
     440          28 :         secp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     441          28 :         if (!secp256k1_ecdsa_signature_parse_der(
     442          28 :                 secp_ctx, &signature, APDU_DATA_PTR, APDU_DATA_SIZE(rx))) {
     443           1 :             secp256k1_context_destroy(secp_ctx);
     444           1 :             reset_upgrade();
     445           1 :             THROW(ERR_UPGRADE_SIGNATURE);
     446             :         }
     447          27 :         signature_valid = 0;
     448          42 :         for (unsigned int i = 0; i < TOTAL_AUTHORIZERS; i++) {
     449             :             // Attempt to verify against this public key
     450          41 :             if (!secp256k1_ec_pubkey_parse(
     451             :                     secp_ctx,
     452             :                     &pubkey,
     453          41 :                     (const unsigned char*)authorizers_pubkeys[i],
     454             :                     sizeof(authorizers_pubkeys[i]))) {
     455           0 :                 secp256k1_context_destroy(secp_ctx);
     456           0 :                 reset_upgrade();
     457           0 :                 THROW(ERR_UPGRADE_SIGNATURE);
     458             :             }
     459             :             signature_valid =
     460          41 :                 secp256k1_ecdsa_verify(secp_ctx,
     461             :                                        &signature,
     462             :                                        upgrade_ctx.expected_message_hash,
     463             :                                        &pubkey);
     464             : 
     465             :             // Found a valid signature?
     466          41 :             if (signature_valid) {
     467             :                 LOG("Valid signature received!\n");
     468          26 :                 upgrade_ctx.authorized_signer_verified[i] = true;
     469          26 :                 break;
     470             :             }
     471             :         }
     472          27 :         secp256k1_context_destroy(secp_ctx);
     473             : 
     474             :         // Reached the threshold?
     475          27 :         valid_count = 0;
     476         108 :         for (unsigned int i = 0; i < TOTAL_AUTHORIZERS; i++)
     477          81 :             if (upgrade_ctx.authorized_signer_verified[i])
     478          39 :                 valid_count++;
     479             : 
     480             :         LOG("Valid signatures so far: %lu\n", valid_count);
     481             : 
     482          27 :         if (valid_count >= THRESHOLD_AUTHORIZERS) {
     483          12 :             SET_APDU_OP(0); // No need for more
     484          12 :             upgrade_ctx.state = upgrade_state_send_self_id;
     485             :             LOG("Threshold reached!\n");
     486             :         } else {
     487          15 :             SET_APDU_OP(1); // We need more
     488             :         }
     489          27 :         return TX_NO_DATA();
     490          13 :     case OP_UPGRADE_IDENTIFY_SELF:
     491          13 :         check_state(upgrade_state_send_self_id);
     492             : 
     493          12 :         if (!upgrade_ctx.evidence) {
     494          12 :             secp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     495             :             do {
     496          12 :                 if (!random_getrandom(upgrade_ctx.my_privkey,
     497             :                                       sizeof(upgrade_ctx.my_privkey))) {
     498             :                     LOG("Unable to generate private key\n");
     499           1 :                     THROW(ERR_UPGRADE_INTERNAL);
     500             :                 }
     501          11 :             } while (!secp256k1_ec_pubkey_create(
     502             :                 secp_ctx, &pubkey, upgrade_ctx.my_privkey));
     503          11 :             upgrade_ctx.my_pubkey_len = sizeof(upgrade_ctx.my_pubkey);
     504          11 :             secp256k1_ec_pubkey_serialize(secp_ctx,
     505             :                                           upgrade_ctx.my_pubkey,
     506             :                                           &upgrade_ctx.my_pubkey_len,
     507             :                                           &pubkey,
     508             :                                           SECP256K1_EC_COMPRESSED);
     509          11 :             if (upgrade_ctx.my_pubkey_len != sizeof(upgrade_ctx.my_pubkey)) {
     510             :                 LOG("Unable to serialize pubkey\n");
     511           0 :                 reset_upgrade();
     512           0 :                 secp256k1_context_destroy(secp_ctx);
     513           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     514             :             }
     515             :             LOG_HEX("My pubkey:",
     516             :                     upgrade_ctx.my_pubkey,
     517             :                     sizeof(upgrade_ctx.my_pubkey));
     518          11 :             secp256k1_context_destroy(secp_ctx);
     519          11 :             explicit_bzero(&format, sizeof(format));
     520          11 :             format.id = EVIDENCE_FORMAT;
     521          11 :             if (!evidence_get_format_settings(&format)) {
     522             :                 LOG("Unable to get evidence format\n");
     523           0 :                 reset_upgrade();
     524           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     525             :             }
     526          11 :             memcpy(format.settings,
     527          11 :                    upgrade_ctx.their_mrenclave,
     528             :                    UPGRADE_MRENCLAVE_SIZE);
     529          11 :             upgrade_ctx.evidence_external = false;
     530          11 :             if (!evidence_generate(&format,
     531             :                                    upgrade_ctx.my_pubkey,
     532             :                                    sizeof(upgrade_ctx.my_pubkey),
     533             :                                    &upgrade_ctx.evidence,
     534             :                                    &upgrade_ctx.evidence_size)) {
     535             :                 LOG("Unable to generate enclave evidence for peer\n");
     536           0 :                 reset_upgrade();
     537           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     538             :             }
     539          11 :             oe_free(format.settings);
     540          11 :             explicit_bzero(&format, sizeof(format));
     541          11 :             upgrade_ctx.trx_offset = 0;
     542             :         }
     543             : 
     544          11 :         tx = send_data(upgrade_ctx.evidence,
     545             :                        upgrade_ctx.evidence_size,
     546             :                        &upgrade_ctx.trx_offset,
     547             :                        &baux);
     548          11 :         SET_APDU_OP(baux ? 1 : 0); // More to send?
     549             : 
     550          11 :         if (!baux) {
     551             :             LOG("Self evidence completely sent\n");
     552          11 :             free_evidence();
     553          11 :             upgrade_ctx.state = upgrade_state_await_peer_id;
     554             :         }
     555             : 
     556          11 :         return TX_FOR_DATA_SIZE(tx);
     557          13 :     case OP_UPGRADE_IDENTIFY_PEER:
     558          13 :         check_state(upgrade_state_await_peer_id);
     559             : 
     560          13 :         upgrade_ctx.evidence_external = true;
     561          13 :         if (receive_data(rx,
     562             :                          &upgrade_ctx.evidence,
     563             :                          &upgrade_ctx.evidence_size,
     564             :                          &upgrade_ctx.trx_offset)) {
     565           2 :             SET_APDU_OP(1); // More
     566           2 :             return TX_NO_DATA();
     567             :         }
     568             :         // We received the entire peer evidence. Perform validation
     569           8 :         if (!evidence_verify_and_extract_claims(EVIDENCE_FORMAT,
     570             :                                                 upgrade_ctx.evidence,
     571             :                                                 upgrade_ctx.evidence_size,
     572             :                                                 &claims,
     573             :                                                 &claims_size)) {
     574             :             LOG("Error verifying peer enclave's evidence\n");
     575           1 :             goto upgrade_process_apdu_identify_peer_error;
     576             :         }
     577           7 :         if (!(claim = evidence_get_claim(
     578             :                   claims, claims_size, OE_CLAIM_UNIQUE_ID))) {
     579             :             LOG("Error extracting peer enclave's mrenclave\n");
     580           0 :             goto upgrade_process_apdu_identify_peer_error;
     581             :         }
     582             :         LOG_HEX("Peer enclave's mrenclave:", claim->value, claim->value_size);
     583           7 :         if (claim->value_size != UPGRADE_MRENCLAVE_SIZE ||
     584           7 :             memcmp(claim->value,
     585           7 :                    upgrade_ctx.their_mrenclave,
     586             :                    UPGRADE_MRENCLAVE_SIZE) != 0) {
     587             :             LOG("Peer enclave's mrenclave does not match the spec's "
     588             :                 "mrenclave\n");
     589           2 :             goto upgrade_process_apdu_identify_peer_error;
     590             :         }
     591           5 :         if (!(claim = evidence_get_custom_claim(claims, claims_size))) {
     592             :             LOG("Error extracting peer enclave's public key\n");
     593           1 :             goto upgrade_process_apdu_identify_peer_error;
     594             :         }
     595           4 :         secp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     596           8 :         if (claim->value_size != sizeof(upgrade_ctx.their_pubkey) ||
     597           4 :             !secp256k1_ec_pubkey_parse(
     598           4 :                 secp_ctx, &pubkey, claim->value, claim->value_size)) {
     599             :             LOG("Invalid peer public key received");
     600           0 :             secp256k1_context_destroy(secp_ctx);
     601           0 :             goto upgrade_process_apdu_identify_peer_error;
     602             :         }
     603           4 :         secp256k1_context_destroy(secp_ctx);
     604           4 :         memcpy(upgrade_ctx.their_pubkey, claim->value, claim->value_size);
     605             :         LOG_HEX("Peer public key:",
     606             :                 upgrade_ctx.their_pubkey,
     607             :                 sizeof(upgrade_ctx.their_pubkey));
     608           4 :         upgrade_ctx.state = upgrade_state_ready_for_xchg;
     609           4 :         SET_APDU_OP(0); // Done
     610           4 :         if (claims)
     611           4 :             oe_free(claims);
     612           4 :         free_evidence();
     613           4 :         return TX_NO_DATA();
     614           4 :     upgrade_process_apdu_identify_peer_error:
     615           4 :         if (claims)
     616           3 :             oe_free(claims);
     617           4 :         reset_upgrade();
     618           4 :         THROW(ERR_UPGRADE_AUTH);
     619           4 :     case OP_UPGRADE_PROCESS_DATA:
     620           4 :         check_state(upgrade_state_ready_for_xchg);
     621             : 
     622           4 :         secp_ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     623           4 :         if (!secp256k1_ec_pubkey_parse(secp_ctx,
     624             :                                        &pubkey,
     625             :                                        upgrade_ctx.their_pubkey,
     626           4 :                                        sizeof(upgrade_ctx.their_pubkey)) ||
     627           4 :             !secp256k1_ecdh(secp_ctx,
     628             :                             key,
     629             :                             &pubkey,
     630             :                             upgrade_ctx.my_privkey,
     631             :                             secp256k1_ecdh_hash_function_sha256,
     632             :                             NULL)) {
     633             :             LOG("Unable to generate data processing key\n");
     634           0 :             reset_upgrade();
     635           0 :             secp256k1_context_destroy(secp_ctx);
     636           0 :             THROW(ERR_UPGRADE_INTERNAL);
     637             :         }
     638           4 :         secp256k1_context_destroy(secp_ctx);
     639           4 :         explicit_bzero(upgrade_ctx.my_privkey, sizeof(upgrade_ctx.my_privkey));
     640           4 :         explicit_bzero(upgrade_ctx.my_pubkey, sizeof(upgrade_ctx.my_pubkey));
     641           4 :         explicit_bzero(upgrade_ctx.their_pubkey,
     642             :                        sizeof(upgrade_ctx.their_pubkey));
     643             : 
     644           4 :         switch (upgrade_ctx.operation) {
     645           2 :         case upgrade_operation_export:
     646             :             LOG("Exporting data...\n");
     647           2 :             sz = APDU_TOTAL_DATA_SIZE_OUT;
     648           2 :             if (!migrate_export(key, sizeof(key), APDU_DATA_PTR, &sz) ||
     649           1 :                 sz != (sz & 0xFF)) {
     650           1 :                 reset_upgrade();
     651           1 :                 THROW(ERR_UPGRADE_DATA_PROCESSING);
     652             :             }
     653             :             LOG("Data export complete\n");
     654           1 :             reset_upgrade();
     655           1 :             return TX_FOR_DATA_SIZE(sz);
     656           2 :         case upgrade_operation_import:
     657             :             LOG("Importing data...\n");
     658           2 :             if (APDU_DATA_SIZE(rx) == 0) {
     659           0 :                 reset_upgrade();
     660           0 :                 THROW(ERR_UPGRADE_PROTOCOL);
     661             :             }
     662           2 :             if (!migrate_import(
     663           2 :                     key, sizeof(key), APDU_DATA_PTR, APDU_DATA_SIZE(rx))) {
     664           1 :                 reset_upgrade();
     665           1 :                 THROW(ERR_UPGRADE_DATA_PROCESSING);
     666             :             }
     667             :             LOG("Data import complete\n");
     668           1 :             reset_upgrade();
     669           1 :             return TX_NO_DATA();
     670           0 :         default:
     671             :             // We should never reach this point
     672             :             LOG("Inconsistent internal state when processing data\n");
     673           0 :             reset_upgrade();
     674           0 :             THROW(ERR_UPGRADE_INTERNAL);
     675             :         }
     676           1 :     default:
     677           1 :         reset_upgrade();
     678           1 :         THROW(ERR_UPGRADE_PROTOCOL);
     679             :         break;
     680             :     }
     681             : }

Generated by: LCOV version 1.16