返回

openHiTLS

构建源码并安装

openEuler系统

openEuler 学习记录

环境

检查系统中构建工具是否已安装,并能正常使用。

名称 推荐版本 说明
Gcc >=7.3.0 Linux
Python >=3.5 Linux
CMake >=3.16 Linux
Sctp 无版本限制 Linux

当前openEuler24.03版本系统自带Gcc和Python,CMake和Sctp需要自行安装,查看版本和安装命令如下:

1
2
3
4
5
6
7
8
gcc -v

python3 -v

sudo dnf install cmake
cmake -version

sudo dnf install lksctp*

源码

使用git submodule的方式下载,可以直接下载源码和依赖的Securec库

1
2
cd ~
git clone --recurse-submodules https://gitcode.com/openhitls/openhitls.git

进入openHiTLS后代码目录结构如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo dnf install tree
cd openhitls
tree -L 1
.
├── auth
├── bsl
├── CMakeLists.txt
├── codecs
├── config
├── configure.py
├── crypto
├── docs
├── include
├── LICENSE
├── pki
├── platform
├── README.md
├── README-zh.md
├── script
├── testcode
├── Third_Party_Open_Source_Software_Notice
└── tls

13 directories, 6 files
  • bsl:存放基础功能相关代码;
  • CMakeLists.txt:构建入口文件
  • configure.py:提供构建配置命令行功能;
  • config、script:存放构建相关脚本;
  • crypto:存放密码学算法能力相关代码;
  • platform:存放其他依赖的代码;
  • testcode:存放测试工程类代码。
  • tls:存放安全传输相关代码;
  • x509:存放x509证书功能相关代码;

源码构建调用CMake进行构建,具体方法下面介绍。

CMake

openHiTLS提供CMake构建方式,可通过configure.py进行配置,之后建议新建build目录用于存放构建过程中的产生的临时文件,进入build目录使用“cmake .. && make”的方式执行构建。configure.py的配置可以通过python3 ./configure.py –help查询,相关参数参考:构建及安装指导 | openHiTLS文档

configure.py脚本会直接基于顶层的compile.json和feature.json配置文件修改已有配置。

CMake构建的总体执行步骤如下:

1
2
3
4
5
cd openhitls
mkdir -p ./build
cd ./build
python3 ../configure.py --system linux --bits 64
cmake ..

img

构建结果会输出在openHiTLS/build目录下。

openHiTLS依赖于libboundscheck库,在之前的准备源码阶段已经一并下载。现在进入Secure_C文件夹中编译,生成动态库libboundscheck.so并放到库文件目录下

1
2
3
cd ../platform/Secure_C
make CC=gcc
sudo cp ./lib/libboundscheck.so /usr/local/lib/

img

  • 回到build目录下进行make编译
1
2
cd ../../build
make

img

构建结果会输出在openHiTLS/build目录下

安装

1
sudo make install

img

头文件默认安装至/usr/local/include,库文件默认安装至/usr/local/lib

测试

构建完OpenHiTLS源码并安装后,执行测试代码。测试工程依赖编译源码

测试代码目录结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
testcode
├── benchmark
├── CMakeLists.txt
├── common
├── demo
├── framework
├── output
├── script
├── sdv
├── test_config
└── testdata

其中:

  • common:公共类测试框架代码
  • demo:openHiTLS功能测试demo
  • framework:openHiTLS测试用例的框架代码
  • output:用例测试结果及过程文件输出目录
  • script:测试脚本类代码目录
  • sdv:openHiTLS功能场景测试用例代码
  • testdata:存放测试类数据等

功能测试执行指导

测试框架说明

使用社区开发的测试框架,提供公共的配置和方法以便社区开发者进行测试代码的编写和执行。一个测试单元由function文件(.c)和data(.data)文件组成,分别保存测试函数和测试数据。

img

脚本参数说明

命令 含义
bash build_hitls.sh 编译全量源码。
bash build_sdv.sh 编译全量测试代码。
bash execute_sdv.sh 执行测试用例。
  • build_hitls.sh 脚本参数说明
脚本参数 执行方式 参数说明
gcov bash build_hitls.sh gcov 开启获取覆盖率能力。
debug bash build_hitls.sh debug 开启debug调试能力。
asan bash build_hitls.sh asan 开启内存监测能力。
  • build_sdv.sh脚本参数说明
