| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you 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 <stdlib.h> |
| #include <string.h> |
| #include "ecp.h" |
| |
| #include "sample_libcrypto.h" |
| |
| |
| #define MAC_KEY_SIZE 16 |
| |
| errno_t memcpy_s( |
| void *dest, |
| size_t numberOfElements, |
| const void *src, |
| size_t count) { |
| if(numberOfElements<count) |
| return -1; |
| memcpy(dest, src, count); |
| return 0; |
| } |
| |
| bool verify_cmac128( |
| sample_ec_key_128bit_t mac_key, |
| const uint8_t *p_data_buf, |
| uint32_t buf_size, |
| const uint8_t *p_mac_buf) { |
| uint8_t data_mac[SAMPLE_EC_MAC_SIZE]; |
| sample_status_t sample_ret; |
| |
| sample_ret = sample_rijndael128_cmac_msg((sample_cmac_128bit_key_t*)mac_key, |
| p_data_buf, |
| buf_size, |
| (sample_cmac_128bit_tag_t *)data_mac); |
| if(sample_ret != SAMPLE_SUCCESS) |
| return false; |
| // In real implementation, should use a time safe version of memcmp here, |
| // in order to avoid side channel attack. |
| if(!memcmp(p_mac_buf, data_mac, SAMPLE_EC_MAC_SIZE)) |
| return true; |
| return false; |
| } |
| |
| |
| #ifdef SUPPLIED_KEY_DERIVATION |
| |
| #pragma message ("Supplied key derivation function is used.") |
| |
| typedef struct _hash_buffer_t { |
| uint8_t counter[4]; |
| sample_ec_dh_shared_t shared_secret; |
| uint8_t algorithm_id[4]; |
| } hash_buffer_t; |
| |
| const char ID_U[] = "SGXRAENCLAVE"; |
| const char ID_V[] = "SGXRASERVER"; |
| |
| // Derive two keys from shared key and key id. |
| bool derive_key( |
| const sample_ec_dh_shared_t *p_shared_key, |
| uint8_t key_id, |
| sample_ec_key_128bit_t *first_derived_key, |
| sample_ec_key_128bit_t *second_derived_key) { |
| sample_status_t sample_ret = SAMPLE_SUCCESS; |
| hash_buffer_t hash_buffer; |
| sample_sha_state_handle_t sha_context; |
| sample_sha256_hash_t key_material; |
| |
| memset(&hash_buffer, 0, sizeof(hash_buffer_t)); |
| |
| /* counter in big endian */ |
| hash_buffer.counter[3] = key_id; |
| |
| /*convert from little endian to big endian */ |
| for (size_t i = 0; i < sizeof(sample_ec_dh_shared_t) ; i++) { |
| hash_buffer.shared_secret.s[i] = p_shared_key->s[sizeof(p_shared_key->s) - 1 - i]; |
| } |
| |
| sample_ret = sample_sha256_init(&sha_context); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| return false; |
| } |
| sample_ret = sample_sha256_update((uint8_t*)&hash_buffer, sizeof(hash_buffer_t), sha_context); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| sample_sha256_close(sha_context); |
| return false; |
| } |
| sample_ret = sample_sha256_update((uint8_t*)ID_U, sizeof(ID_U), sha_context); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| sample_sha256_close(sha_context); |
| return false; |
| } |
| sample_ret = sample_sha256_update((uint8_t*)ID_V, sizeof(ID_V), sha_context); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| sample_sha256_close(sha_context); |
| return false; |
| } |
| sample_ret = sample_sha256_get_hash(sha_context, &key_material); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| sample_sha256_close(sha_context); |
| return false; |
| } |
| sample_ret = sample_sha256_close(sha_context); |
| |
| static_assert(sizeof(sample_ec_key_128bit_t)* 2 == sizeof(sample_sha256_hash_t), "structure size mismatch."); |
| memcpy(first_derived_key, &key_material, sizeof(sample_ec_key_128bit_t)); |
| memcpy(second_derived_key, (uint8_t*)&key_material + sizeof(sample_ec_key_128bit_t), sizeof(sample_ec_key_128bit_t)); |
| |
| // memset here can be optimized away by compiler, so please use memset_s on |
| // windows for production code and similar functions on other OSes. |
| memset(&key_material, 0, sizeof(sample_sha256_hash_t)); |
| |
| return true; |
| } |
| |
| #else |
| |
| #pragma message ("Default key derivation function is used.") |
| |
| #define EC_DERIVATION_BUFFER_SIZE(label_length) ((label_length) +4) |
| |
| const char str_SMK[] = "SMK"; |
| const char str_SK[] = "SK"; |
| const char str_MK[] = "MK"; |
| const char str_VK[] = "VK"; |
| |
| // Derive key from shared key and key id. |
| // key id should be sample_derive_key_type_t. |
| bool derive_key( |
| const sample_ec_dh_shared_t *p_shared_key, |
| uint8_t key_id, |
| sample_ec_key_128bit_t* derived_key) { |
| sample_status_t sample_ret = SAMPLE_SUCCESS; |
| uint8_t cmac_key[MAC_KEY_SIZE]; |
| sample_ec_key_128bit_t key_derive_key; |
| |
| memset(&cmac_key, 0, MAC_KEY_SIZE); |
| |
| sample_ret = sample_rijndael128_cmac_msg( |
| (sample_cmac_128bit_key_t *)&cmac_key, |
| (uint8_t*)p_shared_key, |
| sizeof(sample_ec_dh_shared_t), |
| (sample_cmac_128bit_tag_t *)&key_derive_key); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| // memset here can be optimized away by compiler, so please use memset_s on |
| // windows for production code and similar functions on other OSes. |
| memset(&key_derive_key, 0, sizeof(key_derive_key)); |
| return false; |
| } |
| |
| const char *label = NULL; |
| uint32_t label_length = 0; |
| switch (key_id) { |
| case SAMPLE_DERIVE_KEY_SMK: |
| label = str_SMK; |
| label_length = sizeof(str_SMK) -1; |
| break; |
| case SAMPLE_DERIVE_KEY_SK: |
| label = str_SK; |
| label_length = sizeof(str_SK) -1; |
| break; |
| case SAMPLE_DERIVE_KEY_MK: |
| label = str_MK; |
| label_length = sizeof(str_MK) -1; |
| break; |
| case SAMPLE_DERIVE_KEY_VK: |
| label = str_VK; |
| label_length = sizeof(str_VK) -1; |
| break; |
| default: |
| // memset here can be optimized away by compiler, so please use memset_s on |
| // windows for production code and similar functions on other OSes. |
| memset(&key_derive_key, 0, sizeof(key_derive_key)); |
| return false; |
| break; |
| } |
| /* derivation_buffer = counter(0x01) || label || 0x00 || output_key_len(0x0080) */ |
| uint32_t derivation_buffer_length = EC_DERIVATION_BUFFER_SIZE(label_length); |
| uint8_t *p_derivation_buffer = (uint8_t *)malloc(derivation_buffer_length); |
| if (p_derivation_buffer == NULL) { |
| // memset here can be optimized away by compiler, so please use memset_s on |
| // windows for production code and similar functions on other OSes. |
| memset(&key_derive_key, 0, sizeof(key_derive_key)); |
| return false; |
| } |
| memset(p_derivation_buffer, 0, derivation_buffer_length); |
| |
| /*counter = 0x01 */ |
| p_derivation_buffer[0] = 0x01; |
| /*label*/ |
| memcpy(&p_derivation_buffer[1], label, label_length); |
| /*output_key_len=0x0080*/ |
| uint16_t *key_len = (uint16_t *)(&(p_derivation_buffer[derivation_buffer_length - 2])); |
| *key_len = 0x0080; |
| |
| |
| sample_ret = sample_rijndael128_cmac_msg( |
| (sample_cmac_128bit_key_t *)&key_derive_key, |
| p_derivation_buffer, |
| derivation_buffer_length, |
| (sample_cmac_128bit_tag_t *)derived_key); |
| free(p_derivation_buffer); |
| // memset here can be optimized away by compiler, so please use memset_s on |
| // windows for production code and similar functions on other OSes. |
| memset(&key_derive_key, 0, sizeof(key_derive_key)); |
| if (sample_ret != SAMPLE_SUCCESS) { |
| return false; |
| } |
| return true; |
| } |
| #endif |