diff --git a/src/ngx_http_lua_ssl_certby.c b/src/ngx_http_lua_ssl_certby.c index a265ed80a1..5292bcf38d 100644 --- a/src/ngx_http_lua_ssl_certby.c +++ b/src/ngx_http_lua_ssl_certby.c @@ -914,7 +914,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; @@ -927,7 +927,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"; diff --git a/t/140-ssl-c-api.t b/t/140-ssl-c-api.t index 4ecc2cdaf3..5b4ced16b5 100644 --- a/t/140-ssl-c-api.t +++ b/t/140-ssl-c-api.t @@ -42,7 +42,8 @@ __DATA__ 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); @@ -91,7 +92,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])) @@ -211,7 +212,8 @@ lua ssl server name: "test.com" 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); @@ -260,7 +262,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])) @@ -380,7 +382,8 @@ lua ssl server name: "test.com" 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); ]] local errmsg = ffi.new("char *[1]") @@ -405,7 +408,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])) @@ -497,3 +500,175 @@ failed to parse PEM priv key: PEM_read_bio_PrivateKey failed --- no_error_log [alert] + + + +=== TEST 4: 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 = getfenv(0).__ngx_req + 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", true) + 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] diff --git a/t/cert/test_passphrase.crt b/t/cert/test_passphrase.crt new file mode 100644 index 0000000000..f4d516ba9e --- /dev/null +++ b/t/cert/test_passphrase.crt @@ -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----- diff --git a/t/cert/test_passphrase.key b/t/cert/test_passphrase.key new file mode 100644 index 0000000000..b8fc97634a --- /dev/null +++ b/t/cert/test_passphrase.key @@ -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-----