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

来源:互联网 发布:香奁润色 知乎 编辑:程序博客网 时间:2024/06/05 07:37

1. 摘要

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

2. 测试方法

测试版本:ESP8266_RTOS_SDK - c7b64043

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

  1. 找到 malloc 的具体实现函数pvPortMalloc,位于 ESP8266_RTOS_SDK/third_party/freertos/heap_4.c

    在里面添加全局统计变量:

    size_t s_mem_mark;
  2. 添加复位 API 和 获取 API:

    size_t get_mem_mark(void){    return s_mem_mark;}void reset_mem_mark(void){    s_mem_mark = (size_t)-1;}
  3. 添加统计功能,在 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;}

测试代码代码修改如下:

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

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

    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: http://blog.csdn.net/as3luyuan123/article/details/16812071

    server: http://blog.csdn.net/as3luyuan123/article/details/16850727

5. 附件

cert.sh

#!/bin/bashSAVEIFS=$IFSIFS=$(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_BITSecho ----------------------echo "create root cert request"openssl req -new -key root-key.key -out root-req.csr -text -subj $ROOT_SUBJECTecho ----------------------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_caecho "create 2 level cert key"openssl genrsa -out root-mid.key $KEY_BITSecho ----------------------echo "create 2 level cert csr"openssl req -new -key root-mid.key -out root-mid.csr -text -subj $LEVEL2_SUBJECTecho ----------------------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_caecho "create 3 level cert key"openssl genrsa -out server.key $KEY_BITSecho "create 3 level cert csr"openssl req -new -key server.key -out server.csr -text -subj $LEVEL3_SUBJECTecho "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_caecho ""echo ----------------------echo "server uses certification " $SERVER_CERT_NAME " and key " $SERVER_KEY_NAMEecho "client uses certification " $CLIENT_CERT_NAME " and key " $CLIENT_KEY_NAMErm *.csr *.srlIFS=$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