脚本参数 执行方式 参数说明
–help或-h bash build_sdv.sh –help 获取帮助信息。
no-crypto bash build_sdv.sh no-crypto 裁剪掉crypto模块用例。
no-bsl bash build_sdv.sh no-bsl 裁剪掉bsl模块用例。
verbose bash build_sdv.sh verbose 显示构建过程详细信息。
gcov bash build_sdv.sh gcov 开启获取覆盖率能力。
asan bash build_sdv.sh asan 开启内存监测能力 。
big-endian bash build_sdv.sh big-endian 大端环境编译选项。
run-tests bash build_sdv.sh run-tests=xxx1xxx2xxx3 编译指定测试套。
  • execute_sdv.sh脚本参数说明
脚本参数 执行方式 参数说明
<file name> bash execute_sdv.sh test_suites_xxx … 执行指定文件下的所有用例。
<test name> bash execute_sdv.sh UT_CRYPTO_xxx SDV_CRYPTO_xxx … 执行指定用例名用例。

备注:脚本参数可以以组合形式传给脚本,例如:

  • 默认方式构建源码:bash build_hitls.sh
  • 源码构建过程中开启asan、debug及覆盖率:bash build_hitls.sh asan gcov debug
  • 测试代码构建过程中开启asan、覆盖率及显示构建详情:bash build_sdv.sh asan gcov verbose
  • 默认方式构建源码:bash build_hitls.sh
  • 默认方式执行全量用例:bash execute_sdv.sh
  • 执行指定的测试集合:bash execute_sdv.sh test_suites_xxx1 test_suites_xxx2

用例执行流程

测试工程主要依赖以下脚本:

  • build_hitls.sh: 一键式构建源码脚本
  • build_sdv.sh : 一键式构建测试用例脚本
  • execute_sdv.sh : 一键式执行用例脚本

img

依次执行以下命令

1
2
cd testcode/script/
bash build_hitls.sh

img

1
bash build_sdv.sh

img

1
bash execute_sdv.sh

img

测试通过

测试完成后,可进入output/log目录查看用例执行结果。

调用

在本章节中将以对称加密和TLS两个示例演示如何在您的项目代码中调用openHiTLS提供的接口。

SM4

创建 sm4_cbc.c

1
2
3
mkdir -p ~/oht_test/sm4_cbc 
cd ~/oht_test/sm4_cbc
touch sm4_cbc.c 

sm4_cbc.c 代码如下:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "crypt_eal_cipher.h" // 对称加解密接口头文件
#include "bsl_sal.h"
#include "bsl_err.h"
#include "crypt_algid.h" // 算法id列表
#include "crypt_errno.h" // 错误码列表

void *StdMalloc(uint32_t len) {
    return malloc((size_t)len);
}

void PrintLastError(void) {
    const char *file = NULL;
    uint32_t line = 0;
    BSL_ERR_GetLastErrorFileLine(&file, &line); // 获取错误发生的文件名和行数
    printf("failed at file %s at line %d\n", file, line);
}

