From cae3c7add5a0be5863a03ebc1816405628fb23a7 Mon Sep 17 00:00:00 2001 From: xuraoqing Date: Tue, 18 Feb 2025 12:09:26 +0800 Subject: [PATCH] add ra_tls support Signed-off-by: xuraoqing (cherry picked from commit 7216ea239145e562607e7ab222ad7bd5bfdee486) --- 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