• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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