问个ssl-cert-by-lua的问题

707 views
Skip to first unread message

paul...@gmail.com

unread,
Sep 25, 2015, 1:23:51 AM9/25/15
to openresty
Hi all:

      今天一直按照春哥的https://github.com/openresty/lua-nginx-module/issues/331#issuecomment-77279170在部署https动态加载证书以及私钥的东西。
       
      (1)build文件:
      1 ./configure \
      2     --prefix=/usr/local/dy-nginx \
      3     --with-http_ssl_module \
      4     --with-cc-opt="-I/usr/local/openssl-1.0.2/include -I/usr/local/pcre/include -I/usr/local/zlib/include" \
      5     --with-ld-opt="-L/usr/local/openssl-1.0.2/lib -L/usr/local/pcre/lib -L/usr/local/zlib/lib" \
      6     --add-module=../fcc_module/lua-nginx-module-ssl-cert-by-lua  \
      7     --add-module=../fcc_module/ngx_devel_kit-0.2.18 \
      8     --add-module=../fcc_module/echo-nginx-module-0.58 \
     10     --with-debug
     11 
     12 make -j 8
     13 make install

     (2)编译如下:
     export LUAJIT_LIB=/usr/local/lib 
    export LUAJIT_INC=/usr/local/include/luajit-2.0 
    sh build

     (3)配置:
      其中我的nginx.conf中https server的配置如下(其实是从春哥的测试程序里摘的https://github.com/openresty/lua-nginx-module/blob/ssl-cert-by-lua/t/130-ssl-cert-by.t):
    102         listen       443 ssl;
    103         server_name  localhost;
    104 
    105         ssl_certificate_by_lua '
    106             local ssl = require "ngx.ssl"
    107             ngx.log(ngx.ERR, "Debug... ")
    108             ssl.clear_certs()
    109 
    110             local f = assert(io.open("server.bdstatic.crt.der"))
    111             local cert_data = f:read("*a")
    112             f:close()
    113             local ok, err = ssl.set_der_cert(cert_data)
    114             if not ok then
    115                 ngx.log(ngx.ERR, "failed to set DER cert: ", err)
    116                 return
    117             end
    118             ngx.log(ngx.ERR, "sucess to set DER cert!")
    119 
    120             local f = assert(io.open("server.bdstatic.key.der"))
    121             local pkey_data = f:read("*a")
    122             f:close()
    123             local ok, err = ssl.set_der_priv_key(pkey_data)
    124             if not ok then
    125                 ngx.log(ngx.ERR, "failed to set DER cert: ", err)
    126                 return
    127             end
    128             ngx.log(ngx.ERR, "sucess to set DER key!")
    129             --ssl.clear_certs()
    130         ';
    131
    132         #ssl_certificate ../../cert/test.crt;
    133         #ssl_certificate_key ../../cert/test.key;
    134 
    135         #ssl_certificate      cert.pem;
    136         #ssl_certificate_key  cert.key;

   (3)执行访问:
   启动nginx时没有问题,但是我访问https://myserver.com的时候log里面总是报:
2015/09/25 13:04:31 [error] 95678#0: lua entry thread aborted: runtime error: /usr/local/dy-nginx/lua_files/resty/core/base.lua:22: ngx_lua 0.9.17+ required   

求问有谁遇到过类似的问题?

ps:
目前我用的是lua-nginx-module-ssl-cert-by-lua代替原来的lua-nginx-module-0.9.16rc2,是不是要支持ssl-cert-by-lua还需要安装lua-nginx-module-0.9.16rc2高
一点的版本0.9.17+?但目前lua-nginx-module最高为0.9.16啊?

谢谢了

paulvon
20150925
     

paul...@gmail.com

unread,
Sep 25, 2015, 4:08:19 AM9/25/15
to openresty
新手,不知道是不是已经已解决了
 
在lua-nginx-module-ssl-cert-by-lua模块的src/api/ngx_http_lua_api.h 文件中版本宏更新为9017后即可。

查了github上的代码本应该是9017的,但是lua-nginx-module-ssl-cert-by-lua中的没更新还为9016

#define ngx_http_lua_version 9017

lhmwzy

unread,
Sep 25, 2015, 4:36:17 AM9/25/15
to open...@googlegroups.com
最好是直接用openresty,你这样使用模块,出问题,直接不好查找原因

Yichun Zhang (agentzh)

unread,
Sep 25, 2015, 6:19:10 AM9/25/15
to openresty
Hello!

On Fri, Sep 25, 2015 at 1:23 PM, <paul...@gmail.com> wrote:
> ps:
> 目前我用的是lua-nginx-module-ssl-cert-by-lua代替原来的lua-nginx-module-0.9.16rc2,是不是要支持ssl-cert-by-lua还需要安装lua-nginx-module-0.9.16rc2高
> 一点的版本0.9.17+?但目前lua-nginx-module最高为0.9.16啊?
>

呃,你这里需要较老一点的 lua-resty-core 库,比如 v0.1.1,而不应使用 git master HEAD.

待 ssl_certificate_by_lua 合并进 ngx_lua 模块的主干以后,你就可以考虑直接使用 OpenResty 软件包了。

Regards,
-agentzh

paul...@gmail.com

unread,
Sep 25, 2015, 6:32:37 AM9/25/15
to openresty
原有程序框架,不能动了,只能添砖加瓦,修修补补

On Friday, September 25, 2015 at 4:36:17 PM UTC+8, lhmwzy wrote:
最好是直接用openresty,你这样使用模块,出问题,直接不好查找原因

paul...@gmail.com

unread,
Sep 25, 2015, 6:37:20 AM9/25/15
to openresty
好吧,我再试试低版本的lua-resy-core库。话说我今天把base.lua里的版本判断降成0.9.16了,并且也能运行了,但是不知道有没有隐患,目前还在测试你写的那些配置以及lua-ssl脚本。

Yichun Zhang (agentzh)

unread,
Sep 25, 2015, 7:52:51 AM9/25/15
to openresty
Hello!

2015-09-25 18:37 GMT+08:00 <paul...@gmail.com>:
> 好吧,我再试试低版本的lua-resy-core库。话说我今天把base.lua里的版本判断降成0.9.16了,并且也能运行了,但是不知道有没有隐患,目前还在测试你写的那些配置以及lua-ssl脚本。
>

有隐患。那个版本的 base.lua 文件里要求 0.9.17 是有原因的,lua-resty-core 的一些部分依赖新版 ngx_lua
的 ABI,当这些部分遇到老版 ngx_lua 的时候,轻则内存出错,重则进程崩溃。

Regards,
-agentzh
Message has been deleted

paul...@gmail.com

unread,
Nov 27, 2015, 12:30:11 AM11/27/15
to openresty
春哥:
      你好,最近用你的lua-nginx-module-ssl-cert-by-lua分支有一些疑问,想向你请教下:
1. 分支不支持pem格式的证书,我看了下源码主要是lua-nginx-module-ssl-cert-by-lua/src/ngx_http_lua_sslcertby.c中的函数ngx_http_lua_ffi_ssl_set_der_certificate
    函数在解析证书文件时,你用的openssl接口是d2i_X509_bio;其实若传进来的数据是文本PEM格式的,可以用PEM_read_bio_X509_AUX接口直接解析返回x509       证书结构。当时你实现的时候没考虑用这个接口是否是因为lua传二进制缓存更加安全?还是其他?
2. der编码的证书有个缺点,就是只能对单个证书,不能是证书链(我目前在网上搜索的资料,存证书链都是用pem格式的,很少用der编码的),而PEM格式的证书       可以是证书链。所以,在你的实现中,虽然有对der编码证书循环读证书链,但是der编码证书文件中只有一个证书,故中间证书缺失,导致ssl握手证书验证不过。
3. 目前https服务证书格式基本上都是pem的,很少有der编码的,故个人觉得将此接口改为pem的较好;
4. 当然,私钥也可改变为pem格式的证书;

这是我的一些疑问和建议,还望回复,谢谢
paulvon

如下是在你原来的接口基础上改的支持pem格式证书的接口(在我这里已测试通过)
int
ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r,
    const char *data, size_t len, char **err)
{
    BIO               *bio = NULL;
    X509              *x509 = NULL;
    ngx_ssl_conn_t    *ssl_conn;

    if (r->connection == NULL || r->connection->ssl == NULL) {
        *err = "bad request";
        return NGX_ERROR;
    }

    ssl_conn = r->connection->ssl->connection;
    if (ssl_conn == NULL) {
        *err = "bad ssl conn";
        return NGX_ERROR;
    }

    bio = BIO_new_mem_buf((char *) data, len);
    if (bio == NULL) {
       *err = " BIO_new_mem_buf() failed";
        goto failed;
    }

    //x509 = d2i_X509_bio(bio, NULL);
    x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
    if (x509 == NULL) {
        *err = " PEM_read_bio_X509_AUX() failed";
        goto failed;
    }

    if (SSL_use_certificate(ssl_conn, x509) == 0) {
        *err = " SSL_use_certificate() failed";
        goto failed;
    }

#if 0
    if (SSL_set_ex_data(ssl_conn, ngx_ssl_certificate_index, x509) == 0) {
        *err = " SSL_set_ex_data() failed";
        goto failed;
    }
#endif

    X509_free(x509);
    x509 = NULL;

    // read rest of the chain 
/*
    while (!BIO_eof(bio)) {

        x509 = d2i_X509_bio(bio, NULL);
        if (x509 == NULL) {
            *err = "d2i_X509_bio() failed";
            goto failed;
        }

        if (SSL_add0_chain_cert(ssl_conn, x509) == 0) {
            *err = "SSL_add0_chain_cert() failed";
            goto failed;
        }
    }
*/

    while (!BIO_eof(bio)) {
        x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
        if (x509 == NULL) {
            *err = "PEM_read_bio_X509() failed";
            goto failed;
        }

        if (SSL_add0_chain_cert(ssl_conn, x509) == 0) {
            *err = "SSL_add0_chain_cert() failed";
            goto failed;
        }
    }

    BIO_free(bio);

    *err = NULL;
    return NGX_OK;

failed:

    if (bio) {
        BIO_free(bio);
    }

    if (x509) {
        X509_free(x509);
    }

    return NGX_ERROR;
}


