Skip to content

feature: ssl/tls: support for passphrase protected key. #1991

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ngx_http_lua_ssl_certby.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,7 +1042,7 @@ ngx_http_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der,

int
ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len,
u_char *der, char **err)
const u_char *passphrase, u_char *der, char **err)
{
int len;
BIO *in;
Expand All @@ -1055,7 +1055,7 @@ ngx_http_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len,
return NGX_ERROR;
}

pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);
pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (void *) passphrase);
if (pkey == NULL) {
BIO_free(in);
*err = "PEM_read_bio_PrivateKey() failed";
Expand Down
181 changes: 177 additions & 4 deletions t/140-ssl-c-api.t
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ ffi.cdef[[
size_t pem_len, unsigned char *der, char **err);

int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem,
size_t pem_len, unsigned char *der, char **err);
size_t pem_len, const unsigned char *passphrase,
unsigned char *der, char **err);

int ngx_http_lua_ffi_ssl_set_der_certificate(void *r,
const char *data, size_t len, char **err);
Expand Down Expand Up @@ -130,7 +131,7 @@ __DATA__

out = ffi.new("char [?]", #pkey)

local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, nil, out, errmsg)
if rc < 1 then
ngx.log(ngx.ERR, "failed to parse PEM priv key: ",
ffi.string(errmsg[0]))
Expand Down Expand Up @@ -284,7 +285,7 @@ lua ssl server name: "test.com"

out = ffi.new("char [?]", #pkey)

local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, nil, out, errmsg)
if rc < 1 then
ngx.log(ngx.ERR, "failed to parse PEM priv key: ",
ffi.string(errmsg[0]))
Expand Down Expand Up @@ -422,7 +423,7 @@ lua ssl server name: "test.com"

out = ffi.new("char [?]", #pkey)

local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, out, errmsg)
local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, nil, out, errmsg)
if rc < 1 then
ngx.log(ngx.ERR, "failed to parse PEM priv key: ",
ffi.string(errmsg[0]))
Expand Down Expand Up @@ -1024,3 +1025,175 @@ client certificate subject: nil
--- no_error_log
[error]
[alert]



=== TEST 9: simple cert + private key with passphrase
--- http_config
server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
server_name test.com;

ssl_certificate_by_lua_block {
collectgarbage()

local ffi = require "ffi"

ffi.cdef[[
int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem,
size_t pem_len, unsigned char *der, char **err);

int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem,
size_t pem_len, const unsigned char *passphrase,
unsigned char *der, char **err);

int ngx_http_lua_ffi_ssl_set_der_certificate(void *r,
const char *data, size_t len, char **err);

int ngx_http_lua_ffi_ssl_set_der_private_key(void *r,
const char *data, size_t len, char **err);

int ngx_http_lua_ffi_ssl_clear_certs(void *r, char **err);
]]

local errmsg = ffi.new("char *[1]")

local r = require "resty.core.base" .get_request()
if not r then
ngx.log(ngx.ERR, "no request found")
return
end

ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg)

local f = assert(io.open("t/cert/test_passphrase.crt", "rb"))
local cert = f:read("*all")
f:close()