int main(void)
{
    uint8_t data[10] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x1c, 0x14};
    uint8_t iv[16] = {0};
    uint8_t key[16] = {0};
    uint32_t dataLen = sizeof(data);
    uint8_t cipherText[100];
    uint8_t plainText[100];
    uint32_t outTotalLen = 0;
    uint32_t outLen = sizeof(cipherText);
    uint32_t cipherTextLen;
    int32_t ret;

    printf("plain text to be encrypted: "); // 输出明文
    for (uint32_t i = 0; i < dataLen; i++) {
        printf("%02x", data[i]);
    }
    printf("\n");

    // 初始化错误码模块
    BSL_ERR_Init();

    // BSL_SAL_CallBack_Ctrl
    // 如果未注册并且默认能力没有被裁剪,使用默认linux实现
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC, StdMalloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE, free);

    // 创建上下文
    CRYPT_EAL_CipherCtx *ctx = CRYPT_EAL_CipherNewCtx(CRYPT_CIPHER_SM4_CBC);
    if (ctx == NULL) {
        PrintLastError();
        BSL_ERR_DeInit();
        return 1;
    }
    // 初始化, 最后入参true为加密,false为解密
    ret = CRYPT_EAL_CipherInit(ctx, key, sizeof(key), iv, sizeof(iv), true);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret); // 输出错误码,可借助错误码在crypt_errno.h中找到对应的错误信息
        PrintLastError();
        goto exit;
    }
    // 设置填充模式。
    ret = CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_PKCS7);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    // 输入待计算数据,该接口可以调用多次。此处outLen输入为cipherText长度,输出为处理的数据量
    ret = CRYPT_EAL_CipherUpdate(ctx, data, dataLen, cipherText, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;                     // 目前已处理数据量
    outLen = sizeof(cipherText) - outTotalLen; // cipherText剩余空间

    // 填充并处理最后一段数据
    ret = CRYPT_EAL_CipherFinal(ctx, cipherText + outTotalLen, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;
    printf("cipher text value is: "); // 输出密文

    for (uint32_t i = 0; i < outTotalLen; i++) {
        printf("%02x", cipherText[i]);
    }
    printf("\n");

    // 开始解密流程
    cipherTextLen = outTotalLen;
    outTotalLen = 0;
    outLen = sizeof(plainText);

    // 初始化, 设置为解密
    ret = CRYPT_EAL_CipherInit(ctx, key, sizeof(key), iv, sizeof(iv), false);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret); // 输出错误码,可借助错误码在crypt_errno.h中找到对应的错误信息
        PrintLastError();
        goto exit;
    }

    // 设置填充模式,填充模式必须和加密的填充模式相同
    ret = CRYPT_EAL_CipherSetPadding(ctx, CRYPT_PADDING_PKCS7);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    // 输入密文数据
    ret = CRYPT_EAL_CipherUpdate(ctx, cipherText, cipherTextLen, plainText, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }
    outTotalLen += outLen;                    // 目前已处理数据量
    outLen = sizeof(plainText) - outTotalLen; // buffer剩余空间

    // 解密最后一段数据并去填充
    ret = CRYPT_EAL_CipherFinal(ctx, plainText + outTotalLen, &outLen);
    if (ret != CRYPT_SUCCESS) {
        printf("error code is %x\n", ret);
        PrintLastError();
        goto exit;
    }

    outTotalLen += outLen;

    printf("decrypted plain text value is: "); // 输出明文
    for (uint32_t i = 0; i < outTotalLen; i++) {
        printf("%02x", plainText[i]);
    }
    printf("\n");

    if (outTotalLen != dataLen || memcmp(plainText, data, dataLen) != 0) {
        printf("plaintext comparison failed\n");
        goto exit;
    }
    printf("pass \n");

exit:
    // 释放上下文内存
    CRYPT_EAL_CipherFreeCtx(ctx);
    BSL_ERR_DeInit();
    return ret;
}

在同目录下创建 Makefile 文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
OPEN_PATH= /root/openhitls
BUILD=build
LINK_FLAGS=-pthread -lhitls_tls -lhitls_pki -lhitls_crypto -lhitls_bsl -lboundscheck -lsctp
LIB=-L $(OPEN_PATH)/$(BUILD) -Wl,-rpath,$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/usr/local/lib/
HEADER=-I$(OPEN_PATH)/include/crypto -I$(OPEN_PATH)/include/bsl -I$(OPEN_PATH)/include/tls -I$(OPEN_PATH)/include/pki -I$(OPEN_PATH)/platform/Secure_C/include

all:sm4

sm4:
	gcc $(HEADER) sm4_cbc.c -g -o sm4cbc $(LINK_FLAGS) $(LIB)

clean:
	rm sm4cbc

注意确定头文件路径和链接库路径正确。 编译生成可执行文件sm4cbc并运行

1
2
3
sudo apt-get install -y libsctp-dev
make
./sm4cbc

示例运行成功

img

TLS

由于TLS需要同时运行server和client两个程序,而openEuler没有图形化操作界面操作不便,现介绍用PowerShell实现打开多个终端界面。 首先在openEuler系统中查看ip

1
ifconfig

img

可以看到ip地址为192.168.119.131

在windows中打开PowerShell,输入以下命令,然后输入密码

1
ssh lab-422@192.168.119.131

连接成功

img

接下来开始实现tls示例。 创建tlss.c和tlsc.c,代码如下,注意修改CERT_PATH的路径:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 基于证书认证的TLS客户端
#include <stdio.h> 
#include <stdlib.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include "bsl_sal.h" 
#include "bsl_err.h" 
#include "hitls_error.h" 
#include "hitls_config.h" 
#include "hitls.h" 
// #include "hitls_x509.h"
#include "hitls_cert.h"
#include "hitls_cert_init.h"