int
ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r,
    const char *data, size_t len, char **err)
{
    BIO               *bio = NULL;
    EVP_PKEY          *pkey = NULL;
    ngx_ssl_conn_t    *ssl_conn;

    if (r->connection == NULL || r->connection->ssl == NULL) {
        *err = "bad request";
        return NGX_ERROR;
    }

    ssl_conn = r->connection->ssl->connection;
    if (ssl_conn == NULL) {
        *err = "bad ssl conn";
        return NGX_ERROR;
    }

    bio = BIO_new_mem_buf((char *) data, len);
    if (bio == NULL) {
        *err = "BIO_new_mem_buf() failed";
        goto failed;
    }

    //pkey = d2i_PrivateKey_bio(bio, NULL);
    pkey = PEM_read_bio_PrivateKey(bio, NULL, 0, NULL);
    if (pkey == NULL) {
        *err = "PEM_read_bio_PrivateKey() failed";
        goto failed;
    }

    if (SSL_use_PrivateKey(ssl_conn, pkey) == 0) {
        *err = "SSL_CTX_use_PrivateKey() failed";
        goto failed;
    }

    EVP_PKEY_free(pkey);
    BIO_free(bio);

    return NGX_OK;

failed:

    if (pkey) {
        EVP_PKEY_free(pkey);
    }

    if (bio) {
        BIO_free(bio);
    }

    return NGX_ERROR;
}

