From ee548627af65cc5b2bf329d95b1fb7d504e7ceca Mon Sep 17 00:00:00 2001 From: Jorge Ramirez-Ortiz Date: Mon, 21 Aug 2023 10:11:29 +0200 Subject: [PATCH] options: tee: manufacturing protection This option allows lmp-device-register to interrogate the CAAM hardware for an EC public key (256 bits usually) The key will be stored in /var/sota in PEM format (for reference) and passed to the gateway in DER format. Afer registration aktualizer-lite should periodically request the CAAM hardware to sign random strings and send these signatures to the gateway along with the message. See [1] for optee-client reference. Upon receiving these digests, the gateway shall verify them using the board associated public key [1] https://github.com/OP-TEE/optee_client/pull/352 Signed-off-by: Jorge Ramirez-Ortiz --- CMakeLists.txt | 25 ++++++++--- inc/device_register.h | 9 ++++ inc/pta_imx_manufacturing_protection.h | 35 +++++++++++++++ src/main.cpp | 11 +++++ src/openssl.cpp | 61 ++++++++++++++++++++++++++ src/options.cpp | 12 +++++ src/tee.cpp | 30 +++++++++++++ src/tee_stub.cpp | 21 +++++++++ 8 files changed, 199 insertions(+), 5 deletions(-) create mode 100644 inc/pta_imx_manufacturing_protection.h create mode 100644 src/tee.cpp create mode 100644 src/tee_stub.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1090198..3e3c230 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,14 +63,29 @@ pkg_search_module(GLIB REQUIRED glib-2.0) # Use C++11, but without GNU or other extensions set(CMAKE_CXX_STANDARD 11) +set(LMP_SRCS src/main.cpp src/options.cpp src/auth.cpp src/openssl.cpp) +set(LMP_LIBS ${CURL_LIBRARIES} ${Boost_LIBRARIES} ${GLIB_LDFLAGS} ${OPENSSL_LIBRARIES}) +set(LMP_INCS PRIVATE $ ${GLIB_INCLUDE_DIRS}) + +# PKCS11 configuration if(DISABLE_PKCS11) -add_executable(lmp-device-register src/main.cpp src/options.cpp src/auth.cpp src/pkcs11_stub.cpp src/openssl.cpp) -target_link_libraries(lmp-device-register ${CURL_LIBRARIES} ${Boost_LIBRARIES} ${GLIB_LDFLAGS} ${OPENSSL_LIBRARIES}) +set(LMP_SRCS ${LMP_SRCS} src/pkcs11_stub.cpp) else(DISABLE_PKCS11) pkg_check_modules(LIBP11 REQUIRED libp11) -add_executable(lmp-device-register src/main.cpp src/options.cpp src/auth.cpp src/pkcs11.cpp src/openssl.cpp) -target_link_libraries(lmp-device-register ${CURL_LIBRARIES} ${Boost_LIBRARIES} ${GLIB_LDFLAGS} ${OPENSSL_LIBRARIES} ${LIBP11_LIBRARIES}) +set(LMP_SRCS ${LMP_SRCS} src/pkcs11.cpp) +set(LMP_LIBS ${LMP_LIBS} ${LIBP11_LIBRARIES}) endif(DISABLE_PKCS11) -target_include_directories(lmp-device-register PRIVATE $ ${GLIB_INCLUDE_DIRS}) +# OPTEE_CLIENT configuration +if(ENABLE_TEE) +set(LMP_SRCS ${LMP_SRCS} src/tee.cpp) +set(LMP_LIBS ${LMP_LIBS} ptateec) +set(LMP_INCS ${LMP_INCS} ${OPTEE_TEST_SDK}/host_include) +else(ENABLE_TEE) +set(LMP_SRCS ${LMP_SRCS} src/tee_stub.cpp) +endif(ENABLE_TEE) + +add_executable(lmp-device-register ${LMP_SRCS}) +target_link_libraries(lmp-device-register ${LMP_LIBS}) +target_include_directories(lmp-device-register ${LMP_INCS} ) install(TARGETS lmp-device-register RUNTIME DESTINATION bin) diff --git a/inc/device_register.h b/inc/device_register.h index def8e39..392211d 100644 --- a/inc/device_register.h +++ b/inc/device_register.h @@ -87,8 +87,13 @@ struct lmp_options { string hsm_pin; string sota_dir; string pacman_tags; + struct { + string der; + string pem; + } mprotect_key; bool start_daemon; bool use_server; + bool mprotect; bool production; bool mlock; bool vuuid; @@ -109,9 +114,13 @@ int options_parse(int argc, char **argv, lmp_options &options); int openssl_create_csr(const lmp_options &options, string &key, string &csr); int openssl_gen_csr(const lmp_options &options, EVP_PKEY *pub, EVP_PKEY *priv, string &csr); +int openssl_ec_raw_to_pem_der(string &raw, string &pem, string &der); int pkcs11_create_csr(const lmp_options &options, string &key, string &csr); int pkcs11_store_cert(lmp_options &opt, X509 *cert); int pkcs11_get_uuid(lmp_options &options); int pkcs11_check_hsm(lmp_options &opt); + +int tee_imx_get_mprotect_pubkey(lmp_options &opt); + #endif diff --git a/inc/pta_imx_manufacturing_protection.h b/inc/pta_imx_manufacturing_protection.h new file mode 100644 index 0000000..fe4c274 --- /dev/null +++ b/inc/pta_imx_manufacturing_protection.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * Copyright 2018-2019, 2023 NXP + */ +#ifndef PTA_IMX_MANUFACTURING_PROTECTION_H +#define PTA_IMX_MANUFACTURING_PROTECTION_H + +#define PTA_MANUFACT_PROTEC_UUID { 0x83268b7c, 0x85e3, 0x11e8, \ + { 0xad, 0xc0, 0xfa, 0x7a, 0xe0, 0x1b, 0xbe, 0xbc} } + +/* + * Sign the given message with the manufacturing protection private key + * + * [in] memref[0].buffer Message buffer + * [in] memref[0].size Message size + * [out] memref[1].buffer Signature buffer + * [out] memref[1].size Signature size + * [out] memref[2].buffer MPMR buffer + * [out] memref[2].size MPMR size + */ +#define PTA_IMX_MP_CMD_SIGNATURE_MPMR 0 + +/* + * Get the manufacturing protection public key + * + * [out] memref[0].buffer Public key buffer + * [out] memref[0].size Public key size + * + * Return codes: + * TEE_SUCCESS - Invoke command success + * TEE_ERROR_BAD_PARAMETERS - Incorrect input param + */ +#define PTA_IMX_MP_CMD_GET_PUBLIC_KEY 1 + +#endif /* PTA_IMX_MANUFACTURING_PROTECTION_H */ diff --git a/src/main.cpp b/src/main.cpp index 1c71f79..be1188c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -148,6 +148,10 @@ static void get_device_info(const lmp_options &opt, string &csr, ptree &dev) dev.put("uuid", opt.uuid); dev.put("csr", csr); + /* Manufacturing Protect key */ + if (!opt.mprotect_key.der.empty()) + dev.put("mpkey", opt.mprotect_key.der); + /* HSM information */ put_hsm_info(opt, dev); @@ -214,6 +218,13 @@ static int populate_sota_dir(lmp_options &opt, ptree &resp, string &pkey) out.close(); } + if (!opt.mprotect_key.pem.empty()) { + /* Write the MProtect public key */ + std::ofstream out(opt.sota_dir + "/mprotect_key.pem"); + out << opt.mprotect_key.pem; + out.close(); + } + stringstream sota_toml; for (auto it: resp) { string name = opt.sota_dir + "/" + it.first; diff --git a/src/openssl.cpp b/src/openssl.cpp index 07f0d8f..50e8dd9 100644 --- a/src/openssl.cpp +++ b/src/openssl.cpp @@ -185,3 +185,64 @@ int openssl_create_csr(const lmp_options &options, string &pkey, string &csr) return 0; } + +int openssl_ec_raw_to_pem_der(string &raw, string &key_pem, string &key_der) +{ + EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp256k1); + EC_POINT *point = EC_POINT_new(group); + EC_KEY *ec_key = EC_KEY_new(); + BIGNUM *x_bn = nullptr; + BIGNUM *y_bn = nullptr; + char *pem = nullptr; + char *der = nullptr; + + x_bn = BN_bin2bn((unsigned char *)raw.c_str(), + raw.size() / 2, nullptr); + + y_bn = BN_bin2bn((unsigned char *)raw.c_str() + raw.size() / 2, + raw.size() / 2, nullptr); + + if (!EC_KEY_set_group(ec_key, group)) + leave; + + if (EC_POINT_set_affine_coordinates_GFp(group, point, x_bn, y_bn, + nullptr)) + leave; + + if (!EC_KEY_set_public_key(ec_key, point)) + leave; + + /* Convert the EC public key to DER format and put it in a string */ + int der_len = i2d_EC_PUBKEY(ec_key, (unsigned char **)&der); + if (der_len < 0) + leave; + + string der_str(reinterpret_cast(der), der_len); + key_der = der_str; + + /* Convert the EC public key to PEM format and put it in a string */ + BIO *pem_bio = BIO_new(BIO_s_mem()); + if (pem_bio == nullptr) + leave; + + if (PEM_write_bio_EC_PUBKEY(pem_bio, ec_key) == 0) + leave; + + int pem_len = BIO_get_mem_data(pem_bio, &pem); + if (pem_len < 0) + leave; + + string pem_str(reinterpret_cast(pem), pem_len); + key_pem = pem_str; + + /* Clean up */ + OPENSSL_free(der); + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + BN_free(x_bn); + BN_free(y_bn); + BIO_free(pem_bio); + + return 0; +} \ No newline at end of file diff --git a/src/options.cpp b/src/options.cpp index e16e48b..4e72015 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -52,6 +52,10 @@ namespace po = boost::program_options; #define TAGS_HELP \ "Configure " SOTA_CLIENT " to only apply updates from Targets with these tags." +#define MP_HELP \ +"Enable iMX Manufacturing Protection feature: a board specific ECDSA public" \ +"key will be obtained from the SoC and handled to the server." + #define DAEMON_HELP \ "Start the " SOTA_CLIENT " systemd service after registration." @@ -134,6 +138,7 @@ static void set_default_options(lmp_options &opt, string factory, string tags, ("help", "print usage") OPT_DEF_BOOL("use-ostree-server", opt.use_server, true, OSTREE_SRV_HELP) + OPT_DEF_BOOL("manufacturing-protection,w", opt.mprotect, false, MP_HELP) OPT_DEF_BOOL("production,p", opt.production, prod, PRODUCTION_HELP) OPT_DEF_BOOL("start-daemon", opt.start_daemon,true, DAEMON_HELP) OPT_DEF_STR("sota-dir,d", opt.sota_dir, SOTA_DIR, SOTA_DIR_HELP) @@ -323,6 +328,13 @@ int options_parse(int argc, char **argv, lmp_options &opt) opt.name = opt.uuid; } + if (opt.mprotect) { + if (tee_imx_get_mprotect_pubkey(opt)) { + cerr << "Error reading the MProtection key" << endl; + return -1; + } + } + if (opt.mlock) { if (mlockall(MCL_CURRENT | MCL_FUTURE)) { cout << "Error locking memory " << endl; diff --git a/src/tee.cpp b/src/tee.cpp new file mode 100644 index 0000000..69a5078 --- /dev/null +++ b/src/tee.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023 Foundries.io + * + * SPDX-License-Identifier: MIT + */ +#include +#include +#include + +int tee_imx_get_mprotect_pubkey(lmp_options &opt) +{ + char key[256] = { 0 }; + size_t len = sizeof(key); + string ec_raw; + PTA_RV res; + + memset(key, '\0', len); + + res = pta_imx_mprotect_get_key(key, &len); + if (res != PTAR_OK) { + cout << "Can't get the MProtect key (" << res << ")" << endl; + return -1; + } + + ec_raw = string(key); + + return openssl_ec_raw_to_pem_der(ec_raw, + opt.mprotect_key.pem, + opt.mprotect_key.der); +} \ No newline at end of file diff --git a/src/tee_stub.cpp b/src/tee_stub.cpp new file mode 100644 index 0000000..811f3aa --- /dev/null +++ b/src/tee_stub.cpp @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 Foundries.io + * + * SPDX-License-Identifier: MIT + */ +#include +#include + +int tee_imx_get_mprotect_pubkey(lmp_options &opt) +{ + /* Taken from imx8mm */ + string ec_raw = "8EE2ECDD46EEF367774F225E4EAD75A8" + "0FD71C8A1B03779H9H0808C053584C14" + "6FF5114EA17220A513C15F91D314766D" + "316840DF69740BBB8E48BC39C84887BE"; + + cout << "WARNING: using Manufacturing Protection stub" << endl; + + return openssl_ec_raw_to_pem_der(ec_raw,opt.mprotect_key.pem, + opt.mprotect_key.der); +}