Skip to content

Commit 7598ff3

Browse files
devicenullzhuizhuhaomeng
authored andcommitted
feature: add ngx_http_lua_ffi_parse_der_cert and ngx_http_lua_ffi_parse_der_key functions.
1 parent 0e769b7 commit 7598ff3

File tree

6 files changed

+269
-4
lines changed

6 files changed

+269
-4
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ env:
4343
- LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1
4444
- LUA_INCLUDE_DIR=$LUAJIT_INC
4545
- PCRE_VER=8.45
46-
- PCRE2_VER=10.37
46+
- PCRE2_VER=10.42
4747
- PCRE_PREFIX=/opt/pcre
4848
- PCRE2_PREFIX=/opt/pcre2
4949
- PCRE_LIB=$PCRE_PREFIX/lib
@@ -81,7 +81,7 @@ before_install:
8181
install:
8282
- if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi
8383
- if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; fi
84-
- if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi
84+
- if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi
8585
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
8686
- if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi
8787
- wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz

README.markdown

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7916,11 +7916,11 @@ Set client certificate chain and corresponding private key to the TCP socket obj
79167916
The certificate chain and private key provided will be used later by the [tcpsock:sslhandshake](#tcpsocksslhandshake) method.
79177917

79187918
* `cert` specify a client certificate chain cdata object that will be used while handshaking with
7919-
remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert)
7919+
remote server. These objects can be created using [ngx.ssl.parse\_pem\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_cert) or [ngx.ssl.parse\_der\_cert](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_cert)
79207920
function provided by lua-resty-core. Note that specifying the `cert` option requires
79217921
corresponding `pkey` be provided too. See below.
79227922
* `pkey` specify a private key corresponds to the `cert` option above.
7923-
These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key)
7923+
These objects can be created using [ngx.ssl.parse\_pem\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_pem_priv_key) or [ngx.ssl.parse\_der\_priv\_key](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/ssl.md#parse_der_priv_key)
79247924
function provided by lua-resty-core.
79257925

79267926
If both of `cert` and `pkey` are `nil`, this method will clear any existing client certificate and private key

src/ngx_http_lua_ssl_certby.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,81 @@ ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len,
11721172
}
11731173

11741174

1175+
void *
1176+
ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len,
1177+
char **err)
1178+
{
1179+
BIO *bio;
1180+
X509 *x509;
1181+
STACK_OF(X509) *chain;
1182+
1183+
if (data == NULL || len == 0) {
1184+
*err = "invalid argument";
1185+
ERR_clear_error();
1186+
return NULL;
1187+
}
1188+
1189+
bio = BIO_new_mem_buf((char *) data, len);
1190+
if (bio == NULL) {
1191+
*err = "BIO_new_mem_buf() failed";
1192+
ERR_clear_error();
1193+
return NULL;
1194+
}
1195+
1196+
x509 = d2i_X509_bio(bio, NULL);
1197+
if (x509 == NULL) {
1198+
*err = "d2i_X509_bio() failed";
1199+
BIO_free(bio);
1200+
ERR_clear_error();
1201+
return NULL;
1202+
}
1203+
1204+
chain = sk_X509_new_null();
1205+
if (chain == NULL) {
1206+
*err = "sk_X509_new_null() failed";
1207+
X509_free(x509);
1208+
BIO_free(bio);
1209+
ERR_clear_error();
1210+
return NULL;
1211+
}
1212+
1213+
if (sk_X509_push(chain, x509) == 0) {
1214+
*err = "sk_X509_push() failed";
1215+
sk_X509_free(chain);
1216+
X509_free(x509);
1217+
BIO_free(bio);
1218+
ERR_clear_error();
1219+
return NULL;
1220+
}
1221+
1222+
/* read rest of the chain */
1223+
1224+
while (!BIO_eof(bio)) {
1225+
x509 = d2i_X509_bio(bio, NULL);
1226+
if (x509 == NULL) {
1227+
*err = "d2i_X509_bio() failed in rest of chain";
1228+
sk_X509_pop_free(chain, X509_free);
1229+
BIO_free(bio);
1230+
ERR_clear_error();
1231+
return NULL;
1232+
}
1233+
1234+
if (sk_X509_push(chain, x509) == 0) {
1235+
*err = "sk_X509_push() failed in rest of chain";
1236+
sk_X509_pop_free(chain, X509_free);
1237+
X509_free(x509);
1238+
BIO_free(bio);
1239+
ERR_clear_error();
1240+
return NULL;
1241+
}
1242+
}
1243+
1244+
BIO_free(bio);
1245+
1246+
return chain;
1247+
}
1248+
1249+
11751250
void
11761251
ngx_http_lua_ffi_free_cert(void *cdata)
11771252
{
@@ -1209,6 +1284,40 @@ ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len,
12091284
}
12101285

12111286