Yichun Zhang (agentzh)

unread,
Nov 27, 2015, 1:25:52 AM11/27/15
to openresty
Hello!

2015-11-27 13:30 GMT+08:00 <paul...@gmail.com>:
> 你好,最近用你的lua-nginx-module-ssl-cert-by-lua分支有一些疑问,想向你请教下:
> 1.
> 分支不支持pem格式的证书,我看了下源码主要是lua-nginx-module-ssl-cert-by-lua/src/ngx_http_lua_sslcertby.c中的函数ngx_http_lua_ffi_ssl_set_der_certificate
>
> 函数在解析证书文件时,你用的openssl接口是d2i_X509_bio;其实若传进来的数据是文本PEM格式的,可以用PEM_read_bio_X509_AUX接口直接解析返回x509
> 证书结构。当时你实现的时候没考虑用这个接口是否是因为lua传二进制缓存更加安全?还是其他?

目前的接口当时选择使用 DER 主要是为了直接缓存 DER 而非 PEM. DER 比 PEM
更紧凑更小巧,同时解析起来也更快。不过从现在看来,直接缓存 OpenSSL 解析后的二进制数据结构要比 DER 还要更加高效,毕竟解析
DER 还会在 OpenSSL 内部发生昂贵的 malloc 等动态内存分配操作。确实,这里的 API 最好重新设计一下,以 PEM
作为原始输入,以 OpenSSL 解析证书链后生成的 cdata 作为设置证书链的 API 所使用的输入(这里的 cdata 可以通过
lua-resty-lrucache 进行缓存)。当时使用 DER 而没什么安全上的考量,毕竟证书都是公开的信息。

