• 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.c_str(), 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.c_str(), 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.c_str(), 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   auto x = SSL_get_peer_certificate(ssl);
157   if (!x) {
158     return mrb_str_new_static(mrb, "", 0);
159   }
160 
161   // Currently the largest hash value is SHA-256, which is 32 bytes.
162   std::array<uint8_t, 32> buf;
163   auto slen = tls::get_x509_fingerprint(buf.data(), buf.size(), x, md);
164   X509_free(x);
165   if (slen == -1) {
166     mrb_raise(mrb, E_RUNTIME_ERROR, "could not compute client fingerprint");
167   }
168 
169   // TODO Use template version of format_hex
170   auto &balloc = downstream->get_block_allocator();
171   auto f = util::format_hex(balloc,
172                             StringRef{std::begin(buf), std::begin(buf) + slen});
173   return mrb_str_new(mrb, f.c_str(), f.size());
174 }
175 } // namespace
176 
177 namespace {
env_get_tls_client_fingerprint_sha256(mrb_state * mrb,mrb_value self)178 mrb_value env_get_tls_client_fingerprint_sha256(mrb_state *mrb,
179                                                 mrb_value self) {
180   return env_get_tls_client_fingerprint_md(mrb, EVP_sha256());
181 }
182 } // namespace
183 
184 namespace {
env_get_tls_client_fingerprint_sha1(mrb_state * mrb,mrb_value self)185 mrb_value env_get_tls_client_fingerprint_sha1(mrb_state *mrb, mrb_value self) {
186   return env_get_tls_client_fingerprint_md(mrb, EVP_sha1());
187 }
188 } // namespace
189 
190 namespace {
env_get_tls_client_subject_name(mrb_state * mrb,mrb_value self)191 mrb_value env_get_tls_client_subject_name(mrb_state *mrb, mrb_value self) {
192   auto data = static_cast<MRubyAssocData *>(mrb->ud);
193   auto downstream = data->downstream;
194   auto upstream = downstream->get_upstream();
195   auto handler = upstream->get_client_handler();
196   auto ssl = handler->get_ssl();
197 
198   if (!ssl) {
199     return mrb_str_new_static(mrb, "", 0);
200   }
201 
202   auto x = SSL_get_peer_certificate(ssl);
203   if (!x) {
204     return mrb_str_new_static(mrb, "", 0);
205   }
206 
207   auto &balloc = downstream->get_block_allocator();
208   auto name = tls::get_x509_subject_name(balloc, x);
209   X509_free(x);
210   return mrb_str_new(mrb, name.c_str(), name.size());
211 }
212 } // namespace
213 
214 namespace {
env_get_tls_client_issuer_name(mrb_state * mrb,mrb_value self)215 mrb_value env_get_tls_client_issuer_name(mrb_state *mrb, mrb_value self) {
216   auto data = static_cast<MRubyAssocData *>(mrb->ud);
217   auto downstream = data->downstream;
218   auto upstream = downstream->get_upstream();
219   auto handler = upstream->get_client_handler();
220   auto ssl = handler->get_ssl();
221 
222   if (!ssl) {
223     return mrb_str_new_static(mrb, "", 0);
224   }
225 
226   auto x = SSL_get_peer_certificate(ssl);
227   if (!x) {
228     return mrb_str_new_static(mrb, "", 0);
229   }
230 
231   auto &balloc = downstream->get_block_allocator();
232   auto name = tls::get_x509_issuer_name(balloc, x);
233   X509_free(x);
234   return mrb_str_new(mrb, name.c_str(), name.size());
235 }
236 } // namespace
237 
238 namespace {
env_get_tls_client_serial(mrb_state * mrb,mrb_value self)239 mrb_value env_get_tls_client_serial(mrb_state *mrb, mrb_value self) {
240   auto data = static_cast<MRubyAssocData *>(mrb->ud);
241   auto downstream = data->downstream;
242   auto upstream = downstream->get_upstream();
243   auto handler = upstream->get_client_handler();
244   auto ssl = handler->get_ssl();
245 
246   if (!ssl) {
247     return mrb_str_new_static(mrb, "", 0);
248   }
249 
250   auto x = SSL_get_peer_certificate(ssl);
251   if (!x) {
252     return mrb_str_new_static(mrb, "", 0);
253   }
254 
255   auto &balloc = downstream->get_block_allocator();
256   auto sn = tls::get_x509_serial(balloc, x);
257   X509_free(x);
258   return mrb_str_new(mrb, sn.c_str(), sn.size());
259 }
260 } // namespace
261 
262 namespace {
env_get_tls_client_not_before(mrb_state * mrb,mrb_value self)263 mrb_value env_get_tls_client_not_before(mrb_state *mrb, mrb_value self) {
264   auto data = static_cast<MRubyAssocData *>(mrb->ud);
265   auto downstream = data->downstream;
266   auto upstream = downstream->get_upstream();
267   auto handler = upstream->get_client_handler();
268   auto ssl = handler->get_ssl();
269 
270   if (!ssl) {
271     return mrb_fixnum_value(0);
272   }
273 
274   auto x = SSL_get_peer_certificate(ssl);
275   if (!x) {
276     return mrb_fixnum_value(0);
277   }
278 
279   time_t t;
280   if (tls::get_x509_not_before(t, x) != 0) {
281     return mrb_fixnum_value(0);
282   }
283 
284   return mrb_fixnum_value(t);
285 }
286 } // namespace
287 
288 namespace {
env_get_tls_client_not_after(mrb_state * mrb,mrb_value self)289 mrb_value env_get_tls_client_not_after(mrb_state *mrb, mrb_value self) {
290   auto data = static_cast<MRubyAssocData *>(mrb->ud);
291   auto downstream = data->downstream;
292   auto upstream = downstream->get_upstream();
293   auto handler = upstream->get_client_handler();
294   auto ssl = handler->get_ssl();
295 
296   if (!ssl) {
297     return mrb_fixnum_value(0);
298   }
299 
300   auto x = SSL_get_peer_certificate(ssl);
301   if (!x) {
302     return mrb_fixnum_value(0);
303   }
304 
305   time_t t;
306   if (tls::get_x509_not_after(t, x) != 0) {
307     return mrb_fixnum_value(0);
308   }
309 
310   return mrb_fixnum_value(t);
311 }
312 } // namespace
313 
314 namespace {
env_get_tls_cipher(mrb_state * mrb,mrb_value self)315 mrb_value env_get_tls_cipher(mrb_state *mrb, mrb_value self) {
316   auto data = static_cast<MRubyAssocData *>(mrb->ud);
317   auto downstream = data->downstream;
318   auto upstream = downstream->get_upstream();
319   auto handler = upstream->get_client_handler();
320   auto ssl = handler->get_ssl();
321 
322   if (!ssl) {
323     return mrb_str_new_static(mrb, "", 0);
324   }
325 
326   return mrb_str_new_cstr(mrb, SSL_get_cipher_name(ssl));
327 }
328 } // namespace
329 
330 namespace {
env_get_tls_protocol(mrb_state * mrb,mrb_value self)331 mrb_value env_get_tls_protocol(mrb_state *mrb, mrb_value self) {
332   auto data = static_cast<MRubyAssocData *>(mrb->ud);
333   auto downstream = data->downstream;
334   auto upstream = downstream->get_upstream();
335   auto handler = upstream->get_client_handler();
336   auto ssl = handler->get_ssl();
337 
338   if (!ssl) {
339     return mrb_str_new_static(mrb, "", 0);
340   }
341 
342   return mrb_str_new_cstr(mrb, nghttp2::tls::get_tls_protocol(ssl));
343 }
344 } // namespace
345 
346 namespace {
env_get_tls_session_id(mrb_state * mrb,mrb_value self)347 mrb_value env_get_tls_session_id(mrb_state *mrb, mrb_value self) {
348   auto data = static_cast<MRubyAssocData *>(mrb->ud);
349   auto downstream = data->downstream;
350   auto upstream = downstream->get_upstream();
351   auto handler = upstream->get_client_handler();
352   auto ssl = handler->get_ssl();
353 
354   if (!ssl) {
355     return mrb_str_new_static(mrb, "", 0);
356   }
357 
358   auto session = SSL_get_session(ssl);
359   if (!session) {
360     return mrb_str_new_static(mrb, "", 0);
361   }
362 
363   unsigned int session_id_length = 0;
364   auto session_id = SSL_SESSION_get_id(session, &session_id_length);
365 
366   // TODO Use template version of util::format_hex.
367   auto &balloc = downstream->get_block_allocator();
368   auto id = util::format_hex(balloc, StringRef{session_id, session_id_length});
369   return mrb_str_new(mrb, id.c_str(), id.size());
370 }
371 } // namespace
372 
373 namespace {
env_get_tls_session_reused(mrb_state * mrb,mrb_value self)374 mrb_value env_get_tls_session_reused(mrb_state *mrb, mrb_value self) {
375   auto data = static_cast<MRubyAssocData *>(mrb->ud);
376   auto downstream = data->downstream;
377   auto upstream = downstream->get_upstream();
378   auto handler = upstream->get_client_handler();
379   auto ssl = handler->get_ssl();
380 
381   if (!ssl) {
382     return mrb_false_value();
383   }
384 
385   return SSL_session_reused(ssl) ? mrb_true_value() : mrb_false_value();
386 }
387 } // namespace
388 
389 namespace {
env_get_alpn(mrb_state * mrb,mrb_value self)390 mrb_value env_get_alpn(mrb_state *mrb, mrb_value self) {
391   auto data = static_cast<MRubyAssocData *>(mrb->ud);
392   auto downstream = data->downstream;
393   auto upstream = downstream->get_upstream();
394   auto handler = upstream->get_client_handler();
395   auto alpn = handler->get_alpn();
396   return mrb_str_new(mrb, alpn.c_str(), alpn.size());
397 }
398 } // namespace
399 
400 namespace {
env_get_tls_handshake_finished(mrb_state * mrb,mrb_value self)401 mrb_value env_get_tls_handshake_finished(mrb_state *mrb, mrb_value self) {
402   auto data = static_cast<MRubyAssocData *>(mrb->ud);
403   auto downstream = data->downstream;
404   auto upstream = downstream->get_upstream();
405   auto handler = upstream->get_client_handler();
406   auto conn = handler->get_connection();
407   return SSL_is_init_finished(conn->tls.ssl) ? mrb_true_value()
408                                              : mrb_false_value();
409 }
410 } // namespace
411 
init_env_class(mrb_state * mrb,RClass * module)412 void init_env_class(mrb_state *mrb, RClass *module) {
413   auto env_class =
414       mrb_define_class_under(mrb, module, "Env", mrb->object_class);
415 
416   mrb_define_method(mrb, env_class, "initialize", env_init, MRB_ARGS_NONE());
417   mrb_define_method(mrb, env_class, "req", env_get_req, MRB_ARGS_NONE());
418   mrb_define_method(mrb, env_class, "resp", env_get_resp, MRB_ARGS_NONE());
419   mrb_define_method(mrb, env_class, "ctx", env_get_ctx, MRB_ARGS_NONE());
420   mrb_define_method(mrb, env_class, "phase", env_get_phase, MRB_ARGS_NONE());
421   mrb_define_method(mrb, env_class, "remote_addr", env_get_remote_addr,
422                     MRB_ARGS_NONE());
423   mrb_define_method(mrb, env_class, "server_addr", env_get_server_addr,
424                     MRB_ARGS_NONE());
425   mrb_define_method(mrb, env_class, "server_port", env_get_server_port,
426                     MRB_ARGS_NONE());
427   mrb_define_method(mrb, env_class, "tls_used", env_get_tls_used,
428                     MRB_ARGS_NONE());
429   mrb_define_method(mrb, env_class, "tls_sni", env_get_tls_sni,
430                     MRB_ARGS_NONE());
431   mrb_define_method(mrb, env_class, "tls_client_fingerprint_sha256",
432                     env_get_tls_client_fingerprint_sha256, MRB_ARGS_NONE());
433   mrb_define_method(mrb, env_class, "tls_client_fingerprint_sha1",
434                     env_get_tls_client_fingerprint_sha1, MRB_ARGS_NONE());
435   mrb_define_method(mrb, env_class, "tls_client_issuer_name",
436                     env_get_tls_client_issuer_name, MRB_ARGS_NONE());
437   mrb_define_method(mrb, env_class, "tls_client_subject_name",
438                     env_get_tls_client_subject_name, MRB_ARGS_NONE());
439   mrb_define_method(mrb, env_class, "tls_client_serial",
440                     env_get_tls_client_serial, MRB_ARGS_NONE());
441   mrb_define_method(mrb, env_class, "tls_client_not_before",
442                     env_get_tls_client_not_before, MRB_ARGS_NONE());
443   mrb_define_method(mrb, env_class, "tls_client_not_after",
444                     env_get_tls_client_not_after, MRB_ARGS_NONE());
445   mrb_define_method(mrb, env_class, "tls_cipher", env_get_tls_cipher,
446                     MRB_ARGS_NONE());
447   mrb_define_method(mrb, env_class, "tls_protocol", env_get_tls_protocol,
448                     MRB_ARGS_NONE());
449   mrb_define_method(mrb, env_class, "tls_session_id", env_get_tls_session_id,
450                     MRB_ARGS_NONE());
451   mrb_define_method(mrb, env_class, "tls_session_reused",
452                     env_get_tls_session_reused, MRB_ARGS_NONE());
453   mrb_define_method(mrb, env_class, "alpn", env_get_alpn, MRB_ARGS_NONE());
454   mrb_define_method(mrb, env_class, "tls_handshake_finished",
455                     env_get_tls_handshake_finished, MRB_ARGS_NONE());
456 }
457 
458 } // namespace mruby
459 
460 } // namespace shrpx
461