local out = ffi.new("char [?]", #cert)

local rc = ffi.C.ngx_http_lua_ffi_cert_pem_to_der(cert, #cert, out, errmsg)
if rc < 1 then
ngx.log(ngx.ERR, "failed to parse PEM cert: ",
ffi.string(errmsg[0]))
return
end

local cert_der = ffi.string(out, rc)

local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_certificate(r, cert_der, #cert_der, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to set DER cert: ",
ffi.string(errmsg[0]))
return
end

f = assert(io.open("t/cert/test_passphrase.key", "rb"))
local pkey = f:read("*all")
f:close()

local passphrase = "123456"

out = ffi.new("char [?]", #pkey)

local rc = ffi.C.ngx_http_lua_ffi_priv_key_pem_to_der(pkey, #pkey, passphrase, out, errmsg)
if rc < 1 then
ngx.log(ngx.ERR, "failed to parse PEM priv key: ",
ffi.string(errmsg[0]))
return
end

local pkey_der = ffi.string(out, rc)

local rc = ffi.C.ngx_http_lua_ffi_ssl_set_der_private_key(r, pkey_der, #pkey_der, errmsg)
if rc ~= 0 then
ngx.log(ngx.ERR, "failed to set DER priv key: ",
ffi.string(errmsg[0]))
return
end
}

ssl_certificate ../../cert/test2.crt;
ssl_certificate_key ../../cert/test2.key;

server_tokens off;
location /foo {
default_type 'text/plain';
content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) }
more_clear_headers Date;
}
}
--- config
server_tokens off;
lua_ssl_trusted_certificate ../../cert/test_passphrase.crt;

location /t {
content_by_lua_block {
do
local sock = ngx.socket.tcp()

sock:settimeout(2000)

local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
if not ok then
ngx.say("failed to connect: ", err)
return
end

ngx.say("connected: ", ok)

local sess, err = sock:sslhandshake(nil, "test.com", false)
if not sess then
ngx.say("failed to do SSL handshake: ", err)
return
end

ngx.say("ssl handshake: ", type(sess))

local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n"
local bytes, err = sock:send(req)
if not bytes then
ngx.say("failed to send http request: ", err)
return
end

ngx.say("sent http request: ", bytes, " bytes.")

while true do
local line, err = sock:receive()
if not line then
-- ngx.say("failed to recieve response status line: ", err)
break
end

ngx.say("received: ", line)
end

local ok, err = sock:close()
ngx.say("close: ", ok, " ", err)
end -- do
-- collectgarbage()
}
}

--- request
GET /t
--- response_body
connected: 1
ssl handshake: userdata
sent http request: 56 bytes.
received: HTTP/1.1 201 Created
received: Server: nginx
received: Content-Type: text/plain
received: Content-Length: 4
received: Connection: close
received:
received: foo
close: 1 nil

--- error_log
lua ssl server name: "test.com"

--- no_error_log
[error]
[alert]
17 changes: 17 additions & 0 deletions t/cert/test_passphrase.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICozCCAgwCCQDEutRdSs3vZjANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMC
Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UEBwwIU2hlblpoZW4xEjAQBgNV
BAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0
LmNvbTEjMCEGCSqGSIb3DQEJARYUZ3VhbmdsaW5sdkBnbWFpbC5jb20wIBcNMTYw
NDI4MTQ0MzI4WhgPMjE1MTAzMjcxNDQzMjhaMIGUMQswCQYDVQQGEwJDTjESMBAG
A1UECAwJR3Vhbmdkb25nMREwDwYDVQQHDAhTaGVuWmhlbjESMBAGA1UECgwJT3Bl
blJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRlc3QuY29tMSMw
IQYJKoZIhvcNAQkBFhRndWFuZ2xpbmx2QGdtYWlsLmNvbTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEA2KZ+HdH9R2tarxD8PKqu5EYq2BNGlFRg1xJmrw0XZBRM
UP/VPb+sIeioooz36uhiXfQjExlpBCA/0zNAN+HbFyqpPPTf1qLGrj/dqeE4MJaN
Bwzxiv3fZnENT65u2qbiFWIY+ATNHgA20d50nxNNjPTzLbkx/nYXL92r4kuAGk0C
AwEAATANBgkqhkiG9w0BAQUFAAOBgQCfMo0qbcs3kwl1tcNBO5hCcUUJRzyv041V
ff/nZ/JPIMo/LSZd12K82G/dLRN7uRT9nzqtm+JRkHALHWWWFKi6bdg1vcdOTWqC
08bCkJHQoXJQQLvvA6gNvnR+0b7L4CrCmrcyYgKDLXVGNP9Wv/PqSWWbxsmqngkA
Mvy6CVytFw==
-----END CERTIFICATE-----
18 changes: 18 additions & 0 deletions t/cert/test_passphrase.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,679ACC8E69ACAA92

Ssrjp3VU4somCNPiXkWqcudDnvnwbyj/Q0pS07at3lXKbhQSgI1Tzhg9Pm3BXXj5
mkLdeGG5ocrj1Q9dhtmZgZeHHQIiynZBhjBu1Y+HPef8jXOWLrCOi8EKiWkJ2qG3
V1KFM/95CcDt0mRLykUXEL3IpUst05SFb9XwiLokB7ypeu3NhgNUHjL6G+ubB4ri
TOUjCW4pEoNHjdC22IiqSncwCVhluYSGhr6ktHKehZMhYIXmL1wmSLdhTlsPXCQl
xvYILQ2vJcKIR1BkeYYPD/OQC6zCZlXIErzfgeZiz2+NTudKYpb9VmsQKsO+R8L7
tZ/fNaR0vk8bbimMHgStAV4acVsC/7WxsqOjMJ8VTq1iqhYPl6N7kRdR3H3kSSOm
cN9T3SrOHDVaHbnWgToaOE4mKFjvFSLIOcWgus0iOHWXmY+SLG+Ndag3oVB6R9oB
cAHX19mq99+GhzA8IV4I0En2UCKQhnGPvkM+9mcCDxhRETlwncDjlMGOHpQ65J9r
eReVPIpnDkvHxPGTtsR3ZHTdWTZb+C0W2N3QIlJKrOzxFmfoj++yG3tMX42aDY0g
DVkrXgcKobiWN0AVrJNAwfG7uObKSCFYgz/0RRMCO4cjXRW99nxdjVDZhyc6R0Te
jzuF04okkOLNb25n2hP+yIULrn+6Nv/uHtFI0j0n3hOzcKh//dNbACSAKgkHni9g
JKDFJXgLJxf+Wc3So0DF9gYMKJJ+WbcdVT9gkC7RyQHlC90Pn7kNXzHr0ZawUsNI
ZxSkL4dMhYAfA4lUBJbOkwbSurv97LinOSRffpM0Nmf7VNw/Ue15eg==
-----END RSA PRIVATE KEY-----