本文主要列举实际测试的 mbedTLS 在各种配置参数下,SSL 握手的内存开销和相应的测试方法。
测试版本:ESP-IDF - tag: v2.1.1
测试思路是原子级
的测试内存的开销,也就是说每次只要
有内存分配就统计剩余的内存。代码修改方法如下:
找到 malloc
的桩函数 _malloc_r
,位于 esp-idf/components/newlib/syscalls.c
size_t s_mem_mark;
添加复位 API 和 获取 API:
size_t IRAM_ATTR get_mem_mark(void)
{
return s_mem_mark;
}
void IRAM_ATTR reset_mem_mark(void)
{
s_mem_mark = (size_t)-1;
}
修改 _malloc_r
函数如下:
void* IRAM_ATTR _malloc_r(struct _reent *r, size_t size)
{
void *p =heap_caps_malloc_default( size );
if (p) {
size_t mem_size = esp_get_free_heap_size();
if (mem_size < s_mem_mark)
s_mem_mark = mem_size;
}
return p;
}
测试代码代码修改如下:
找到 example/protocol/openssl_client/openssl_client_example_main.c,添加全局API 声明:
extern size_t get_mem_mark(void);
extern void reset_mem_mark(void);
extern size_t esp_get_free_heap_size(void);
在 ESP_LOGI(TAG, "create SSL context ......");
之前添加:
reset_mem_mark();
printf("start heap %d\n", esp_get_free_heap_size());
在以下代码
ret = SSL_connect(ssl);
if (!ret) {
ESP_LOGI(TAG, "failed " );
goto failed4;
}
ESP_LOGI(TAG, "OK");
下方添加:
printf("min heap %d\n", get_mem_mark());
printf("end heap %d\n", esp_get_free_heap_size());
while (1);
SSL server 代码部分也做类似的修改。
通过以上的修改,可以统计出 SSL 握手之前的内存,握手中系统剩余的最小内存和握手结束以后的内存。为了测试方便可以用2个 ESP32 模组进行测试,1个做 server,1个做 client,通过 menuconfig 配置 WIFI 和连接参数进行测试。
本章主要列举各种配置参数和具体测试数据。
本节具体列举了 client
模式下非认证,本地认证,双向认证模式下,配置各种大小的 fragment
和证书所消耗的内存。
测试非认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2048 | 234764 | 213140 | 222692 | 21624 | 12072 |
3072 | 234764 | 211404 | 220692 | 23360 | 14072 |
4096 | 234760 | 209288 | 218568 | 25472 | 16192 |
5120 | 234760 | 207248 | 216568 | 27512 | 18192 |
6144 | 234764 | 205284 | 214568 | 29480 | 20196 |
7168 | 234764 | 202844 | 212484 | 31920 | 22280 |
8192 | 234764 | 200796 | 210424 | 33968 | 24340 |
测试本地认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2048 | 234764 | 211432 | 220024 | 23332 | 14740 |
3072 | 234760 | 208700 | 217976 | 26060 | 16784 |
4096 | 234760 | 206644 | 215920 | 28116 | 18840 |
5120 | 234760 | 204600 | 213716 | 30160 | 21044 |
6144 | 234760 | 202560 | 211860 | 32200 | 22900 |
7168 | 234764 | 200520 | 209804 | 34244 | 24960 |
8192 | 234764 | 198496 | 207748 | 36268 | 27016 |
测试双向认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2048 | 234764 | 208484 | 216452 | 26280 | 18312 |
3072 | 234764 | 205108 | 214404 | 29656 | 20360 |
4096 | 234760 | 202616 | 212012 | 32144 | 22748 |
5120 | 234764 | 201004 | 210304 | 33760 | 24460 |
6144 | 234760 | 198592 | 208192 | 36168 | 26568 |
7168 | 234764 | 196884 | 206172 | 37880 | 28592 |
8192 | 234760 | 194828 | 204096 | 39932 | 30664 |
测试非认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2936 | 234764 | 208484 | 216452 | 26280 | 18312 |
4065 | 234764 | 205108 | 214404 | 29656 | 20360 |
5195 | 234760 | 202616 | 212012 | 32144 | 22748 |
6324 | 234764 | 201004 | 210304 | 33760 | 24460 |
7449 | 234760 | 198592 | 208192 | 36168 | 26568 |
8575 | 234764 | 196884 | 206172 | 37880 | 28592 |
9709 | 234760 | 194828 | 204096 | 39932 | 30664 |
测试单向认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:
server 使用 RSA2048 - RSA8192 的秘钥和生成的证书。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
4197 | 234564 | 198148 | 207760 | 36416 | 26804 |
5679 | 234760 | 195028 | 203772 | 39732 | 30988 |
7155 | 234564 | 192028 | 202200 | 42536 | 32364 |
8633 | 234760 | 188760 | 200552 | 46000 | 34208 |
10103 | 234760 | 186336 | 198772 | 48424 | 35988 |
11575 | 234760 | 184000 | 197228 | 50760 | 37532 |
13058 | 234760 | 179832 | 195572 | 54928 | 39188 |
测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书,以下表格首项为 client 和 server 端认证证书,证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
8394 | 234760 | 194816 | 204104 | 39944 | 30656 |
11358 | 234760 | 189988 | 199072 | 44772 | 35688 |
14310 | 234760 | 188208 | 196672 | 46552 | 38088 |
17266 | 234760 | 183472 | 194060 | 51288 | 40700 |
20206 | 234760 | 178840 | 191296 | 55920 | 43464 |
23150 | 234760 | 173740 | 188488 | 61020 | 46272 |
26116 | 234760 | 170400 | 186056 | 64360 | 48704 |
本节具体列举了 server 模式下非认证模式,双向认证模式和配置各种大小的证书所消耗的内存。
测试非认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2048 | 234780 | 202724 | 216284 | 32056 | 18496 |
3072 | 234780 | 200691 | 214271 | 34089 | 20509 |
4096 | 234780 | 198659 | 212261 | 36121 | 22519 |
5120 | 234780 | 196628 | 210251 | 38152 | 24529 |
6144 | 234780 | 194597 | 208241 | 40183 | 26539 |
7168 | 234780 | 192565 | 206231 | 42215 | 28549 |
8192 | 234780 | 190536 | 204224 | 44244 | 30556 |
测试双向认证模式下各 fragment
大小和内存开销的关系,限定测试条件如下:
Fragment/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2048 | 234964 | 199148 | 211048 | 35816 | 23916 |
3072 | 234964 | 196693 | 208964 | 38271 | 26000 |
4096 | 234964 | 194241 | 206882 | 40723 | 28082 |
5120 | 234964 | 191789 | 204801 | 43175 | 30163 |
6144 | 234964 | 189337 | 202720 | 45627 | 32244 |
7168 | 234964 | 186885 | 200638 | 48079 | 34326 |
8192 | 234964 | 184436 | 198560 | 50528 | 36404 |
测试非认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
2965 | 234780 | 190536 | 204224 | 44244 | 30556 |
4097 | 234780 | 186153 | 202446 | 48631 | 32334 |
5229 | 234780 | 181767 | 200672 | 53017 | 34108 |
6361 | 234780 | 177380 | 198897 | 57404 | 35883 |
7493 | 234780 | 172994 | 197122 | 61790 | 37658 |
8625 | 234780 | 168607 | 195347 | 66177 | 39433 |
9704 | 234780 | 164356 | 193632 | 70424 | 41148 |
测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:
server 使用 RSA2048 — RSA8192 的秘钥和生成的证书。,以下首项为 server 端证书和秘钥的总和。
证书和秘钥/B | 开始 | 最小 | 最大 | 最大消耗/B | 最后消耗/B |
---|---|---|---|---|---|
4226 | 234964 | 184436 | 198560 | 50528 | 36404 |
5705 | 234964 | 180291 | 195530 | 54677 | 39434 |
7184 | 234964 | 176147 | 192498 | 58821 | 42466 |
8663 | 234964 | 172002 | 189465 | 62966 | 45499 |
10142 | 234964 | 167858 | 186432 | 67110 | 48532 |
11621 | 234964 | 163713 | 183399 | 71255 | 51565 |
13053 | 234964 | 159700 | 180460 | 75264 | 54504 |
cert.sh
用于生成测试使用的证书,openssl.cnf
为生成证书的配置文件,可以通过修改 cert.sh
中的全局变量 KEY_BITS
来起到修改证书的大小的作用,直接修改其他参数也能实现,但是感觉意义不大
如果手头只有1个 ESP32 模组,可以使用 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