使用OpenSSL TLS1.3 Demo

尝试使用官方的server demo和client demo程序
https://wiki.openssl.org/index.php/Main_Page

  1. server程序在 https://wiki.openssl.org/index.php/Simple_TLS_Server
  2. Client程序在https://wiki.openssl.org/index.php/SSL/TLS_Client
  3. 证书尝试使用Chromium QUIC Toy教程中,使用./generate-certs.sh 脚本生成的证书
    在Quic Toy的使用过程中, Server使用的证书和密钥文件为:
    --certificate_file=./leaf_cert.pem --key_file=./leaf_cert.pkcs8
    而且需要讲根证书添加到系统可信域内:
    certutil -d sql:$HOME/.pki/nssdb -A -t "C,," -n -i
  4. 将Simple_TLS_Server.c放入到Ubuntu系统里编译:gcc Simple_TLS_Server.c -o tls_server
    编译出错,找不到一系列符号:
/tmp/cc7arh7v.o: In function `init_openssl':
Simple_TLS_Server.c:(.text+0xbf): undefined reference to `SSL_load_error_strings'
Simple_TLS_Server.c:(.text+0xc4): undefined reference to `SSL_library_init'
/tmp/cc7arh7v.o: In function `cleanup_openssl':
Simple_TLS_Server.c:(.text+0xd0): undefined reference to `EVP_cleanup'
/tmp/cc7arh7v.o: In function `create_context':
Simple_TLS_Server.c:(.text+0xe0): undefined reference to `SSLv23_server_method'
Simple_TLS_Server.c:(.text+0xf0): undefined reference to `SSL_CTX_new'
Simple_TLS_Server.c:(.text+0x114): undefined reference to `ERR_print_errors_fp'
/tmp/cc7arh7v.o: In function `configure_context':
Simple_TLS_Server.c:(.text+0x14b): undefined reference to `SSL_CTX_ctrl'
Simple_TLS_Server.c:(.text+0x161): undefined reference to `SSL_CTX_use_certificate_file'
Simple_TLS_Server.c:(.text+0x174): undefined reference to `ERR_print_errors_fp'
Simple_TLS_Server.c:(.text+0x194): undefined reference to `SSL_CTX_use_PrivateKey_file'
Simple_TLS_Server.c:(.text+0x1a7): undefined reference to `ERR_print_errors_fp'
/tmp/cc7arh7v.o: In function `main':
Simple_TLS_Server.c:(.text+0x246): undefined reference to `SSL_new'
Simple_TLS_Server.c:(.text+0x25b): undefined reference to `SSL_set_fd'
Simple_TLS_Server.c:(.text+0x267): undefined reference to `SSL_accept'
Simple_TLS_Server.c:(.text+0x27a): undefined reference to `ERR_print_errors_fp'
Simple_TLS_Server.c:(.text+0x29d): undefined reference to `SSL_write'
Simple_TLS_Server.c:(.text+0x2a9): undefined reference to `SSL_free'

增加编译选项-lssl : gcc Simple_TLS_Server.c -lssl -o tls_server

/usr/bin/ld: /tmp/cc5pFn01.o: undefined reference to symbol 'EVP_cleanup@@OPENSSL_1.0.0'
//lib/x86_64-linux-gnu/libcrypto.so.1.0.0: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status

还剩下一个,再增加编译选项: -lcrypto
编译通过。

  1. 配置密钥
    从Chromium Quic中拷贝证书到当前目录,重命名leaf_cert.pem为cert.pem。、,leaf_cert.key为key.pem
    需要注意的是,我在Quic Toy中使用的是./leaf_cert.pkcs8,但是这里用的是leaf_cert.key,如果使用leaf_cert.pkcs.8会报错。

    启动./tls_server

  2. 使用openssl的s_client功能测试tls_server
    先查看一下openssl s_client功能说明

    # openssl s_client help
    

    -host 选项用于指定地址,-port选项用于指定端口

