From 7216ea239145e562607e7ab222ad7bd5bfdee486 Mon Sep 17 00:00:00 2001 From: xuraoqing Date: Tue, 18 Feb 2025 12:09:26 +0800 Subject: [PATCH 1/2] add ra_tls support Signed-off-by: xuraoqing --- 0090-add-ra_tls-support.patch | 2054 +++++++++++++++++++++++++++++++++ secGear.spec | 29 +- 2 files changed, 2080 insertions(+), 3 deletions(-) create mode 100644 0090-add-ra_tls-support.patch diff --git a/0090-add-ra_tls-support.patch b/0090-add-ra_tls-support.patch new file mode 100644 index 0000000..1313fec --- /dev/null +++ b/0090-add-ra_tls-support.patch @@ -0,0 +1,2054 @@ +From dcb66bb5945fdb61aaa42799a8a13899a92f04ff Mon Sep 17 00:00:00 2001 +From: xuraoqing +Date: Tue, 18 Feb 2025 11:59:35 +0800 +Subject: [PATCH] add ra_tls support + +Signed-off-by: xuraoqing +--- + component/CMakeLists.txt | 1 + + component/ra_tls/CMakeLists.txt | 43 ++ + component/ra_tls/LICENSE | 194 +++++++ + component/ra_tls/README.md | 3 + + component/ra_tls/openssl_imp.c | 669 ++++++++++++++++++++++++ + component/ra_tls/ra_tls.c | 898 ++++++++++++++++++++++++++++++++ + component/ra_tls/ra_tls.h | 65 +++ + component/ra_tls/ra_tls_imp.h | 97 ++++ + 8 files changed, 1970 insertions(+) + create mode 100644 component/ra_tls/CMakeLists.txt + create mode 100644 component/ra_tls/LICENSE + create mode 100644 component/ra_tls/README.md + create mode 100644 component/ra_tls/openssl_imp.c + create mode 100644 component/ra_tls/ra_tls.c + create mode 100644 component/ra_tls/ra_tls.h + create mode 100644 component/ra_tls/ra_tls_imp.h + +diff --git a/component/CMakeLists.txt b/component/CMakeLists.txt +index 83aa4cd1..4d917455 100644 +--- a/component/CMakeLists.txt ++++ b/component/CMakeLists.txt +@@ -14,6 +14,7 @@ ADD_SUBDIRECTORY(secure_channel) + + ADD_SUBDIRECTORY(remote_attest) + ADD_SUBDIRECTORY(local_attest) ++ADD_SUBDIRECTORY(ra_tls) + + + +diff --git a/component/ra_tls/CMakeLists.txt b/component/ra_tls/CMakeLists.txt +new file mode 100644 +index 00000000..c46a3ee4 +--- /dev/null ++++ b/component/ra_tls/CMakeLists.txt +@@ -0,0 +1,43 @@ ++# Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++# secGear is licensed under the Mulan PSL v2. ++# You can use this software according to the terms and conditions of the Mulan PSL v2. ++# You may obtain a copy of Mulan PSL v2 at: ++# http://license.coscl.org.cn/MulanPSL2 ++# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++# PURPOSE. ++# See the Mulan PSL v2 for more details. ++ ++cmake_minimum_required(VERSION 3.10 FATAL_ERROR) ++project(ra_tls VERSION 0.1) ++ ++set(LIB_NAME ra_tls) ++set(LIB_SRC ${CMAKE_CURRENT_SOURCE_DIR}/ra_tls.c) ++set(LD_SO cjson curl) ++set(HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/ra_tls.h ${CMAKE_CURRENT_SOURCE_DIR}/ra_tls_imp.h) ++if (NOT TLS_LIB) ++set(TLS_LIB OPENSSL) ++endif() ++if (CMAKE_BUILD_TYPE MATCHES Debug) ++add_definitions(-DDEBUG) ++endif() ++if (TLS_LIB MATCHES OPENSSL) ++ add_definitions(-DUSE_OPENSSL) ++ set(LD_SO ${LD_SO} crypto ssl) ++ set(LIB_SRC ${LIB_SRC} ${CMAKE_CURRENT_SOURCE_DIR}/openssl_imp.c) ++else() ++ message(FATAL_ERROR "TLS_LIB should defined") ++endif() ++ ++FILE(GLOB_RECURSE BASE64_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/base64url/*.c") ++include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/base64url) ++ ++set(LIB_SRC ${LIB_SRC} ${BASE64_SRC}) ++add_library(${LIB_NAME} SHARED ${LIB_SRC}) ++target_link_libraries(${LIB_NAME} PUBLIC ${LD_SO}) ++ ++set_target_properties(${LIB_NAME} PROPERTIES PUBLIC_HEADER "${HEADER_FILES}") ++install(TARGETS ${LIB_NAME} ++ LIBRARY DESTINATION ${LOCAL_ROOT_PATH_INSTALL}/usr/lib64 ++ PUBLIC_HEADER DESTINATION ${LOCAL_ROOT_PATH_INSTALL}/usr/include/secGear ++ PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +\ No newline at end of file +diff --git a/component/ra_tls/LICENSE b/component/ra_tls/LICENSE +new file mode 100644 +index 00000000..f63f5a9c +--- /dev/null ++++ b/component/ra_tls/LICENSE +@@ -0,0 +1,194 @@ ++木兰宽松许可证,第2版 ++ ++木兰宽松许可证,第2版 ++ ++2020年1月 http://license.coscl.org.cn/MulanPSL2 ++ ++您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: ++ ++0. 定义 ++ ++“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 ++ ++“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 ++ ++“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 ++ ++“法人实体” 是指提交贡献的机构及其“关联实体”。 ++ ++“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是 ++指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 ++ ++1. 授予版权许可 ++ ++每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可 ++以复制、使用、修改、分发其“贡献”,不论修改与否。 ++ ++2. 授予专利许可 ++ ++每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定 ++撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡 ++献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软 ++件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“ ++关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或 ++其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权 ++行动之日终止。 ++ ++3. 无商标许可 ++ ++“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定 ++的声明义务而必须使用除外。 ++ ++4. 分发限制 ++ ++您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“ ++本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 ++ ++5. 免责声明与责任限制 ++ ++“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对 ++任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于 ++何种法律理论,即使其曾被建议有此种损失的可能性。 ++ ++6. 语言 ++ ++“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文 ++版为准。 ++ ++条款结束 ++ ++如何将木兰宽松许可证,第2版,应用到您的软件 ++ ++如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: ++ ++1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; ++ ++2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; ++ ++3, 请将如下声明文本放入每个源文件的头部注释中。 ++ ++Copyright (c) [Year] [name of copyright holder] ++[Software Name] is licensed under Mulan PSL v2. ++You can use this software according to the terms and conditions of the Mulan ++PSL v2. ++You may obtain a copy of Mulan PSL v2 at: ++ http://license.coscl.org.cn/MulanPSL2 ++THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++See the Mulan PSL v2 for more details. ++ ++Mulan Permissive Software License,Version 2 ++ ++Mulan Permissive Software License,Version 2 (Mulan PSL v2) ++ ++January 2020 http://license.coscl.org.cn/MulanPSL2 ++ ++Your reproduction, use, modification and distribution of the Software shall ++be subject to Mulan PSL v2 (this License) with the following terms and ++conditions: ++ ++0. Definition ++ ++Software means the program and related documents which are licensed under ++this License and comprise all Contribution(s). ++ ++Contribution means the copyrightable work licensed by a particular ++Contributor under this License. ++ ++Contributor means the Individual or Legal Entity who licenses its ++copyrightable work under this License. ++ ++Legal Entity means the entity making a Contribution and all its ++Affiliates. ++ ++Affiliates means entities that control, are controlled by, or are under ++common control with the acting entity under this License, ‘control’ means ++direct or indirect ownership of at least fifty percent (50%) of the voting ++power, capital or other securities of controlled or commonly controlled ++entity. ++ ++1. Grant of Copyright License ++ ++Subject to the terms and conditions of this License, each Contributor hereby ++grants to you a perpetual, worldwide, royalty-free, non-exclusive, ++irrevocable copyright license to reproduce, use, modify, or distribute its ++Contribution, with modification or not. ++ ++2. Grant of Patent License ++ ++Subject to the terms and conditions of this License, each Contributor hereby ++grants to you a perpetual, worldwide, royalty-free, non-exclusive, ++irrevocable (except for revocation under this Section) patent license to ++make, have made, use, offer for sale, sell, import or otherwise transfer its ++Contribution, where such patent license is only limited to the patent claims ++owned or controlled by such Contributor now or in future which will be ++necessarily infringed by its Contribution alone, or by combination of the ++Contribution with the Software to which the Contribution was contributed. ++The patent license shall not apply to any modification of the Contribution, ++and any other combination which includes the Contribution. If you or your ++Affiliates directly or indirectly institute patent litigation (including a ++cross claim or counterclaim in a litigation) or other patent enforcement ++activities against any individual or entity by alleging that the Software or ++any Contribution in it infringes patents, then any patent license granted to ++you under this License for the Software shall terminate as of the date such ++litigation or activity is filed or taken. ++ ++3. No Trademark License ++ ++No trademark license is granted to use the trade names, trademarks, service ++marks, or product names of Contributor, except as required to fulfill notice ++requirements in section 4. ++ ++4. Distribution Restriction ++ ++You may distribute the Software in any medium with or without modification, ++whether in source or executable forms, provided that you provide recipients ++with a copy of this License and retain copyright, patent, trademark and ++disclaimer statements in the Software. ++ ++5. Disclaimer of Warranty and Limitation of Liability ++ ++THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY ++KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR ++COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT ++LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING ++FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO ++MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF ++THE POSSIBILITY OF SUCH DAMAGES. ++ ++6. Language ++ ++THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION ++AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF ++DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION ++SHALL PREVAIL. ++ ++END OF THE TERMS AND CONDITIONS ++ ++How to Apply the Mulan Permissive Software License,Version 2 ++(Mulan PSL v2) to Your Software ++ ++To apply the Mulan PSL v2 to your work, for easy identification by ++recipients, you are suggested to complete following three steps: ++ ++i. Fill in the blanks in following statement, including insert your software ++name, the year of the first publication of your software, and your name ++identified as the copyright owner; ++ ++ii. Create a file named "LICENSE" which contains the whole context of this ++License in the first directory of your software package; ++ ++iii. Attach the statement to the appropriate annotated syntax at the ++beginning of each source file. ++ ++Copyright (c) [Year] [name of copyright holder] ++[Software Name] is licensed under Mulan PSL v2. ++You can use this software according to the terms and conditions of the Mulan ++PSL v2. ++You may obtain a copy of Mulan PSL v2 at: ++ http://license.coscl.org.cn/MulanPSL2 ++THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY ++KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ++NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. ++See the Mulan PSL v2 for more details. +diff --git a/component/ra_tls/README.md b/component/ra_tls/README.md +new file mode 100644 +index 00000000..f926477f +--- /dev/null ++++ b/component/ra_tls/README.md +@@ -0,0 +1,3 @@ ++# ra-tls ++ ++secGear支持ra-tls +\ No newline at end of file +diff --git a/component/ra_tls/openssl_imp.c b/component/ra_tls/openssl_imp.c +new file mode 100644 +index 00000000..82e0fd0a +--- /dev/null ++++ b/component/ra_tls/openssl_imp.c +@@ -0,0 +1,669 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "ra_tls_imp.h" ++ ++#define OID_LEN_MAX 64 ++#define CERT_TIME_STR_LEN 17 ++#define RSA_PRIVATE_KEY_BITS_2048 2048 ++#define RSA_PRIVATE_KEY_BITS_3072 3072 ++#define RSA_PRIVATE_KEY_BUF_2048 2048 ++#define RSA_PRIVATE_KEY_BUF_3072 3072 ++#define RSA_PUB_KEY_BUF_2048 512 ++#define RSA_PUB_KEY_BUF_3072 650 ++ ++#define ERR_CHECK(CONDITION, RESULT, ERRNO, GOTO_ERR, PREFIX) do { \ ++ if ((CONDITION)) { \ ++ RESULT = ERRNO; \ ++ printf("%s:%d, %s: %s", __FILE__, __LINE__, PREFIX, ERR_reason_error_string(ERR_get_error())); \ ++ goto GOTO_ERR; \ ++ } \ ++} while (0) ++ ++const size_t MIN_CERTIFICATE_SIZE = 4096; ++ ++int ra_tls_buf_init(ra_tls_buf *buf, int len) ++{ ++ if (buf == NULL || len < 0) { ++ return -1; ++ } ++ if (len == 0) { ++ buf->buf = NULL; ++ buf->len = 0; ++ buf->filled = 0; ++ return 0; ++ } ++ buf->buf = malloc(len); ++ if (buf->buf == NULL) { ++ return -1; ++ } ++ memset(buf->buf, 0, len); ++ buf->len = len; ++ buf->filled = 0; ++ return len; ++} ++ ++void ra_tls_buf_free(ra_tls_buf *buf) ++{ ++ if (buf == NULL) { ++ return; ++ } ++ if (buf->buf) { ++ free(buf->buf); ++ buf->buf = NULL; ++ } ++ buf->len = 0; ++ buf->filled = 0; ++} ++ ++static int generate_pkey_rsa(EVP_PKEY *pk, key_size key_len) ++{ ++ int ret = -1; ++ int key_bits = 0; ++ if (pk == NULL) { ++ return ret; ++ } ++ EVP_PKEY_CTX *ctx = NULL; ++ if (key_len == RSA_2048) { ++ key_bits = RSA_PRIVATE_KEY_BITS_2048; ++ } else if (key_len == RSA_3072) { ++ key_bits = RSA_PRIVATE_KEY_BITS_3072; ++ } else { ++ printf("unknown key length:%d\n", key_len); ++ return ret; ++ } ++ ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); ++ if (ctx == NULL) { ++ return ret; ++ } ++ int res = EVP_PKEY_keygen_init(ctx); ++ if (res <= 0) { ++ printf("key generate failed (%d)\n", res); ++ ret = -1; ++ goto done; ++ } ++ ++ res = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, key_bits); ++ if (res <= 0) { ++ printf("set_rsa_kengen_bits failed (%d)\n", res); ++ ret = -1; ++ goto done; ++ } ++ res = EVP_PKEY_keygen(ctx, &pk); ++ if (res <= 0) { ++ printf("keygen failed (%d)\n", res); ++ ret = -1; ++ goto done; ++ } ++ ret = 0; ++done: ++ if (ctx) { ++ EVP_PKEY_CTX_free(ctx); ++ } ++ ++ return ret; ++} ++ ++// type = 0, 公钥,=1 私钥 ++static int read_key(EVP_PKEY *pkey, key_type type, ra_tls_buf *key) ++{ ++ BIO *bio = NULL; ++ int ret = -1; ++ int res; ++ if (pkey == NULL) { ++ return ret; ++ } ++ bio = BIO_new(BIO_s_mem()); ++ if (bio == NULL) { ++ printf("bio new failed"); ++ return ret; ++ } ++ if (type == KEY_PUBLIC) { ++ ret = i2d_PUBKEY_bio(bio, pkey); ++ } else if (type == KEY_PRIVATE) { ++ ret = i2d_PrivateKey_bio(bio, pkey); ++ } else { ++ printf("unknown key type\n"); ++ ret = -1; ++ } ++ res = BIO_read(bio, key->buf, key->len); ++ if (res > 0) { ++ ret = 0; ++ key->filled = res; ++ } ++ if (bio) { ++ BIO_free(bio); ++ } ++ bio = NULL; ++ return ret; ++} ++ ++static X509_NAME *create_x509_name(const char *country_name, const char *org, const char *comm_name) ++{ ++ X509_NAME* name = X509_NAME_new(); ++ X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (const unsigned char *)country_name, -1, -1, 0); ++ X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (const unsigned char *)org, -1, -1, 0); ++ X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char *)comm_name, -1, -1, 0); ++ return name; ++} ++ ++static int set_public_key(X509 *cert, ra_tls_buf *pub_key) ++{ ++ int ret = -1; ++ int res = 0; ++ EVP_PKEY *pkey = NULL; ++ BIO *bio = NULL; ++ pkey = EVP_PKEY_new(); ++ ERR_CHECK(pkey == NULL, ret, -1, err, "new public key error"); ++ bio = BIO_new_mem_buf((const void*)pub_key->buf, (int)pub_key->filled); ++ ERR_CHECK(bio == NULL, ret, -1, err, "bio new error"); ++ EVP_PKEY *key = d2i_PUBKEY_bio(bio, &pkey); ++ ERR_CHECK(key == NULL, ret, -1, err, "read public key error"); ++ res = X509_set_pubkey(cert, pkey); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 public key error"); ++ ret = 0; ++err: ++ if (bio) { ++ BIO_free(bio); ++ } ++ if (pkey) { ++ EVP_PKEY_free(pkey); ++ } ++ return ret; ++} ++ ++static int sign_cert(X509 *cert, ra_tls_buf *prv_key) ++{ ++ int ret = -1; ++ int res = 0; ++ EVP_PKEY *pkey = NULL; ++ BIO *bio = NULL; ++ pkey = EVP_PKEY_new(); ++ ERR_CHECK(pkey == NULL, ret, -1, err, "new private key error"); ++ bio = BIO_new_mem_buf((const void*)prv_key->buf, (int)prv_key->filled); ++ ERR_CHECK(bio == NULL, ret, -1, err, "bio new error"); ++ EVP_PKEY *key = d2i_PrivateKey_bio(bio, &pkey); ++ ERR_CHECK(key == NULL, ret, -1, err, "read private key error"); ++ res = X509_sign(cert, pkey, EVP_sha256()); ++ ERR_CHECK(res == 0, ret, -1, err, "sign error"); ++ ret = 0; ++err: ++ if (bio) { ++ BIO_free(bio); ++ } ++ if (pkey) { ++ EVP_PKEY_free(pkey); ++ } ++ return ret; ++} ++ ++static int set_subject(X509 *cert) ++{ ++ int ret = -1; ++ int res = 0; ++ X509_NAME *name = NULL; ++ name = create_x509_name("ZH", "Huawei Corporation", "VirtCCA Enclave"); ++ ERR_CHECK(name == NULL, ret, -1, err, "create subject name error"); ++ res = X509_set_subject_name(cert, name); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 subject name error"); ++ ret = 0; ++err: ++ if (name) { ++ X509_NAME_free(name); ++ } ++ return ret; ++} ++ ++static int set_issuer(X509 *cert) ++{ ++ int ret = -1; ++ int res = 0; ++ X509_NAME *name = NULL; ++ name = create_x509_name("ZH", "Huawei Corporation", "VirtCCA Enclave"); ++ ERR_CHECK(name == NULL, ret, -1, err, "create issuer name error"); ++ res = X509_set_issuer_name(cert, name); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 issuer name error"); ++ ret = 0; ++err: ++ if (name) { ++ X509_NAME_free(name); ++ } ++ return ret; ++} ++ ++static int set_extension(X509 *cert, cert_config *cfg) ++{ ++ int res = 0; ++ int ret = -1; ++ X509V3_CTX ctx; ++ ASN1_OBJECT *obj = NULL; ++ ASN1_OCTET_STRING *data = NULL; ++ X509_EXTENSION *ext = NULL; ++ ++ X509V3_set_ctx_nodb(&ctx); ++ X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0); ++ ++ // set extension ++ ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "CA:FALSE"); ++ res = X509_add_ext(cert, ext, -1); ++ ERR_CHECK(res == 0, ret, -1, err, "x509 add basic constraints error"); ++ X509_EXTENSION_free(ext); ++ ext = NULL; ++ ++ ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_key_identifier, "hash"); ++ res = X509_add_ext(cert, ext, -1); ++ ERR_CHECK(res == 0, ret, -1, err, "x509 add subject key identifier error"); ++ X509_EXTENSION_free(ext); ++ ext = NULL; ++ ++ ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_authority_key_identifier, "keyid:always"); ++ res = X509_add_ext(cert, ext, -1); ++ ERR_CHECK(res == 0, ret, -1, err, "x509 add authority key identifier error"); ++ X509_EXTENSION_free(ext); ++ ext = NULL; ++ ++ // add extension evidence ++ obj = OBJ_txt2obj(cfg->ext_oid, 1); ++ ERR_CHECK(obj == NULL, ret, -1, err, "create asn1 obj error"); ++ data = ASN1_OCTET_STRING_new(); ++ ERR_CHECK(data == NULL, ret, -1, err, "create asn1 string error"); ++ res = ASN1_OCTET_STRING_set(data, cfg->ext.buf, strlen((const char *)cfg->ext.buf)); ++ ERR_CHECK(res == 0, ret, -1, err, "asn1 set string error"); ++ ext = X509_EXTENSION_create_by_OBJ(&ext, obj, 0, data); ++ ERR_CHECK(ext == NULL, ret, -1, err, "create x509 extension error"); ++ res = X509_add_ext(cert, ext, -1); ++ ERR_CHECK(res == 0, ret, -1, err, "x509 add evidence error"); ++ ret = 0; ++err: ++ if (ext) { ++ X509_EXTENSION_free(ext); ++ } ++ if (data) { ++ ASN1_OCTET_STRING_free(data); ++ } ++ if (obj) { ++ ASN1_OBJECT_free(obj); ++ } ++ return ret; ++} ++ ++static int output_certificate_der(ra_tls_buf *output, X509 *cert) ++{ ++ int ret = -1; ++ int res = 0; ++ BIO *bio = NULL; ++ bio = BIO_new(BIO_s_mem()); ++ ERR_CHECK(bio == NULL, ret, -1, err, "bio new failed"); ++ ERR_clear_error(); ++ res = i2d_X509_bio(bio, cert); ++ ERR_CHECK(res == 0, ret, -1, err, "output certificate to bio error"); ++ res = BIO_read(bio, output->buf, output->len); ++ ERR_CHECK(res <= 0, ret, -1, err, "read cert from bio error"); ++ output->filled = res; ++ ret = 0; ++ goto end; ++err: ++ ra_tls_buf_free(output); ++end: ++ if (bio) { ++ BIO_free(bio); ++ } ++ return ret; ++} ++ ++static int generate_x509_self_signed_certificate(ra_tls_buf *output_cert, cert_config *cfg) ++{ ++ int res = 0; ++ int ret = -1; ++ const int x509_ver = 2; // 2 means X509 Version 3 ++ X509 *x509cert = NULL; ++ if (output_cert == NULL || cfg == NULL) { ++ return ret; ++ } ++ ERR_load_crypto_strings(); ++ OPENSSL_init_crypto(0, NULL); ++ // certificate version 3 ++ x509cert = X509_new(); ++ res = X509_set_version(x509cert, x509_ver); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 version error"); ++ ret = set_public_key(x509cert, &(cfg->pub_key)); ++ ERR_CHECK(res < 0, ret, -1, err, "set x509 public key error"); ++ res = set_subject(x509cert); ++ ERR_CHECK(res < 0, ret, -1, err, "set x509 subject name error"); ++ res = set_issuer(x509cert); ++ ERR_CHECK(res < 0, ret, -1, err, "set x509 issuer name error"); ++ ++ // set serial number ++ res = ASN1_INTEGER_set(X509_get_serialNumber(x509cert), 1); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 serial number error"); ++ ++ // set date ++ res = ASN1_TIME_set_string(X509_getm_notBefore(x509cert), cfg->not_before); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 not before error"); ++ res = ASN1_TIME_set_string(X509_getm_notAfter(x509cert), cfg->not_after); ++ ERR_CHECK(res == 0, ret, -1, err, "set x509 not after error"); ++ ++ // set extension ++ res = set_extension(x509cert, cfg); ++ ERR_CHECK(res < 0, ret, -1, err, "set x509 extension error"); ++ // sign certificate ++ res = sign_cert(x509cert, &(cfg->prv_key)); ++ ERR_CHECK(res < 0, ret, -1, err, "sign error"); ++ // output certificate ++ res = ra_tls_buf_init(output_cert, cfg->pub_key.len + cfg->ext.len + MIN_CERTIFICATE_SIZE); ++ ERR_CHECK(res <= 0, ret, -1, err, "init buffer failed"); ++ res = output_certificate_der(output_cert, x509cert); ++ ERR_CHECK(res < 0, ret, -1, err, "output certificate failed"); ++ ret = 0; ++err: ++ if (x509cert) { ++ X509_free(x509cert); ++ } ++ return ret; ++} ++ ++static int openssl_generate_certificate_with_extension(ra_tls_buf *cert, ra_tls_buf *ext, ++ ra_tls_buf *public_key, ra_tls_buf *private_key, const char *oid) ++{ ++ int res = 0; ++ int ret = -1; ++ char not_before[CERT_TIME_STR_LEN] = {0}; ++ char not_after[CERT_TIME_STR_LEN] = {0}; ++ // fill config and generate certificate ++ if (cert == NULL || ext == NULL || public_key == NULL || private_key == NULL || oid == NULL) { ++ return ret; ++ } ++ time_t now = time(NULL); ++ struct tm *tm = localtime(&now); ++ ++ res = strftime(not_before, CERT_TIME_STR_LEN, "%Y%m%d%H%M%SZ", tm); ++ if (!res) { ++ return ret; ++ } ++ tm->tm_year += DEFAULT_CERT_LIFETIME_YEARS; ++ res = strftime(not_after, CERT_TIME_STR_LEN, "%Y%m%d%H%M%SZ", tm); ++ if (!res) { ++ return ret; ++ } ++ cert_config cert_cfg; ++ cert_cfg.prv_key = *private_key; ++ cert_cfg.pub_key = *public_key; ++ cert_cfg.not_before = not_before; ++ cert_cfg.not_after = not_after; ++ cert_cfg.ext_oid = oid; ++ cert_cfg.ext = *ext; ++ res = generate_x509_self_signed_certificate(cert, &cert_cfg); ++ if (res >= 0) { ++ ret = 0; ++ } ++ return ret; ++} ++ ++static int init_key_buffer(key_size key_len, ra_tls_buf *public_key, ra_tls_buf *private_key) ++{ ++ int ret = -1; ++ int pub_len = 0; ++ int prv_len = 0; ++ if (key_len == RSA_2048) { ++ pub_len = RSA_PUB_KEY_BUF_2048; ++ prv_len = RSA_PRIVATE_KEY_BUF_2048; ++ } else if (key_len == RSA_3072) { ++ pub_len = RSA_PUB_KEY_BUF_3072; ++ prv_len = RSA_PRIVATE_KEY_BUF_3072; ++ } else { ++ printf("unknown key length\n"); ++ return -1; ++ } ++ if (ra_tls_buf_init(public_key, pub_len) < 0) { ++ ret = -1; ++ goto err; ++ } ++ if (ra_tls_buf_init(private_key, prv_len) < 0) { ++ ret = -1; ++ goto err; ++ } ++ ret = 0; ++ return ret; ++err: ++ ra_tls_buf_free(public_key); ++ ra_tls_buf_free(private_key); ++ return ret; ++} ++ ++static int get_sha256(ra_tls_buf* hash, ra_tls_buf* input) ++{ ++ int res = 0; ++ int ret = -1; ++ unsigned int hash_len; ++ EVP_MD_CTX *md_ctx; ++ if (hash == NULL || input == NULL) { ++ return ret; ++ } ++ md_ctx = EVP_MD_CTX_new(); ++ if (EVP_DigestInit_ex(md_ctx, EVP_sha256(), NULL) != 1) { ++ goto err; ++ } ++ EVP_DigestUpdate(md_ctx, input->buf, input->filled); ++ ra_tls_buf_init(hash, EVP_MAX_MD_SIZE); ++ hash_len = EVP_MAX_MD_SIZE; ++ res = EVP_DigestFinal_ex(md_ctx, hash->buf, &hash_len); ++ if (res <= 0) { ++ ret = -1; ++ goto err; ++ } ++ hash->filled = hash_len; ++ ret = 0; ++ goto end; ++err: ++ ra_tls_buf_free(hash); ++end: ++ if (md_ctx) { ++ EVP_MD_CTX_free(md_ctx); ++ } ++ return ret; ++} ++ ++int generate_key_pair_der(key_size key_len, ra_tls_buf *public_key, ra_tls_buf *private_key) ++{ ++ int res; ++ int ret = -1; ++ EVP_PKEY *pkey = NULL; ++ ra_tls_buf pub_key = RA_TLS_BUF_INIT; ++ ra_tls_buf prv_key = RA_TLS_BUF_INIT; ++ if (public_key == NULL || private_key == NULL) { ++ return ret; ++ } ++ res = init_key_buffer(key_len, &pub_key, &prv_key); ++ if (res < 0) { ++ return -1; ++ } ++ ++ pkey = EVP_PKEY_new(); ++ if (pkey == NULL) { ++ printf("EVP_PKEY_new return NULL\n"); ++ return ret; ++ } ++ res = generate_pkey_rsa(pkey, key_len); ++ if (res < 0) { ++ printf("generate rsa key failed\n"); ++ ret = -1; ++ goto err; ++ } ++ res = read_key(pkey, KEY_PUBLIC, &pub_key); ++ if (res < 0) { ++ printf("read public key failed\n"); ++ ret = -1; ++ goto err; ++ } ++ res = read_key(pkey, KEY_PRIVATE, &prv_key); ++ if (res < 0) { ++ printf("read private key failed\n"); ++ ret = -1; ++ goto err; ++ } ++ *public_key = pub_key; ++ *private_key = prv_key; ++ ret = 0; ++err: ++ if (pkey) { ++ EVP_PKEY_free(pkey); ++ } ++ return ret; ++} ++ ++int get_hash(ra_tls_buf *hash, ra_tls_buf *input, hash_type type) ++{ ++ switch (type) { ++ case SHA_256: ++ get_sha256(hash, input); ++ break; ++ default: ++ printf("unknown hash type\n"); ++ return -1; ++ } ++ return 0; ++} ++ ++int generate_certificate_with_extension(ra_tls_buf *cert, ra_tls_buf *extension, ra_tls_buf *public_key, ++ ra_tls_buf *private_key, const char *oid) ++{ ++ return openssl_generate_certificate_with_extension(cert, extension, public_key, private_key, oid); ++} ++ ++static int get_extension_from_X509(ra_tls_buf *ext_buf, ra_tls_buf *oid, X509 *cert) ++{ ++ int extensions_cnt = 0; ++ if (cert == NULL || ext_buf == NULL || oid == NULL) { ++ return -1; ++ } ++ const STACK_OF(X509_EXTENSION) *extensions = NULL; ++ if (!(extensions = X509_get0_extensions(cert))) { ++ printf("get extensions failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ return -1; ++ } ++ extensions_cnt = sk_X509_EXTENSION_num(extensions); ++ ++ ra_tls_buf_init(oid, OID_LEN_MAX + 1); ++ for (int i = 0; i < extensions_cnt; i++) { ++ X509_EXTENSION *ext; ++ ASN1_OBJECT *asn1_obj; ++ ASN1_OCTET_STRING *asn1_str; ++ ext = sk_X509_EXTENSION_value(extensions, i); ++ if (ext == NULL) { ++ printf("get extension[%d] failed: %s\n", i, ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ if (!(asn1_obj = X509_EXTENSION_get_object(ext))) { ++ printf("get extensions obj failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ if (!OBJ_obj2txt((char *)oid->buf, oid->len, asn1_obj, 1)) { ++ printf("get extensions oid failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ if (strcmp((const char *)oid->buf, EVIDENCE_OID) != 0 && strcmp((const char *)oid->buf, TOKEN_OID) != 0) { ++ continue; ++ } ++ if (!(asn1_str = X509_EXTENSION_get_data(ext))) { ++ printf("get extensions data failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ ra_tls_buf_init(ext_buf, asn1_str->length + 1); ++ memcpy(ext_buf->buf, asn1_str->data, asn1_str->length); ++ ext_buf->filled = asn1_str->length; ++ ext_buf->buf[ext_buf->filled] = '\0'; ++#ifdef DEBUG ++ printf("oid: %s\n", oid->buf); ++ printf("extension:\n%s\n", ext_buf->buf); ++#endif ++ return 0; ++ } ++err: ++ ra_tls_buf_free(ext_buf); ++ ra_tls_buf_free(oid); ++ return -1; ++} ++// for verify ++int get_extension_from_certificate_context(ra_tls_buf *ext_buf, ra_tls_buf *oid, void *cert_ctx) ++{ ++ int ret = -1; ++ X509 *cert = NULL; ++ X509_STORE_CTX *x509_ctx = (X509_STORE_CTX *)cert_ctx; ++ if (ext_buf == NULL || oid == NULL) { ++ goto end; ++ } ++ cert = X509_STORE_CTX_get_current_cert(x509_ctx); ++ if (cert == NULL) { ++ printf("get certificate failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto end; ++ } ++ if (get_extension_from_X509(ext_buf, oid, cert) < 0) { ++ goto end; ++ } ++ ret = 0; ++end: ++ return ret; ++} ++ ++int get_public_key_from_certificate_context(ra_tls_buf* key_der, void* cert_ctx) ++{ ++ int ret = -1; ++ X509 *cert = NULL; ++ unsigned char *pub_key = NULL; ++ int pub_key_len = 0; ++ X509_STORE_CTX *x509_ctx = (X509_STORE_CTX*)cert_ctx; ++ cert = X509_STORE_CTX_get_current_cert(x509_ctx); ++ if (cert == NULL) { ++ printf("get certificate failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ ra_tls_buf_init(key_der, KEY_SIZE_MAX); ++ pub_key = key_der->buf; ++ pub_key_len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &pub_key); ++ if (pub_key_len <= 0) { ++ printf("get public key failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ key_der->filled = pub_key_len; ++ ret = 0; ++err: ++ return ret; ++} ++ ++int get_extension_from_certificate_der(ra_tls_buf *ext_buf, ra_tls_buf *oid, ra_tls_buf *cert_der) ++{ ++ int ret = -1; ++ BIO *bio_cert = BIO_new_mem_buf(cert_der->buf, cert_der->filled); ++ X509 *icert = NULL; ++ if (d2i_X509_bio(bio_cert, &icert) == NULL) { ++ printf("der read certificate failed: %s\n", ERR_reason_error_string(ERR_get_error())); ++ goto err; ++ } ++ if (get_extension_from_X509(ext_buf, oid, icert) < 0) { ++ goto err; ++ } ++ ret = 0; ++err: ++ if (bio_cert) { ++ BIO_free(bio_cert); ++ } ++ if (icert) { ++ X509_free(icert); ++ } ++ return ret; ++} +diff --git a/component/ra_tls/ra_tls.c b/component/ra_tls/ra_tls.c +new file mode 100644 +index 00000000..eba084fa +--- /dev/null ++++ b/component/ra_tls/ra_tls.c +@@ -0,0 +1,898 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "base64url.h" ++#include "ra_tls.h" ++ ++static char *agent_addr = NULL; ++ ++typedef enum { ++ EVIDENCE, ++ TOKEN ++}extension_type; ++ ++/* internal api */ ++static size_t wb(char *ptr, size_t size, size_t nmemb, void *userdata) ++{ ++ size_t total = size * nmemb; ++ ra_tls_buf *buf = (ra_tls_buf*)userdata; ++ ra_tls_buf_init(buf, total + 1); ++ memcpy(buf->buf, ptr, total); ++ buf->filled = total; ++ buf->buf[buf->filled] = '\0'; ++ return total; ++} ++ ++static int http_request(const char *endpoint, const char *type, const char *data, ra_tls_buf *response) ++{ ++ int ret = -1; ++ CURLcode res; ++ CURL *curl = NULL; ++ struct curl_slist *plist = NULL; ++ curl = curl_easy_init(); ++ if (curl == NULL) { ++ goto err; ++ } ++ plist = curl_slist_append(NULL, "Content-Type:application/json;charset=UTF-8"); ++ curl_easy_setopt(curl, CURLOPT_HTTPHEADER, plist); ++ curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, type); ++ if (data) { ++ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data); ++ } ++ curl_easy_setopt(curl, CURLOPT_URL, endpoint); ++ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, wb); ++ curl_easy_setopt(curl, CURLOPT_WRITEDATA, response); ++ curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); ++ res = curl_easy_perform(curl); ++ if (res != CURLE_OK) { ++ ret = -1; ++ goto err; ++ } ++ ret = 0; ++ goto end; ++err: ++ ra_tls_buf_free(response); ++end: ++ if (plist) { ++ curl_slist_free_all(plist); ++ } ++ if (curl) { ++ curl_easy_cleanup(curl); ++ } ++ return ret; ++} ++ ++static int get_quote(ra_tls_buf *quote, const char *endpoint_prefix, const char *type, ++ const char *uuid, ra_tls_buf *challenge) ++{ ++ int ret = -1; ++ int res = 0; ++ char *endpoint = NULL; ++ size_t endpoint_len = 0; ++ const char *http_data_format = "{\"challenge\":\"%s\",\"uuid\":\"%s\"}"; ++ char *http_data = NULL; ++ int http_data_len; ++ if (endpoint_prefix == NULL || quote == NULL || uuid == NULL || challenge == NULL) { ++ return -1; ++ } ++ endpoint_len = strlen(endpoint_prefix) + strlen(type) + 1; ++ endpoint = malloc(endpoint_len); ++ if (endpoint == NULL) { ++ goto err; ++ } ++ strcpy(endpoint, endpoint_prefix); ++ strcat(endpoint, type); ++ http_data_len = strlen(uuid) + challenge->filled + strlen(http_data_format) + 1; ++ http_data = malloc(http_data_len); ++ if (http_data == NULL) { ++ ret = -1; ++ goto err; ++ } ++ res = sprintf(http_data, http_data_format, challenge->buf, uuid); ++ ++ res = http_request(endpoint, "GET", http_data, quote); ++ if (res < 0) { ++ goto err; ++ } ++ ret = 0; ++ goto end; ++err: ++ ra_tls_buf_free(quote); ++end: ++ if (http_data) { ++ free(http_data); ++ } ++ if (endpoint) { ++ free(endpoint); ++ } ++ return ret; ++} ++ ++static int get_evidence_ok(const ra_tls_buf *evidence) ++{ ++ int ret = -1; ++ cJSON *json_root = NULL; ++ if (evidence == NULL) { ++ return ret; ++ } ++ if (evidence->filled <= 0) { ++ return ret; ++ } ++ json_root = cJSON_Parse((char*)evidence->buf); ++ if (json_root != NULL) { ++ ret = 0; ++ } ++ cJSON_Delete(json_root); ++ return ret; ++} ++static int get_evidence(ra_tls_buf *evidence, const char *endpoint_prefix, const char *uuid, ra_tls_buf *challenge) ++{ ++ int ret = -1; ++ int res = 0; ++ res = get_quote(evidence, endpoint_prefix, "evidence", uuid, challenge); ++ if (res < 0) { ++ return ret; ++ } ++ res = get_evidence_ok(evidence); ++ if (res < 0) { ++ return ret; ++ } ++ ret = 0; ++ return ret; ++} ++ ++static int get_token_ok(const ra_tls_buf *token) ++{ ++ int ret = -1; ++ size_t offset = 0; ++ cJSON *json_root = NULL; ++ uint8_t *header_base64 = NULL; ++ int header_base64_len = 0; ++ char *header = NULL; ++ size_t header_len = 0; ++ if (token == NULL) { ++ return ret; ++ } ++ if (token->filled <= 0) { ++ return ret; ++ } ++ while (offset < token->filled) { ++ // token sperated by '.' ++ if (token->buf[offset] == '.') { ++ break; ++ } ++ offset++; ++ } ++ if (offset == token->filled) { ++ goto err; ++ } ++ header_base64_len = offset; ++ header_base64 = malloc(header_base64_len + 1); ++ memcpy(header_base64, token->buf, header_base64_len); ++ header_base64[header_base64_len] = '\0'; ++ header = (char*)kpsecl_base64urldecode((const char*)header_base64, header_base64_len, &header_len); ++ if (header_len <= 0) { ++ goto err; ++ } ++ json_root = cJSON_Parse((const char*)header); ++ if (json_root != NULL) { ++ ret = 0; ++ } ++err: ++ if (json_root) { ++ cJSON_Delete(json_root); ++ } ++ if (header_base64) { ++ free(header_base64); ++ } ++ if (header) { ++ free(header); ++ } ++ return ret; ++} ++static int get_token(ra_tls_buf *token, const char *endpoint_prefix, const char *uuid, ra_tls_buf *challenge) ++{ ++ int ret = -1; ++ int res = 0; ++ res = get_quote(token, endpoint_prefix, "token", uuid, challenge); ++ if (res < 0) { ++ return ret; ++ } ++ res = get_token_ok(token); ++ if (res < 0) { ++ return ret; ++ } ++ ret = 0; ++ return ret; ++} ++ ++static char *fill_endpoint(char **endpoint, const char *prefix, const char *source) ++{ ++ size_t endpoint_len = 0; ++ endpoint_len = strlen(prefix) + strlen(source) + 1; ++ *endpoint = malloc(endpoint_len); ++ if (*endpoint == NULL) { ++ return NULL; ++ } ++ strcpy(*endpoint, prefix); ++ strcat(*endpoint, source); ++ return *endpoint; ++} ++ ++static char *fill_http_data(char **data, ra_tls_buf *key_hash) ++{ ++ const char *http_data_format = "{\"user_data\":[]}"; ++ size_t data_len = 0; ++ int res; ++ char *ptr; ++ data_len = strlen(http_data_format) + PUBLIC_KEY_HASH_PRINT_LEN + strlen("]}") + 1; ++ *data = malloc(data_len); ++ if (*data == NULL) { ++ return NULL; ++ } ++ ptr = *data; ++ res = sprintf(ptr, "{\"user_data\":["); ++ ptr += res; ++ for (size_t i = 0; i < key_hash->filled; i++) { ++ res = sprintf(ptr, "%hhu,", key_hash->buf[i]); ++ ptr += res; ++ if (ptr >= *data + data_len) { ++ goto err; ++ } ++ } ++ // point to last character ++ --ptr; ++ if (data_len - (ptr - *data) < 3) { // 3 means min buffer left to filled ++ goto err; ++ } ++ (void)sprintf(ptr, "]}"); ++ goto end; ++err: ++ if (*data) { ++ free(*data); ++ *data = NULL; ++ } ++end: ++ return *data; ++} ++ ++static int get_challenge(ra_tls_buf *challenge, const char *endpoint_prefix, ra_tls_buf *user_data) ++{ ++ int res; ++ int ret = -1; ++ const char *source_name = "challenge"; ++ char *endpoint = NULL; ++ char *http_data = NULL; ++ ra_tls_buf key_hash = RA_TLS_BUF_INIT; ++ ra_tls_buf *pub_key = user_data; ++ if (endpoint_prefix == NULL || challenge == NULL || pub_key == NULL) { ++ return -1; ++ } ++ ra_tls_buf_init(&key_hash, 0); ++ get_hash(&key_hash, pub_key, SHA_256); ++#ifdef DEBUG ++ printf("public key hash:"); ++ for (size_t i = 0; i < key_hash.filled; i++) { ++ printf("%02X", key_hash.buf[i]); ++ } ++ printf("\n"); ++#endif ++ if (fill_endpoint(&endpoint, endpoint_prefix, source_name) == NULL) { ++ goto err; ++ } ++ if (fill_http_data(&http_data, &key_hash) == NULL) { ++ goto err; ++ } ++ res = http_request(endpoint, "GET", http_data, challenge); ++ if (res < 0) { ++ goto err; ++ } ++ ret = 0; ++err: ++ if (endpoint) { ++ free(endpoint); ++ } ++ if (http_data) { ++ free(http_data); ++ } ++ ra_tls_buf_free(&key_hash); ++ return ret; ++} ++ ++static int generate_extension_string(ra_tls_buf *extension, ra_tls_buf *challenge, ra_tls_buf *quote) ++{ ++ int ret = -1; ++ cJSON *ext = NULL; ++ char *json_str = NULL; ++ if (extension == NULL || challenge == NULL || quote == NULL) { ++ return ret; ++ } ++ ext = cJSON_CreateObject(); ++ if (ext == NULL) { ++ return ret; ++ } ++ cJSON_AddStringToObject(ext, "challenge", (char *)challenge->buf); ++ cJSON_AddStringToObject(ext, "quote", (char *)quote->buf); ++ if ((json_str = cJSON_PrintUnformatted(ext)) == NULL) { ++ goto err; ++ } ++ cJSON_Minify(json_str); ++ ra_tls_buf_init(extension, strlen(json_str) + 1); ++ strcpy((char *)extension->buf, json_str); ++ extension->filled = strlen(json_str) + 1; ++ ret = 0; ++err: ++ if (ext) { ++ cJSON_Delete(ext); ++ } ++ if (json_str) { ++ cJSON_free(json_str); ++ } ++ return ret; ++} ++ ++static int get_quote_ra(ra_tls_buf *quote, ra_tls_buf *challenge, ra_tls_buf *pub_key, ra_cfg *cfg) ++{ ++ int ret = -1; ++ int res = 0; ++/* ++ get challenge ++ The public key in the signature certificate needs to be protected. ++ now we use pub_key hash concatenated with challenge. ++*/ ++ res = get_challenge(challenge, cfg->aa_addr, pub_key); ++ if (res < 0) { ++ printf("get challenge failed\n"); ++ goto err; ++ } ++#ifdef DEBUG ++ printf("challenge: %s\n", challenge->buf); ++#endif ++ if (cfg->mode == BACKGROUND) { ++ // get evidence ++ res = get_evidence(quote, cfg->aa_addr, cfg->uuid, challenge); ++ if (res < 0) { ++ printf("get evidence failed\n"); ++ goto err; ++ } ++#ifdef DEBUG ++ printf("evidence: %s\n", quote->buf); ++#endif ++ } else if (cfg->mode == PASSPORT) { ++ // get token ++ res = get_token(quote, cfg->aa_addr, cfg->uuid, challenge); ++ if (res < 0) { ++ printf("get token failed\n"); ++ goto err; ++ } ++#ifdef DEBUG ++ printf("token: %s\n", quote->buf); ++#endif ++ } else { ++ printf("unknown work mode\n"); ++ goto err; ++ } ++ ret = 0; ++err: ++ return ret; ++} ++ ++/* output certificate and private key */ ++int ra_tls_generate_certificate(ra_tls_buf *cert, ra_tls_buf *private_key, ra_cfg *cfg, key_size size) ++{ ++ int res; ++ int ret = -1; ++ const char* oid = NULL; ++ ra_tls_buf pub_key = RA_TLS_BUF_INIT; ++ ra_tls_buf prv_key = RA_TLS_BUF_INIT; ++ ra_tls_buf challenge = RA_TLS_BUF_INIT; ++ ra_tls_buf extension = RA_TLS_BUF_INIT; ++ ra_tls_buf quote = RA_TLS_BUF_INIT; ++ if (cert == NULL || private_key == NULL || cfg == NULL) { ++ return ret; ++ } ++ if (cfg->aa_addr == NULL || cfg->uuid == NULL) { ++ return ret; ++ } ++ if (cfg->aa_addr[strlen(cfg->aa_addr) - 1] != '/') { ++ printf("aa_addr should end with '/'\n"); ++ return ret; ++ } ++ res = generate_key_pair_der(size, &pub_key, &prv_key); ++ if (res < 0) { ++ return ret; ++ } ++ *private_key = prv_key; ++ res = get_quote_ra("e, &challenge, &pub_key, cfg); ++ if (res < 0) { ++ goto err; ++ } ++// extension contained: evidence or token and challenge ++ if (generate_extension_string(&extension, &challenge, "e) < 0) { ++ goto err; ++ } ++#ifdef DEBUG ++ printf("certificate extension: %s\n", extension.buf); ++#endif ++// generate certificate ++ oid = (cfg->mode == BACKGROUND)? EVIDENCE_OID : TOKEN_OID; ++ res = generate_certificate_with_extension(cert, &extension, &pub_key, &prv_key, oid); ++ if (res < 0) { ++ ret = -1; ++ } ++ ret = 0; ++err: ++ ra_tls_buf_free(&pub_key); ++ ra_tls_buf_free(&challenge); ++ ra_tls_buf_free(&extension); ++ ra_tls_buf_free("e); ++ return ret; ++} ++ ++// for client to verify externsion in certificate ++int ra_tls_set_addr(char *addr) ++{ ++ if (addr == NULL) { ++ return -1; ++ } ++ if (addr[strlen(addr) - 1] != '/') { ++ printf("host should end with '/'\n"); ++ return -1; ++ } ++ agent_addr = addr; ++ return 0; ++} ++ ++/* ++ token is a string, separated by '.', like this: ++ HEADER.CLAIM.SIGNATURE ++ HEADER,CLAIM encoded by base64_url ++*/ ++static int parse_claim_from_token(ra_tls_buf *claim, ra_tls_buf *token) ++{ ++ size_t claim_start = 0; ++ size_t claim_end = 0; ++ while (claim_start < token->filled) { ++ if (token->buf[claim_start] != '.') { ++ claim_start++; ++ } else { ++ break; ++ } ++ } ++ claim_start++; ++ claim_end = claim_start; ++ while (claim_end < token->filled) { ++ if (token->buf[claim_end] != '.') { ++ claim_end++; ++ } else { ++ break; ++ } ++ } ++ claim_end--; ++ if (claim_end <= claim_start) { ++ return -1; ++ } ++ ra_tls_buf_init(claim, claim_end - claim_start + 1); ++ (void)memcpy(claim->buf, &token->buf[claim_start], claim_end - claim_start + 1); ++ claim->filled = claim_end - claim_start + 1; ++ return 0; ++} ++ ++static int expect_response_true(ra_tls_buf *resp, extension_type mode) ++{ ++ int ret = -1; ++ cJSON *root = NULL; ++ cJSON *obj_parse = NULL; ++ cJSON *obj_get = NULL; ++ if (resp == NULL || resp->buf == NULL) { ++ return -1; ++ } ++ if (mode == EVIDENCE) { ++ root = cJSON_Parse((const char *)resp->buf); ++ cJSON *obj_get = cJSON_GetObjectItemCaseSensitive(root, "evaluation_reports"); ++ if (obj_get == NULL) { ++ goto err; ++ } ++ if (NULL == (obj_get = cJSON_GetObjectItemCaseSensitive(obj_get, "eval_result"))) { ++ goto err; ++ } ++ if (cJSON_IsTrue(obj_get)) { ++ ret = 0; ++ } ++ } else { ++ root = cJSON_Parse((const char*)resp->buf); ++ obj_get = cJSON_GetObjectItemCaseSensitive(root, "claim"); ++ if (obj_get == NULL) { ++ goto err; ++ } ++ char *str = cJSON_GetStringValue(obj_get); ++ if (str == NULL) { ++ goto err; ++ } ++ cJSON* obj_parse = cJSON_Parse(str); ++ cJSON* obj_get = cJSON_GetObjectItemCaseSensitive(obj_parse, "evaluation_reports"); ++ if (obj_get == NULL) { ++ goto err; ++ } ++ if (NULL == (obj_get = cJSON_GetObjectItemCaseSensitive(obj_get, "eval_result"))) { ++ goto err; ++ } ++ if (cJSON_IsTrue(obj_get)) { ++ ret = 0; ++ } ++ } ++err: ++ if (root) { ++ cJSON_Delete(root); ++ } ++ if (obj_parse) { ++ cJSON_Delete(obj_parse); ++ } ++ return ret; ++} ++// extension like this:"{"challenge":"base64_url string","quote":"token or evidence"}" ++static int parse_challenge_from_extension(ra_tls_buf *challenge, ra_tls_buf *ext) ++{ ++ int ret = -1; ++ cJSON *json_root = NULL; ++ cJSON *obj; ++ char *str = NULL; ++ if (challenge == NULL || ext == NULL) { ++ return ret; ++ } ++ if (NULL == (json_root = cJSON_Parse((const char*)ext->buf))) { ++ goto err; ++ } ++ if (NULL == (obj = cJSON_GetObjectItemCaseSensitive(json_root, "challenge"))) { ++ goto err; ++ } ++ if (NULL == (str = cJSON_GetStringValue(obj))) { ++ goto err; ++ } ++ ra_tls_buf_init(challenge, strlen(str) + 1); ++ strcpy((char *)challenge->buf, str); ++ challenge->filled = strlen(str) + 1; ++ ret = 0; ++err: ++ if (json_root) { ++ cJSON_Delete(json_root); ++ } ++ return ret; ++} ++ ++static int parse_quote_from_extension(ra_tls_buf *quote, ra_tls_buf *ext) ++{ ++ int ret = -1; ++ cJSON *json_root = NULL; ++ cJSON *obj; ++ char *str = NULL; ++ if (quote == NULL || ext == NULL) { ++ return ret; ++ } ++ if (NULL == (json_root = cJSON_Parse((const char *)ext->buf))) { ++ goto err; ++ } ++ if (NULL == (obj = cJSON_GetObjectItemCaseSensitive(json_root, "quote"))) { ++ goto err; ++ } ++ if (NULL == (str = cJSON_GetStringValue(obj))) { ++ goto err; ++ } ++ ra_tls_buf_init(quote, strlen(str) + 1); ++ strcpy((char *)quote->buf, str); ++ quote->filled = strlen(str) + 1; ++ ret = 0; ++err: ++ if (json_root) { ++ cJSON_Delete(json_root); ++ } ++ return ret; ++} ++ ++static char *generate_ra_http_data(extension_type type, char **http_data, ra_tls_buf *quote, ra_tls_buf *challenge) ++{ ++ if (type == EVIDENCE) { ++ cJSON* obj = cJSON_CreateObject(); ++ cJSON_AddStringToObject(obj, "evidence", (const char *)quote->buf); ++ cJSON_AddStringToObject(obj, "challenge", (const char *)challenge->buf); ++ *http_data = cJSON_PrintUnformatted(obj); ++ cJSON_Minify(*http_data); ++ cJSON_Delete(obj); ++ } else { ++ cJSON* obj = cJSON_CreateObject(); ++ cJSON_AddStringToObject(obj, "token", (const char *)quote->buf); ++ *http_data = cJSON_PrintUnformatted(obj); ++ cJSON_Minify(*http_data); ++ cJSON_Delete(obj); ++ } ++ return *http_data; ++} ++ ++static int verify_extension_ra(extension_type type, ra_tls_buf *quote, ra_tls_buf *challenge) ++{ ++ int ret = -1; ++ int res = 0; ++ ra_tls_buf response = RA_TLS_BUF_INIT; ++ const char *source_name = NULL; ++ char *endpoint = NULL; ++ size_t endpoint_len = 0; ++ char *http_data = NULL; ++ ++ if (type == EVIDENCE) { ++ source_name = "evidence"; ++ } else if (type == TOKEN) { ++ source_name = "token"; ++ } else { ++ printf("unkonwn extension type\n"); ++ goto err; ++ } ++ endpoint_len = strlen(agent_addr) + strlen(source_name) + 1; ++ endpoint = malloc(endpoint_len); ++ if (endpoint == NULL) { ++ goto err; ++ } ++ strcpy(endpoint, agent_addr); ++ strcat(endpoint, source_name); ++ generate_ra_http_data(type, &http_data, quote, challenge); ++#ifdef DEBUG ++ printf("http request\n"); ++ printf("endpoint: %s\n", endpoint); ++ printf("http data: %s\n", http_data); ++#endif ++ res = http_request(endpoint, "POST", http_data, &response); ++ if (res < 0) { ++ goto err; ++ } ++#ifdef DEBUG ++ printf("response: %s\n", response.buf); ++#endif ++ // check as service response ++ if (expect_response_true(&response, type) != 0) { ++ printf("expect evaluation_reports.eval_result = true, but false or not exist\n"); ++ goto err; ++ } ++ ret = 0; ++err: ++ if (endpoint) { ++ free(endpoint); ++ } ++ if (http_data) { ++ cJSON_free(http_data); ++ } ++ ra_tls_buf_free(&response); ++ return ret; ++} ++ ++static int verify_extension(ra_tls_buf *ext, extension_type type) ++{ ++ int ret = -1; ++ int res; ++ ra_tls_buf challenge = RA_TLS_BUF_INIT; ++ ra_tls_buf quote = RA_TLS_BUF_INIT; ++ ++ if (agent_addr == NULL || ext == NULL) { ++ return ret; ++ } ++ res = parse_challenge_from_extension(&challenge, ext); ++ if (res < 0) { ++ goto err; ++ } ++ res = parse_quote_from_extension("e, ext); ++ if (res < 0) { ++ goto err; ++ } ++ res = verify_extension_ra(type, "e, &challenge); ++ if (res != 0) { ++ ret = -1; ++ } else { ++ ret = 0; ++ } ++err: ++ ra_tls_buf_free(&challenge); ++ ra_tls_buf_free("e); ++ return ret; ++} ++ ++// challenge :last 32 bytes in base64_url_decode(challenge) is the public key hash ++static int get_public_key_hash(ra_tls_buf *key_hash, ra_tls_buf *ext) ++{ ++ int ret = -1; ++ int res; ++ ra_tls_buf challenge_base64 = RA_TLS_BUF_INIT; ++ uint8_t* challenge = NULL; ++ size_t challenge_len = 0; ++ res = parse_challenge_from_extension(&challenge_base64, ext); ++ if (res < 0) { ++ goto err; ++ } ++ challenge = kpsecl_base64urldecode((const char*)challenge_base64.buf, challenge_base64.filled, &challenge_len); ++ if (challenge == NULL || challenge_len < HASH_OFFSET + HASH_LEN) { ++ goto err; ++ } ++ ra_tls_buf_init(key_hash, HASH_LEN); ++ memcpy(key_hash->buf, &challenge[HASH_OFFSET], HASH_LEN); ++ key_hash->filled = HASH_LEN; ++ ret = 0; ++err: ++ ra_tls_buf_free(&challenge_base64); ++ if (challenge) { ++ free(challenge); ++ } ++ return ret; ++} ++ ++static int check_public_key_hash(ra_tls_buf *key_hash, ra_tls_buf *ker_der) ++{ ++ int ret = -1; ++ ra_tls_buf cal_hash = RA_TLS_BUF_INIT; ++ ra_tls_buf_init(&cal_hash, HASH_LEN); ++ if (key_hash->filled != HASH_LEN) { ++ return -1; ++ } ++ if (0 != get_hash(&cal_hash, ker_der, SHA_256)) { ++ goto err; ++ } ++#ifdef DEBUG ++ printf("compare key hash\n"); ++ printf("expected: "); ++ for (size_t i = 0; i < key_hash->filled; i++) { ++ printf("%02X", key_hash->buf[i]); ++ } ++ printf("\n"); ++ printf("get hash of input: "); ++ for (size_t i = 0; i < cal_hash.filled; i++) { ++ printf("%02X", cal_hash.buf[i]); ++ } ++ printf("\n"); ++#endif ++ if (0 != memcmp(key_hash->buf, cal_hash.buf, cal_hash.filled)) { ++ printf("public key hash check Failed\n"); ++ goto err; ++ } ++ ret = 0; ++err: ++ ra_tls_buf_free(&cal_hash); ++ return ret; ++} ++ ++bool ra_tls_cert_extension_expired(ra_tls_buf *cert) ++{ ++ bool ret = true; ++ ra_tls_buf token = RA_TLS_BUF_INIT; ++ ra_tls_buf oid = RA_TLS_BUF_INIT; ++ ra_tls_buf claim = RA_TLS_BUF_INIT; ++ char *raw_claim = NULL; ++ size_t raw_claim_len = 0; ++ cJSON *root = NULL; ++ cJSON *obj_get = NULL; ++ size_t expired = 0; ++ if (cert == NULL || cert->filled == 0) { ++ goto err; ++ } ++ if (get_extension_from_certificate_der(&token, &oid, cert) < 0) { ++ goto err; ++ } ++ // check extension expired ++ if (parse_claim_from_token(&claim, &token) < 0) { ++ goto err; ++ } ++ raw_claim = (char*)kpsecl_base64urldecode((const char *)claim.buf, claim.filled, &raw_claim_len); ++ if (raw_claim == NULL) { ++ goto err; ++ } ++#ifdef DEBUG ++ printf("raw claim: %s", raw_claim); ++#endif ++ root = cJSON_Parse(raw_claim); ++ if (root == NULL) { ++ goto err; ++ } ++ obj_get = cJSON_GetObjectItemCaseSensitive(root, "exp"); ++ if (obj_get == NULL || !cJSON_IsNumber(obj_get)) { ++ goto err; ++ } ++ expired = cJSON_GetNumberValue(obj_get); ++ if ((size_t)time(NULL) + EXTENSION_EXPIRED_OFFSET_SECONDS >= expired) { ++ ret = true; ++ } else { ++ ret = false; ++ } ++err: ++ ra_tls_buf_free(&token); ++ ra_tls_buf_free(&oid); ++ ra_tls_buf_free(&claim); ++ if (raw_claim) { ++ free(raw_claim); ++ } ++ if (root) { ++ cJSON_Delete(root); ++ } ++ return ret; ++} ++ ++static int verify_certificate_extension(void *cert_ctx) ++{ ++ int res; ++ int ret = -1; ++ ra_tls_buf ext = RA_TLS_BUF_INIT; ++ ra_tls_buf key_hash = RA_TLS_BUF_INIT; ++ ra_tls_buf key_der = RA_TLS_BUF_INIT; ++ ra_tls_buf oid = RA_TLS_BUF_INIT; ++ extension_type type; ++ ++// below depend api declare in ra_tls_imp.h ++ res = get_extension_from_certificate_context(&ext, &oid, cert_ctx); ++ if (res < 0) { ++ printf("get extension from certificate failed\n"); ++ goto err; ++ } ++ if (strcmp((const char*)oid.buf, EVIDENCE_OID) == 0) { ++ type = EVIDENCE; ++ } else if (strcmp((const char*)oid.buf, TOKEN_OID) == 0) { ++ type = TOKEN; ++ } else { ++ goto err; ++ } ++ res = verify_extension(&ext, type); ++ if (res < 0) { ++ printf("extension verfiy failed\n"); ++ goto err; ++ } ++ res = get_public_key_from_certificate_context(&key_der, cert_ctx); ++ if (res < 0) { ++ printf("get public key failed\n"); ++ } ++ res = get_public_key_hash(&key_hash, &ext); ++ if (res < 0) { ++ printf("get public key hash failed\n"); ++ } ++ res = check_public_key_hash(&key_hash, &key_der); ++ if (res < 0) { ++ printf("public key hash check failed\n"); ++ goto err; ++ } ++ // success ++ ret = 0; ++err: ++ ra_tls_buf_free(&ext); ++ ra_tls_buf_free(&key_hash); ++ ra_tls_buf_free(&key_der); ++ ra_tls_buf_free(&oid); ++ return ret; ++} ++ ++#ifdef USE_OPENSSL ++// 0 failed 1 ok ++int ra_tls_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) ++{ ++ int res; ++ int ret = 1; ++ if (preverify_ok == 0) { ++ res = X509_STORE_CTX_get_error(x509_ctx); ++ if (res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { ++ printf("self-signed certificate\n"); ++ ret = 1; ++ return ret; ++ } ++ } ++ res = verify_certificate_extension(x509_ctx); ++ if (res < 0) { ++ ret = 0; ++ } ++ return ret; ++} ++#endif +\ No newline at end of file +diff --git a/component/ra_tls/ra_tls.h b/component/ra_tls/ra_tls.h +new file mode 100644 +index 00000000..a3dca269 +--- /dev/null ++++ b/component/ra_tls/ra_tls.h +@@ -0,0 +1,65 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++#ifndef RA_TLS_H_ ++#define RA_TLS_H_ ++ ++#ifndef __cplusplus ++#include ++#endif ++#if defined(USE_OPENSSL) ++#include ++#include ++#include ++#elif defined(USE_MBEDTLS) ++#include ++#include ++#include ++#endif ++#include "ra_tls_imp.h" ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++typedef struct { ++ // attestation agent listen address ++ char *aa_addr; ++ char *uuid; ++ ra_mode mode; ++}ra_cfg; ++ ++#define CHALLENGE_LEN 64 ++#define HASH_LEN 32 ++#define HASH_OFFSET 32 ++#define PUBLIC_KEY_HASH_PRINT_LEN (4 * HASH_LEN) ++#define EXTENSION_EXPIRED_OFFSET_SECONDS (5) ++ ++int ra_tls_generate_certificate(ra_tls_buf *cert, ra_tls_buf *private_key, ra_cfg *cfg_ra, key_size size); ++// set attestation agent address, addr is ip:port or domain:port ++int ra_tls_set_addr(char *addr); ++// cert is DER-encoded ++bool ra_tls_cert_extension_expired(ra_tls_buf *cert); ++ ++#if defined(USE_OPENSSL) ++// return 0 failed, 1 ok ++int ra_tls_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); ++#elif defined(USE_MBEDTLS) ++// return 0 ok, or failed result ++int ra_tls_verify_callback(void *data, mbedtls_509_crt *crt, int depth, uint32_t *flasgs); ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +\ No newline at end of file +diff --git a/component/ra_tls/ra_tls_imp.h b/component/ra_tls/ra_tls_imp.h +new file mode 100644 +index 00000000..5d85ba98 +--- /dev/null ++++ b/component/ra_tls/ra_tls_imp.h +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++#ifndef RA_TLS_IMP_H_ ++#define RA_TLS_IMP_H_ ++#include ++#include ++#if defined(USE_OPENSSL) ++#include ++#include ++#include ++#else ++ #error TLS library Must be specified ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++// todo register oid ++#define EVIDENCE_OID "1.3.6.1.4.1.2011.2.8" ++#define TOKEN_OID "1.3.6.1.4.1.2011.2.10" ++ ++#define KEY_SIZE_MAX (3072) ++#define DEFAULT_CERT_LIFETIME_YEARS (1) ++ ++typedef struct { ++ uint8_t *buf; ++ size_t len; ++ size_t filled; ++} ra_tls_buf; ++ ++typedef enum key_size_t { ++ RSA_2048, ++ RSA_3072 ++} key_size; ++ ++typedef enum key_type_t { ++ KEY_PUBLIC, ++ KEY_PRIVATE ++} key_type; ++ ++typedef enum hash_type_t { ++ SHA_256, ++ SHA_512 ++} hash_type; ++ ++typedef enum ra_mode_t { ++ BACKGROUND, ++ PASSPORT ++} ra_mode; ++ ++typedef struct { ++ ra_tls_buf prv_key; ++ ra_tls_buf pub_key; ++ char *subject_name; ++ char *issuer_name; ++ char *not_before; // format:YYYYMMDDHHMMSSZ ++ char *not_after; // format:YYYYMMDDHHMMSSZ ++ const char *ext_oid; ++ ra_tls_buf ext; ++} cert_config; ++ ++#define RA_TLS_BUF_INIT {NULL, 0, 0} ++int ra_tls_buf_init(ra_tls_buf *buf, int len); ++void ra_tls_buf_free(ra_tls_buf *buf); ++ ++int get_hash(ra_tls_buf *hash, ra_tls_buf *input, hash_type type); ++int generate_key_pair_der(key_size key_len, ra_tls_buf *public_key, ra_tls_buf *private_key); ++// generate pem certificate,use evidence filled extension specified by oid ++int generate_certificate_with_extension(ra_tls_buf *cert, ra_tls_buf *evidence, ra_tls_buf *public_key, ++ ra_tls_buf *private_key, const char *oid); ++ ++#if defined(USE_OPENSSL) ++/* ++ get extension by oid (EVIDENCE_OID or TOKEN_OID) in certificate ++ cert_ctx associate with library, it may be a runtime context ++*/ ++int get_extension_from_certificate_context(ra_tls_buf *ext_buf, ra_tls_buf *oid, void *cert_ctx); ++int get_public_key_from_certificate_context(ra_tls_buf *key_der, void *cert_ctx); ++int get_extension_from_certificate_der(ra_tls_buf *ext_buf, ra_tls_buf *oid, ra_tls_buf *cert_der); ++#endif ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +-- +2.46.0 + diff --git a/secGear.spec b/secGear.spec index 53871b1..4f20e68 100644 --- a/secGear.spec +++ b/secGear.spec @@ -1,6 +1,6 @@ Name: secGear Version: 0.1.0 -Release: 53 +Release: 54 Summary: secGear is an SDK to develop confidential computing apps based on hardware enclave features @@ -98,8 +98,8 @@ Patch84: 0085-fix-multi-thread-request-as-generate-challenge-and-v.patch Patch85: 0086-add-error-type-for-api.patch Patch86: 0087-use-id-when-get-policy.patch Patch87: 0088-fix-evidence-decode-typos.patch -Patch88: 0089-features-support-resource-maitainance.patch - +Patch88: 0089-features-support-resource-maitainance.patch +Patch89: 0090-add-ra_tls-support.patch BuildRequires: gcc python automake autoconf libtool BUildRequires: glibc glibc-devel cmake ocaml-dune rpm gcc-c++ compat-openssl11-libs compat-openssl11-devel @@ -158,6 +158,19 @@ Summary: Attestation Client for %{name} The %{name}-ac provides command line tool for attestation service. %endif +%package ra_tls +Summary: RA_TLS for %{name} +Requires: cjson curl compat-openssl11-libs +BUildRequires: libcurl-devel cjson-devel compat-openssl11-devel +%description ra_tls +The %{name}-ra_tls package support tls depend on remote attestation + +%package ra_tls-devel +Summary: Development files for %{name}-ra_tls-devel +Requires: libcurl-devel cjson-devel compat-openssl11-devel +%description ra_tls-devel +The %{name}-ra_tls-devel contains Header file for using RA_TLS + %prep %autosetup -n %{name} -p1 %ifnarch x86_64 @@ -287,6 +300,7 @@ popd %exclude %{_bindir}/attestation-service %exclude %{_bindir}/attestation-client %{_includedir}/secGear/* +%exclude %{_includedir}/secGear/ra_tls* %ifarch x86_64 %files sim @@ -313,10 +327,19 @@ popd %endif +%files ra_tls +%{_libdir}/libra_tls.so + +%files ra_tls-devel +%{_includedir}/secGear/ra_tls* + %post systemctl restart rsyslog %changelog +* Tue Feb 18 2025 xuraoqing - 0.1.0-54 +- add ra_tls support + * Sat Feb 15 chenjiayi - 0.1.0-53 - support resource maintainance -- Gitee From 0253984c60fc57446f5b1d34e4e2224c881ad6b4 Mon Sep 17 00:00:00 2001 From: chenjiayi Date: Wed, 19 Feb 2025 00:37:50 +0800 Subject: [PATCH 2/2] fix: fix some bugs 1. allow bind, unbind and clear resource policy when the resource already exists. 2. use etc as the base directory for resource storage instead of run, to avoid data loss after system reboot. --- ...nbind-and-clear-resource-policy-when.patch | 119 ++++++++++++++++++ ...he-base-directory-for-resource-stora.patch | 39 ++++++ secGear.spec | 11 +- 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 0091-fix-allow-bind-unbind-and-clear-resource-policy-when.patch create mode 100644 0092-fix-use-etc-as-the-base-directory-for-resource-stora.patch diff --git a/0091-fix-allow-bind-unbind-and-clear-resource-policy-when.patch b/0091-fix-allow-bind-unbind-and-clear-resource-policy-when.patch new file mode 100644 index 0000000..4a197f1 --- /dev/null +++ b/0091-fix-allow-bind-unbind-and-clear-resource-policy-when.patch @@ -0,0 +1,119 @@ +From 435f93ddb97be16f60fcd1ace909cafb418f642b Mon Sep 17 00:00:00 2001 +From: chenjiayi +Date: Wed, 19 Feb 2025 10:59:20 +0800 +Subject: [PATCH 1/1] fix: allow bind, unbind and clear resource policy when + resource already exists + +This influence the interface behavior for: +resource policy bind, +resource policy unbind, +resource policy clear. +--- + .../src/resource/admin/simple.rs | 2 +- + .../src/resource/storage/mod.rs | 9 +++++++-- + .../src/resource/storage/simple.rs | 19 ++++++++++++------- + 3 files changed, 20 insertions(+), 10 deletions(-) + +diff --git a/service/attestation/attestation-types/src/resource/admin/simple.rs b/service/attestation/attestation-types/src/resource/admin/simple.rs +index 5967be9..bf2b5dd 100644 +--- a/service/attestation/attestation-types/src/resource/admin/simple.rs ++++ b/service/attestation/attestation-types/src/resource/admin/simple.rs +@@ -106,7 +106,7 @@ impl ResourceAdminInterface for SimpleResourceAdmin { + self.storage_engine + .lock() + .await +- .store(location, resource) ++ .store(location, resource, false) + .await + } + +diff --git a/service/attestation/attestation-types/src/resource/storage/mod.rs b/service/attestation/attestation-types/src/resource/storage/mod.rs +index fd7b0c7..3614769 100644 +--- a/service/attestation/attestation-types/src/resource/storage/mod.rs ++++ b/service/attestation/attestation-types/src/resource/storage/mod.rs +@@ -29,7 +29,12 @@ pub(crate) trait StorageOp: Send + Sync { + /// Traverse and collect resource list in particular vendor. + async fn list(&self, vendor: &str) -> Result>; + /// Create a new resource if it does not exist. If the resource already exists, error will be thrown. +- async fn store(&self, location: ResourceLocation, resource: Resource) -> Result<()>; ++ async fn store( ++ &self, ++ location: ResourceLocation, ++ resource: Resource, ++ force: bool, ++ ) -> Result<()>; + /// Override the content field in the resource, while keep other fields the same. + async fn modify(&self, location: ResourceLocation, content: String) -> Result<()>; + /// Delete the resource inside the storage. +@@ -51,7 +56,7 @@ pub(crate) trait PolicyOp: StorageOp + Send + Sync { + /// Get all policy from the resource. + async fn get_all_policies(&self, location: ResourceLocation) -> Result>; + /// Clear the original policy inside the resource. +- async fn clea_policies(&self, location: ResourceLocation) -> Result<()>; ++ async fn clear_policies(&self, location: ResourceLocation) -> Result<()>; + /// Delete the specific policy from the resource. + async fn unbind_policies( + &self, +diff --git a/service/attestation/attestation-types/src/resource/storage/simple.rs b/service/attestation/attestation-types/src/resource/storage/simple.rs +index b8fd536..d5f1bc5 100644 +--- a/service/attestation/attestation-types/src/resource/storage/simple.rs ++++ b/service/attestation/attestation-types/src/resource/storage/simple.rs +@@ -82,10 +82,15 @@ impl StorageOp for SimpleStorage { + Ok(ret) + } + +- async fn store(&self, location: ResourceLocation, resource: Resource) -> Result<()> { ++ async fn store( ++ &self, ++ location: ResourceLocation, ++ resource: Resource, ++ force: bool, ++ ) -> Result<()> { + let regularized = self.regular(&format!("{}", location))?; + +- if regularized.exists() { ++ if !force && regularized.exists() { + return Err(ResourceError::ResourceExist(location.to_string())); + } + +@@ -132,16 +137,16 @@ impl PolicyOp for SimpleStorage { + ) -> Result<()> { + let mut resource = self.get(location.clone()).await?; + resource.set_policy(policy); +- self.store(location, resource).await ++ self.store(location, resource, true).await + } + async fn get_all_policies(&self, location: ResourceLocation) -> Result> { + let resource = self.get(location).await?; + Ok(resource.get_policy()) + } +- async fn clea_policies(&self, location: ResourceLocation) -> Result<()> { ++ async fn clear_policies(&self, location: ResourceLocation) -> Result<()> { + let mut resource = self.get(location.clone()).await?; + resource.policy = vec![]; +- self.store(location, resource).await ++ self.store(location, resource, true).await + } + async fn unbind_policies( + &self, +@@ -155,7 +160,7 @@ impl PolicyOp for SimpleStorage { + resource.policy.remove(idx); + } + } +- self.store(location, resource).await ++ self.store(location, resource, true).await + } + async fn bind_policies( + &self, +@@ -166,7 +171,7 @@ impl PolicyOp for SimpleStorage { + for p in policy.iter() { + resource.policy.push(format!("{}", p)); + } +- self.store(location.clone(), resource).await ++ self.store(location.clone(), resource, true).await + } + } + +-- +2.46.0 + diff --git a/0092-fix-use-etc-as-the-base-directory-for-resource-stora.patch b/0092-fix-use-etc-as-the-base-directory-for-resource-stora.patch new file mode 100644 index 0000000..867f63c --- /dev/null +++ b/0092-fix-use-etc-as-the-base-directory-for-resource-stora.patch @@ -0,0 +1,39 @@ +From 7cd62c2fa0d264ea3a1898d7522cfc55f2b16d39 Mon Sep 17 00:00:00 2001 +From: chenjiayi +Date: Wed, 19 Feb 2025 16:44:44 +0800 +Subject: [PATCH 1/1] fix: use etc as the base directory for resource storage + +--- + .../attestation-types/src/resource/policy/opa/mod.rs | 2 +- + .../attestation-types/src/resource/storage/simple.rs | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/service/attestation/attestation-types/src/resource/policy/opa/mod.rs b/service/attestation/attestation-types/src/resource/policy/opa/mod.rs +index 0ec506a..ad159f5 100644 +--- a/service/attestation/attestation-types/src/resource/policy/opa/mod.rs ++++ b/service/attestation/attestation-types/src/resource/policy/opa/mod.rs +@@ -21,7 +21,7 @@ use async_trait::async_trait; + use std::path::PathBuf; + + pub(crate) const DEFAULT_RESOURCE_POLICY_DIR: &str = +- "/run/attestation/attestation-service/resource/policy/"; ++ "/etc/attestation/attestation-service/resource/policy/"; + pub(crate) const DEFAULT_RESOURCE_VIRTCCA_DEFAULT_POLICY: &str = "virtcca.rego"; + + pub(crate) struct OpenPolicyAgent { +diff --git a/service/attestation/attestation-types/src/resource/storage/simple.rs b/service/attestation/attestation-types/src/resource/storage/simple.rs +index d5f1bc5..dad24e0 100644 +--- a/service/attestation/attestation-types/src/resource/storage/simple.rs ++++ b/service/attestation/attestation-types/src/resource/storage/simple.rs +@@ -24,7 +24,7 @@ use super::PolicyOp; + use super::Resource; + use super::StorageEngine; + +-pub(crate) const STORAGE_BASE: &str = "/run/attestation/attestation-service/resource/storage/"; ++pub(crate) const STORAGE_BASE: &str = "/etc/attestation/attestation-service/resource/storage/"; + + pub(crate) struct SimpleStorage { + base: PathBuf, +-- +2.46.0 + diff --git a/secGear.spec b/secGear.spec index 4f20e68..6147687 100644 --- a/secGear.spec +++ b/secGear.spec @@ -1,6 +1,6 @@ Name: secGear Version: 0.1.0 -Release: 54 +Release: 55 Summary: secGear is an SDK to develop confidential computing apps based on hardware enclave features @@ -100,6 +100,8 @@ Patch86: 0087-use-id-when-get-policy.patch Patch87: 0088-fix-evidence-decode-typos.patch Patch88: 0089-features-support-resource-maitainance.patch Patch89: 0090-add-ra_tls-support.patch +Patch90: 0091-fix-allow-bind-unbind-and-clear-resource-policy-when.patch +Patch91: 0092-fix-use-etc-as-the-base-directory-for-resource-stora.patch BuildRequires: gcc python automake autoconf libtool BUildRequires: glibc glibc-devel cmake ocaml-dune rpm gcc-c++ compat-openssl11-libs compat-openssl11-devel @@ -254,8 +256,10 @@ install -d %{buildroot}%{_sysconfdir}/attestation/attestation-service/token install -d %{buildroot}%{_sysconfdir}/attestation/attestation-service/policy install -d %{buildroot}%{_sysconfdir}/attestation/attestation-service/verifier/itrustee install -d %{buildroot}%{_sysconfdir}/attestation/attestation-service/verifier/virtcca +install -d %{buildroot}%{_sysconfdir}/attestation/attestation-service/resource/policy/oeas install -pm 644 service/attestation/attestation-service/service/attestation-service.conf %{buildroot}%{_sysconfdir}/attestation/attestation-service/ install -pm 644 service/attestation/attestation-service/policy/src/opa/*.rego %{buildroot}%{_sysconfdir}/attestation/attestation-service/policy/ +install -pm 644 service/attestation/attestation-types/src/resource/policy/opa/virtcca.rego %{buildroot}%{_sysconfdir}/attestation/attestation-service/resource/policy/oeas/ install -pm 751 service/attestation/attestation-service/target/release/attestation-service %{buildroot}/%{_bindir} install -pm 751 service/attestation/attestation-client/target/release/attestation-client %{buildroot}/%{_bindir} %endif @@ -321,6 +325,7 @@ popd %{_sysconfdir}/attestation/attestation-service/policy/* %{_sysconfdir}/attestation/attestation-service/verifier/itrustee %{_sysconfdir}/attestation/attestation-service/verifier/virtcca +%{_sysconfdir}/attestation/attestation-service/resource/policy/oeas/virtcca.rego %files ac %{_bindir}/attestation-client @@ -337,6 +342,10 @@ popd systemctl restart rsyslog %changelog +* Web Feb 19 2025 chenjiayi - 0.1.0-55 +- fix bugs on resource policy binding, unbindg, etc. Also install +- default resource policy. + * Tue Feb 18 2025 xuraoqing - 0.1.0-54 - add ra_tls support -- Gitee