> 2.
> der编码的证书有个缺点,就是只能对单个证书,不能是证书链(我目前在网上搜索的资料,存证书链都是用pem格式的,很少用der编码的),而PEM格式的证书
> 可以是证书链。所以,在你的实现中,虽然有对der编码证书循环读证书链,但是der编码证书文件中只有一个证书,故中间证书缺失,导致ssl握手证书验证不过。

是的,这是一个常见的潜在问题。如果用户使用外部工具链自己进行 pem -> der 的(预)转换,很可能导致证书链不完整。目前的 API
需要用户自己调用 ngx.ssl 模块中的 cert_pem_to_der() 函数进行 PEM 到 DER 的转换。这个 API
会保留完整的证书链。

> 3. 目前https服务证书格式基本上都是pem的,很少有der编码的,故个人觉得将此接口改为pem的较好;

目前的 Lua API 其实也只是把 DER 作为中间编码。当然,我觉得直接用 OpenSSL 生成的 C 数据结构的指针作为中间结果更高效也更灵活。

> 4. 当然,私钥也可改变为pem格式的证书;
>

私钥使用 DER 的好处是方便直接进行上一层的加密。当然,我们可以提供 priv_key_pem_to_der()
这个转换函数(我记得已经有 pull request 实现了该函数)。

Regards,
-agentzh
Message has been deleted

Yichun Zhang (agentzh)

unread,
Nov 27, 2015, 2:47:46 AM11/27/15
to openresty
Hello!

2015-11-27 15:44 GMT+08:00 <paul...@gmail.com>:
> 其实我想着看能不能扩展下,就是pem格式,der编码的都支持,加载到模块后,让模块自动解析其格式,像nginx本身或Apache那样,证书或私钥的格式对上层透明。
>

在 API 层面,我还是希望显式指定格式,毕竟格式自动识别一来容易引入不必要的额外开销,二来也不完全靠谱。

Regards,
-agentzh

paul...@gmail.com

