diff --git a/CMakeLists.txt b/CMakeLists.txt index 9910399..2952424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,7 @@ target_sources(pico_hsm PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src/rng/neug.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/crypto_utils.c ${CMAKE_CURRENT_LIST_DIR}/src/hsm/dkek.c + ${CMAKE_CURRENT_LIST_DIR}/src/hsm/eac.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/sha256.c ${CMAKE_CURRENT_LIST_DIR}/mbedtls/library/aes.c diff --git a/src/hsm/eac.c b/src/hsm/eac.c new file mode 100644 index 0000000..a1bc696 --- /dev/null +++ b/src/hsm/eac.c @@ -0,0 +1,67 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "eac.h" +#include "crypto_utils.h" +#include "random.h" +#include "mbedtls/cmac.h" + +static uint8_t nonce[8]; +static uint8_t auth_token[8]; +static uint8_t sm_kmac[16]; +static uint8_t sm_kenc[16]; +static MSE_protocol sm_protocol; + +bool is_secured_apdu() { + return (CLA(apdu) & 0xC); +} + +void sm_derive_key(const uint8_t *input, size_t input_len, uint8_t counter, const uint8_t *nonce, size_t nonce_len, uint8_t *out) { + uint8_t *b = (uint8_t *)calloc(1, input_len+nonce_len+4); + if (input) + memcpy(b, input, input_len); + if (nonce) + memcpy(b+input_len, nonce, nonce_len); + b[input_len+nonce_len+3] = counter; + uint8_t digest[20]; + generic_hash(MBEDTLS_MD_SHA1, b, input_len+nonce_len+4, digest); + memcpy(out, digest, 16); + free(b); +} + +void sm_derive_all_keys(const uint8_t *derived, size_t derived_len) { + memcpy(nonce, random_bytes_get(8), 8); + sm_derive_key(derived, derived_len, 1, nonce, sizeof(nonce), sm_kenc); + sm_derive_key(derived, derived_len, 2, nonce, sizeof(nonce), sm_kmac); +} + +void sm_set_protocol(MSE_protocol proto) { + sm_protocol = proto; +} + +MSE_protocol sm_get_protocol() { + return sm_protocol; +} + +uint8_t *sm_get_nonce() { + return nonce; +} + +int sm_sign(uint8_t *in, size_t in_len, uint8_t *out) { + return mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), sm_kmac, 128, in, in_len, out); +} + diff --git a/src/hsm/eac.h b/src/hsm/eac.h new file mode 100644 index 0000000..0f02a8c --- /dev/null +++ b/src/hsm/eac.h @@ -0,0 +1,37 @@ +/* + * This file is part of the Pico HSM distribution (https://github.com/polhenarejos/pico-hsm). + * Copyright (c) 2022 Pol Henarejos. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _EAC_H_ +#define _EAC_H_ + +#include +#include "pico/stdlib.h" +#include "hsm2040.h" + +typedef enum MSE_protocol { + MSE_AES = 0, + MSE_3DES, + MSE_NONE +}MSE_protocol; + +extern void sm_derive_all_keys(const uint8_t *input, size_t input_len); +extern void sm_set_protocol(MSE_protocol proto); +extern MSE_protocol sm_get_protocol(); +extern uint8_t *sm_get_nonce(); +extern int sm_sign(uint8_t *in, size_t in_len, uint8_t *out); + +#endif diff --git a/src/hsm/hsm2040.h b/src/hsm/hsm2040.h index 996e29d..0b48620 100644 --- a/src/hsm/hsm2040.h +++ b/src/hsm/hsm2040.h @@ -106,7 +106,7 @@ enum ccid_state { CCID_STATE_EXEC_REQUESTED, /* Exec requested */ }; -#define CLS(a) a.cmd_apdu_head[0] +#define CLA(a) a.cmd_apdu_head[0] #define INS(a) a.cmd_apdu_head[1] #define P1(a) a.cmd_apdu_head[2] #define P2(a) a.cmd_apdu_head[3] diff --git a/src/hsm/sc_hsm.c b/src/hsm/sc_hsm.c index c1a2e92..f92d89f 100644 --- a/src/hsm/sc_hsm.c +++ b/src/hsm/sc_hsm.c @@ -33,6 +33,7 @@ #include "crypto_utils.h" #include "dkek.h" #include "hardware/rtc.h" +#include "eac.h" const uint8_t sc_hsm_aid[] = { 11, @@ -1801,14 +1802,6 @@ static int cmd_extras() { return SW_OK(); } -enum MSE_protocol { - MSE_AES = 0, - MSE_3DES, - MSE_NONE -} mse_protocol; -uint8_t nonce[8]; -uint8_t auth_token[8]; - static int cmd_mse() { int p1 = P1(apdu); int p2 = P2(apdu); @@ -1820,12 +1813,13 @@ static int cmd_mse() { uint8_t tag_len = *p++; if (tag == 0x80) { if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", tag_len) == 0) - mse_protocol = MSE_AES; + sm_set_protocol(MSE_AES); else if (tag_len == 10 && memcmp(p, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", tag_len) == 0) - mse_protocol = MSE_3DES; + sm_set_protocol(MSE_3DES); else return SW_REFERENCE_NOT_FOUND(); } + p += tag_len; } } else @@ -1841,23 +1835,70 @@ int cmd_general_authenticate() { if (apdu.cmd_apdu_data[0] == 0x7C) { const uint8_t *p = &apdu.cmd_apdu_data[2]; int r = 0; - mbedtls_ecp_point P; - mbedtls_ecp_point_init(&P); - mbedtls_ecp_group grp; - mbedtls_ecp_group_init(&grp); - r = mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1); - if (r != 0) - return SW_EXEC_ERROR(); + size_t pubkey_len = 0; + const uint8_t *pubkey = NULL; while (p-apdu.cmd_apdu_data < apdu.cmd_apdu_data[1]) { uint8_t tag = *p++; uint8_t tag_len = *p++; if (tag == 0x80) { - int r = mbedtls_ecp_point_read_binary(&grp, &P, p, tag_len); - if (r != 0) - return SW_WRONG_DATA(); + pubkey = p-1; //mbedtls ecdh starts reading one pos before + pubkey_len = tag_len+1; } + p += tag_len; } - memcpy(nonce, random_bytes_get(8), 8); + mbedtls_ecdh_context ctx; + int key_size = file_read_uint16(termca_pk); + mbedtls_ecdh_init(&ctx); + mbedtls_ecp_group_id gid = MBEDTLS_ECP_DP_SECP192R1; + r = mbedtls_ecdh_setup(&ctx, gid); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + r = mbedtls_mpi_read_binary(&ctx.ctx.mbed_ecdh.d, termca_pk+2, key_size); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + r = mbedtls_ecdh_read_public(&ctx, pubkey, pubkey_len); + if (r != 0) { + mbedtls_ecdh_free(&ctx); + return SW_DATA_INVALID(); + } + size_t olen = 0; + uint8_t derived[MBEDTLS_ECP_MAX_BYTES]; + r = mbedtls_ecdh_calc_secret(&ctx, &olen, derived, MBEDTLS_ECP_MAX_BYTES, random_gen, NULL); + mbedtls_ecdh_free(&ctx); + if (r != 0) { + return SW_EXEC_ERROR(); + } + + sm_derive_all_keys(derived, olen); + + uint8_t *t = (uint8_t *)calloc(1, pubkey_len+16); + memcpy(t, "\x7F\x49\x3F\x06\x0A", 5); + if (sm_get_protocol() == MSE_AES) + memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x02", 10); + else if (sm_get_protocol() == MSE_3DES) + memcpy(t+5, "\x04\x00\x7F\x00\x07\x02\x02\x03\x02\x01", 10); + t[15] = 0x86; + memcpy(t+16, pubkey, pubkey_len); + + res_APDU[res_APDU_size++] = 0x7C; + res_APDU[res_APDU_size++] = 20; + res_APDU[res_APDU_size++] = 0x81; + res_APDU[res_APDU_size++] = 8; + memcpy(res_APDU+res_APDU_size, sm_get_nonce(), 8); + res_APDU_size += 8; + res_APDU[res_APDU_size++] = 0x82; + res_APDU[res_APDU_size++] = 8; + + r = sm_sign(t, pubkey_len+16, res_APDU+res_APDU_size); + + free(t); + if (r != HSM_OK) + return SW_EXEC_ERROR(); + res_APDU_size += 8; } } return SW_OK();