本文主要列举实际测试的 wolfSSL 在各种配置参数下,SSL 握手的内存开销和相应的测试方法。
ESP8266 SDK 版本:ESP8266_RTOS_SDK - c7b64043
git clone https://github.com/espressif/ESP8266_RTOS_SDK.git
git checkout c7b64043
wolfSSL 版本: https://github.com/wolfSSL/wolfssl/releases/tag/v3.12.2-stable
下载完毕后请参照ESP8266 wolfSSL 入门指南搭建工程。
测试思路是在每次内存分配就记录剩余的内存,并在最终打印握手过程中的最小剩余内存以及最终剩余内存。代码修改方法如下:
找到 malloc
的具体实现函数pvPortMalloc
,位于 ESP8266_RTOS_SDK/third_party/freertos/heap_4.c
,在里面添加全局统计变量:
size_t s_mem_mark;
添加复位 API 和 获取 API:
size_t get_mem_mark(void)
{
return s_mem_mark;
}
void reset_mem_mark(void)
{
s_mem_mark = (size_t)-1;
}
添加统计功能,在 pvPortMalloc
函数的返回结果(return pvReturn
)之前添加如下代码:
if (pvReturn) {
extern size_t system_get_free_heap_size(void);
size_t mem_size = system_get_free_heap_size();
if (mem_size < s_mem_mark)
s_mem_mark = mem_size;
}
直接运行位于 ESP8266_RTOS_SDK/third_party
下的脚本 make_lib.sh
生成新的 libfreertos.a
,命令如下:
./make_lib.sh freertos
测试代码代码修改如下:
找到 esp8266-wolfssl/blob/master/user/wolfssl_client/wolfssl_client.c
,添加全局API 声明:
extern size_t get_mem_mark(void);
extern void reset_mem_mark(void);
extern size_t system_get_free_heap_size(void);
在 ret = wolfSSL_Init();
之前添加:
reset_mem_mark();
printf("start heap %d\n", system_get_free_heap_size());
在以下代码
ret = wolfSSL_connect(ssl);
if (!ret) {
goto failed4;
}
下方添加:
printf("min heap %d\n", get_mem_mark());
printf("end heap %d\n", system_get_free_heap_size());
SSL server 代码部分也做类似的修改。
通过以上的修改,可以统计出 SSL 握手之前的内存,握手中系统剩余的最小内存和握手结束以后的内存。为了测试方便可以用2个 ESP8266 模组进行测试,1个做 server,1个做 client,通过 user_config.h
配置 WIFI 和连接参数进行测试。
本章主要列举各种配置参数和具体测试数据,由于 wolfSSL 宏观上不需要用户自己配置 fragment,所以也就不做相关的测试了,而且默认支持最大 RSA4096 计算,所以也就不做秘钥大于4096的测试。
本节具体列举了 client
模式下非认证,本地认证,双向认证模式下,配置各种大小证书所消耗的内存。
测试非认证模式下各证书加秘钥总大小和内存开销的关系。
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2936 | 35152 | 19584 | 31736 | 15568 | 3416 |
4065 | 35152 | 16944 | 31736 | 18208 | 3416 |
5195 | 35152 | 14296 | 31736 | 20856 | 3416 |
测试单向认证模式下各证书加秘钥总大小和内存开销的关系。
server 使用 RSA2048 - RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
4197 | 35832 | 19120 | 32008 | 16712 | 3824 |
5679 | 35480 | 16480 | 31528 | 19000 | 3952 |
7155 | 35128 | 13512 | 31040 | 21616 | 4088 |
测试双向认证模式下各证书加秘钥大小和内存开销的关系。
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书,以下表格首项为 client 和 server 端认证证书,证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
8394 | 35320 | 10192 | 28544 | 25128 | 6776 |
11358 | 33680 | 2992 | 25800 | 30688 | 7880 |
本节具体列举了 server 模式下非认证模式,双向认证模式和配置各种大小的证书所消耗的内存。
测试非认证模式下各证书加秘钥大小和内存开销的关系。
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2965 | 36632 | 13368 | 26184 | 23264 | 10448 |
4097 | 35592 | 7352 | 23896 | 28240 | 11696 |
测试双向认证模式下各证书加秘钥大小和内存开销的关系。
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
4226 | 35336 | 11688 | 24488 | 23648 | 10848 |
5729 | 33848 | 5192 | 21728 | 28656 | 12120 |
cert.sh
用于生成测试使用的证书,openssl.cnf
为生成证书的配置文件,可以通过修改 cert.sh
中的全局变量 KEY_BITS
来起到修改证书的大小的作用,直接修改其他参数也能实现,但是感觉意义不大
如果手头只有1个 ESP8266 模组,可以使用 openssl 命令来创建 client 和 server 进行测试,参考链接如下:
client: http://blog.csdn.net/as3luyuan123/article/details/16812071
server: http://blog.csdn.net/as3luyuan123/article/details/16850727
cert.sh
#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
ROOT_SUBJECT="/C=C1/ST=JS1/L=WX1/O=ESP1/OU=ESP1/CN=Server1 CA/emailAddress=ESP1"
LEVEL2_SUBJECT="/C=C2/ST=JS22/L=WX22/O=ESP22/OU=ESP22/CN=Server22 CA/emailAddress=ESP22"
LEVEL3_SUBJECT="/C=C3/ST=JS333/L=WX333/O=ESP333/OU=ESP333/CN=Server333 CA/emailAddress=ESP333"
SERVER_CERT_NAME="RootCA.crt"
SERVER_KEY_NAME="root-key.key"
CLIENT_CERT_NAME="RootCA.crt"
CLIENT_KEY_NAME="root-key.key"
KEY_BITS="4096"
echo "create root CA key"
openssl genrsa -out root-key.key $KEY_BITS
echo ----------------------
echo "create root cert request"
openssl req -new -key root-key.key -out root-req.csr -text -subj $ROOT_SUBJECT
echo ----------------------
echo "create root self sign cert"
openssl x509 -req -in root-req.csr -out RootCA.crt -sha1 -signkey root-key.key -days 3650 -text -extfile openssl.cnf -extensions v3_ca
echo "create 2 level cert key"
openssl genrsa -out root-mid.key $KEY_BITS
echo ----------------------
echo "create 2 level cert csr"
openssl req -new -key root-mid.key -out root-mid.csr -text -subj $LEVEL2_SUBJECT
echo ----------------------
echo "sign with root-crt"
openssl x509 -req -in root-mid.csr -CA RootCA.crt -CAkey root-key.key -CAcreateserial -days 3650 -out RootMid.crt -text -extfile openssl.cnf -extensions v3_ca
echo "create 3 level cert key"
openssl genrsa -out server.key $KEY_BITS
echo "create 3 level cert csr"
openssl req -new -key server.key -out server.csr -text -subj $LEVEL3_SUBJECT
echo "sign with level2 cert-crt"
openssl x509 -req -in server.csr -CA RootMid.crt -CAkey root-mid.key -CAcreateserial -days 3560 -out Server.crt -text -extfile openssl.cnf -extensions v3_ca
echo ""
echo ----------------------
echo "server uses certification " $SERVER_CERT_NAME " and key " $SERVER_KEY_NAME
echo "client uses certification " $CLIENT_CERT_NAME " and key " $CLIENT_KEY_NAME
rm *.csr *.srl
IFS=$SAVEIFS
openssl.cnf
################################################################
# openssl example configuration file.
# This is mostly used for generation of certificate requests.
#################################################################
[ ca ]
default_ca= CA_default # The default ca section
#################################################################
[ CA_default ]
dir=~/tmp/cert # Where everything is kept
certs=$dir # Where the issued certs are kept
crl_dir= $dir/crl # Where the issued crl are kept
database= $dir/index.txt # database index file
new_certs_dir= $dir/new_certs # default place for new certs
certificate=$dir/CA/OrbixCA # The CA certificate
serial= $dir/serial # The current serial number
crl= $dir/crl.pem # The current CRL
private_key= $dir/CA/OrbixCA.pk # The private key
RANDFILE= $dir/.rand # private random number file
default_days= 365 # how long to certify for
default_crl_days= 30 # how long before next CRL
default_md= md5 # which message digest to use
preserve= no # keep passed DN ordering
# A few different ways of specifying how closely the request should
# conform to the details of the CA
policy= policy_match # For the CA policy
[ policy_match ]
countryName= match
stateOrProvinceName= match
organizationName= match
organizationalUnitName= optional
commonName= supplied
emailAddress= optional
# For the `anything' policy
# At this point in time, you must list all acceptable `object'
# types
[ policy_anything ]
countryName = optional
stateOrProvinceName= optional
localityName= optional
organizationName = optional
organizationalUnitName = optional
commonName= supplied
emailAddress= optional
[ req ]
default_bits = 1024
default_keyfile= privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
[ req_distinguished_name ]
countryName= Country Name (2 letter code)
countryName_min= 2
countryName_max = 2
stateOrProvinceName= State or Province Name (full name)
localityName = Locality Name (eg, city)
organizationName = Organization Name (eg, company)
organizationalUnitName = Organizational Unit Name (eg, section)
commonName = Common Name (eg. YOUR name)
commonName_max = 64
emailAddress = Email Address
emailAddress_max = 40
[ req_attributes ]
challengePassword = A challenge password
challengePassword_min = 4
challengePassword_max = 20
unstructuredName= An optional company name
[ v3_ca ]
basicConstraints = CA:true