尝试连接:
openssl s_client -host 127.0.0.1 -port 4433
```
 root@ubuntu:~/chromium/src# openssl s_client -host 127.0.0.1 -port 4433
 CONNECTED(00000003)
。。。。。此处省略大量细节  
test
read:errno=0
```
前面证书校验好像出错,但是仍然完成了握手过程,收到了来自server的"test"响应。
抓包展示如下:
![image.png](https://upload-images.jianshu.io/upload_images/1939047-c2d5fbbd4e2525b2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
  1. 使用Client demo访问tls server
    https://wiki.openssl.org/index.php/SSL/TLS_Client
    这个Client程序使用BIO方式访问一个网页,里面讲解了各个接口的作用。代码在最后的download章节可以下载到。
    将下载的压缩文件包Openssl-bio-fetch.tar.gz中的代码openssl-bio-fetch.c与openssl-bio-fetch.h以及Makefile拷贝到Ubuntu机器。
    修改Makefile中ssl与crypto的链接:
    OPENSSL_LDFLAGS = -Bstatic $(OPENSSL_LIBDIR)/libssl.a $(OPENSSL_LIBDIR)/libcrypto.a
    为如下:
    OPENSSL_LDFLAGS = -Bstatic -lssl -lcrypto
    执行Make:
```
root@ubuntu:/home/zengyi/data/openssl# make
cc   -g3 -ggdb -O0 -DDEBUG=1 -std=c99 -Wall -Wextra -Wconversion -Wformat -Wformat=2 -Wformat-security -Wno-deprecated-declarations -Wno-unused-function  -I/usr/local/ssl/macosx-x64/include openssl-bio-fetch.c -o openssl-bio-fetch.exe   -Bstatic -lssl -lcrypto
In file included from openssl-bio-fetch.c:2:0:
openssl-bio-fetch.h: In function ‘InstallDebugTrapHandler’:
openssl-bio-fetch.h:65:22: error: storage size of ‘new_handler’ isn’t known
     struct sigaction new_handler, old_handler;
                      ^
openssl-bio-fetch.h:65:35: error: storage size of ‘old_handler’ isn’t known
     struct sigaction new_handler, old_handler;
                                   ^
openssl-bio-fetch.h:70:15: warning: implicit declaration of function ‘sigaction’ [-Wimplicit-function-declaration]
         ret = sigaction (SIGTRAP, NULL, &old_handler);
               ^
openssl-bio-fetch.h:83:15: warning: implicit declaration of function ‘sigemptyset’ [-Wimplicit-function-declaration]
         ret = sigemptyset (&new_handler.sa_mask);
               ^
openssl-bio-fetch.h:65:35: warning: unused variable ‘old_handler’ [-Wunused-variable]
     struct sigaction new_handler, old_handler;
                                   ^
openssl-bio-fetch.h:65:22: warning: unused variable ‘new_handler’ [-Wunused-variable]
     struct sigaction new_handler, old_handler;
                      ^
Makefile:31: recipe for target 'openssl-bio-fetch.exe' failed
make: *** [openssl-bio-fetch.exe] Error 1    
```

struct sigaction类型找不到定义,是因为编译选项中使用-std=c99选项导致。
sigaction属于Posix.1-2001中新增的接口,c99标准中还未启用,因此会报错。修改方式可以是将sigaction使用更普遍的signal类型替换,或者去掉c99标准,或者去掉DEBUG宏,disable掉相关信号处理函数。
我们去掉C99标准选项。
修改Makefile,去掉std=c99选项,重新编译成功。
由于Client程序硬编码访问的是www.example.org,需要将其修改为127.0.0.1,端口修改为4433。
运行client,连接server握手

root@ubuntu:/home/zengyi/data/openssl# ./openssl-bio-fetch.exe
  Warning: thread locking is not implemented
  Assertion: openssl-bio-fetch.c: function main, line 115
  No such file or directory
  verify_callback (depth=0)(preverify=0)
    Issuer (cn): QUIC Server Root CA
    Subject (cn): 127.0.0.1
    Subject (san): www.example.org
    Subject (san): mail.example.org
    Subject (san): mail.example.com
    Unknown GENERAL_NAME type: 7
    Error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
  verify_callback (depth=0)(preverify=0)
    Issuer (cn): QUIC Server Root CA
    Subject (cn): 127.0.0.1
    Subject (san): www.example.org
    Subject (san): mail.example.org
    Subject (san): mail.example.com
    Unknown GENERAL_NAME type: 7
    Error = 21
  Assertion: openssl-bio-fetch.c: function main, line 268
  SSL_get_verify_results failed: 21 (0x15)

看起来是证书验证失败了。
去掉client中关于verify callback的注册:
注释掉 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback);一行

root@ubuntu:/home/zengyi/data/openssl# ./openssl-bio-fetch.exe
Warning: thread locking is not implemented
Assertion: openssl-bio-fetch.c: function main, line 115
No such file or directory
Assertion: openssl-bio-fetch.c: function main, line 268
SSL lib