unread,
Nov 27, 2015, 2:48:31 AM11/27/15
to openresty
其实我想着看能不能扩展下,就是pem格式,der编码的都支持,加载到模块后,让模块自动解析其格式,像nginx本身或Apache那样,证书或私钥的格式对上层透明。

谢谢春哥的即时回复,很受用,再有什么疑问,再来请教。
paulvon


On Friday, November 27, 2015 at 2:25:52 PM UTC+8, agentzh wrote:
Hello! 

2015-11-27 13:30 GMT+08:00  <paul...@gmail.com>: 
>       你好,最近用你的lua-nginx-module-ssl-cert-by-lua分支有一些疑问,想向你请教下: 
> 1. 
> 分支不支持pem格式的证书,我看了下源码主要是lua-nginx-module-ssl-cert-by-lua/src/ngx_http_lua_sslcertby.c中的函数ngx_http_lua_ffi_ssl_set_der_certificate 

> 函数在解析证书文件时,你用的openssl接口是d2i_X509_bio;其实若传进来的数据是文本PEM格式的,可以用PEM_read_bio_X509_AUX接口直接解析返回x509 
> 证书结构。当时你实现的时候没考虑用这个接口是否是因为lua传二进制缓存更加安全?还是其他? 

目前的接口当时选择使用 DER 主要是为了直接缓存 DER 而非 PEM. DER 比 PEM 
更紧凑更小巧,同时解析起来也更快。不过从现在看来,直接缓存 OpenSSL 解析后的二进制数据结构要比 DER 还要更加高效,毕竟解析 
DER 还会在 OpenSSL 内部发生昂贵的 malloc 等动态内存分配操作。确实,这里的 API 最好重新设计一下,以 PEM 
作为原始输入,以 OpenSSL 解析证书链后生成的 cdata 作为设置证书链的 API 所使用的输入(这里的 cdata 可以通过 
lua-resty-lrucache 进行缓存)。当时使用 DER 而没什么安全上的考量,毕竟证书都是公开的信息。 
    
   恩,明白你的意思 。对于你说的 「cdata 可以通过 lua-resty-lrucache 进行缓存」,我下去研究下,这块不懂:)

> 2. 
> der编码的证书有个缺点,就是只能对单个证书,不能是证书链(我目前在网上搜索的资料,存证书链都是用pem格式的,很少用der编码的),而PEM格式的证书 
> 可以是证书链。所以,在你的实现中,虽然有对der编码证书循环读证书链,但是der编码证书文件中只有一个证书,故中间证书缺失,导致ssl握手证书验证不过。 

是的,这是一个常见的潜在问题。如果用户使用外部工具链自己进行 pem -> der 的(预)转换,很可能导致证书链不完整。目前的 API 
需要用户自己调用 ngx.ssl 模块中的 cert_pem_to_der() 函数进行 PEM 到 DER 的转换。这个 API 
会保留完整的证书链。 

    恩,看到你实现了这个转换的函数,不过还没测试过,我得先测试下 :)

> 3. 目前https服务证书格式基本上都是pem的,很少有der编码的,故个人觉得将此接口改为pem的较好; 

目前的 Lua API 其实也只是把 DER 作为中间编码。当然,我觉得直接用 OpenSSL 生成的 C 数据结构的指针作为中间结果更高效也更灵活。 

    恩,确实是这样的 

> 4. 当然,私钥也可改变为pem格式的证书; 


私钥使用 DER 的好处是方便直接进行上一层的加密。当然,我们可以提供 priv_key_pem_to_der() 
这个转换函数(我记得已经有 pull request 实现了该函数)。 

    恩,明白,一般cert和prikey方法都是成对的,你应该提供了:)

Regards, 
-agentzh 

paul...@gmail.com

unread,
Nov 27, 2015, 2:55:35 AM11/27/15
to openresty
恩 你说的确实有道理
哈哈,我就只在我所开发的项目中弄个试试看 :)

谢谢~
paulvon
Reply all
Reply to author
Forward
0 new messages