Skip to content

Commit 6351efe

Browse files
devicenullzhuizhuhaomeng
authored andcommitted
feature: add parse_der_cert and parse_der_priv_key functions.
1 parent 812b2d3 commit 6351efe

File tree

6 files changed

+315
-2
lines changed

6 files changed

+315
-2
lines changed

lib/ngx/ssl.lua

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ local ngx_lua_ffi_priv_key_pem_to_der
3232
local ngx_lua_ffi_ssl_get_tls1_version
3333
local ngx_lua_ffi_parse_pem_cert
3434
local ngx_lua_ffi_parse_pem_priv_key
35+
local ngx_lua_ffi_parse_der_cert
36+
local ngx_lua_ffi_parse_der_priv_key
3537
local ngx_lua_ffi_set_cert
3638
local ngx_lua_ffi_set_priv_key
3739
local ngx_lua_ffi_free_cert
@@ -77,6 +79,12 @@ if subsystem == 'http' then
7779
void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem,
7880
size_t pem_len, char **err);
7981

82+
void *ngx_http_lua_ffi_parse_der_cert(const char *data,
83+
size_t len, char **err);
84+
85+
void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len,
86+
char **err) ;
87+
8088
int ngx_http_lua_ffi_set_cert(void *r, void *cdata, char **err);
8189

8290
int ngx_http_lua_ffi_set_priv_key(void *r, void *cdata, char **err);
@@ -103,6 +111,8 @@ if subsystem == 'http' then
103111
ngx_lua_ffi_ssl_get_tls1_version = C.ngx_http_lua_ffi_ssl_get_tls1_version
104112
ngx_lua_ffi_parse_pem_cert = C.ngx_http_lua_ffi_parse_pem_cert
105113
ngx_lua_ffi_parse_pem_priv_key = C.ngx_http_lua_ffi_parse_pem_priv_key
114+
ngx_lua_ffi_parse_der_cert = C.ngx_http_lua_ffi_parse_der_cert
115+
ngx_lua_ffi_parse_der_priv_key = C.ngx_http_lua_ffi_parse_der_priv_key
106116
ngx_lua_ffi_set_cert = C.ngx_http_lua_ffi_set_cert
107117
ngx_lua_ffi_set_priv_key = C.ngx_http_lua_ffi_set_priv_key
108118
ngx_lua_ffi_free_cert = C.ngx_http_lua_ffi_free_cert
@@ -145,9 +155,15 @@ elseif subsystem == 'stream' then
145155
void *ngx_stream_lua_ffi_parse_pem_cert(const unsigned char *pem,
146156
size_t pem_len, char **err);
147157

158+
void *ngx_stream_lua_ffi_parse_der_cert(const unsigned char *der,
159+
size_t der_len, char **err);
160+
148161
void *ngx_stream_lua_ffi_parse_pem_priv_key(const unsigned char *pem,
149162
size_t pem_len, char **err);
150163

164+
void *ngx_stream_lua_ffi_parse_der_priv_key(const unsigned char *der,
165+
size_t der_len, char **err);
166+
151167
int ngx_stream_lua_ffi_set_cert(void *r, void *cdata, char **err);
152168

153169
int ngx_stream_lua_ffi_set_priv_key(void *r, void *cdata, char **err);
@@ -173,7 +189,9 @@ elseif subsystem == 'stream' then
173189
ngx_lua_ffi_priv_key_pem_to_der = C.ngx_stream_lua_ffi_priv_key_pem_to_der
174190
ngx_lua_ffi_ssl_get_tls1_version = C.ngx_stream_lua_ffi_ssl_get_tls1_version
175191
ngx_lua_ffi_parse_pem_cert = C.ngx_stream_lua_ffi_parse_pem_cert
192+
ngx_lua_ffi_parse_der_cert = C.ngx_stream_lua_ffi_parse_der_cert
176193
ngx_lua_ffi_parse_pem_priv_key = C.ngx_stream_lua_ffi_parse_pem_priv_key
194+
ngx_lua_ffi_parse_der_priv_key = C.ngx_stream_lua_ffi_parse_der_priv_key
177195
ngx_lua_ffi_set_cert = C.ngx_stream_lua_ffi_set_cert
178196
ngx_lua_ffi_set_priv_key = C.ngx_stream_lua_ffi_set_priv_key
179197
ngx_lua_ffi_free_cert = C.ngx_stream_lua_ffi_free_cert
@@ -387,6 +405,26 @@ function _M.parse_pem_priv_key(pem)
387405
end
388406