把代码中整个step 1的部分全部注释掉(250 - 275行)。

  root@ubuntu:/home/zengyi/data/openssl# ./openssl-bio-fetch.exe
  Warning: thread locking is not implemented
  Assertion: openssl-bio-fetch.c: function main, line 115
  No such file or directory

  Fetching: /cgi-bin/randbyte?nbytes=32&format=h

  test    

嗯,测试成功!

  1. 更新OpenSSL库
    目前我Ubuntu上的OpenSSL库版本比较低,不支持TLS1.3.

    root@ubuntu:~/openssl/openssl-1.1.1c# openssl version
    OpenSSL 1.0.2g  1 Mar 2016
    root@ubuntu:~/openssl/openssl-1.1.1c# openssl ciphers -v 'ALL:COMPLEMENTOFALL' | grep TLSv1.3
    root@ubuntu:~/openssl/openssl-1.1.1c#
    

    下载最新OpenSSL版本,从官网上的值目前最新的稳定版本是1.1.1系列。我下载了openssl-1.1.1c.tar.gz,链接地址:https://www.openssl.org/source/openssl-1.1.1c.tar.gz
    放到Ubuntu上解压。
    根据Cookbook介绍按部就班,为了不影响现有OpenSSL库,配置好前缀。
    ./config --prefix=/usr/local/openssl-1.1.1c --openssldir=/usr/local/openssl-1.1.1c enable-ec_nistp_64_gcc_128
    make depend
    make
    sudo make install
    先看一下效果:

    root@ubuntu:~/openssl/openssl-1.1.1c# cd /usr/local/openssl-1.1.1c/
    root@ubuntu:/usr/local/openssl-1.1.1c# ./bin/openssl version
    root@ubuntu:/usr/local/openssl-1.1.1c/bin# ./openssl version
    ./openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
    

    报错找不到libssl.so.1.1,先临时配置一下环境变量:

     root@ubuntu:/usr/local/openssl-1.1.1c# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./lib
     root@ubuntu:/usr/local/openssl-1.1.1c# ./bin/openssl version
     OpenSSL 1.1.1c  28 May 2019
    

    版本是正确的,再看一下加密套件支持情况:

    root@ubuntu:/usr/local/openssl-1.1.1c# ./bin/openssl  ciphers -v 'ALL:COMPLEMENTOFALL' | grep TLSv1.3
    TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
    TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256)   Mac=AEAD
    TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
    

    将新版本的openssl配置到系统。
    移除原有OpenSSL版本(先搜索查看原有的ssl库在哪些地方,然后对应配置一下):

    mv /usr/bin/openssl /usr/bin/openssl.1.0.2g
    ln -s /usr/local/openssl-1.1.1c/bin/openssl /usr/bin/openssl
    mv /usr/include/openssl/ /usr/include/openssl.1.0.2g
    ln -s /usr/local/openssl-1.1.1c/include/openssl /usr/include/openssl
    rm -rf /usr/lib/x86_64-linux-gnu/libssl.so
    ln -s /usr/local/openssl-1.1.1c/lib/libssl.so.1.1 /usr/lib/x86_64-linux-gnu/libssl.so
    rm /usr/lib/x86_64-linux-gnu/libcrypt.so
    ln -s /usr/local/openssl-1.1.1c/lib/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypt.so
    cp /usr/local/openssl-1.1.1c/lib/libssl.so.1.1 /lib/x86_64-linux-gnu/
    cp /usr/local/openssl-1.1.1c/lib/libcrypto.so.1.1 /lib/x86_64-linux-gnu/
    mv /usr/lib/x86_64-linux-gnu/libssl.a /usr/lib/x86_64-linux-gnu/libssl.a.1.0.2g
    cp /usr/local/openssl-1.1.1c/lib/libssl.a /usr/lib/x86_64-linux-gnu/
    mv /usr/lib/x86_64-linux-gnu/libcrypto.a /usr/lib/x86_64-linux-gnu/libcrypto.a.1.0.2g
    cp /usr/local/openssl-1.1.1c/lib/libcrypto.a /usr/lib/x86_64-linux-gnu/
    cp /usr/local/openssl-1.1.1c/lib/libssl.so.1.1 /usr/lib/i386-linux-gnu/
    cp /usr/local/openssl-1.1.1c/lib/libssl.so.1.1 /lib/i386-linux-gnu/
    cp /usr/local/openssl-1.1.1c/lib/libcrypto.so.1.1 /lib/i386-linux-gnu/
    cp /usr/local/openssl-1.1.1c/lib/libcrypto.so.1.1 /usr/lib/i386-linux-gnu/
    rm -rf /usr/lib/i386-linux-gnu/libcrypto.so
    ln -s /lib/i386-linux-gnu/libcrypto.so.1.1 /usr/lib/i386-linux-gnu/libcrypto.so
    rm -rf /usr/lib/x86_64-linux-gnu/libcrypto.so
    ln -s /lib/x86_64-linux-gnu/libcrypto.so.1.1 /usr/lib/x86_64-linux-gnu/libcrypto.so
    rm -rf /usr/lib/i386-linux-gnu/libssl.so
    ln -s /lib/i386-linux-gnu/libssl.so.1.1 /usr/lib/i386-linux-gnu/libssl.so

    在一个新的Shell中运行,openssl版本已经更新

    root@ubuntu:~/chromium/src# openssl version
    OpenSSL 1.1.1c  28 May 2019
    root@ubuntu:~/chromium/src# openssl ciphers -v 'ALL:COMPLEMENTOFALL' | grep TLSv1.3
    TLS_AES_256_GCM_SHA384  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(256) Mac=AEAD
    TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any      Au=any  Enc=CHACHA20/POLY1305(256)     Mac=AEAD
    TLS_AES_128_GCM_SHA256  TLSv1.3 Kx=any      Au=any  Enc=AESGCM(128) Mac=AEAD
    

    重新编译Server和Client,出现大量错误:DEPRECATEDIN_1_1_0等符号找不到定义。
    这个符号是在opensslconf.in.h中定义的,在Make的时候会自动生成为opensslconf.h(竟然这样的骚操作,本地代码上根本看不到这个opensslconf.h)。但是即使这样,系统的openssconf.h也已经正常被生成,应该不会有问题。搜索一下系统,发现还有其他的目录下存在这个文件,需要替换掉。
    存在opensslconf.h的目录有:/usr/include/x86_64-linux-gnu/openssl/,/usr/include/i386-linux-gnu/openssl/
    替换为最新的文件解决问题。

    重新编译server和client,发现有一些函数已经处于未定义状态:

    root@ubuntu:/home/zengyi/data/openssl# gcc Simple_TLS_Server.c -lssl -lcrypto -o tls_server
    /tmp/ccssBesj.o: In function `init_openssl':
    Simple_TLS_Server.c:(.text+0xbf): undefined reference to `SSL_load_error_strings'
    Simple_TLS_Server.c:(.text+0xc4): undefined reference to `SSL_library_init'
    /tmp/ccssBesj.o: In function `cleanup_openssl':
    Simple_TLS_Server.c:(.text+0xd0): undefined reference to `EVP_cleanup'
    /tmp/ccssBesj.o: In function `create_context':
    Simple_TLS_Server.c:(.text+0xe0): undefined reference to `SSLv23_server_method'
    collect2: error: ld returned 1 exit status
    

    查看源码,发现这些函数确实已经废弃,版本号小于1.0.1才有用:

    # if OPENSSL_API_COMPAT < 0x10100000L
    #  define SSL_load_error_strings() \
        OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS \
                         | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL)
    # endif  
    

    从SSL_library_init()手册看,SSL_load_error_strings()与SSL_library_init(),EVP_Cleanup()接口已经被OPENSSL_init_ssl()替代。SSLv23_server_method()接口已经被TLS_server_method()接口替代,TLS_server_method()接口已经摒弃了具体的协议约束。

    The SSL_library_init() and OpenSSL_add_ssl_algorithms() functions were deprecated in OpenSSL 1.1.0 by OPENSSL_init_ssl().
    Calling this function will explicitly initialise BOTH libcrypto and libssl.
    The OpenSSL_add_all_algorithms(), OpenSSL_add_all_ciphers(), OpenSSL_add_all_digests(), and EVP_cleanup(), functions were deprecated in OpenSSL 1.1.0 by OPENSSL_init_crypto().
    SSLv23_method(), SSLv23_server_method() and SSLv23_client_method() were deprecated and the preferred TLS_method(), TLS_server_method() and TLS_client_method() functions were introduced in OpenSSL 1.1.0.
    All version-specific methods were deprecated in OpenSSL 1.1.0.

      int OPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);    
    

    将SSL_load_error_strings();OpenSSL_add_ssl_algorithms();函数替换为OPENSSL_init_ssl,将 EVP_cleanup()注释掉,将SSLv23_server_method();修改为TLS_server_method()。编译成功!
    运行tls_server
    运行 openssl s_client
    可以看到使用了TLSv1.3握手!
    抓包如下:


    使用OpenSSL TLS1.3 Demo_第1张图片
    image.png

你可能感兴趣的:(使用OpenSSL TLS1.3 Demo)