Jarvis's Blog

白帽子、全栈、IoT安全专家、嵌入式系统专家

ESP32移植wolfssl方法

自2015年ESP32发布以后,官方号称很牛逼,关注度也挺高,但实际上呢,我们这些拿到芯片开发的第一批用户来说,也踩了不少坑,文档渣、例子少,生态相比传统大公司比如TI,ST之流还是有很大差距,这次打算移植wolfssl这个库到ESP32上也费了不少劲,过程顺便记录下方便大家参考。

wolfssl是一个轻量级的的SSL库,支持的协议还挺全的,比较适合嵌入式系统,而且使用起来比OpenSSL和mbedTLS简单多了。所以就打算在ESP32上移植这个ssl库。另外,ESP32上自带了OpenSSL和mbedTLS,如果仅仅是实现SSL功能,用这两个库已经足够,但是api用起来没有wolfssl那么简洁好用,所以个人还是更喜欢wolfssl这个库。

好了接下来开始吧,网上完全找不到类似的资料,在wolfssl论坛上有人尝试移植成功过,但是并没有放出方法以及源码,所以此时此刻只能自己尝试移植了。我这里移植用的是乐鑫官方的esp-idf模板库,arduino应该也大同小异。

ESP官方的esp-idf把组件也就是库放在components目录下,每个组件一个文件夹,在组件文件夹目录里会有一个component.mk文件,用于指定每个组件的include目录和源码目录。而整个工程的project.mk会搜索components目录下的每个目录,寻找component.mk来对每个组件进行编译。所以我们要把wolfssl源码放在components目录下。

首先,我们去wolfssl官网下载最新的源代码:

https://wolfssl.com/wolfSSL/download/downloadForm.php

然后,我们在components文件夹下新建wolfssl目录,然后把源码拷贝过来,目录结构如下:

.
├── build
├── components
│   │ 
│   │      ... 
│   ├── wolfssl
│   │
│          ...
├── main
│   ...
├── Makefile
├── README.md
├── sdkconfig
└── sdkconfig.old

wolfssl目录下保持源码原来的结构即可,如图:

然后,在wolfssl目录下新建一个component.mk文件,内容如下:

#
# Component Makefile
#

COMPONENT_ADD_INCLUDEDIRS := ../wolfssl
COMPONENT_PRIV_INCLUDEDIRS := ../freertos/include/freertos
COMPONENT_SRCDIRS := src wolfcrypt/src

为什么是这样我大概解释一下,如果有需要的可以看wolfssl官方的说明,wolfssl根目录下面看似有很多文件夹,但实际有用的只有这几个:
./wolfssl — 这个文件夹是wolfssl的所有头文件
./src — 这个是wolfssl功能代码
./wolfcrypt/src — 这个是wolfssl的所有加密算法源码实现
由于wolfssl的代码中对头文件的引用都是wolfssl/xxxx.h这种形式的,所以我们头文件包含的目录应该是wolfssl的根目录,所以我们COMPONENT_ADD_INCLUDEDIRS变量要设置为当前目录,才变成我的这种写法,另外由于esp-idf使用的系统是FreeRTOS,所以wolfssl也要结合FreeRTOS来编译,所以FreeRTOS的头文件目录也要加上。

这一步完成了之后,我们需要修改wolfssl/wolfcrypt/settings.h
大致修改如下几处:
一、反注释FREERTOS和WOLFSSL_LWIP宏定义,因为esp-idf使用的是FreeRTOS+lwip方式的系统+协议栈。

...
/* Uncomment next line if using PIC32MZ Crypto Engine */
/* #define WOLFSSL_MICROCHIP_PIC32MZ */

/* Uncomment next line if using FreeRTOS */
 #define FREERTOS

/* Uncomment next line if using FreeRTOS+ TCP */
/* #define FREERTOS_TCP */

/* Uncomment next line if using FreeRTOS Windows Simulator */
/* #define FREERTOS_WINSIM */