#include "hitls_crypt_init.h"

#include "crypt_eal_rand.h"
#include "crypt_eal_encode.h"

#define HTTP_BUF_MAXLEN (18 * 1024)  /* 18KB */ 
#define CERT_PATH "/home/lab-422/openhitls/testcode/testdata/tls/certificate/der/rsa_sha256/"

int TCP_Connect(const char* ip, const char* port, struct sockaddr_in* sockAddr) {
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket");
        return -1;
    }

    memset(sockAddr, 0, sizeof(struct sockaddr_in));
    sockAddr->sin_family = AF_INET;
    sockAddr->sin_port = htons(atoi(port));
    if (inet_pton(AF_INET, ip, &(sockAddr->sin_addr)) <= 0) {
        perror("inet_pton");
        close(sockfd);
        return -1;
    }

    if (connect(sockfd, (struct sockaddr*)sockAddr, sizeof(struct sockaddr_in)) == -1) {
        perror("connect");
        close(sockfd);
        return -1;
    }

    return sockfd;
}

void TCP_Close(int fd) {
    close(fd);
}

int main(int32_t argc, char *argv[]) 
{ 
    int32_t exitValue = -1; 
    int32_t ret = 0; 
    HITLS_Config *config = NULL; 
    HITLS_Ctx *ctx = NULL; 
    BSL_UIO *uio = NULL; 

    /* 注册BSL内存能力、仅供参考 */ 
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC_CB_FUNC, malloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE_CB_FUNC, free);
    BSL_ERR_Init();

    HITLS_CertMethodInit();
    CRYPT_EAL_RandInit(CRYPT_RAND_SHA256, NULL, NULL, NULL, 0);
    HITLS_CryptMethodInit();

    /* TCP链接需用户实现能力 */
    struct sockaddr_in sockAddr; 
    int fd = TCP_Connect("127.0.0.1", "12345", &sockAddr); 
    if (fd < 0) { 
        printf("SCTP_Connect failed.\n"); 
        return -1; 
    } 

    config = HITLS_CFG_NewTLSConfig(); 
    if (config == NULL) { 
        printf("HITLS_CFG_NewTLS12Config failed.\n"); 
        return -1; 
    } 
    HITLS_CFG_SetCheckKeyUsage(config,false);
    HITLS_CFG_SetFlightTransmitSwitch(config,true);
    /* 加载证书:需要用户实现 */ 
    int r=0;
    HITLS_CERT_X509 *ca_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"ca.der",
                                &ca_cert);
    printf("ca parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, ca_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add ca cert r=0x%x\n", r);

    HITLS_CERT_X509 *inter_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"inter.der",
                                &inter_cert);
    printf("inter parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, inter_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add inter cert r=0x%x\n", r);
    // r=HITLS_CFG_LoadCertFile(config, "/home/ling/ca_server.crt", TLS_CERT_STORE_TYPE_DEFAULT);
    // printf("add encCert r=0x%x\n", r);
    /* 新建openHiTLS上下文 */ 
    ctx = HITLS_New(config); 
    if (ctx == NULL) { 
        printf("HITLS_New failed.\n"); 
        goto exit; 
    } 

    /* 用户可按需实现method */ 
    uio = BSL_UIO_New(BSL_UIO_TcpMethod()); 
    if (uio == NULL) { 
        printf("BSL_UIO_New failed.\n"); 
        goto exit; 
    } 

    ret = BSL_UIO_Ctrl(uio, BSL_UIO_SET_FD, (int32_t)sizeof(fd), &fd); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("BSL_UIO_SET_FD failed, fd = %u.\n", fd); 
        goto exit; 
    } 

    ret = HITLS_SetUio(ctx, uio); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("HITLS_SetUio failed. ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 进行TLS连接、用户需按实际场景考虑返回值 */ 
    ret = HITLS_Connect(ctx); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Connect failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 向对端发送报文、用户需按实际场景考虑返回值 */ 
    const uint8_t sndBuf[] = "Hi, this is client\n"; 
    ret = HITLS_Write(ctx, sndBuf, sizeof(sndBuf), &ret); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Write error:error code:%d\n", ret); 
        goto exit; 
    } 

    /* 读取对端报文、用户需按实际场景考虑返回值 */ 
    uint8_t readBuf[HTTP_BUF_MAXLEN + 1] = {0}; 
    uint32_t readLen = 0; 
    ret = HITLS_Read(ctx, readBuf, HTTP_BUF_MAXLEN, &readLen); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Read failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    printf("get from server size:%u :%s\n", readLen, readBuf); 

    exitValue = 0; 
