Skip to content

Commit 921e593

Browse files
authored
feat(ssl): add variable to get upstream ssl certificate and connection (#111)
One customer wants to get ssl certificate information from upstream request, such as CN for common name C for country name ST for state or province name L for locality name O for organization OU for organization unit And also they want to know if upstream ssl is enabled and get ssl version from upstream request. So in this PR, we provide ngx.var.kong_ssl_upstream_raw_cert and ngx.var.kong_upstream_ssl_protocol to get ssl certificate with PEM format and tls version for ssl connection, so that in Kong we can get information from those data structures. With a small fix about a potential double free problem related with bio. * feat(ssl): add variables to get upstream ssl certificate and tls version add ssl_upstream_raw_cert and upstream_ssl_protocol as nginx variable to get upstream ssl certificate and tls version * feat(ssl): update doc and test cases about getting upstream ssl certificate and connection Refactor variable name with "kong_*" prefix to prevent potential conflict with Nginx. * fix(ssl): fix a potential double free problem in bio --------- Signed-off-by: Walker Zhao <[email protected]>
1 parent feb1787 commit 921e593

File tree

7 files changed

+618
-4
lines changed

7 files changed

+618
-4
lines changed

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ Table of Contents
1515
* [lua\_kong\_error\_log\_request\_id](#lua_kong_error_log_request_id)
1616
* [Variables](#variables)
1717
* [$kong\_request\_id](#kong_request_id)
18+
* [$kong\_upstream\_ssl\_server\_raw\_cert](#kong_upstream_ssl_server_raw_cert)
19+
* [$kong\_upstream\_ssl\_protocol](#kong_upstream_ssl_protocol)
1820
* [Methods](#methods)
1921
* [resty.kong.tls.disable\_session\_reuse](#restykongtlsdisable_session_reuse)
2022
* [resty.kong.tls.get\_full\_client\_certificate\_chain](#restykongtlsget_full_client_certificate_chain)
@@ -183,6 +185,22 @@ $kong\_request\_id
183185
Unique request identifier generated from 16 pseudo-random bytes, in hexadecimal.
184186
This variable is indexed.
185187

188+
[Back to TOC](#table-of-contents)
189+
190+
$kong\_upstream\_ssl\_server\_raw\_cert
191+
----------------------------------------------------
192+
193+
Returns the upstream server certificate in the PEM format for an established SSL connection.
194+
195+
[Back to TOC](#table-of-contents)
196+
197+
$kong\_upstream\_ssl\_protocol
198+
----------------------------------------------------
199+
200+
Returns the protocol of an established SSL connection for an upstream
201+
HTTP request.
202+
203+
186204
[Back to TOC](#table-of-contents)
187205

188206
Methods
@@ -425,6 +443,9 @@ Retrieves the OpenSSL `SSL*` object for the current HTTP request.
425443

426444
On success, this function returns the pointer of type `SSL`. Otherwise `nil` and a string
427445
describing the error will be returned.
446+
447+
[Back to TOC](#table-of-contents)
448+
428449
resty.kong.tls.disable\_http2\_alpn
429450
----------------------------------------------------
430451
**syntax:** *ok, err = resty.kong.tls.disable\_http2\_alpn()*
@@ -548,6 +569,7 @@ default `log_level` setting from Nginx configuration immediately.
548569
If this method is called again before the timeout, the log level and timeout will be overwritten.
549570

550571
If we don’t pass timeout to set_log_level(), it will raise a Lua error.
572+
551573
[Back to TOC](#table-of-contents)
552574

553575
resty.kong.log.get\_log\_level

src/ngx_http_lua_kong_var_index.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ static ngx_str_t default_vars[] = {
8383
ngx_string("ssl_client_verify"),
8484
ngx_string("ssl_protocol"),
8585
ngx_string("ssl_server_name"),
86+
ngx_string("kong_upstream_ssl_server_raw_cert"),
87+
ngx_string("kong_upstream_ssl_protocol"),
8688
#endif
8789

8890
ngx_string("upstream_http_connection"),

src/ngx_http_lua_kong_vars.c

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,179 @@ ngx_http_lua_kong_variable_request_id(ngx_http_request_t *r,
5353
}
5454

5555

56+
#if (NGX_SSL)
57+
static ngx_int_t
58+
ngx_http_lua_kong_get_ssl_raw_certificate(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
59+
{
60+
size_t len;
61+
BIO *bio;
62+
X509 *cert;
63+
64+
s->len = 0;
65+
66+
cert = SSL_get_peer_certificate(c->ssl->connection);
67+
if (cert == NULL) {
68+
return NGX_OK;
69+
}
70+
71+
bio = BIO_new(BIO_s_mem());
72+
if (bio == NULL) {
73+
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
74+
X509_free(cert);
75+
return NGX_ERROR;
76+
}
77+
78+
if (PEM_write_bio_X509(bio, cert) == 0) {
79+
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "PEM_write_bio_X509() failed");
80+
goto failed;
81+
}
82+
83+
len = BIO_pending(bio);
84+
s->len = len;
85+
86+
s->data = ngx_pnalloc(pool, len);
87+
if (s->data == NULL) {
88+
goto failed;
89+
}
90+
91+
BIO_read(bio, s->data, len);
92+
93+
BIO_free(bio);
94+
X509_free(cert);
95+
96+
return NGX_OK;
97+
98+
failed:
99+
BIO_free(bio);
100+
X509_free(cert);
101+
102+
return NGX_ERROR;
103+
}
104+
105+
106+
static ngx_int_t
107+
ngx_http_lua_kong_get_upstream_raw_certificate(ngx_http_request_t *r, ngx_http_variable_value_t *v,
108+
uintptr_t data)
109+
{
110+
ngx_str_t s;
111+
112+
ngx_connection_t *uc;
113+
ngx_http_upstream_t *u;
114+
ngx_peer_connection_t *peer;
115+
116+
u = r->upstream;
117+
if (u == NULL) {
118+
goto not_found;
119+
}
120+
121+
peer = &(u->peer);
122+
if (peer == NULL) {
123+
goto not_found;
124+
}
125+
126+
uc = peer->connection;
127+
if (uc == NULL) {
128+
goto not_found;
129+
}
130+
131+
if (uc->ssl) {
132+
if (ngx_http_lua_kong_get_ssl_raw_certificate(uc, r->pool, &s) != NGX_OK) {
133+
return NGX_ERROR;
134+
}
135+
136+
v->len = s.len;
137+
v->data = s.data;
138+
139+
if (v->len) {
140+
v->valid = 1;
141+
v->no_cacheable = 0;
142+
v->not_found = 0;
143+
144+
return NGX_OK;
145+
}
146+
}
147+
148+
not_found:
149+
150+
v->not_found = 1;
151+
152+
return NGX_OK;
153+
}
154+
155+
156+
static ngx_int_t
157+
ngx_http_lua_kong_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
158+
{
159+
s->data = (u_char *) SSL_get_version(c->ssl->connection);
160+
return NGX_OK;
161+
}
162+
163+
164+
static ngx_int_t
165+
ngx_http_lua_kong_get_upstream_tls_protocol(ngx_http_request_t *r, ngx_http_variable_value_t *v,
166+
uintptr_t data)
167+
{
168+
size_t len;
169+
ngx_str_t s;
170+
171+
ngx_connection_t *uc;
172+
ngx_http_upstream_t *u;
173+
ngx_peer_connection_t *peer;
174+
175+
u = r->upstream;
176+
if (u == NULL) {
177+
goto not_found;
178+
}
179+
180+
peer = &(u->peer);
181+
if (peer == NULL) {
182+
goto not_found;
183+
}
184+
185+
uc = peer->connection;
186+
if (uc == NULL) {
187+
goto not_found;
188+
}
189+
190+
if (uc->ssl) {
191+
(void) ngx_http_lua_kong_ssl_get_protocol(uc, NULL, &s);
192+
193+
v->data = s.data;
194+
195+
for (len = 0; v->data[len]; len++) { /* void */ }
196+
197+
v->len = len;
198+
v->valid = 1;
199+
v->no_cacheable = 0;
200+
v->not_found = 0;
201+
202+
return NGX_OK;
203+
}
204+
205+
not_found:
206+
207+
v->not_found = 1;
208+
209+
return NGX_OK;
210+
}
211+
#endif /* NGX_SSL */
212+
213+
56214
static ngx_http_variable_t ngx_http_lua_kong_variables[] = {
57215

58216
{ ngx_string("kong_request_id"), NULL,
59217
ngx_http_lua_kong_variable_request_id,
60218
0, 0, 0 },
61-
219+
#if (NGX_SSL)
220+
{ ngx_string("kong_upstream_ssl_server_raw_cert"), NULL,
221+
ngx_http_lua_kong_get_upstream_raw_certificate,
222+
0,
223+
NGX_HTTP_VAR_CHANGEABLE, 0 },
224+
{ ngx_string("kong_upstream_ssl_protocol"), NULL,
225+
ngx_http_lua_kong_get_upstream_tls_protocol,
226+
0,
227+
NGX_HTTP_VAR_CHANGEABLE, 0 },
228+
#endif
62229
ngx_http_null_variable
63230
};
64231

src/ssl/ngx_lua_kong_ssl.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ ngx_lua_kong_ssl_get_full_client_certificate_chain(ngx_connection_t *c,
156156
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "BIO_new() failed");
157157

158158
X509_free(cert);
159-
ret = NGX_ERROR;
160-
goto done;
159+
return NGX_ERROR;
161160
}
162161

163162
if (PEM_write_bio_X509(bio, cert) == 0) {

0 commit comments

Comments
 (0)