open62541 加密示例-使用mbedTLS

一、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.der4个文件。
在这里插入图片描述
证书参数,可以使用如下命令来查看 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

https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/tls/tls?id=_3-rt-thread%e4%bd%bf%e7%94%a8tls

https://github.com/Mbed-TLS/mbedtls/tree/development

https://blog.csdn.net/m0_69605900/article/details/127373242

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值