exit: 
    HITLS_Close(ctx); 
    HITLS_Free(ctx); 
    HITLS_CFG_FreeConfig(config); 
    TCP_Close(fd); 
    return exitValue; 
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//基于证书认证的TLS服务端
#define HITLS_CRYPTO_EAL
#define HITLS_CRYPTO_CIPHER
#include <stdio.h> 
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h> 
#include <arpa/inet.h>
#include "bsl_sal.h" 
#include "bsl_err.h" 
#include "hitls_error.h" 
#include "hitls_config.h" 
#include "hitls.h" 
// #include "hitls_x509.h"
#include "hitls_cert.h"
#include "hitls_cert_init.h"

#include "hitls_crypt_init.h"

#include "crypt_eal_rand.h"
#include "crypt_eal_encode.h"

#define HTTP_BUF_MAXLEN (18 * 1024)  /* 18KB */ 
#define CERT_PATH "/home/lab-422/openhitls/testcode/testdata/tls/certificate/der/rsa_sha256/"
int TCP_Bind(const char* port) {
    int sockfd;
    struct sockaddr_in serverAddr;

    // 创建套接字
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd == -1) {
        perror("socket creation failed");
        return -1;
    }

    // 设置服务器地址信息
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(atoi(port));

    // 绑定套接字到指定端口
    if (bind(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        perror("bind failed");
        close(sockfd);
        return -1;
    }

    // 开始监听连接请求
    if (listen(sockfd, 10) == -1) {
        perror("listen failed");
        close(sockfd);
        return -1;
    }

    return sockfd;
}

int TCP_Accept(int listenFd, struct sockaddr_in* clientAddr) {
    int clientFd;
    socklen_t clientAddrLen;
    struct sockaddr_in addr;

    // 等待客户端连接请求
    clientAddrLen = sizeof(struct sockaddr_in);
    clientFd = accept(listenFd, (struct sockaddr*)&addr, &clientAddrLen);
    if (clientFd == -1) {
        perror("accept failed");
        return -1;
    }

    // 将客户端地址信息保存到clientAddr中
    memcpy(clientAddr, &addr, sizeof(struct sockaddr_in));

    return clientFd;
}

void TCP_Close(int fd) {
    close(fd);
}

