text: /*
   * Copyright (c) 2019-2020 Arm Limited. All rights reserved.
   *
   * SPDX-License-Identifier: Apache-2.0
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #include "rtos.h"
  #include "mbed_assert.h"
  #include "val_interfaces.h"
  #include "pal_common.h"
  
  #include "psa/crypto.h"
  #include "entropy_poll.h"
  
  #include "psa_attest_inject_key.h"
  #include "psa_initial_attestation_api.h"
  
  #include "pal_mbed_os_intf.h"
  
  #include "lifecycle.h"
  
  #define TEST_STACK_SIZE 8192
  #define TEST_KEY_ID_VALUE 17
  
  extern val_api_t val_api;
  extern psa_api_t psa_api;
  #ifdef PS_TEST
  extern "C" psa_status_t psa_ps_reset();
  #endif
  
  test_entry_f test_g = NULL;
  compliance_test_type type_g = COMPLIANCE_TEST_UNDEFINED;
  
  // randomly generated attestation key used for testing the attestation feature.
  // The specific key chosen shouldn't matter to the attestation test
  // the test just needs a key to be injected before it is run.
  static const uint8_t private_key_data[] = {
      0x49, 0xc9, 0xa8, 0xc1, 0x8c, 0x4b, 0x88, 0x56,
      0x38, 0xc4, 0x31, 0xcf, 0x1d, 0xf1, 0xc9, 0x94,
      0x13, 0x16, 0x09, 0xb5, 0x80, 0xd4, 0xfd, 0x43,
      0xa0, 0xca, 0xb1, 0x7d, 0xb2, 0xf1, 0x3e, 0xee
  };
  
  static const uint8_t public_key_data[] = {
      0x04, 0x77, 0x72, 0x65, 0x6f, 0x81, 0x4b, 0x39,
      0x92, 0x79, 0xd5, 0xe1, 0xf1, 0x78, 0x1f, 0xac,
      0x6f, 0x09, 0x9a, 0x3c, 0x5c, 0xa1, 0xb0, 0xe3,
      0x53, 0x51, 0x83, 0x4b, 0x08, 0xb6, 0x5e, 0x0b,
      0x57, 0x25, 0x90, 0xcd, 0xaf, 0x8f, 0x76, 0x93,
      0x61, 0xbc, 0xf3, 0x4a, 0xcf, 0xc1, 0x1e, 0x5e,
      0x07, 0x4e, 0x84, 0x26, 0xbd, 0xde, 0x04, 0xbe,
      0x6e, 0x65, 0x39, 0x45, 0x44, 0x96, 0x17, 0xde,
      0x45
  };
  
  static void psa_attestation_destroy_key_for_test()
  {
      psa_key_handle_t handle = 0;
      psa_open_key(TEST_KEY_ID_VALUE, &handle);
      psa_destroy_key(handle);
  }
  
  static void psa_attestation_inject_key_for_test(void)
  {
      size_t exported_length;
      uint8_t exported[sizeof(public_key_data)];
  
      psa_attestation_destroy_key_for_test();
      psa_attestation_inject_key(private_key_data,
                                 sizeof(private_key_data),
                                 PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_CURVE_SECP_R1),
                                 exported,
                                 sizeof(exported),
                                 &exported_length);
  }
  
  
  
  static void reset_storage_for_compliance_test()
  {
  #ifdef ITS_TEST
      mbed_psa_reboot_and_request_new_security_state(PSA_LIFECYCLE_ASSEMBLY_AND_TEST);
  #elif PS_TEST
      psa_ps_reset();
  #endif
  }
  
  #if !defined(MAX)
  #define MAX(a,b) (((a)>(b))?(a):(b))
  #endif
  
  #define MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE \
              MAX(MBEDTLS_ENTROPY_MIN_PLATFORM, MBEDTLS_ENTROPY_BLOCK_SIZE)
  
  static void inject_entropy()
  {
  #if defined(MBEDTLS_ENTROPY_NV_SEED)
      uint8_t seed[MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE] = { 0 };
      for (int i = 0; i < MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE; ++i) {
          seed[i] = i;
      }
      mbedtls_psa_inject_entropy(seed, MBEDTLS_PSA_INJECT_ENTROPY_MIN_SIZE);
  #endif // defined(MBEDTLS_ENTROPY_NV_SEED)
  }
  
  
  
  void main_wrapper(void)
  {
      test_g(&val_api, &psa_api);
  }
  
  
  void pal_mbed_os_compliance_test_initialize(void)
  {
      if (COMPLIANCE_TEST_CRYPTO == type_g) {
          inject_entropy();
      } else if (COMPLIANCE_TEST_STORAGE == type_g) {
          reset_storage_for_compliance_test();
      } else if (COMPLIANCE_TEST_ATTESTATION == type_g) {
          reset_storage_for_compliance_test();
          inject_entropy();
          psa_crypto_init();
          psa_attestation_inject_key_for_test(); // inject key in case needed
      }
  
  }
  
  void pal_mbed_os_compliance_test_destroy(void)
  {
      reset_storage_for_compliance_test();
  }
  
  int test_start(test_entry_f test_f, compliance_test_type type)
  {
      test_g = test_f;
      type_g = type;
  #if defined(MBED_CONF_RTOS_PRESENT)
      MBED_ASSERT((type > COMPLIANCE_TEST_START) && (type < COMPLIANCE_TEST_END));
      Thread thread(osPriorityNormal, TEST_STACK_SIZE, NULL);
      thread.start(main_wrapper);
      thread.join();
  #endif
      return 0;
  }
  