1. 摘要
本文主要列举实际测试的 mbedTLS 在各种配置参数下,SSL 握手的内存开销和相应的测试方法。
2. 测试方法
测试版本:ESP8266_RTOS_SDK - c7b64043
测试思路是原子级
的测试内存的开销,也就是说每次只要
有内存分配就统计剩余的内存。代码修改方法如下:
- 找到
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/examples/openssl_demo/programs/openssl_demo.c,添加全局API 声明:
extern size_t get_mem_mark(void);
extern void reset_mem_mark(void);
extern size_t system_get_free_heap_size(void);
```
- 在
os_printf("create SSL context ......");
之前添加:
reset_mem_mark();
os_printf("start heap %d\n", system_get_free_heap_size());
- 在以下代码
ret = SSL_connect(ssl);
if (!ret) {
os_printf("failed, return [-0x%x]\n", -ret);
goto failed7;
}
os_printf("OK\n");
下方添加:
os_printf("min heap %d\n", get_mem_mark());
os_printf("end heap %d\n", system_get_free_heap_size());
while (1);
SSL server 代码部分也做类似的修改。
通过以上的修改,可以统计出 SSL 握手之前的内存,握手中系统剩余的最小内存和握手结束以后的内存。为了测试方便可以用2个 ESP8266 模组进行测试,1个做 server,1个做 client,通过 user_config.h
配置 WIFI 和连接参数进行测试。
3. 测试数据
本章主要列举各种配置参数和具体测试数据。
3.1 client 模式
本节具体列举了 client
模式下非认证,本地认证,双向认证模式下,配置各种大小的 fragment
和证书所消耗的内存。
3.1.1 非认证 Fragment 测试
测试非认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
- RSA2048 加密
- 秘钥大小 1704 Bytes
- 证书大小 1261 Bytes
3.1.1.1 数据
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2048 | 41440 | 25496 | 29712 | 15944 | 11728 |
3072 | 41440 | 23448 | 27664 | 17992 | 13776 |
4096 | 41440 | 21400 | 25616 | 20040 | 15824 |
5120 | 41288 | 19352 | 23568 | 21936 | 17720 |
6144 | 41552 | 17304 | 21520 | 24248 | 20032 |
7168 | 41440 | 15256 | 19472 | 26184 | 21968 |
8192 | 41288 | 13208 | 17416 | 28080 | 23872 |
3.1.2 本地认证 Fragment 测试
测试本地认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
- RSA2048 加密
- 秘钥大小 1704 Bytes
- 证书大小 1261 Bytes
- 认证证书大小 1261 Bytes
3.1.2.1 数据
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2048 | 41440 | 23666 | 27044 | 17774 | 14396 |
3072 | 41440 | 20938 | 25000 | 20502 | 16440 |
4096 | 41440 | 18882 | 22944 | 22558 | 18496 |
5120 | 41288 | 16686 | 20588 | 24602 | 20700 |
6144 | 41552 | 14910 | 18996 | 26642 | 22556 |
7168 | 41440 | 12754 | 16824 | 28686 | 24616 |
8192 | 41288 | 10578 | 14616 | 30710 | 26672 |
3.1.3 双向认证 Fragment 测试
测试双向认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
- RSA2048 加密
- 秘钥大小 1704 Bytes
- 证书大小 1261 Bytes
- CA证书大小 1261 Bytes
3.1.3.1 数据
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2048 | 41440 | 20718 | 23472 | 20722 | 17968 |
3072 | 41440 | 17342 | 21424 | 24098 | 20016 |
4096 | 41440 | 14854 | 19036 | 26586 | 22404 |
5120 | 41288 | 13086 | 17172 | 28202 | 24116 |
6144 | 41552 | 10942 | 15328 | 30610 | 26224 |
7168 | 41440 | 9118 | 13192 | 32322 | 28248 |
8192 | 41288 | 6914 | 10968 | 34374 | 30320 |
3.1.4 非认证证书测试
测试非认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:
- fragment 为 5KB
3.1.4.1.数据
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2936 | 41440 | 19774 | 23820 | 21666 | 17620 |
4065 | 41440 | 17734 | 20369 | 23706 | 21071 |
5195 | 41440 | 15334 | 19384 | 26106 | 22056 |
6324 | 41288 | 13342 | 18184 | 27946 | 23104 |
7449 | 41552 | 10178 | 17440 | 31374 | 24112 |
3.1.5 单向认证证书测试
测试单向认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:
- fragment 为 5KB
3.1.5.1 数据
server 使用 RSA2048 - RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
4197 | 41440 | 16726 | 21124 | 24714 | 20316 |
5679 | 41440 | 13410 | 16940 | 28030 | 24500 |
7155 | 41440 | 10606 | 15564 | 30834 | 25876 |
8633 | 41288 | 6990 | 13568 | 34298 | 27720 |
3.1.6 双向认证证书测试
测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
- fragment 为 5KB
3.1.6.1 数据
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书,以下表格首项为 client 和 server 端认证证书,证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
8394 | 41440 | 13198 | 17272 | 28242 | 24168 |
11358 | 41440 | 8370 | 12240 | 33070 | 29200 |
14310 | 41440 | 6590 | 9840 | 34850 | 31600 |
3.2 server 模式
本节具体列举了 server 模式下非认证模式,双向认证模式和配置各种大小的证书所消耗的内存。
3.2.1 非认证 Fragment 测试
测试非认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
- RSA2048 加密
- 秘钥大小 1704 Bytes
- 证书大小 1261 Bytes
3.2.1.1 数据
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2048 | 41440 | 14942 | 23288 | 26498 | 18152 |
3072 | 41440 | 12909 | 21275 | 28531 | 20165 |
4096 | 41440 | 10877 | 19265 | 30563 | 22175 |
5120 | 41288 | 8694 | 17103 | 32594 | 24185 |
6144 | 41552 | 6927 | 15357 | 34625 | 26195 |
3.2.2 双向认证 Fragment 测试
测试双向认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
- RSA2048 加密
- 秘钥大小 1704 Bytes
- 证书大小 1261 Bytes
3.2.2.1 数据
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2048 | 41440 | 11182 | 17868 | 30258 | 23572 |
3072 | 41440 | 8727 | 15784 | 32713 | 25656 |
4096 | 41440 | 6275 | 13702 | 35165 | 27738 |
3.2.3 非认证证书测试
测试非认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
- fragment 为 3KB
3.2.3.1 数据
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
2965 | 41440 | 12994 | 21468 | 28446 | 19972 |
4097 | 41440 | 8607 | 19690 | 32833 | 21750 |
3.2.4 双向认证证书测试
测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
- fragment 为 3KB
3.2.4.1 数据
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
4226 | 41440 | 6710 | 15620 | 34730 | 25820 |
4. 帮助
cert.sh
用于生成测试使用的证书,openssl.cnf
为生成证书的配置文件,可以通过修改cert.sh
中的全局变量KEY_BITS
来起到修改证书的大小的作用,直接修改其他参数也能实现,但是感觉意义不大- 如果手头只有1个 ESP8266 模组,可以使用 openssl 命令来创建 client 和 server 进行测试,参考链接如下:
client:
server:
#5. 附件
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