int main(int32_t argc, char *argv[]) 
{ 
    int32_t exitValue = -1; 
    int32_t ret = 0; 
    HITLS_Config *config = NULL; 
    HITLS_Ctx *ctx = NULL; 
    BSL_UIO *uio = NULL; 

    /* 注册BSL内存能力、仅供参考 */ 
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_MALLOC_CB_FUNC, malloc);
    BSL_SAL_CallBack_Ctrl(BSL_SAL_MEM_FREE_CB_FUNC, free);
    BSL_ERR_Init();

    HITLS_CertMethodInit();
    CRYPT_EAL_RandInit(CRYPT_RAND_SHA256, NULL, NULL, NULL, 0);
    HITLS_CryptMethodInit();
    /* TCP链接需用户实现能力 */
    int listenFd = TCP_Bind("12345");  
    struct sockaddr_in sockAddr;  
    int fd = TCP_Accept(listenFd, &sockAddr);  
    if (fd < 0) {  
        printf("TCP_Accept failed.\n");  
        return -1;  
    }

    config = HITLS_CFG_NewTLSConfig(); 
    if (config == NULL) { 
        printf("HITLS_CFG_NewTLS12Config failed.\n"); 
        return -1; 
    } 
    HITLS_CFG_SetCheckKeyUsage(config,false);
    HITLS_CFG_SetFlightTransmitSwitch(config,true);
    /* 加载证书:需要用户实现 */ 
    int r=0;
    HITLS_CERT_X509 *ca_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"ca.der",
                                // "/home/ling/ca_server.crt"
                                &ca_cert);
    printf("ca parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, ca_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add ca cert r=0x%x\n", r);

    HITLS_CERT_X509 *inter_cert = NULL;
    r = HITLS_X509_CertParseFile(TLS_PARSE_FORMAT_PEM,
                                CERT_PATH"inter.der",
                                &inter_cert);
    printf("inter parse r=0x%x\n", r);
    r = HITLS_CFG_AddCertToStore(config, inter_cert, TLS_CERT_STORE_TYPE_DEFAULT,
                                false);
    printf("add inter cert r=0x%x\n", r);

    // 从文件中加载加密证书和私钥    
    r=HITLS_CFG_LoadCertFile(config, CERT_PATH"server.der", TLS_PARSE_FORMAT_ASN1);
    printf("add encCert r=0x%x\n", r);
    r=HITLS_CFG_LoadKeyFile(config, CERT_PATH"server.key.der", TLS_PARSE_FORMAT_ASN1);
    printf("add encKey r=0x%x\n", r);
    
    /* 新建openHiTLS上下文 */ 
    ctx = HITLS_New(config); 
    if (ctx == NULL) { 
        printf("HITLS_New failed.\n"); 
        goto exit; 
    } 

    /* 用户可按需实现method */ 
    uio = BSL_UIO_New(BSL_UIO_TcpMethod()); 
    if (uio == NULL) { 
        printf("BSL_UIO_New failed.\n"); 
        goto exit; 
    } 

    ret = BSL_UIO_Ctrl(uio, BSL_UIO_SET_FD, (int32_t)sizeof(fd), &fd); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("BSL_UIO_SET_FD failed, fd = %u.\n", fd); 
        goto exit; 
    } 

    ret = HITLS_SetUio(ctx, uio); 
    if (ret != HITLS_SUCCESS) { 
        BSL_UIO_Free(uio); 
        printf("HITLS_SetUio failed. ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 进行TLS连接、用户需按实际场景考虑返回值 */ 
    ret = HITLS_Accept(ctx); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Accept failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 

    /* 读取对端报文、用户需按实际场景考虑返回值 */ 
    uint8_t readBuf[HTTP_BUF_MAXLEN + 1] = {0}; 
    uint32_t readLen = 0; 
    ret = HITLS_Read(ctx, readBuf, HTTP_BUF_MAXLEN, &readLen); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Read failed, ret = 0x%x.\n", ret); 
        goto exit; 
    } 
    printf("get from client size:%u :%s\n", readLen, readBuf); 

    /* 向对端发送报文、用户需按实际场景考虑返回值 */ 
    const uint8_t sndBuf[] = "Hi, this is server\n"; 
    ret = HITLS_Write(ctx, sndBuf, sizeof(sndBuf), &ret); 
    if (ret != HITLS_SUCCESS) { 
        printf("HITLS_Write error:error code:%d\n", ret); 
        goto exit; 
    }
    exitValue = 0; 
exit: 
    HITLS_Close(ctx); 
    HITLS_Free(ctx); 
    HITLS_CFG_FreeConfig(config); 
    TCP_Close(fd); 
    return exitValue; 
}

在同目录下创建Makefile文件,内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
OPEN_PATH=openhitls
BUILD=build
USER=lab-422
LINK_FLAGS=-pthread -lhitls_tls -lhitls_pki -lhitls_crypto -lhitls_bsl -lboundscheck -lsctp
LIB=-L /home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/home/$(USER)/$(OPEN_PATH)/$(BUILD) -Wl,-rpath,/usr/local/lib/
HEADER=-I/home/$(USER)/$(OPEN_PATH)/include/crypto -I/home/$(USER)/$(OPEN_PATH)/include/bsl -I/home/$(USER)/$(OPEN_PATH)/include/tls -I/home/$(USER)/$(OPEN_PATH)/include/pki -I/home/$(USER)/$(OPEN_PATH)/platform/Secure_C/include

all:tls

tls:
	gcc $(HEADER) tlss.c -g -o tlss $(LINK_FLAGS) $(LIB)
	gcc $(HEADER) tlsc.c -g -o tlsc $(LINK_FLAGS) $(LIB)

clean:
	rm tlss tlsc

输入make,并运行tls服务端

1
2
make
./tlss

启动一个新的PowerShell窗口,ssh连接到openEuler系统,运行tls服务端

1
./tlsc

可以看到两个窗口都有输出,示例运行成功

img

img

mlkem、mldsa 测试代码

Built with Hugo
Theme Stack designed by Jimmy