1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2015 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "shrpx_mruby_module_env.h"
26
27 #include <mruby/variable.h>
28 #include <mruby/string.h>
29 #include <mruby/hash.h>
30
31 #include "shrpx_downstream.h"
32 #include "shrpx_upstream.h"
33 #include "shrpx_client_handler.h"
34 #include "shrpx_mruby.h"
35 #include "shrpx_mruby_module.h"
36 #include "shrpx_log.h"
37 #include "shrpx_tls.h"
38
39 namespace shrpx {
40
41 namespace mruby {
42
43 namespace {
env_init(mrb_state * mrb,mrb_value self)44 mrb_value env_init(mrb_state *mrb, mrb_value self) { return self; }
45 } // namespace
46
47 namespace {
env_get_req(mrb_state * mrb,mrb_value self)48 mrb_value env_get_req(mrb_state *mrb, mrb_value self) {
49 return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "req"));
50 }
51 } // namespace
52
53 namespace {
env_get_resp(mrb_state * mrb,mrb_value self)54 mrb_value env_get_resp(mrb_state *mrb, mrb_value self) {
55 return mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "resp"));
56 }
57 } // namespace
58
59 namespace {
env_get_ctx(mrb_state * mrb,mrb_value self)60 mrb_value env_get_ctx(mrb_state *mrb, mrb_value self) {
61 auto data = reinterpret_cast<MRubyAssocData *>(mrb->ud);
62 auto downstream = data->downstream;
63
64 auto dsym = intern_ptr(mrb, downstream);
65
66 auto ctx = mrb_iv_get(mrb, self, dsym);
67 if (mrb_nil_p(ctx)) {
68 ctx = mrb_hash_new(mrb);
69 mrb_iv_set(mrb, self, dsym, ctx);
70 }
71
72 return ctx;
73 }
74 } // namespace
75
76 namespace {
env_get_phase(mrb_state * mrb,mrb_value self)77 mrb_value env_get_phase(mrb_state *mrb, mrb_value self) {
78 auto data = static_cast<MRubyAssocData *>(mrb->ud);
79
80 return mrb_fixnum_value(data->phase);
81 }
82 } // namespace
83
84 namespace {
env_get_remote_addr(mrb_state * mrb,mrb_value self)85 mrb_value env_get_remote_addr(mrb_state *mrb, mrb_value self) {
86 auto data = static_cast<MRubyAssocData *>(mrb->ud);
87 auto downstream = data->downstream;
88 auto upstream = downstream->get_upstream();
89 auto handler = upstream->get_client_handler();
90
91 auto &ipaddr = handler->get_ipaddr();
92
93 return mrb_str_new(mrb, ipaddr.data(), ipaddr.size());
94 }
95 } // namespace
96
97 namespace {
env_get_server_port(mrb_state * mrb,mrb_value self)98 mrb_value env_get_server_port(mrb_state *mrb, mrb_value self) {
99 auto data = static_cast<MRubyAssocData *>(mrb->ud);
100 auto downstream = data->downstream;
101 auto upstream = downstream->get_upstream();
102 auto handler = upstream->get_client_handler();
103 auto faddr = handler->get_upstream_addr();
104
105 return mrb_fixnum_value(faddr->port);
106 }
107 } // namespace
108
109 namespace {
env_get_server_addr(mrb_state * mrb,mrb_value self)110 mrb_value env_get_server_addr(mrb_state *mrb, mrb_value self) {
111 auto data = static_cast<MRubyAssocData *>(mrb->ud);
112 auto downstream = data->downstream;
113 auto upstream = downstream->get_upstream();
114 auto handler = upstream->get_client_handler();
115 auto faddr = handler->get_upstream_addr();
116
117 return mrb_str_new(mrb, faddr->host.data(), faddr->host.size());
118 }
119 } // namespace
120
121 namespace {
env_get_tls_used(mrb_state * mrb,mrb_value self)122 mrb_value env_get_tls_used(mrb_state *mrb, mrb_value self) {
123 auto data = static_cast<MRubyAssocData *>(mrb->ud);
124 auto downstream = data->downstream;
125 auto upstream = downstream->get_upstream();
126 auto handler = upstream->get_client_handler();
127
128 return handler->get_ssl() ? mrb_true_value() : mrb_false_value();
129 }
130 } // namespace
131
132 namespace {
env_get_tls_sni(mrb_state * mrb,mrb_value self)133 mrb_value env_get_tls_sni(mrb_state *mrb, mrb_value self) {
134 auto data = static_cast<MRubyAssocData *>(mrb->ud);
135 auto downstream = data->downstream;
136 auto upstream = downstream->get_upstream();
137 auto handler = upstream->get_client_handler();
138 auto sni = handler->get_tls_sni();
139
140 return mrb_str_new(mrb, sni.data(), sni.size());
141 }
142 } // namespace
143
144 namespace {
env_get_tls_client_fingerprint_md(mrb_state * mrb,const EVP_MD * md)145 mrb_value env_get_tls_client_fingerprint_md(mrb_state *mrb, const EVP_MD *md) {
146 auto data = static_cast<MRubyAssocData *>(mrb->ud);
147 auto downstream = data->downstream;
148 auto upstream = downstream->get_upstream();
149 auto handler = upstream->get_client_handler();
150 auto ssl = handler->get_ssl();
151
152 if (!ssl) {
153 return mrb_str_new_static(mrb, "", 0);
154 }
155
156 #if OPENSSL_3_0_0_API
157 auto x = SSL_get0_peer_certificate(ssl);
158 #else // !OPENSSL_3_0_0_API
159 auto x = SSL_get_peer_certificate(ssl);
160 #endif // !OPENSSL_3_0_0_API
161 if (!x) {
162 return mrb_str_new_static(mrb, "", 0);
163 }
164
165 // Currently the largest hash value is SHA-256, which is 32 bytes.
166 std::array<uint8_t, 32> buf;
167 auto slen = tls::get_x509_fingerprint(buf.data(), buf.size(), x, md);
168 #if !OPENSSL_3_0_0_API
169 X509_free(x);
170 #endif // !OPENSSL_3_0_0_API
171 if (slen == -1) {
172 mrb_raise(mrb, E_RUNTIME_ERROR, "could not compute client fingerprint");
173 }
174
175 auto &balloc = downstream->get_block_allocator();
176 auto f = util::format_hex(balloc,
177 std::span{buf.data(), static_cast<size_t>(slen)});
178 return mrb_str_new(mrb, f.data(), f.size());
179 }
180 } // namespace
181
182 namespace {
env_get_tls_client_fingerprint_sha256(mrb_state * mrb,mrb_value self)183 mrb_value env_get_tls_client_fingerprint_sha256(mrb_state *mrb,
184 mrb_value self) {
185 return env_get_tls_client_fingerprint_md(mrb, EVP_sha256());
186 }
187 } // namespace
188
189 namespace {
env_get_tls_client_fingerprint_sha1(mrb_state * mrb,mrb_value self)190 mrb_value env_get_tls_client_fingerprint_sha1(mrb_state *mrb, mrb_value self) {
191 return env_get_tls_client_fingerprint_md(mrb, EVP_sha1());
192 }
193 } // namespace
194
195 namespace {
env_get_tls_client_subject_name(mrb_state * mrb,mrb_value self)196 mrb_value env_get_tls_client_subject_name(mrb_state *mrb, mrb_value self) {
197 auto data = static_cast<MRubyAssocData *>(mrb->ud);
198 auto downstream = data->downstream;
199 auto upstream = downstream->get_upstream();
200 auto handler = upstream->get_client_handler();
201 auto ssl = handler->get_ssl();
202
203 if (!ssl) {
204 return mrb_str_new_static(mrb, "", 0);
205 }
206
207 #if OPENSSL_3_0_0_API
208 auto x = SSL_get0_peer_certificate(ssl);
209 #else // !OPENSSL_3_0_0_API
210 auto x = SSL_get_peer_certificate(ssl);
211 #endif // !OPENSSL_3_0_0_API
212 if (!x) {
213 return mrb_str_new_static(mrb, "", 0);
214 }
215
216 auto &balloc = downstream->get_block_allocator();
217 auto name = tls::get_x509_subject_name(balloc, x);
218 #if !OPENSSL_3_0_0_API
219 X509_free(x);
220 #endif // !OPENSSL_3_0_0_API
221 return mrb_str_new(mrb, name.data(), name.size());
222 }
223 } // namespace
224
225 namespace {
env_get_tls_client_issuer_name(mrb_state * mrb,mrb_value self)226 mrb_value env_get_tls_client_issuer_name(mrb_state *mrb, mrb_value self) {
227 auto data = static_cast<MRubyAssocData *>(mrb->ud);
228 auto downstream = data->downstream;
229 auto upstream = downstream->get_upstream();
230 auto handler = upstream->get_client_handler();
231 auto ssl = handler->get_ssl();
232
233 if (!ssl) {
234 return mrb_str_new_static(mrb, "", 0);
235 }
236
237 #if OPENSSL_3_0_0_API
238 auto x = SSL_get0_peer_certificate(ssl);
239 #else // !OPENSSL_3_0_0_API
240 auto x = SSL_get_peer_certificate(ssl);
241 #endif // !OPENSSL_3_0_0_API
242 if (!x) {
243 return mrb_str_new_static(mrb, "", 0);
244 }
245
246 auto &balloc = downstream->get_block_allocator();
247 auto name = tls::get_x509_issuer_name(balloc, x);
248 #if !OPENSSL_3_0_0_API
249 X509_free(x);
250 #endif // !OPENSSL_3_0_0_API
251 return mrb_str_new(mrb, name.data(), name.size());
252 }
253 } // namespace
254
255 namespace {
env_get_tls_client_serial(mrb_state * mrb,mrb_value self)256 mrb_value env_get_tls_client_serial(mrb_state *mrb, mrb_value self) {
257 auto data = static_cast<MRubyAssocData *>(mrb->ud);
258 auto downstream = data->downstream;
259 auto upstream = downstream->get_upstream();
260 auto handler = upstream->get_client_handler();
261 auto ssl = handler->get_ssl();
262
263 if (!ssl) {
264 return mrb_str_new_static(mrb, "", 0);
265 }
266
267 #if OPENSSL_3_0_0_API
268 auto x = SSL_get0_peer_certificate(ssl);
269 #else // !OPENSSL_3_0_0_API
270 auto x = SSL_get_peer_certificate(ssl);
271 #endif // !OPENSSL_3_0_0_API
272 if (!x) {
273 return mrb_str_new_static(mrb, "", 0);
274 }
275
276 auto &balloc = downstream->get_block_allocator();
277 auto sn = tls::get_x509_serial(balloc, x);
278 #if !OPENSSL_3_0_0_API
279 X509_free(x);
280 #endif // !OPENSSL_3_0_0_API
281 return mrb_str_new(mrb, sn.data(), sn.size());
282 }
283 } // namespace
284
285 namespace {
env_get_tls_client_not_before(mrb_state * mrb,mrb_value self)286 mrb_value env_get_tls_client_not_before(mrb_state *mrb, mrb_value self) {
287 auto data = static_cast<MRubyAssocData *>(mrb->ud);
288 auto downstream = data->downstream;
289 auto upstream = downstream->get_upstream();
290 auto handler = upstream->get_client_handler();
291 auto ssl = handler->get_ssl();
292
293 if (!ssl) {
294 return mrb_fixnum_value(0);
295 }
296
297 #if OPENSSL_3_0_0_API
298 auto x = SSL_get0_peer_certificate(ssl);
299 #else // !OPENSSL_3_0_0_API
300 auto x = SSL_get_peer_certificate(ssl);
301 #endif // !OPENSSL_3_0_0_API
302 if (!x) {
303 return mrb_fixnum_value(0);
304 }
305
306 time_t t;
307 if (tls::get_x509_not_before(t, x) != 0) {
308 t = 0;
309 }
310
311 #if !OPENSSL_3_0_0_API
312 X509_free(x);
313 #endif // !OPENSSL_3_0_0_API
314
315 return mrb_fixnum_value(t);
316 }
317 } // namespace
318
319 namespace {
env_get_tls_client_not_after(mrb_state * mrb,mrb_value self)320 mrb_value env_get_tls_client_not_after(mrb_state *mrb, mrb_value self) {
321 auto data = static_cast<MRubyAssocData *>(mrb->ud);
322 auto downstream = data->downstream;
323 auto upstream = downstream->get_upstream();
324 auto handler = upstream->get_client_handler();
325 auto ssl = handler->get_ssl();
326
327 if (!ssl) {
328 return mrb_fixnum_value(0);
329 }
330
331 #if OPENSSL_3_0_0_API
332 auto x = SSL_get0_peer_certificate(ssl);
333 #else // !OPENSSL_3_0_0_API
334 auto x = SSL_get_peer_certificate(ssl);
335 #endif // !OPENSSL_3_0_0_API
336 if (!x) {
337 return mrb_fixnum_value(0);
338 }
339
340 time_t t;
341 if (tls::get_x509_not_after(t, x) != 0) {
342 t = 0;
343 }
344
345 #if !OPENSSL_3_0_0_API
346 X509_free(x);
347 #endif // !OPENSSL_3_0_0_API
348
349 return mrb_fixnum_value(t);
350 }
351 } // namespace
352
353 namespace {
env_get_tls_cipher(mrb_state * mrb,mrb_value self)354 mrb_value env_get_tls_cipher(mrb_state *mrb, mrb_value self) {
355 auto data = static_cast<MRubyAssocData *>(mrb->ud);
356 auto downstream = data->downstream;
357 auto upstream = downstream->get_upstream();
358 auto handler = upstream->get_client_handler();
359 auto ssl = handler->get_ssl();
360
361 if (!ssl) {
362 return mrb_str_new_static(mrb, "", 0);
363 }
364
365 return mrb_str_new_cstr(mrb, SSL_get_cipher_name(ssl));
366 }
367 } // namespace
368
369 namespace {
env_get_tls_protocol(mrb_state * mrb,mrb_value self)370 mrb_value env_get_tls_protocol(mrb_state *mrb, mrb_value self) {
371 auto data = static_cast<MRubyAssocData *>(mrb->ud);
372 auto downstream = data->downstream;
373 auto upstream = downstream->get_upstream();
374 auto handler = upstream->get_client_handler();
375 auto ssl = handler->get_ssl();
376
377 if (!ssl) {
378 return mrb_str_new_static(mrb, "", 0);
379 }
380
381 return mrb_str_new_cstr(mrb, nghttp2::tls::get_tls_protocol(ssl));
382 }
383 } // namespace
384
385 namespace {
env_get_tls_session_id(mrb_state * mrb,mrb_value self)386 mrb_value env_get_tls_session_id(mrb_state *mrb, mrb_value self) {
387 auto data = static_cast<MRubyAssocData *>(mrb->ud);
388 auto downstream = data->downstream;
389 auto upstream = downstream->get_upstream();
390 auto handler = upstream->get_client_handler();
391 auto ssl = handler->get_ssl();
392
393 if (!ssl) {
394 return mrb_str_new_static(mrb, "", 0);
395 }
396
397 auto session = SSL_get_session(ssl);
398 if (!session) {
399 return mrb_str_new_static(mrb, "", 0);
400 }
401
402 unsigned int session_id_length = 0;
403 auto session_id = SSL_SESSION_get_id(session, &session_id_length);
404
405 auto &balloc = downstream->get_block_allocator();
406 auto id = util::format_hex(balloc, std::span{session_id, session_id_length});
407 return mrb_str_new(mrb, id.data(), id.size());
408 }
409 } // namespace
410
411 namespace {
env_get_tls_session_reused(mrb_state * mrb,mrb_value self)412 mrb_value env_get_tls_session_reused(mrb_state *mrb, mrb_value self) {
413 auto data = static_cast<MRubyAssocData *>(mrb->ud);
414 auto downstream = data->downstream;
415 auto upstream = downstream->get_upstream();
416 auto handler = upstream->get_client_handler();
417 auto ssl = handler->get_ssl();
418
419 if (!ssl) {
420 return mrb_false_value();
421 }
422
423 return SSL_session_reused(ssl) ? mrb_true_value() : mrb_false_value();
424 }
425 } // namespace
426
427 namespace {
env_get_alpn(mrb_state * mrb,mrb_value self)428 mrb_value env_get_alpn(mrb_state *mrb, mrb_value self) {
429 auto data = static_cast<MRubyAssocData *>(mrb->ud);
430 auto downstream = data->downstream;
431 auto upstream = downstream->get_upstream();
432 auto handler = upstream->get_client_handler();
433 auto alpn = handler->get_alpn();
434 return mrb_str_new(mrb, alpn.data(), alpn.size());
435 }
436 } // namespace
437
438 namespace {
env_get_tls_handshake_finished(mrb_state * mrb,mrb_value self)439 mrb_value env_get_tls_handshake_finished(mrb_state *mrb, mrb_value self) {
440 auto data = static_cast<MRubyAssocData *>(mrb->ud);
441 auto downstream = data->downstream;
442 auto upstream = downstream->get_upstream();
443 auto handler = upstream->get_client_handler();
444 auto conn = handler->get_connection();
445 return SSL_is_init_finished(conn->tls.ssl) ? mrb_true_value()
446 : mrb_false_value();
447 }
448 } // namespace
449
init_env_class(mrb_state * mrb,RClass * module)450 void init_env_class(mrb_state *mrb, RClass *module) {
451 auto env_class =
452 mrb_define_class_under(mrb, module, "Env", mrb->object_class);
453
454 mrb_define_method(mrb, env_class, "initialize", env_init, MRB_ARGS_NONE());
455 mrb_define_method(mrb, env_class, "req", env_get_req, MRB_ARGS_NONE());
456 mrb_define_method(mrb, env_class, "resp", env_get_resp, MRB_ARGS_NONE());
457 mrb_define_method(mrb, env_class, "ctx", env_get_ctx, MRB_ARGS_NONE());
458 mrb_define_method(mrb, env_class, "phase", env_get_phase, MRB_ARGS_NONE());
459 mrb_define_method(mrb, env_class, "remote_addr", env_get_remote_addr,
460 MRB_ARGS_NONE());
461 mrb_define_method(mrb, env_class, "server_addr", env_get_server_addr,
462 MRB_ARGS_NONE());
463 mrb_define_method(mrb, env_class, "server_port", env_get_server_port,
464 MRB_ARGS_NONE());
465 mrb_define_method(mrb, env_class, "tls_used", env_get_tls_used,
466 MRB_ARGS_NONE());
467 mrb_define_method(mrb, env_class, "tls_sni", env_get_tls_sni,
468 MRB_ARGS_NONE());
469 mrb_define_method(mrb, env_class, "tls_client_fingerprint_sha256",
470 env_get_tls_client_fingerprint_sha256, MRB_ARGS_NONE());
471 mrb_define_method(mrb, env_class, "tls_client_fingerprint_sha1",
472 env_get_tls_client_fingerprint_sha1, MRB_ARGS_NONE());
473 mrb_define_method(mrb, env_class, "tls_client_issuer_name",
474 env_get_tls_client_issuer_name, MRB_ARGS_NONE());
475 mrb_define_method(mrb, env_class, "tls_client_subject_name",
476 env_get_tls_client_subject_name, MRB_ARGS_NONE());
477 mrb_define_method(mrb, env_class, "tls_client_serial",
478 env_get_tls_client_serial, MRB_ARGS_NONE());
479 mrb_define_method(mrb, env_class, "tls_client_not_before",
480 env_get_tls_client_not_before, MRB_ARGS_NONE());
481 mrb_define_method(mrb, env_class, "tls_client_not_after",
482 env_get_tls_client_not_after, MRB_ARGS_NONE());
483 mrb_define_method(mrb, env_class, "tls_cipher", env_get_tls_cipher,
484 MRB_ARGS_NONE());
485 mrb_define_method(mrb, env_class, "tls_protocol", env_get_tls_protocol,
486 MRB_ARGS_NONE());
487 mrb_define_method(mrb, env_class, "tls_session_id", env_get_tls_session_id,
488 MRB_ARGS_NONE());
489 mrb_define_method(mrb, env_class, "tls_session_reused",
490 env_get_tls_session_reused, MRB_ARGS_NONE());
491 mrb_define_method(mrb, env_class, "alpn", env_get_alpn, MRB_ARGS_NONE());
492 mrb_define_method(mrb, env_class, "tls_handshake_finished",
493 env_get_tls_handshake_finished, MRB_ARGS_NONE());
494 }
495
496 } // namespace mruby
497
498 } // namespace shrpx
499