一、mbedTLS的介绍
mbedTLS(之前称为PolarSSL),是一个由ARM公司开源和维护的SSL/TLS算法库。它使用C编程语言编写,以最小的编码占用空间实现了SSL/TLS功能及各种加密算法,非常适合于嵌入式设备和资源受限的环境。mbedTLS的设计目标是易于理解、使用、集成和扩展,方便开发人员轻松地在嵌入式产品中使用SSL/TLS功能。它提供了完整的SSL v3、TLS v1.0、TLS v1.1和TLS v1.2协议实现,支持X.509证书处理、基于TCP的TLS传输加密以及基于UDP的DTLS(Datagram TLS)传输加密。mbedTLS也因其高效、便于移植和集成的特点,在物联网设备和嵌入式系统中得到广泛应用。
open62541在v1.1.1版本之后开始支持OpenSSL加密,OpenSSL在桌面端应用广泛,mbedTLS主要用在嵌入式领域,桌面端也可以使用。
mbedTLS 和 OpenSSL 的区别:
二、生成自签名证书和私匙
open62541 版本:V1.3.9
可参考示例中的文档:
Install required packages:
sudo apt -y install acl autoconf autoconf-archive automake build-essential cmake doxygen gcc git iproute2 libcurl4-openssl-dev libjson-c-dev libcmocka0 libcmocka-dev libglib2.0-dev libini-config-dev libmbedtls-dev libssl-dev libsqlite3-dev libtool libyaml-dev pkg-config procps python3-pip sqlite3 udev uthash-dev
Install the netifaces dependency
sudo pip install netifaces
实际步骤如下:
来源:
https://blog.csdn.net/whahu1989/article/details/103212001
想实现加密通信,就需要自签名证书和私匙。可以使用open62541自带工具生成
源码路径
open62541/tools/certs
2个文件
使用这个python脚本去生成证书和私匙,但需要预先安装一个python模块 netifaces,输入以下命令安装
sudo apt install python3-pip
pip3 install netifaces
PS:使用pip3是因为我们会使用python3去运行这个脚本。
安装完netifaces后,我们先看下这个脚本的帮助信息,如下指令:
python3 create_self-signed.py -h
其中 -u 是最重要的参数,用于指定证书的URI值,这个值后面会讲到,代码里需要设置成相同值。
证书生成
验证加密通信需要server和client,它们都需要证书和私匙。
首先生成server的证书,执行下面的命令去生成。
python3 create_self-signed.py ./ -u urn:open62541.server.application -c server
生成client的证书,指令如下:
python3 create_self-signed.py ./ -u urn:open62541.client.application -c client
会在当前目录下生成server_cert.der 、server_key.der 、client_cert.der 、client_key.der这4个文件。
证书参数,可以使用如下命令来查看 server 证书的URI 参数
openssl x509 -in server_cert.der -inform der -noout -text
同理可查看 client 端 URI 参数,指令
openssl x509 -in client_cert.der -inform der -noout -text
拷贝证书到工程中。
三、编译mbedTLS
官网地址:
https://www.trustedfirmware.org/projects/mbed-tls/
mbedTLS 源码下载:
https://github.com/Mbed-TLS/mbedtls/releases
https://gitee.com/sparklefire/mbedtls
mbedTLS 版本为 2.26.0
Ubuntu 版本为 22.04.03
进入其源码目录,然后按如下步骤操作
1.新建build目录并cd进入
mkdir build
cd build
2.执行cmake … && make
cmake .. && make
报错。。。。
将 mbedTLS 版本改为 mbedtls-3.5.1 。
按照上面步骤重新编译,编译成功。
交叉编译
mbedTLS 版本为 2.26.0
选择交叉编译器,两种方法:
①直接将编译器设置到环境变量
export CC=/gcc路径/
export CXX=/g++路径/
②用宏
cmake .. -DCMAKE_C_COMPILER=/gcc路径/gcc
例如:
cmake .. -DCMAKE_C_COMPILER=/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin/arm-linux-gcc
总步骤如下:
export PATH=$PATH:/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin/arm-linux-gcc
cmake .. -DENABLE_TESTING:Bool=OFF -DENABLE_PROGRAMS:Bool=ON
make
查看静态库的支持的是arm平台还是x86平台
readelf -h libmbedcrypto.a
创建目录 encryption_mbedtls
进入 encryption_mbedtls 文件夹,创建 目录 mbedtls
cd encryption_mbedtls
mkdir mbedtls
pwd
/home/user/Desktop/opcua/1.3.9/open62541-tlc/encryption_mbedtls/mbedtls
把 mbedTLS 源码目录下的 include目录和build目录下的library目录拷贝到此文件夹下。(build目录下也有include目录,里面是符号链接,所以不需要)。
四、 编译open62541
版本:v1.3.9
4.1 配置
在open62541源码目录下的CMakeLists.txt里找到以下4个option,
UA_ENABLE_AMALGAMATION
UA_ENABLE_ENCRYPTION
UA_ENABLE_ENCRYPTION_OPENSSL
UA_ENABLE_ENCRYPTION_MBEDTLS
把第1,2和4改为ON,第3改为OFF。
4.2 配置
查找mbedTLS
打开open62541源码目录下的tools/cmake/FindMbedTLS.cmake,有如下内容,
#check environment variable
if("$ENV{MBEDTLS_FOLDER_INCLUDE}")
set(MBEDTLS_FOLDER_INCLUDE "$ENV{MBEDTLS_FOLDER_INCLUDE}")
endif()
if("$ENV{MBEDTLS_FOLDER_LIBRARY}")
set(MBEDTLS_FOLDER_LIBRARY "$ENV{MBEDTLS_FOLDER_LIBRARY}")
endif()
把 encryption_mbedtls/mbedTLS 的存放目录添加进来就行了,如下
#check environment variable
if("$ENV{MBEDTLS_FOLDER_INCLUDE}")
set(MBEDTLS_FOLDER_INCLUDE "$ENV{MBEDTLS_FOLDER_INCLUDE}")
else()
set(MBEDTLS_FOLDER_INCLUDE "/home/user/Desktop/opcua/1.3.9/open62541-tlc/encryption_mbedtls/mbedtls/include")
endif()
if("$ENV{MBEDTLS_FOLDER_LIBRARY}")
set(MBEDTLS_FOLDER_LIBRARY "$ENV{MBEDTLS_FOLDER_LIBRARY}")
else()
set(MBEDTLS_FOLDER_LIBRARY "/home/user/Desktop/opcua/1.3.9/open62541-tlc/encryption_mbedtls/mbedtls/library")
endif()
4.3 交叉编译
export PATH=$PATH:/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin/arm-linux-gcc
make
五、工程测试
工程结构:
在工程目录下生成CMakeLists.txt并新建bin和build目录,CMakeLists.txt内容如下
cmake_minimum_required(VERSION 3.5)
project(demoOpen62541)
set (EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
add_definitions(-std=c99)
include_directories(${PROJECT_SOURCE_DIR}/open62541)
include_directories(${PROJECT_SOURCE_DIR}/mbedtls/include)
include_directories(${PROJECT_SOURCE_DIR}/src)
find_library(OPEN62541_LIB libopen62541.a HINTS ${PROJECT_SOURCE_DIR}/open62541)
find_library(MBEDCRYPTO_LIB libmbedcrypto.a HINTS ${PROJECT_SOURCE_DIR}/mbedtls/library)
find_library(MBEDTLS_LIB libmbedtls.a HINTS ${PROJECT_SOURCE_DIR}/mbedtls/library)
find_library(MBEDX509_LIB libmbedx509.a HINTS ${PROJECT_SOURCE_DIR}/mbedtls/library)
add_executable(server ${PROJECT_SOURCE_DIR}/src/server.c)
target_link_libraries(server ${OPEN62541_LIB} ${MBEDCRYPTO_LIB} ${MBEDTLS_LIB} ${MBEDX509_LIB})
#add_executable(client ${PROJECT_SOURCE_DIR}/src/client.c)
#target_link_libraries(client ${OPEN62541_LIB} ${MBEDCRYPTO_LIB} ${MBEDTLS_LIB} ${MBEDX509_LIB})
服务端代码
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
*
* Copyright 2019 (c) Kalycito Infotech Private Limited
*
*/
#include <signal.h>
#include <stdlib.h>
#include "open62541.h"
//#include "common.h"
/* loadFile parses the certificate file.
*
* @param path specifies the file name given in argv[]
* @return Returns the file content after parsing */
static UA_INLINE UA_ByteString loadFile(const char *const path) {
UA_ByteString fileContents = UA_STRING_NULL;
/* Open the file */
FILE *fp = fopen(path, "rb");
if(!fp) {
errno = 0; /* We read errno also from the tcp layer... */
return fileContents;
}
/* Get the file length, allocate the data and read */
fseek(fp, 0, SEEK_END);
fileContents.length = (size_t)ftell(fp);
fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
if(fileContents.data) {
fseek(fp, 0, SEEK_SET);
size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
if(read != fileContents.length)
UA_ByteString_clear(&fileContents);
} else {
fileContents.length = 0;
}
fclose(fp);
return fileContents;
}
static UA_INLINE UA_StatusCode
writeFile(const char* const path, const UA_ByteString buffer) {
FILE *fp = NULL;
fp = fopen(path, "wb");
if(fp == NULL)
return UA_STATUSCODE_BADINTERNALERROR;
for(UA_UInt32 bufIndex = 0; bufIndex < buffer.length; bufIndex++) {
int retVal = fputc(buffer.data[bufIndex], fp);
if(retVal == EOF) {
fclose(fp);
return UA_STATUSCODE_BADINTERNALERROR;
}
}
fclose(fp);
return UA_STATUSCODE_GOOD;
}
UA_Boolean running = true;
static void stopHandler(int sig) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
running = false;
}
int main(int argc, char* argv[]) {
signal(SIGINT, stopHandler);
signal(SIGTERM, stopHandler);
if(argc < 3) {
UA_LOG_FATAL(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
"Missing arguments. Arguments are "
"<server-certificate.der> <private-key.der> "
"[<trustlist1.der>, ...]");
return EXIT_FAILURE;
}
/* Load certificate and private key */
UA_ByteString certificate = loadFile(argv[1]);
UA_ByteString privateKey = loadFile(argv[2]);
/* Load the trustlist */
size_t trustListSize = 0;
if(argc > 3)
trustListSize = (size_t)argc-3;
UA_STACKARRAY(UA_ByteString, trustList, trustListSize);
for(size_t i = 0; i < trustListSize; i++)
trustList[i] = loadFile(argv[i+3]);
/* Loading of a issuer list, not used in this application */
size_t issuerListSize = 0;
UA_ByteString *issuerList = NULL;
/* Loading of a revocation list currently unsupported */
UA_ByteString *revocationList = NULL;
size_t revocationListSize = 0;
UA_Server *server = UA_Server_new();
UA_ServerConfig *config = UA_Server_getConfig(server);
UA_StatusCode retval =
UA_ServerConfig_setDefaultWithSecurityPolicies(config, 4840,
&certificate, &privateKey,
trustList, trustListSize,
issuerList, issuerListSize,
revocationList, revocationListSize);
// 填坑的地方,非常重要
UA_String_deleteMembers(&config->applicationDescription.applicationUri);
config->applicationDescription.applicationUri = UA_STRING_ALLOC("urn:open62541.server.application");
for (size_t i = 0; i < config->endpointsSize; ++i)
{
UA_String_deleteMembers(&config->endpoints[i].server.applicationUri);
config->endpoints[i].server.applicationUri = UA_String_fromChars("urn:open62541.server.application");
}
UA_ByteString_clear(&certificate);
UA_ByteString_clear(&privateKey);
for(size_t i = 0; i < trustListSize; i++)
UA_ByteString_clear(&trustList[i]);
if(retval != UA_STATUSCODE_GOOD)
goto cleanup;
retval = UA_Server_run(server, &running);
cleanup:
UA_Server_delete(server);
return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
交叉编译
mkdir bin
mkdir build
cd build
cmake .. -DCMAKE_C_COMPILER=/home/user/Desktop/nuc980-sdk/buildroot-2022.02.3/output/host/bin/arm-linux-gcc
make
将可执行程序和 certs 文件夹拷贝到开发板
开发板:
启动服务端
./server ./certs/server_cert.der ./certs/server_key.der
打开客户端软件验证
参考:
https://blog.csdn.net/whahu1989/article/details/103212001