ESP32 基础篇: mbedTLS 内存开销分析

1. 摘要

本文主要列举实际测试的 mbedTLS 在各种配置参数下,SSL 握手的内存开销和相应的测试方法。

2. 测试方法

测试版本:ESP-IDF - tag: v2.1.1

测试思路是原子级的测试内存的开销,也就是说每次只要有内存分配就统计剩余的内存。代码修改方法如下:

  1. 找到 malloc 的桩函数 _malloc_r,位于 esp-idf/components/newlib/syscalls.c

    • 在里面添加全局统计变量:
    size_t s_mem_mark;
  2. 添加复位 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;
    }
  3. 修改 _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;
    }

测试代码代码修改如下:

  1. 找到 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);
  2. ESP_LOGI(TAG, "create SSL context ......"); 之前添加:

    reset_mem_mark();
    printf("start heap %d\n", esp_get_free_heap_size());
  3. 在以下代码

    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 和连接参数进行测试。

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 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

3.1.2 本地认证 Fragment 测试

测试本地认证模式下各 fragment 大小和内存开销的关系,限定测试条件如下:

  • RSA2048 加密
  • 秘钥大小 1704 Bytes
  • 证书大小 1261 Bytes
  • 认证证书大小 1261 Bytes

3.1.2.1 数据

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

3.1.3 双向认证 Fragment 测试

测试双向认证模式下各 fragment 大小和内存开销的关系,限定测试条件如下:

  • RSA2048 加密
  • 秘钥大小 1704 Bytes
  • 证书大小 1261 Bytes
  • CA证书大小 1261 Bytes

3.1.3.1 数据

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

3.1.4 非认证证书测试

测试非认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:

  • fragment 为 8KB

3.1.4.1.数据

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

3.1.5 单向认证证书测试

测试单向认证模式下各证书加秘钥总大小和内存开销的关系,限定测试条件如下:

  • fragment 为 8KB

3.1.5.1 数据

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

3.1.6 双向认证证书测试

测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:

  • fragment 为 8KB

3.1.6.1 数据

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

3.2 server 模式

本节具体列举了 server 模式下非认证模式,双向认证模式和配置各种大小的证书所消耗的内存。

3.2.1 非认证 Fragment 测试

测试非认证模式下各 fragment 大小和内存开销的关系,限定测试条件如下:

  • RSA2048 加密
  • 秘钥大小 1704 Bytes
  • 证书大小 1261 Bytes

3.2.1.1 数据

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

3.2.2 双向认证 Fragment 测试

测试双向认证模式下各 fragment 大小和内存开销的关系,限定测试条件如下:

  • RSA2048 加密
  • 秘钥大小 1704 Bytes
  • 证书大小 1261 Bytes

3.2.2.1 数据

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

3.2.3 非认证证书测试

测试非认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:

  • fragment 为 8KB

3.2.3.1 数据

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

3.2.4 双向认证证书测试

测试双向认证模式下各证书加秘钥大小和内存开销的关系,限定测试条件如下:

  • fragment 为 8KB

3.2.4.1 数据

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

4. 帮助

  • 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

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

你可能感兴趣的:(SSL/TLS)