389407

408+
function _M.parse_der_cert(der)
409+
local cert = ngx_lua_ffi_parse_der_cert(der, #der, errmsg)
410+
if cert ~= nil then
411+
return ffi_gc(cert, ngx_lua_ffi_free_cert)
412+
end
413+
414+
return nil, ffi_str(errmsg[0])
415+
end
416+
417+
418+
function _M.parse_der_priv_key(der)
419+
local pkey = ngx_lua_ffi_parse_der_priv_key(der, #der, errmsg)
420+
if pkey ~= nil then
421+
return ffi_gc(pkey, ngx_lua_ffi_free_priv_key)
422+
end
423+
424+
return nil, ffi_str(errmsg[0])
425+
end
426+
427+
390428
function _M.set_cert(cert)
391429
local r = get_request()
392430
if not r then

lib/ngx/ssl.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Table of Contents
2424
* [get_tls1_version_str](#get_tls1_version_str)
2525
* [parse_pem_cert](#parse_pem_cert)
2626
* [parse_pem_priv_key](#parse_pem_priv_key)
27+
* [parse_der_cert](#parse_der_cert)
28+
* [parse_der_priv_key](#parse_der_priv_key)
2729
* [set_cert](#set_cert)
2830
* [set_priv_key](#set_priv_key)
2931
* [verify_client](#verify_client)
@@ -457,14 +459,49 @@ This function was first added in version `0.1.7`.
457459

458460
[Back to TOC](#table-of-contents)
459461

462+
parse_der_cert
463+
--------------
464+
**syntax:** *cert_chain, err = ssl.parse_der_cert(der_cert_chain)*
465+
466+
**context:** *any*
467+
468+
Converts the DER-formated SSL certificate chain data into an opaque cdata pointer (for later uses
469+
in the [set_cert](#set_cert)
470+
function, for example).
471+
472+
In case of failures, returns `nil` and a string describing the error.
473+
474+
You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme)
475+
to cache the cdata result.
476+
477+
This function can be called in any context.
478+
479+
[Back to TOC](#table-of-contents)
480+
481+
parse_der_priv_key
482+
------------------
483+
**syntax:** *priv_key, err = ssl.parse_der_priv_key(der_priv_key)*
484+
485+
**context:** *any*
486+
487+
Converts the DER-formatted SSL private key data into an opaque cdata pointer (for later uses
488+
in the [set_priv_key](#set_priv_key)
489+
function, for example).
490+
491+
In case of failures, returns `nil` and a string describing the error.
492+
493+
This function can be called in any context.
494+
495+
[Back to TOC](#table-of-contents)
496+
460497
set_cert
461498
--------
462499
**syntax:** *ok, err = ssl.set_cert(cert_chain)*
463500

464501
**context:** *ssl_certificate_by_lua**
465502

466503
Sets the SSL certificate chain opaque pointer returned by the
467-
[parse_pem_cert](#parse_pem_cert) function for the current SSL connection.
504+
[parse_pem_cert](#parse_pem_cert) or [parse_der_cert](#parse_der_cert)function for the current SSL connection.
468505

469506
Returns `true` on success, or a `nil` value and a string describing the error otherwise.
470507

@@ -483,7 +520,7 @@ set_priv_key
483520
**context:** *ssl_certificate_by_lua**
484521

485522
Sets the SSL private key opaque pointer returned by the
486-
[parse_pem_priv_key](#parse_pem_priv_key) function for the current SSL connection.
523+
[parse_pem_priv_key](#parse_pem_priv_key) or [parse_der_priv_key](#parse_der_priv_key) function for the current SSL connection.
487524

488525
Returns `true` on success, or a `nil` value and a string describing the error otherwise.
489526

t/cert/test_der.crt

1.52 KB
Binary file not shown.

t/cert/test_der.key

2.32 KB
Binary file not shown.

t/ssl.t

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2837,3 +2837,136 @@ lua ssl server name: "test.com"
28372837
[error]
28382838
[alert]
28392839
[emerg]
2840+
2841+
2842+
2843+
=== TEST 29: parse PEM cert and key to cdata
2844+
--- http_config
2845+
lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH";
2846+
2847+
server {
2848+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
2849+
server_name test.com;
2850+
ssl_certificate_by_lua_block {
2851+
local ssl = require "ngx.ssl"
2852+
2853+
ssl.clear_certs()
2854+
2855+
local f = assert(io.open("t/cert/chain/chain.der"))
2856+
local cert_data = f:read("*a")
2857+
f:close()
2858+
2859+
local cert, err = ssl.parse_der_cert(cert_data)
2860+
if not cert then
2861+
ngx.log(ngx.ERR, "failed to parse pem cert: ", err)
2862+
return
2863+
end
2864+
2865+
local ok, err = ssl.set_cert(cert)
2866+
if not ok then
2867+
ngx.log(ngx.ERR, "failed to set cert: ", err)
2868+
return
2869+
end
2870+
2871+
local f = assert(io.open("t/cert/chain/test-com.key.der"))
2872+
local pkey_data = f:read("*a")
2873+
f:close()
2874+
2875+
local pkey, err = ssl.parse_der_priv_key(pkey_data)
2876+
if not pkey then
2877+
ngx.log(ngx.ERR, "failed to parse pem key: ", err)
2878+
return
2879+
end
2880+
2881+
local ok, err = ssl.set_priv_key(pkey)
2882+
if not ok then
2883+
ngx.log(ngx.ERR, "failed to set private key: ", err)
2884+
return
2885+
end
2886+
}
2887+
ssl_certificate ../../cert/test2.crt;
2888+
ssl_certificate_key ../../cert/test2.key;
2889+
2890+
server_tokens off;
2891+
location /foo {
2892+
default_type 'text/plain';
2893+
content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) }
2894+
more_clear_headers Date;
2895+
}
2896+
}
2897+
--- config
2898+
server_tokens off;
2899+
lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt;
2900+
lua_ssl_verify_depth 3;
2901+
2902+
location /t {
2903+
content_by_lua_block {
2904+
do
2905+
local sock = ngx.socket.tcp()
2906+
2907+
sock:settimeout(3000)
2908+
2909+
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
2910+
if not ok then
2911+
ngx.say("failed to connect: ", err)
2912+
return
2913+
end
2914+
2915+
ngx.say("connected: ", ok)
2916+
2917+
local sess, err = sock:sslhandshake(nil, "test.com", true)
2918+
if not sess then
2919+
ngx.say("failed to do SSL handshake: ", err)
2920+
return
2921+
end
2922+
2923+
ngx.say("ssl handshake: ", type(sess))
2924+
2925+
local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n"
2926+
local bytes, err = sock:send(req)
2927+
if not bytes then
2928+
ngx.say("failed to send http request: ", err)
2929+
return
2930+
end
2931+
2932+
ngx.say("sent http request: ", bytes, " bytes.")
2933+
2934+
while true do
2935+
local line, err = sock:receive()
2936+
if not line then
2937+
-- ngx.say("failed to receive response status line: ", err)
2938+
break
2939+
end
2940+
2941+
ngx.say("received: ", line)
2942+
end
2943+
2944+
local ok, err = sock:close()
2945+
ngx.say("close: ", ok, " ", err)
2946+
end -- do
2947+
-- collectgarbage()
2948+
}
2949+
}
2950+
2951+
--- request
2952+
GET /t
2953+
--- response_body
2954+
connected: 1
2955+
ssl handshake: cdata
2956+
sent http request: 56 bytes.
2957+
received: HTTP/1.1 201 Created
2958+
received: Server: nginx
2959+
received: Content-Type: text/plain
2960+
received: Content-Length: 4
2961+
received: Connection: close
2962+
received:
2963+
received: foo
2964+
close: 1 nil
2965+
2966+
--- error_log
2967+
lua ssl server name: "test.com"
2968+
2969+
--- no_error_log
2970+
[error]
2971+
[alert]
2972+
[emerg]

t/stream/ssl.t

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2140,3 +2140,108 @@ lua ssl server name: "test.com"
21402140
[error]
21412141
[alert]
21422142
[emerg]
2143+
2144+
2145+
=== TEST 27: parse DER cert and key to cdata
2146+
--- stream_config
2147+
lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH";
2148+
2149+
server {
2150+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
2151+
ssl_certificate_by_lua_block {
2152+
local ssl = require "ngx.ssl"
2153+
2154+
ssl.clear_certs()
2155+
2156+
local f = assert(io.open("t/cert/chain/chain.der"))
2157+
local cert_data = f:read("*a")
2158+
f:close()
2159+
2160+
local cert, err = ssl.parse_der_cert(cert_data)
2161+
if not cert then
2162+
ngx.log(ngx.ERR, "failed to parse DER cert: ", err)
2163+
return
2164+
end
2165+
2166+
local ok, err = ssl.set_cert(cert)
2167+
if not ok then
2168+
ngx.log(ngx.ERR, "failed to set cert: ", err)
2169+
return
2170+
end
2171+
2172+
local f = assert(io.open("t/cert/chain/test-com.key.der"))
2173+
local pkey_data = f:read("*a")
2174+
f:close()
2175+
2176+
local pkey, err = ssl.parse_der_priv_key(pkey_data)
2177+
if not pkey then
2178+
ngx.log(ngx.ERR, "failed to parse DER key: ", err)
2179+
return
2180+
end
2181+
2182+
local ok, err = ssl.set_priv_key(pkey)
2183+
if not ok then
2184+
ngx.log(ngx.ERR, "failed to set private key: ", err)
2185+
return
2186+
end
2187+
}
2188+
ssl_certificate ../../cert/test2.crt;
2189+
ssl_certificate_key ../../cert/test2.key;
2190+
2191+
return 'it works!\n';
2192+
}
2193+
--- stream_server_config
2194+
lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt;
2195+
lua_ssl_verify_depth 3;
2196+
2197+
content_by_lua_block {
2198+
do
2199+
local sock = ngx.socket.tcp()
2200+
2201+
sock:settimeout(3000)
2202+
2203+
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
2204+
if not ok then
2205+
ngx.say("failed to connect: ", err)
2206+
return
2207+
end
2208+
2209+
ngx.say("connected: ", ok)
2210+
2211+
local sess, err = sock:sslhandshake(nil, "test.com", true)
2212+
if not sess then
2213+
ngx.say("failed to do SSL handshake: ", err)
2214+
return
2215+
end
2216+
2217+
ngx.say("ssl handshake: ", type(sess))
2218+
2219+
while true do
2220+
local line, err = sock:receive()
2221+
if not line then
2222+
-- ngx.say("failed to receive response status line: ", err)
2223+
break
2224+
end
2225+
2226+
ngx.say("received: ", line)
2227+
end
2228+
2229+
local ok, err = sock:close()
2230+
ngx.say("close: ", ok, " ", err)
2231+
end -- do
2232+
-- collectgarbage()
2233+
}
2234+
2235+
--- stream_response
2236+
connected: 1
2237+
ssl handshake: userdata
2238+
received: it works!
2239+
close: 1 nil
2240+
2241+
--- error_log
2242+
lua ssl server name: "test.com"
2243+
2244+
--- no_error_log
2245+
[error]
2246+
[alert]
2247+
[emerg]

0 commit comments

Comments
 (0)