/* Uncomment next line if using RTIP */
/* #define EBSNET */

/* Uncomment next line if using lwip */
 #define WOLFSSL_LWIP

/* Uncomment next line if building wolfSSL for a game console */
/* #define WOLFSSL_GAME_BUILD */
...

二、找到如下地方,添加一些宏定义:

...
#ifdef FREERTOS
    #include "FreeRTOS.h"

    /* FreeRTOS pvPortRealloc() only in AVR32_UC3 port */
    #if !defined(XMALLOC_USER) && !defined(NO_WOLFSSL_MEMORY)
        #define XMALLOC(s, h, type)  pvPortMalloc((s))
        #define XFREE(p, h, type)    vPortFree((p))
        //新增如下一行:
        #define XREALLOC(p, n, h, type) pvPortRealloc((p), (n))

    #endif

    #ifndef NO_WRITEV
        #define NO_WRITEV
    #endif
    #ifndef HAVE_SHA512
        #ifndef NO_SHA512
            #define NO_SHA512
        #endif
    #endif
    #ifndef HAVE_DH
        #ifndef NO_DH
            #define NO_DH
        #endif
    #endif
    #ifndef NO_DSA
        #define NO_DSA
    #endif
    #ifndef NO_HC128
        #define NO_HC128
    #endif

    #ifndef SINGLE_THREADED
        #include "semphr.h"
    #endif

    //新增下面的宏定义:
    #ifndef HAVE_ECC
        #define HAVE_ECC
    #endif

    #define WOLFSSL_DTLS
    #define HAVE_SOCKADDR
    #define DEBUG_WOLFSSL
    #define NO_DEV_RANDOM
    #include "esp_system.h"
#endif
...

另外,由于esp-idf里的freeRTOS没有pvPortRealloc这个定义,但这个功能是已经实现的只是没封装,所以现在要自己去封装这个函数:
找到components/freertos/port.c,在vPortFree函数后面添加如下函数:

...
void *pvPortMalloc( size_t xWantedSize )
{
	return heap_caps_malloc(xWantedSize, MALLOC_CAP_8BIT);
}

void vPortFree( void *pv )
{
	return heap_caps_free(pv);
}
//添加如下内容:
void *pvPortRealloc( void *pv, size_t size )
{
	return heap_caps_realloc(pv, size,MALLOC_CAP_8BIT);
}
...

然后找到components/freertos/include/freertos/portable.h
在vPortFree的定义后面添加pvPortRealloc的定义:

...
void *pvPortMalloc( size_t xSize ) PRIVILEGED_FUNCTION;
void vPortFree( void *pv ) PRIVILEGED_FUNCTION;
//添加如下一行:
void *pvPortRealloc( void *pv, size_t size ) PRIVILEGED_FUNCTION;
void vPortInitialiseBlocks( void ) PRIVILEGED_FUNCTION;
...

最后,由于wolfssl要正常工作还需要一个随机数发生器,默认使用的是/dev/urandom,但是FreeRTOS上面是没有这个io设备的,所以我们在前面有定义过NO_DEV_RANDOM,这时候我们需要自己实现随机数生成的函数,不过好在ESP32自带了硬件随机数发生器,所以写起来也比较简单:
修改wolfcrypt/src/random.c
找到如下位置,在wc_GenerateSeed函数里填上具体实现的代码,下面的代码是我的实现,你也可以自己实现,esp_random()函数一次能获得4个字节随机数,我直接只用最低字节,方便点:

...
#elif defined(NO_DEV_RANDOM)

    //#error "you need to write an os specific wc_GenerateSeed() here"


    int wc_GenerateSeed(OS_Seed* os, byte* output, word32 sz)
    {
    	for (int i=0;i<sz;i++)
    		output[i] = esp_random()&0xFF;

        return 0;
    }
...

完成这些步骤之后,我们编译esp-idf,这时候wolfssl库应该就能正常编译通过了,会在build/wolfssl目录下生成libwolfssl.a,这时候我们在自己编写app的时候就可以使用wolfssl相关的头文件了。

