Skip to content

Commit af96930

Browse files
devicenullzhuizhuhaomeng
authored andcommitted
feature: add functions to parse DER formatted certificates/keys.
1 parent f1499e3 commit af96930

File tree

4 files changed

+230
-3
lines changed

4 files changed

+230
-3
lines changed

src/ngx_stream_lua_ssl_certby.c

Lines changed: 101 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -986,8 +986,8 @@ ngx_stream_lua_ffi_ssl_raw_client_addr(ngx_stream_lua_request_t *r, char **addr,
986986

987987

988988
int
989-
ngx_stream_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len, u_char *der,
990-
char **err)
989+
ngx_stream_lua_ffi_cert_pem_to_der(const u_char *pem, size_t pem_len,
990+
u_char *der, char **err)
991991
{
992992
int total, len;
993993
BIO *bio;
@@ -1079,7 +1079,7 @@ ngx_stream_lua_ffi_priv_key_pem_to_der(const u_char *pem, size_t pem_len,
10791079
return NGX_ERROR;
10801080
}
10811081

1082-
pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (void *)passphrase);
1082+
pkey = PEM_read_bio_PrivateKey(in, NULL, NULL, (void *) passphrase);
10831083
if (pkey == NULL) {
10841084
BIO_free(in);
10851085
*err = "PEM_read_bio_PrivateKey() failed";
@@ -1186,6 +1186,75 @@ ngx_stream_lua_ffi_parse_pem_cert(const u_char *pem, size_t pem_len,
11861186
}
11871187

11881188

1189+
void *
1190+
ngx_stream_lua_ffi_parse_der_cert(const char *data, size_t len,
1191+
char **err)
1192+
{
1193+
BIO *bio;
1194+
X509 *x509;
1195+
STACK_OF(X509) *chain;
1196+
1197+
bio = BIO_new_mem_buf((char *) data, len);
1198+
if (bio == NULL) {
1199+
*err = "BIO_new_mem_buf() failed";
1200+
ERR_clear_error();
1201+
return NULL;
1202+
}
1203+
1204+
x509 = d2i_X509_bio(bio, NULL);
1205+
if (x509 == NULL) {
1206+
*err = "d2i_X509_bio() failed";
1207+
BIO_free(bio);
1208+
ERR_clear_error();
1209+
return NULL;
1210+
}
1211+
1212+
chain = sk_X509_new_null();
1213+
if (chain == NULL) {
1214+
*err = "sk_X509_new_null() failed";
1215+
X509_free(x509);
1216+
BIO_free(bio);
1217+
ERR_clear_error();
1218+
return NULL;
1219+
}
1220+
1221+
if (sk_X509_push(chain, x509) == 0) {
1222+
*err = "sk_X509_push() failed";
1223+
sk_X509_free(chain);
1224+
X509_free(x509);
1225+
BIO_free(bio);
1226+
ERR_clear_error();
1227+
return NULL;
1228+
}
1229+
1230+
/* read rest of the chain */
1231+
1232+
while (!BIO_eof(bio)) {
1233+
x509 = d2i_X509_bio(bio, NULL);
1234+
if (x509 == NULL) {
1235+
*err = "d2i_X509_bio() failed in rest of chain";
1236+
sk_X509_pop_free(chain, X509_free);
1237+
BIO_free(bio);
1238+
ERR_clear_error();
1239+
return NULL;
1240+
}
1241+
1242+
if (sk_X509_push(chain, x509) == 0) {
1243+
*err = "sk_X509_push() failed in rest of chain";
1244+
sk_X509_pop_free(chain, X509_free);
1245+
X509_free(x509);
1246+
BIO_free(bio);
1247+
ERR_clear_error();
1248+
return NULL;
1249+
}
1250+
}
1251+
1252+
BIO_free(bio);
1253+
1254+
return chain;
1255+
}
1256+
1257+
11891258
void
11901259
ngx_stream_lua_ffi_free_cert(void *cdata)
11911260
{
@@ -1223,6 +1292,35 @@ ngx_stream_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t pem_len,
12231292
}
12241293

12251294

1295+
void *
1296+
ngx_stream_lua_ffi_parse_der_priv_key(const char *data, size_t len,
1297+
char **err)
1298+
{
1299+
BIO *bio = NULL;
1300+
EVP_PKEY *pkey = NULL;
1301+
1302+
bio = BIO_new_mem_buf((char *) data, len);
1303+
if (bio == NULL) {
1304+
*err = "BIO_new_mem_buf() failed";
1305+
BIO_free(bio);
1306+
ERR_clear_error();
1307+
return NULL;
1308+
}
1309+
1310+
pkey = d2i_PrivateKey_bio(bio, NULL);
1311+
if (pkey == NULL) {
1312+
*err = "d2i_PrivateKey_bio() failed";
1313+
BIO_free(bio);
1314+
ERR_clear_error();
1315+
return NULL;
1316+
}
1317+
1318+
BIO_free(bio);
1319+
1320+
return pkey;
1321+
}
1322+
1323+
12261324
void
12271325
ngx_stream_lua_ffi_free_priv_key(void *cdata)
12281326
{

t/140-ssl-c-api.t

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ ffi.cdef[[
4848
void *ngx_stream_lua_ffi_parse_pem_cert(const unsigned char *pem,
4949
size_t pem_len, char **err);
5050
51+
void *ngx_stream_lua_ffi_parse_der_cert(const unsigned char *der,
52+
size_t der_len, char **err);
53+
5154
void *ngx_stream_lua_ffi_parse_pem_priv_key(const unsigned char *pem,
5255
size_t pem_len, char **err);
5356
57+
void *ngx_stream_lua_ffi_parse_der_priv_key(const unsigned char *der,
58+
size_t der_len, char **err);
59+
5460
int ngx_stream_lua_ffi_set_cert(void *r,
5561
void *cdata, char **err);
5662
@@ -990,3 +996,126 @@ lua ssl server name: "test.com"
990996
--- no_error_log
991997
[error]
992998
[alert]
999+
1000+
1001+
1002+
=== TEST 10: DER cert + private key cdata
1003+
--- stream_config
1004+
server {
1005+
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
1006+
1007+
ssl_certificate_by_lua_block {
1008+
collectgarbage()
1009+
1010+
local ffi = require "ffi"
1011+
require "defines"
1012+
1013+
local errmsg = ffi.new("char *[1]")
1014+
1015+
local r = require "resty.core.base" .get_request()
1016+
if not r then
1017+
ngx.log(ngx.ERR, "no request found")
1018+
return
1019+
end
1020+
1021+
ffi.C.ngx_stream_lua_ffi_ssl_clear_certs(r, errmsg)
1022+
1023+
local f = assert(io.open("t/cert/test_der.crt", "rb"))
1024+
local cert_data = f:read("*all")
1025+
f:close()
1026+
1027+
local cert = ffi.C.ngx_stream_lua_ffi_parse_der_cert(cert_data, #cert_data, errmsg)
1028+
if not cert then
1029+
ngx.log(ngx.ERR, "failed to parse DER cert: ",
1030+
ffi.string(errmsg[0]))
1031+
return
1032+
end
1033+
1034+
local rc = ffi.C.ngx_stream_lua_ffi_set_cert(r, cert, errmsg)
1035+
if rc ~= 0 then
1036+
ngx.log(ngx.ERR, "failed to set cdata cert: ",
1037+
ffi.string(errmsg[0]))
1038+
return
1039+
end
1040+
1041+
ffi.C.ngx_stream_lua_ffi_free_cert(cert)
1042+
1043+
f = assert(io.open("t/cert/test_der.key", "rb"))
1044+
local pkey_data = f:read("*all")
1045+
f:close()
1046+
1047+
local pkey = ffi.C.ngx_stream_lua_ffi_parse_der_priv_key(pkey_data, #pkey_data, errmsg)
1048+
if pkey == nil then
1049+
ngx.log(ngx.ERR, "failed to parse DER priv key: ",
1050+
ffi.string(errmsg[0]))
1051+
return
1052+
end
1053+
1054+
local rc = ffi.C.ngx_stream_lua_ffi_set_priv_key(r, pkey, errmsg)
1055+
if rc ~= 0 then
1056+
ngx.log(ngx.ERR, "failed to set cdata priv key: ",
1057+
ffi.string(errmsg[0]))
1058+
return
1059+
end
1060+
1061+
ffi.C.ngx_stream_lua_ffi_free_priv_key(pkey)
1062+
}
1063+
1064+
ssl_certificate ../../cert/test2.crt;
1065+
ssl_certificate_key ../../cert/test2.key;
1066+
1067+
return 'it works!\n';
1068+
}
1069+
--- stream_server_config
1070+
lua_ssl_trusted_certificate ../../cert/test.crt;
1071+
1072+
content_by_lua_block {
1073+
do
1074+
local sock = ngx.socket.tcp()
1075+
1076+
sock:settimeout(2000)
1077+
1078+
local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock")
1079+
if not ok then
1080+
ngx.say("failed to connect: ", err)
1081+
return
1082+
end
1083+
1084+
ngx.say("connected: ", ok)
1085+
1086+
local sess, err = sock:sslhandshake(nil, "test.com", true)
1087+
if not sess then
1088+
ngx.say("failed to do SSL handshake: ", err)
1089+
return
1090+
end
1091+
1092+
ngx.say("ssl handshake: ", type(sess))
1093+
1094+
while true do
1095+
local line, err = sock:receive()
1096+
if not line then
1097+
-- ngx.say("failed to receive response status line: ", err)
1098+
break
1099+
end
1100+
1101+
ngx.say("received: ", line)
1102+
end
1103+
1104+
local ok, err = sock:close()
1105+
ngx.say("close: ", ok, " ", err)
1106+
end -- do
1107+
-- collectgarbage()
1108+
}
1109+
1110+
--- stream_response
1111+
connected: 1
1112+
ssl handshake: userdata
1113+
received: it works!
1114+
close: 1 nil
1115+
1116+
--- error_log
1117+
lua ssl server name: "test.com"
1118+
1119+
--- no_error_log
1120+
[error]
1121+
[alert]

t/cert/test_der.crt

685 Bytes
Binary file not shown.

t/cert/test_der.key

636 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)