* This file is part of the openHiTLS project.
*
* openHiTLS 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 <arpa/inet.h>
#include <ctype.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "bsl_err.h"
#include "bsl_log.h"
#include "bsl_sal.h"
#include "bsl_uio.h"
#include "crypt_eal_init.h"
#include "crypt_errno.h"
#include "hitls.h"
#include "hitls_dtls_cid.h"
#include "hitls_cert.h"
#include "hitls_cert_init.h"
#include "hitls_config.h"
#include "hitls_crypt_init.h"
#include "hitls_error.h"
#include "hitls_pki_cert.h"
#define CERTS_PATH "../../../testcode/testdata/tls/certificate/der/ecdsa_sha256/"
#define DEFAULT_PORT 12345
#define DEMO_BUF_SIZE 2048
#define KEYLOG_FILE "key.log"
static bool IsPortArg(const char *arg)
{
if (arg == NULL || arg[0] == '\0') {
return false;
}
for (const char *p = arg; *p != '\0'; p++) {
if (!isdigit((unsigned char)*p)) {
return false;
}
}
return true;
}
static const char *LogLevelStr(uint32_t level)
{
switch (level) {
case BSL_LOG_LEVEL_SEC:
return "SEC";
case BSL_LOG_LEVEL_FATAL:
return "FATAL";
case BSL_LOG_LEVEL_ERR:
return "ERR";
case BSL_LOG_LEVEL_WARN:
return "WARN";
case BSL_LOG_LEVEL_INFO:
return "INFO";
case BSL_LOG_LEVEL_DEBUG:
return "DEBUG";
default:
return "UNKNOWN";
}
}
static void DemoBinLogFixLen(uint32_t logId, uint32_t logLevel, uint32_t logType,
void *format, void *para1, void *para2, void *para3, void *para4)
{
fprintf(stderr, "[BINLOG][%s][id=%u][type=0x%x] ", LogLevelStr(logLevel), logId, logType);
if (format != NULL) {
fprintf(stderr, (const char *)format, para1, para2, para3, para4);
}
fprintf(stderr, "\n");
}
static void DemoBinLogVarLen(uint32_t logId, uint32_t logLevel, uint32_t logType, void *format, void *para)
{
fprintf(stderr, "[BINLOG][%s][id=%u][type=0x%x] ", LogLevelStr(logLevel), logId, logType);
if (format != NULL && para != NULL) {
fprintf(stderr, (const char *)format, (const char *)para);
} else if (format != NULL) {
fprintf(stderr, "%s", (const char *)format);
}
fprintf(stderr, "\n");
}
static void DemoErrStackLog(uint64_t threadId, const char *file, uint32_t lineNo, int32_t errCode, bool mark)
{
fprintf(stderr, "[ERRSTACK][tid=%llu][%s:%u][mark=%d] err=0x%x\n",
(unsigned long long)threadId, (file != NULL) ? file : "", lineNo, mark ? 1 : 0, errCode);
}
static void RegisterDemoLog(void)
{
BSL_LOG_BinLogFuncs funcs = {
.fixLenFunc = DemoBinLogFixLen,
.varLenFunc = DemoBinLogVarLen,
};
(void)BSL_LOG_RegBinLogFunc(&funcs);
(void)BSL_LOG_SetBinLogLevel(BSL_LOG_LEVEL_DEBUG);
BSL_ERR_RegErrStackLog(DemoErrStackLog);
}
static void DemoKeyLogCb(HITLS_Ctx *ctx, const char *line)
{
(void)ctx;
if (line == NULL) {
return;
}
FILE *fp = fopen(KEYLOG_FILE, "a");
if (fp == NULL) {
fprintf(stderr, "open %s failed for key log\n", KEYLOG_FILE);
return;
}
(void)fprintf(fp, "%s\n", line);
(void)fclose(fp);
}
static int32_t HiTLSInit(void)
{
int32_t ret = CRYPT_EAL_Init(CRYPT_EAL_INIT_ALL);
if (ret != CRYPT_SUCCESS) {
printf("CRYPT_EAL_Init failed, ret = 0x%x\n", ret);
return ret;
}
HITLS_CertMethodInit();
HITLS_CryptMethodInit();
RegisterDemoLog();
return HITLS_SUCCESS;
}
static int32_t LoadServerCertificate(HITLS_Config *config, HITLS_X509_Cert **rootCA, HITLS_X509_Cert **subCA)
{
int32_t ret = HITLS_X509_CertParseFile(BSL_FORMAT_ASN1, CERTS_PATH "ca.der", rootCA);
if (ret != HITLS_SUCCESS) {
printf("Parse ca failed, ret = 0x%x\n", ret);
return ret;
}
ret = HITLS_X509_CertParseFile(BSL_FORMAT_ASN1, CERTS_PATH "inter.der", subCA);
if (ret != HITLS_SUCCESS) {
printf("Parse inter ca failed, ret = 0x%x\n", ret);
return ret;
}
ret = HITLS_CFG_AddCertToStore(config, *rootCA, TLS_CERT_STORE_TYPE_DEFAULT, true);
if (ret != HITLS_SUCCESS) {
printf("Add root ca failed, ret = 0x%x\n", ret);
return ret;
}
ret = HITLS_CFG_AddCertToStore(config, *subCA, TLS_CERT_STORE_TYPE_DEFAULT, true);
if (ret != HITLS_SUCCESS) {
printf("Add inter ca failed, ret = 0x%x\n", ret);
return ret;
}
ret = HITLS_CFG_LoadCertFile(config, CERTS_PATH "server.der", TLS_PARSE_FORMAT_ASN1);
if (ret != HITLS_SUCCESS) {
printf("Load server cert failed, ret = 0x%x\n", ret);
return ret;
}
ret = HITLS_CFG_LoadKeyFile(config, CERTS_PATH "server.key.der", TLS_PARSE_FORMAT_ASN1);
if (ret != HITLS_SUCCESS) {
printf("Load server key failed, ret = 0x%x\n", ret);
}
return ret;
}
static int32_t SetupUdpUio(BSL_UIO **uio, int32_t fd)
{
*uio = BSL_UIO_New(BSL_UIO_UdpMethod());
if (*uio == NULL) {
printf("BSL_UIO_New UDP failed.\n");
return HITLS_INTERNAL_EXCEPTION;
}
int32_t ret = BSL_UIO_Ctrl(*uio, BSL_UIO_SET_FD, (int32_t)sizeof(fd), &fd);
if (ret != HITLS_SUCCESS) {
printf("BSL_UIO_SET_FD failed, ret = 0x%x\n", ret);
}
return ret;
}
int main(int32_t argc, char *argv[])
{
uint16_t port = DEFAULT_PORT;
bool hrrMode = false;
for (int32_t i = 1; i < argc; i++) {
if (IsPortArg(argv[i])) {
port = (uint16_t)atoi(argv[i]);
} else if (strcmp(argv[i], "hrr") == 0) {
hrrMode = true;
} else {
printf("Unknown option: %s\n", argv[i]);
printf("Usage: %s [port] [hrr]\n", argv[0]);
return -1;
}
}
int32_t exitValue = -1;
int32_t fd = -1;
HITLS_Config *config = NULL;
HITLS_Ctx *ctx = NULL;
BSL_UIO *uio = NULL;
HITLS_X509_Cert *rootCA = NULL;
HITLS_X509_Cert *subCA = NULL;
if (HiTLSInit() != HITLS_SUCCESS) {
return -1;
}
fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
printf("Create UDP socket failed.\n");
goto EXIT;
}
int option = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)) < 0) {
printf("setsockopt SO_REUSEADDR failed.\n");
goto EXIT;
}
struct sockaddr_in serverAddr;
(void)memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(fd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) != 0) {
printf("bind UDP port %u failed.\n", port);
goto EXIT;
}
config = HITLS_CFG_NewDTLS13Config();
if (config == NULL) {
printf("HITLS_CFG_NewDTLS13Config failed.\n");
goto EXIT;
}
int32_t ret = HITLS_CFG_SetClientVerifySupport(config, false);
if (ret != HITLS_SUCCESS) {
printf("Disable client verify failed, ret = 0x%x\n", ret);
goto EXIT;
}
ret = HITLS_CFG_SetDtlsCookieExchangeSupport(config, true);
if (ret != HITLS_SUCCESS) {
printf("HITLS_CFG_SetDtlsCookieExchangeSupport failed, ret = 0x%x\n", ret);
goto EXIT;
}
ret = HITLS_CFG_SetKeyLogCb(config, DemoKeyLogCb);
if (ret != HITLS_SUCCESS) {
printf("HITLS_CFG_SetKeyLogCb failed, ret = 0x%x\n", ret);
goto EXIT;
}
if (hrrMode) {
uint16_t groups[] = {HITLS_EC_GROUP_SECP384R1};
ret = HITLS_CFG_SetGroups(config, groups, sizeof(groups) / sizeof(groups[0]));
if (ret != HITLS_SUCCESS) {
printf("HITLS_CFG_SetGroups failed, ret = 0x%x\n", ret);
goto EXIT;
}
ret = HITLS_CFG_SetDtlsCookieExchangeSupport(config, true);
if (ret != HITLS_SUCCESS) {
printf("HITLS_CFG_SetDtlsCookieExchangeSupport failed, ret = 0x%x\n", ret);
goto EXIT;
}
printf("HiTLS HRR mode enabled: supported_groups=secp384r1, dtls_cookie=yes\n");
}
ret = LoadServerCertificate(config, &rootCA, &subCA);
if (ret != HITLS_SUCCESS) {
goto EXIT;
}
ret = HITLS_CFG_SetDtlsCidSupport(config, true);
if (ret != HITLS_SUCCESS) {
printf("HITLS_CFG_SetDtlsCidSupport failed, ret = 0x%x\n", ret);
goto EXIT;
}
ctx = HITLS_New(config);
if (ctx == NULL) {
printf("HITLS_New failed.\n");
goto EXIT;
}
static const uint8_t serverCid[] = {0xAA, 0xBB, 0xCC, 0xDD};
ret = HITLS_SetDtlsRecvCid(ctx, serverCid, sizeof(serverCid));
if (ret != HITLS_SUCCESS) {
printf("HITLS_SetDtlsRecvCid failed, ret = 0x%x\n", ret);
goto EXIT;
}
ret = SetupUdpUio(&uio, fd);
if (ret != HITLS_SUCCESS) {
goto EXIT;
}
ret = HITLS_SetUio(ctx, uio);
if (ret != HITLS_SUCCESS) {
printf("HITLS_SetUio failed, ret = 0x%x\n", ret);
goto EXIT;
}
printf("DTLS 1.3 UDP server listening on 0.0.0.0:%u\n", port);
ret = HITLS_Accept(ctx);
if (ret != HITLS_SUCCESS) {
printf("HITLS_Accept failed, ret = 0x%x\n", ret);
BSL_ERR_OutputErrorStack();
goto EXIT;
}
printf("DTLS 1.3 UDP server accepted one client\n");
bool isCidNeg = false;
HITLS_GetDtlsIsCidNegotiated(ctx, &isCidNeg);
printf("CID negotiated: %s\n", isCidNeg ? "yes" : "no");
if (isCidNeg) {
HITLS_DtlsCidEntry sendEntries[4];
uint8_t sendCount = 4;
if (HITLS_GetDtlsSendCid(ctx, sendEntries, &sendCount) == HITLS_SUCCESS && sendCount > 0) {
printf("Server send CID (len=%u): ", sendEntries[0].cidLen);
for (uint8_t i = 0; i < sendEntries[0].cidLen; i++) {
printf("%02x", sendEntries[0].cidVal[i]);
}
printf("\n");
}
}
uint8_t readBuf[DEMO_BUF_SIZE + 1] = {0};
uint32_t readLen = 0;
ret = HITLS_Read(ctx, readBuf, DEMO_BUF_SIZE, &readLen);
if (ret != HITLS_SUCCESS) {
printf("HITLS_Read failed, ret = 0x%x\n", ret);
BSL_ERR_OutputErrorStack();
goto EXIT;
}
readBuf[readLen] = '\0';
printf("get from client size:%u: %s\n", readLen, readBuf);
const uint8_t sndBuf[] = "Hi, this is DTLS 1.3 UDP server\n";
uint32_t writeLen = 0;
ret = HITLS_Write(ctx, sndBuf, (uint32_t)strlen((const char *)sndBuf), &writeLen);
if (ret != HITLS_SUCCESS) {
printf("HITLS_Write failed, ret = 0x%x\n", ret);
BSL_ERR_OutputErrorStack();
goto EXIT;
}
exitValue = 0;
EXIT:
HITLS_Close(ctx);
HITLS_Free(ctx);
HITLS_CFG_FreeConfig(config);
HITLS_X509_CertFree(rootCA);
HITLS_X509_CertFree(subCA);
BSL_UIO_Free(uio);
if (fd >= 0) {
close(fd);
}
CRYPT_EAL_Cleanup(CRYPT_EAL_INIT_ALL);
return exitValue;
}