最后,如果app要引用wolfssl的话,编译到wolfssl的时候可能会报错找不到头文件,这时候就需要在app/main目录下的component.mk文件中添加如下行:

#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the 
# src/ directory, compile them and link them into lib(subdirectory_name).a 
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
COMPONENT_PRIV_INCLUDEDIRS := ../../components/freertos/include/freertos ../../components/wolfssl

然后就可以正常使用wolfssl的函数了。

MTK编译环境安装注意事项

上一篇

MTK功能机平台死机原因调试方法

下一篇
评论
发表评论 说点什么
  • luckyclovertt

    能交流更详细的过程吗,现在把wolfssll移植到mqx系统上,也出现了一些问题,希望可以借鉴你的移植方法

  • 先生,您好,可否每一步和ssl原理结合起来详细说明一下,因为ESP32的一些库文件改变了,这样移植就很蒙

    • 先生,您好,非常谢谢你,我已经编译通过了,也生成了libwolfssl.a,可能版本不一样,我这两天移植时出了不少问题,其中ESP32中的components/freertos/port.c已经没有些代码了 void *pvPortMalloc( size_t xWantedSize ) { return heap_caps_malloc(xWantedSize, MALLOC_CAP_8BIT); } void vPortFree( void *pv ) { return heap_caps_free(pv); } //添加如下内容: void *pvPortRealloc( void *pv, size_t size ) { return heap_caps_realloc(pv, size,MALLOC_CAP_8BIT); } 而是在components/freertos/include/freertos/portable.h中直接用了下面的宏去代替这些函数的代码 #define pvPortMalloc malloc #define vPortFree free 所以我只加了下一行代码就OK了 #define pvPortRealloc realloc 所以谢谢你的帮助 一开始,我是想不明白为什么每步都要这么做。这两天摸索下来我也有了眉目了,谢谢老师

    • 你那边有没有出现fatal error: wolfssl/wolfcrypt/settings.h: No such file or directory 这个错误呢?

  • 你好,最近移植这个时候,编译程序出现error: /home/linux/esp/project/esp32-onenet-master/components/espmqtt/include/mqtt.h:80:3: error: unknown type name 'QueueHandle_t' QueueHandle_t xSendingQueue; ^ /home/linux/esp/esp-idf/components/wolfssl/src/keys.c:29:40: fatal error: wolfssl/wolfcrypt/settings.h: No such file or directory 不知道什么原因,能帮忙吗?

    • 你是不是去掉了一些文件?若果是那就重新移植吧 如果不是,这就检查你这行代码是否拼写错误了 希望得到反馈

  • 因为先前的虚拟机的配置有问题,导致图形界面无法进入,今天重新移植了wolfssl到ESP32上 。现在有了些时间,我就重新总结下过程吧,先要确保ESP32的环境安装好, (1)【准备篇】去WOLFSSL官网下载wolfssl完整的库,然后移到esp/esp-idf/components中,然后直接解压成名字为wolfssl(比如下载的时候是wolfssl-3.15.3.zip 解压成 wolfssl 放在components目录下)ps:如果不熟悉库就不要动里面的东西,按步骤来。 (2)【配置wolfssl库】(按博主的改就OK了,此处不赘述) (a)wolfssl目录下新建一个component.mk文件 (b) 修改wolfssl/wolfcrypt/settings.h (c)wolfcrypt/src/random.c添加随机函数 (3)【配置freertos文件】(因为ESP32的库是更新的,所以就会跟原贴的移植有些出入,当前方法适用于2018年10月23日) (a) 打开 components/freertos/include/freertos/portable.h文件 (b) 寻找 #define pvPortMalloc malloc #define vPortFree free这两行定义 (c) 在#define pvPortMalloc malloc #define vPortFree free 下一行,添加代码#define pvPortRealloc realloc (d)保存 (4)移植成功

10191
3

    浙公网安备 33011002014706号