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          89 : static void free_evidence() {
     154          89 :     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          89 :     upgrade_ctx.evidence = NULL;
     161          89 :     upgrade_ctx.evidence_size = 0;
     162          89 : }
     163             : 
     164             : /*
     165             :  * Reset the upgrade context
     166             :  */
     167          57 : static void reset_upgrade() {
     168          57 :     free_evidence();
     169          57 :     explicit_bzero(&upgrade_ctx, sizeof(upgrade_ctx));
     170          57 : }
     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          87 : static void check_state(upgrade_state_t expected) {
     181             :     // Consistency check
     182          87 :     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          87 :     } else if (upgrade_ctx.state != upgrade_state_await_spec &&
     187          57 :                upgrade_ctx.operation == upgrade_operation_none) {
     188           0 :         reset_upgrade();
     189           0 :         THROW(ERR_UPGRADE_PROTOCOL);
     190             :     }
     191             :     // Expectation check
     192          87 :     if (upgrade_ctx.state != expected) {
     193           2 :         reset_upgrade();
     194           2 :         THROW(ERR_UPGRADE_PROTOCOL);
     195             :     }
     196          85 : }
     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 :         if (!*dest) {
     288             :             LOG("Unable to allocate memory\n");
     289           0 :             THROW(ERR_UPGRADE_INTERNAL);
     290             :         }
     291           9 :         *dest_offset = 0;
     292             :         LOG("Expecting %lu bytes of data\n", *dest_size);
     293             :     }
     294          11 :     if (APDU_DATA_SIZE(rx) - pl > *dest_size - *dest_offset) {
     295             :         LOG("Data buffer overflow\n");
     296           1 :         reset_upgrade();
     297           1 :         THROW(ERR_UPGRADE_PROTOCOL);
     298             :     }
     299          10 :     memcpy(*dest + *dest_offset, APDU_DATA_PTR + pl, APDU_DATA_SIZE(rx) - pl);
     300          10 :     *dest_offset += APDU_DATA_SIZE(rx) - pl;
     301             :     LOG("Received %lu bytes of data\n", APDU_DATA_SIZE(rx) - pl);
     302          10 :     return *dest_offset < *dest_size; // More?
     303             : }
     304             : 
     305          46 : static secp256k1_context* assert_secp256k1_context_create_and_randomize() {
     306             :     unsigned char randomize[32];
     307          46 :     secp256k1_context* ctx = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
     308          46 :     if (!random_getrandom(randomize, sizeof(randomize))) {
     309             :         LOG("Error generating random seed for "
     310             :             "secp256k1 context randomisation\n");
     311           1 :         reset_upgrade();
     312           1 :         THROW(ERR_INTERNAL);
     313             :     }
     314          45 :     if (!secp256k1_context_randomize(ctx, randomize)) {
     315             :         LOG("Error randomising secp256k1 context\n");
     316           0 :         reset_upgrade();
     317           0 :         THROW(ERR_INTERNAL);
     318             :     }
     319          45 :     explicit_bzero(randomize, sizeof(randomize));
     320          45 :     return ctx;
     321             : }
     322             : 
     323             : // -----------------------------------------------------------------------
     324             : // Protocol implementation
     325             : // -----------------------------------------------------------------------
     326             : 
     327          30 : void upgrade_init() {
     328             :     // Build should fail when more authorizers than supported are provided
     329             :     COMPILE_TIME_ASSERT(TOTAL_AUTHORIZERS <= MAX_AUTHORIZERS);
     330             :     // Build should fail if hash size size differs from expected key size
     331             :     COMPILE_TIME_ASSERT(HASH_LENGTH == AES_GCM_KEY_SIZE);
     332             : 
     333          30 :     reset_upgrade();
     334             :     LOG("Upgrade module initialized\n");
     335          30 : }
     336             : 
     337           1 : void upgrade_reset() {
     338           1 :     reset_upgrade();
     339           1 : }
     340             : 
     341          88 : unsigned int upgrade_process_apdu(volatile unsigned int rx) {
     342             :     uint8_t key[AES_GCM_KEY_SIZE];
     343          88 :     size_t sz = 0;
     344             :     unsigned int tx;
     345             :     bool baux;
     346             :     int signature_valid;
     347             :     long unsigned valid_count;
     348             :     secp256k1_context* secp_ctx;
     349             :     secp256k1_ecdsa_signature signature;
     350             :     secp256k1_pubkey pubkey;
     351          88 :     oe_claim_t* claims = NULL;
     352             :     size_t claims_size;
     353             :     oe_claim_t* claim;
     354             :     evidence_format_t format;
     355             :     uint16_t error;
     356             : 
     357          88 :     switch (APDU_OP()) {
     358          31 :     case OP_UPGRADE_START:
     359          31 :         check_state(upgrade_state_await_spec);
     360             : 
     361             :         // We expect a from/to upgrade spec plus an operation type byte
     362          30 :         if (APDU_DATA_SIZE(rx) != UPGRADE_MRENCLAVE_SIZE * 2 + 1) {
     363           2 :             reset_upgrade();
     364           2 :             THROW(ERR_UPGRADE_PROTOCOL);
     365             :         }
     366             :         // Operation validations
     367          28 :         switch (APDU_DATA_PTR[0]) {
     368          20 :         case upgrade_operation_export:
     369          20 :             REQUIRE_ONBOARDED();
     370          19 :             REQUIRE_UNLOCKED();
     371          18 :             break;
     372           8 :         case upgrade_operation_import:
     373           8 :             REQUIRE_NOT_ONBOARDED();
     374           7 :             break;
     375           0 :         default:
     376           0 :             reset_upgrade();
     377           0 :             THROW(ERR_UPGRADE_PROTOCOL);
     378             :         }
     379          25 :         upgrade_ctx.operation = APDU_DATA_PTR[0];
     380             :         // Spec
     381          25 :         memcpy(upgrade_ctx.spec.mrenclave_from,
     382          25 :                APDU_DATA_PTR + 1,
     383             :                UPGRADE_MRENCLAVE_SIZE);
     384          25 :         memcpy(upgrade_ctx.spec.mrenclave_to,
     385          25 :                APDU_DATA_PTR + 1 + UPGRADE_MRENCLAVE_SIZE,
     386             :                UPGRADE_MRENCLAVE_SIZE);
     387          25 :         upgrade_ctx.my_mrenclave =
     388          25 :             upgrade_ctx.operation == upgrade_operation_export
     389             :                 ? upgrade_ctx.spec.mrenclave_from
     390          25 :                 : upgrade_ctx.spec.mrenclave_to;
     391          25 :         upgrade_ctx.their_mrenclave =
     392          25 :             upgrade_ctx.operation == upgrade_operation_export
     393             :                 ? upgrade_ctx.spec.mrenclave_to
     394          25 :                 : upgrade_ctx.spec.mrenclave_from;
     395             :         LOG("Spec received\n");
     396             :         LOG_HEX(
     397             :             "From:", upgrade_ctx.spec.mrenclave_from, UPGRADE_MRENCLAVE_SIZE);
     398             :         LOG_HEX("To:", upgrade_ctx.spec.mrenclave_to, UPGRADE_MRENCLAVE_SIZE);
     399             :         LOG("Role: %s\n",
     400             :             upgrade_ctx.operation == upgrade_operation_export ? "exporter"
     401             :                                                               : "importer");
     402             :         // Check this enclave's mrenclave matches the corresponding
     403             :         // value in the spec according to the specified role
     404          25 :         explicit_bzero(&format, sizeof(format));
     405          25 :         format.id = EVIDENCE_FORMAT;
     406          25 :         upgrade_ctx.evidence_external = false;
     407          25 :         if (!evidence_generate(&format,
     408             :                                NULL,
     409             :                                0,
     410             :                                &upgrade_ctx.evidence,
     411             :                                &upgrade_ctx.evidence_size)) {
     412             :             LOG("Unable to generate enclave evidence for self\n");
     413           2 :             error = ERR_UPGRADE_INTERNAL;
     414           2 :             goto upgrade_process_apdu_start_error;
     415             :         }
     416          23 :         if (!evidence_verify_and_extract_claims(EVIDENCE_FORMAT,
     417             :                                                 upgrade_ctx.evidence,
     418             :                                                 upgrade_ctx.evidence_size,
     419             :                                                 &claims,
     420             :                                                 &claims_size)) {
     421             :             LOG("Error verifying this enclave's evidence\n");
     422           2 :             error = ERR_UPGRADE_INTERNAL;
     423           2 :             goto upgrade_process_apdu_start_error;
     424             :         }
     425          21 :         if (!(claim = evidence_get_claim(
     426             :                   claims, claims_size, OE_CLAIM_UNIQUE_ID))) {
     427             :             LOG("Error extracting this enclave's mrenclave\n");
     428           2 :             error = ERR_UPGRADE_INTERNAL;
     429           2 :             goto upgrade_process_apdu_start_error;
     430             :         }
     431             :         LOG_HEX("This enclave's mrenclave:", claim->value, claim->value_size);
     432          19 :         if (claim->value_size != UPGRADE_MRENCLAVE_SIZE ||
     433          19 :             memcmp(claim->value,
     434          19 :                    upgrade_ctx.my_mrenclave,
     435             :                    UPGRADE_MRENCLAVE_SIZE) != 0) {
     436             :             LOG("This enclave's mrenclave does not match the spec's "
     437             :                 "mrenclave\n");
     438           2 :             error = ERR_UPGRADE_SPEC;
     439           2 :             goto upgrade_process_apdu_start_error;
     440             :         }
     441          17 :         generate_message_to_verify();
     442             :         LOG_HEX("Message to verify:",
     443             :                 upgrade_ctx.expected_message_hash,
     444             :                 sizeof(upgrade_ctx.expected_message_hash));
     445          17 :         upgrade_ctx.state = upgrade_state_await_spec_sigs;
     446          17 :         if (claims) {
     447          17 :             if (!evidence_free_claims(claims, claims_size)) {
     448             :                 LOG("Error freeing claims\n");
     449           0 :                 THROW(ERR_INTERNAL);
     450             :             }
     451          17 :             claims = NULL;
     452          17 :             claims_size = 0;
     453          17 :             claim = NULL;
     454             :         }
     455          17 :         free_evidence();
     456          17 :         return TX_NO_DATA();
     457           8 :     upgrade_process_apdu_start_error:
     458           8 :         if (claims) {
     459           4 :             if (!evidence_free_claims(claims, claims_size)) {
     460             :                 LOG("Error freeing claims\n");
     461           0 :                 THROW(ERR_INTERNAL);
     462             :             }
     463           4 :             claims = NULL;
     464           4 :             claims_size = 0;
     465           4 :             claim = NULL;
     466             :         }
     467           8 :         reset_upgrade();
     468           8 :         THROW(error);
     469          27 :     case OP_UPGRADE_SPEC_SIG:
     470          27 :         check_state(upgrade_state_await_spec_sigs);
     471             : 
     472          27 :         if (APDU_DATA_SIZE(rx) < 1) {
     473           0 :             reset_upgrade();
     474           0 :             THROW(ERR_UPGRADE_PROTOCOL);
     475             :         }
     476             :         // Check to see whether we find a matching authorized signer
     477          27 :         secp_ctx = assert_secp256k1_context_create_and_randomize();
     478          26 :         if (!secp256k1_ecdsa_signature_parse_der(
     479          26 :                 secp_ctx, &signature, APDU_DATA_PTR, APDU_DATA_SIZE(rx))) {
     480           1 :             secp256k1_context_destroy(secp_ctx);
     481           1 :             reset_upgrade();
     482           1 :             THROW(ERR_UPGRADE_SIGNATURE);
     483             :         }
     484          39 :         for (unsigned int i = 0; i < TOTAL_AUTHORIZERS; i++) {
     485             :             // Attempt to verify against this public key
     486          38 :             if (!secp256k1_ec_pubkey_parse(
     487             :                     secp_ctx,
     488             :                     &pubkey,
     489          38 :                     (const unsigned char*)authorizers_pubkeys[i],
     490             :                     sizeof(authorizers_pubkeys[i]))) {
     491           0 :                 secp256k1_context_destroy(secp_ctx);
     492           0 :                 reset_upgrade();
     493           0 :                 THROW(ERR_UPGRADE_SIGNATURE);
     494             :             }
     495             :             signature_valid =
     496          38 :                 secp256k1_ecdsa_verify(secp_ctx,
     497             :                                        &signature,
     498             :                                        upgrade_ctx.expected_message_hash,
     499             :                                        &pubkey);
     500             : 
     501             :             // Found a valid signature?
     502          38 :             if (signature_valid) {
     503             :                 LOG("Valid signature received!\n");
     504          24 :                 upgrade_ctx.authorized_signer_verified[i] = true;
     505          24 :                 break;
     506             :             }
     507             :         }
     508          25 :         secp256k1_context_destroy(secp_ctx);
     509             : 
     510             :         // Reached the threshold?
     511          25 :         valid_count = 0;
     512         100 :         for (unsigned int i = 0; i < TOTAL_AUTHORIZERS; i++)
     513          75 :             if (upgrade_ctx.authorized_signer_verified[i])
     514          36 :                 valid_count++;
     515             : 
     516             :         LOG("Valid signatures so far: %lu\n", valid_count);
     517             : 
     518          25 :         if (valid_count >= THRESHOLD_AUTHORIZERS) {
     519          11 :             SET_APDU_OP(0); // No need for more
     520          11 :             upgrade_ctx.state = upgrade_state_send_self_id;
     521             :             LOG("Threshold reached!\n");
     522             :         } else {
     523          14 :             SET_APDU_OP(1); // We need more
     524             :         }
     525          25 :         return TX_NO_DATA();
     526          12 :     case OP_UPGRADE_IDENTIFY_SELF:
     527          12 :         check_state(upgrade_state_send_self_id);
     528             : 
     529          11 :         if (!upgrade_ctx.evidence) {
     530          11 :             secp_ctx = assert_secp256k1_context_create_and_randomize();
     531             :             do {
     532          11 :                 if (!random_getrandom(upgrade_ctx.my_privkey,
     533             :                                       sizeof(upgrade_ctx.my_privkey))) {
     534             :                     LOG("Unable to generate private key\n");
     535           0 :                     THROW(ERR_UPGRADE_INTERNAL);
     536             :                 }
     537          11 :             } while (!secp256k1_ec_pubkey_create(
     538             :                 secp_ctx, &pubkey, upgrade_ctx.my_privkey));
     539          11 :             upgrade_ctx.my_pubkey_len = sizeof(upgrade_ctx.my_pubkey);
     540          11 :             secp256k1_ec_pubkey_serialize(secp_ctx,
     541             :                                           upgrade_ctx.my_pubkey,
     542             :                                           &upgrade_ctx.my_pubkey_len,
     543             :                                           &pubkey,
     544             :                                           SECP256K1_EC_COMPRESSED);
     545          11 :             if (upgrade_ctx.my_pubkey_len != sizeof(upgrade_ctx.my_pubkey)) {
     546             :                 LOG("Unable to serialize pubkey\n");
     547           0 :                 reset_upgrade();
     548           0 :                 secp256k1_context_destroy(secp_ctx);
     549           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     550             :             }
     551             :             LOG_HEX("My pubkey:",
     552             :                     upgrade_ctx.my_pubkey,
     553             :                     sizeof(upgrade_ctx.my_pubkey));
     554          11 :             secp256k1_context_destroy(secp_ctx);
     555          11 :             explicit_bzero(&format, sizeof(format));
     556          11 :             format.id = EVIDENCE_FORMAT;
     557          11 :             if (!evidence_get_format_settings(&format)) {
     558             :                 LOG("Unable to get evidence format\n");
     559           0 :                 reset_upgrade();
     560           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     561             :             }
     562          11 :             memcpy(format.settings,
     563          11 :                    upgrade_ctx.their_mrenclave,
     564             :                    UPGRADE_MRENCLAVE_SIZE);
     565          11 :             upgrade_ctx.evidence_external = false;
     566          11 :             if (!evidence_generate(&format,
     567             :                                    upgrade_ctx.my_pubkey,
     568             :                                    sizeof(upgrade_ctx.my_pubkey),
     569             :                                    &upgrade_ctx.evidence,
     570             :                                    &upgrade_ctx.evidence_size)) {
     571             :                 LOG("Unable to generate enclave evidence for peer\n");
     572           0 :                 reset_upgrade();
     573           0 :                 THROW(ERR_UPGRADE_INTERNAL);
     574             :             }
     575          11 :             if (!evidence_free_format_settings(format.settings)) {
     576             :                 LOG("Unable to free format settings\n");
     577           0 :                 THROW(ERR_INTERNAL);
     578             :             }
     579          11 :             explicit_bzero(&format, sizeof(format));
     580          11 :             upgrade_ctx.trx_offset = 0;
     581             :         }
     582             : 
     583          11 :         tx = send_data(upgrade_ctx.evidence,
     584             :                        upgrade_ctx.evidence_size,
     585             :                        &upgrade_ctx.trx_offset,
     586             :                        &baux);
     587          11 :         SET_APDU_OP(baux ? 1 : 0); // More to send?
     588             : 
     589          11 :         if (!baux) {
     590             :             LOG("Self evidence completely sent\n");
     591          11 :             free_evidence();
     592          11 :             upgrade_ctx.state = upgrade_state_await_peer_id;
     593             :         }
     594             : 
     595          11 :         return TX_FOR_DATA_SIZE(tx);
     596          13 :     case OP_UPGRADE_IDENTIFY_PEER:
     597          13 :         check_state(upgrade_state_await_peer_id);
     598             : 
     599          13 :         upgrade_ctx.evidence_external = true;
     600          13 :         if (receive_data(rx,
     601             :                          &upgrade_ctx.evidence,
     602             :                          &upgrade_ctx.evidence_size,
     603             :                          &upgrade_ctx.trx_offset)) {
     604           2 :             SET_APDU_OP(1); // More
     605           2 :             return TX_NO_DATA();
     606             :         }
     607             :         // We received the entire peer evidence. Perform validation
     608           8 :         if (!evidence_verify_and_extract_claims(EVIDENCE_FORMAT,
     609             :                                                 upgrade_ctx.evidence,
     610             :                                                 upgrade_ctx.evidence_size,
     611             :                                                 &claims,
     612             :                                                 &claims_size)) {
     613             :             LOG("Error verifying peer enclave's evidence\n");
     614           1 :             goto upgrade_process_apdu_identify_peer_error;
     615             :         }
     616           7 :         if (!(claim = evidence_get_claim(
     617             :                   claims, claims_size, OE_CLAIM_UNIQUE_ID))) {
     618             :             LOG("Error extracting peer enclave's mrenclave\n");
     619           0 :             goto upgrade_process_apdu_identify_peer_error;
     620             :         }
     621             :         LOG_HEX("Peer enclave's mrenclave:", claim->value, claim->value_size);
     622           7 :         if (claim->value_size != UPGRADE_MRENCLAVE_SIZE ||
     623           7 :             memcmp(claim->value,
     624           7 :                    upgrade_ctx.their_mrenclave,
     625             :                    UPGRADE_MRENCLAVE_SIZE) != 0) {
     626             :             LOG("Peer enclave's mrenclave does not match the spec's "
     627             :                 "mrenclave\n");
     628           2 :             goto upgrade_process_apdu_identify_peer_error;
     629             :         }
     630           5 :         if (!(claim = evidence_get_custom_claim(claims, claims_size))) {
     631             :             LOG("Error extracting peer enclave's public key\n");
     632           1 :             goto upgrade_process_apdu_identify_peer_error;
     633             :         }
     634           4 :         secp_ctx = assert_secp256k1_context_create_and_randomize();
     635           8 :         if (claim->value_size != sizeof(upgrade_ctx.their_pubkey) ||
     636           4 :             !secp256k1_ec_pubkey_parse(
     637           4 :                 secp_ctx, &pubkey, claim->value, claim->value_size)) {
     638             :             LOG("Invalid peer public key received");
     639           0 :             secp256k1_context_destroy(secp_ctx);
     640           0 :             goto upgrade_process_apdu_identify_peer_error;
     641             :         }
     642           4 :         secp256k1_context_destroy(secp_ctx);
     643           4 :         memcpy(upgrade_ctx.their_pubkey, claim->value, claim->value_size);
     644             :         LOG_HEX("Peer public key:",
     645             :                 upgrade_ctx.their_pubkey,
     646             :                 sizeof(upgrade_ctx.their_pubkey));
     647           4 :         upgrade_ctx.state = upgrade_state_ready_for_xchg;
     648           4 :         SET_APDU_OP(0); // Done
     649           4 :         if (claims) {
     650           4 :             if (!evidence_free_claims(claims, claims_size)) {
     651             :                 LOG("Error freeing claims\n");
     652           0 :                 THROW(ERR_INTERNAL);
     653             :             }
     654           4 :             claims = NULL;
     655           4 :             claims_size = 0;
     656           4 :             claim = NULL;
     657             :         }
     658           4 :         free_evidence();
     659           4 :         return TX_NO_DATA();
     660           4 :     upgrade_process_apdu_identify_peer_error:
     661           4 :         if (claims) {
     662           3 :             if (!evidence_free_claims(claims, claims_size)) {
     663             :                 LOG("Error freeing claims\n");
     664           0 :                 THROW(ERR_INTERNAL);
     665             :             }
     666           3 :             claims = NULL;
     667           3 :             claims_size = 0;
     668           3 :             claim = NULL;
     669             :         }
     670           4 :         reset_upgrade();
     671           4 :         THROW(ERR_UPGRADE_AUTH);
     672           4 :     case OP_UPGRADE_PROCESS_DATA:
     673           4 :         check_state(upgrade_state_ready_for_xchg);
     674             : 
     675           4 :         secp_ctx = assert_secp256k1_context_create_and_randomize();
     676           4 :         if (!secp256k1_ec_pubkey_parse(secp_ctx,
     677             :                                        &pubkey,
     678             :                                        upgrade_ctx.their_pubkey,
     679           4 :                                        sizeof(upgrade_ctx.their_pubkey)) ||
     680           4 :             !secp256k1_ecdh(secp_ctx,
     681             :                             key,
     682             :                             &pubkey,
     683             :                             upgrade_ctx.my_privkey,
     684             :                             secp256k1_ecdh_hash_function_sha256,
     685             :                             NULL)) {
     686             :             LOG("Unable to generate data processing key\n");
     687           0 :             reset_upgrade();
     688           0 :             secp256k1_context_destroy(secp_ctx);
     689           0 :             THROW(ERR_UPGRADE_INTERNAL);
     690             :         }
     691           4 :         secp256k1_context_destroy(secp_ctx);
     692           4 :         explicit_bzero(upgrade_ctx.my_privkey, sizeof(upgrade_ctx.my_privkey));
     693           4 :         explicit_bzero(upgrade_ctx.my_pubkey, sizeof(upgrade_ctx.my_pubkey));
     694           4 :         explicit_bzero(upgrade_ctx.their_pubkey,
     695             :                        sizeof(upgrade_ctx.their_pubkey));
     696             : 
     697           4 :         switch (upgrade_ctx.operation) {
     698           2 :         case upgrade_operation_export:
     699             :             LOG("Exporting data...\n");
     700           2 :             sz = APDU_TOTAL_DATA_SIZE_OUT;
     701           2 :             if (!migrate_export(key, sizeof(key), APDU_DATA_PTR, &sz) ||
     702           1 :                 sz != (sz & 0xFF)) {
     703           1 :                 reset_upgrade();
     704           1 :                 THROW(ERR_UPGRADE_DATA_PROCESSING);
     705             :             }
     706             :             LOG("Data export complete\n");
     707           1 :             reset_upgrade();
     708           1 :             return TX_FOR_DATA_SIZE(sz);
     709           2 :         case upgrade_operation_import:
     710             :             LOG("Importing data...\n");
     711           2 :             if (APDU_DATA_SIZE(rx) == 0) {
     712           0 :                 reset_upgrade();
     713           0 :                 THROW(ERR_UPGRADE_PROTOCOL);
     714             :             }
     715           2 :             if (!migrate_import(
     716           2 :                     key, sizeof(key), APDU_DATA_PTR, APDU_DATA_SIZE(rx))) {
     717           1 :                 reset_upgrade();
     718           1 :                 THROW(ERR_UPGRADE_DATA_PROCESSING);
     719             :             }
     720             :             LOG("Data import complete\n");
     721           1 :             reset_upgrade();
     722           1 :             return TX_NO_DATA();
     723           0 :         default:
     724             :             // We should never reach this point
     725             :             LOG("Inconsistent internal state when processing data\n");
     726           0 :             reset_upgrade();
     727           0 :             THROW(ERR_UPGRADE_INTERNAL);
     728             :         }
     729           1 :     default:
     730           1 :         reset_upgrade();
     731           1 :         THROW(ERR_UPGRADE_PROTOCOL);
     732             :         break;
     733             :     }
     734             : }
       |