1287+
void *
1288+
ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len,
1289+
char **err)
1290+
{
1291+
BIO *bio = NULL;
1292+
EVP_PKEY *pkey = NULL;
1293+
1294+
if (data == NULL || len == 0) {
1295+
*err = "invalid argument";
1296+
ERR_clear_error();
1297+
return NULL;
1298+
}
1299+
1300+
bio = BIO_new_mem_buf((char *) data, len);
1301+
if (bio == NULL) {
1302+
*err = "BIO_new_mem_buf() failed";
1303+
ERR_clear_error();
1304+
return NULL;
1305+
}
1306+
1307+
pkey = d2i_PrivateKey_bio(bio, NULL);
1308+
if (pkey == NULL) {
1309+
*err = "d2i_PrivateKey_bio() failed";
1310+
BIO_free(bio);
1311+
ERR_clear_error();
1312+
return NULL;
1313+
}
1314+
1315+
BIO_free(bio);
1316+
1317+
return pkey;
1318+
}
1319+
1320+
12121321
void
12131322
ngx_http_lua_ffi_free_priv_key(void *cdata)
12141323
{

t/140-ssl-c-api.t

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ ffi.cdef[[
5353
void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem,
5454
size_t pem_len, char **err);
5555
56+
void *ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len,
57+
char **err);
58+
59+
void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len,
60+
char **err);
61+
5662
int ngx_http_lua_ffi_set_cert(void *r,
5763
void *cdata, char **err);
5864
@@ -1323,3 +1329,153 @@ SNI is test.com
13231329
--- no_error_log
13241330
[error]
13251331
[alert]
1332+
1333+
1334+
1335+
=== TEST 11: DER cert + private key cdata
1336+
--- http_config
1337+
server {
1338+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
1339+
server_name test.com;
1340+
1341+
ssl_certificate_by_lua_block {
1342+
collectgarbage()
1343+
1344+
local ffi = require "ffi"
1345+
require "defines"
1346+
1347+
local errmsg = ffi.new("char *[1]")
1348+
1349+
local r = require "resty.core.base" .get_request()
1350+
if r == nil then
1351+
ngx.log(ngx.ERR, "no request found")
1352+
return
1353+
end
1354+
1355+
ffi.C.ngx_http_lua_ffi_ssl_clear_certs(r, errmsg)
1356+
1357+
local f = assert(io.open("t/cert/test_der.crt", "rb"))
1358+
local cert_data = f:read("*all")
1359+
f:close()
1360+
1361+
local cert = ffi.C.ngx_http_lua_ffi_parse_der_cert(cert_data, #cert_data, errmsg)
1362+
if not cert then
1363+
ngx.log(ngx.ERR, "failed to parse DER cert: ",
1364+
ffi.string(errmsg[0]))
1365+
return
1366+
end
1367+
1368+
local rc = ffi.C.ngx_http_lua_ffi_set_cert(r, cert, errmsg)
1369+
if rc ~= 0 then
1370+
ngx.log(ngx.ERR, "failed to set cdata cert: ",
1371+
ffi.string(errmsg[0]))
1372+
return
1373+
end
1374+
1375+
ffi.C.ngx_http_lua_ffi_free_cert(cert)
1376+
1377+
f = assert(io.open("t/cert/test_der.key", "rb"))
1378+
local pkey_data = f:read("*all")
1379+
f:close()
1380+
1381+
local pkey = ffi.C.ngx_http_lua_ffi_parse_der_priv_key(pkey_data, #pkey_data, errmsg)
1382+
if pkey == nil then
1383+
ngx.log(ngx.ERR, "failed to parse DER priv key: ",
1384+
ffi.string(errmsg[0]))
1385+
return
1386+
end
1387+
1388+
local rc = ffi.C.ngx_http_lua_ffi_set_priv_key(r, pkey, errmsg)
1389+
if rc ~= 0 then
1390+
ngx.log(ngx.ERR, "failed to set cdata priv key: ",
1391+
ffi.string(errmsg[0]))
1392+
return
1393+
end
1394+
1395+
ffi.C.ngx_http_lua_ffi_free_priv_key(pkey)
1396+
}
1397+
1398+
ssl_certificate ../../cert/test2.crt;
1399+
ssl_certificate_key ../../cert/test2.key;
1400+
1401+
server_tokens off;
1402+
location /foo {
1403+
default_type 'text/plain';
1404+
content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) }
1405+
more_clear_headers Date;
1406+
}
1407+
}
1408+
--- config
1409+
server_tokens off;
1410+
lua_ssl_trusted_certificate ../../cert/test.crt;
1411+
1412+
location /t {
1413+
content_by_lua_block {
1414+
do
1415+
local sock = ngx.socket.tcp()
1416+
1417+
sock:settimeout(2000)
1418+
1419+
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
1420+
if not ok then
1421+
ngx.say("failed to connect: ", err)
1422+
return
1423+
end
1424+
1425+
ngx.say("connected: ", ok)
1426+
1427+
local sess, err = sock:sslhandshake(nil, "test.com", true)
1428+
if not sess then
1429+
ngx.say("failed to do SSL handshake: ", err)
1430+
return
1431+
end
1432+
1433+
ngx.say("ssl handshake: ", type(sess))
1434+
1435+
local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n"
1436+
local bytes, err = sock:send(req)
1437+
if not bytes then
1438+
ngx.say("failed to send http request: ", err)
1439+
return
1440+
end
1441+
1442+
ngx.say("sent http request: ", bytes, " bytes.")
1443+
1444+
while true do
1445+
local line, err = sock:receive()
1446+
if not line then
1447+
-- ngx.say("failed to receive response status line: ", err)
1448+
break
1449+
end
1450+
1451+
ngx.say("received: ", line)
1452+
end
1453+
1454+
local ok, err = sock:close()
1455+
ngx.say("close: ", ok, " ", err)
1456+
end -- do
1457+
-- collectgarbage()
1458+
}
1459+
}
1460+
1461+
--- request
1462+
GET /t
1463+
--- response_body
1464+
connected: 1
1465+
ssl handshake: cdata
1466+
sent http request: 56 bytes.
1467+
received: HTTP/1.1 201 Created
1468+
received: Server: nginx
1469+
received: Content-Type: text/plain
1470+
received: Content-Length: 4
1471+
received: Connection: close
1472+
received:
1473+
received: foo
1474+
close: 1 nil
1475+
1476+
--- error_log
1477+
lua ssl server name: "test.com"
1478+
1479+
--- no_error_log
1480+
[error]
1481+
[alert]

t/cert/test_der.crt

955 Bytes
Binary file not shown.

t/cert/test_der.key

1.19 KB
Binary file not shown.

0 commit comments

Comments
 (0)