Merge pull request #1123 from nghttp2/mruby-client-cert-not-before-after

nghttpx: Add mruby tls_client_not_before, and tls_client_not_after
This commit is contained in:
Tatsuhiro Tsujikawa 2018-02-10 16:00:29 +09:00 committed by GitHub
commit 65157811d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 157 additions and 0 deletions

View File

@ -388,6 +388,16 @@ respectively.
Return the serial number of a client certificate.
.. rb:attr_reader:: tls_client_not_before
Return the start date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_client_not_after
Return the end date of a client certificate in seconds since
the epoch.
.. rb:attr_reader:: tls_cipher
Return a TLS cipher negotiated in this connection.

View File

@ -259,6 +259,58 @@ mrb_value env_get_tls_client_serial(mrb_state *mrb, mrb_value self) {
}
} // namespace
namespace {
mrb_value env_get_tls_client_not_before(mrb_state *mrb, mrb_value self) {
auto data = static_cast<MRubyAssocData *>(mrb->ud);
auto downstream = data->downstream;
auto upstream = downstream->get_upstream();
auto handler = upstream->get_client_handler();
auto ssl = handler->get_ssl();
if (!ssl) {
return mrb_fixnum_value(0);
}
auto x = SSL_get_peer_certificate(ssl);
if (!x) {
return mrb_fixnum_value(0);
}
time_t t;
if (tls::get_x509_not_before(t, x) != 0) {
return mrb_fixnum_value(0);
}
return mrb_fixnum_value(t);
}
} // namespace
namespace {
mrb_value env_get_tls_client_not_after(mrb_state *mrb, mrb_value self) {
auto data = static_cast<MRubyAssocData *>(mrb->ud);
auto downstream = data->downstream;
auto upstream = downstream->get_upstream();
auto handler = upstream->get_client_handler();
auto ssl = handler->get_ssl();
if (!ssl) {
return mrb_fixnum_value(0);
}
auto x = SSL_get_peer_certificate(ssl);
if (!x) {
return mrb_fixnum_value(0);
}
time_t t;
if (tls::get_x509_not_after(t, x) != 0) {
return mrb_fixnum_value(0);
}
return mrb_fixnum_value(t);
}
} // namespace
namespace {
mrb_value env_get_tls_cipher(mrb_state *mrb, mrb_value self) {
auto data = static_cast<MRubyAssocData *>(mrb->ud);
@ -374,6 +426,10 @@ void init_env_class(mrb_state *mrb, RClass *module) {
env_get_tls_client_subject_name, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "tls_client_serial",
env_get_tls_client_serial, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "tls_client_not_before",
env_get_tls_client_not_before, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "tls_client_not_after",
env_get_tls_client_not_after, MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "tls_cipher", env_get_tls_cipher,
MRB_ARGS_NONE());
mrb_define_method(mrb, env_class, "tls_protocol", env_get_tls_protocol,

View File

@ -64,6 +64,7 @@
#include "tls.h"
#include "template.h"
#include "ssl_compat.h"
#include "timegm.h"
using namespace nghttp2;
@ -1992,6 +1993,74 @@ StringRef get_x509_serial(BlockAllocator &balloc, X509 *x) {
#endif // !OPENSSL_1_1_API
}
namespace {
// Performs conversion from |at| to time_t. The result is stored in
// |t|. This function returns 0 if it succeeds, or -1.
int time_t_from_asn1_time(time_t &t, const ASN1_TIME *at) {
int rv;
#if OPENSSL_1_1_1_API
struct tm tm;
rv = ASN1_TIME_to_tm(at, &tm);
if (rv != 1) {
return -1;
}
t = nghttp2_timegm(&tm);
#else // !OPENSSL_1_1_1_API
auto b = BIO_new(BIO_s_mem());
if (!b) {
return -1;
}
auto bio_deleter = defer(BIO_free, b);
rv = ASN1_TIME_print(b, at);
if (rv != 1) {
return -1;
}
unsigned char *s;
auto slen = BIO_get_mem_data(b, &s);
auto tt = util::parse_openssl_asn1_time_print(
StringRef{s, static_cast<size_t>(slen)});
if (tt == 0) {
return -1;
}
t = tt;
#endif // !OPENSSL_1_1_1_API
return 0;
}
} // namespace
int get_x509_not_before(time_t &t, X509 *x) {
#if OPENSSL_1_1_API
auto at = X509_get0_notBefore(x);
#else // !OPENSSL_1_1_API
auto at = X509_get_notBefore(x);
#endif // !OPENSSL_1_1_API
if (!at) {
return -1;
}
return time_t_from_asn1_time(t, at);
}
int get_x509_not_after(time_t &t, X509 *x) {
#if OPENSSL_1_1_API
auto at = X509_get0_notAfter(x);
#else // !OPENSSL_1_1_API
auto at = X509_get_notAfter(x);
#endif // !OPENSSL_1_1_API
if (!at) {
return -1;
}
return time_t_from_asn1_time(t, at);
}
} // namespace tls
} // namespace shrpx

View File

@ -288,6 +288,14 @@ StringRef get_x509_issuer_name(BlockAllocator &balloc, X509 *x);
// number, it returns an empty string. number
StringRef get_x509_serial(BlockAllocator &balloc, X509 *x);
// Fills NotBefore of |x| in |t|. This function returns 0 if it
// succeeds, or -1.
int get_x509_not_before(time_t &t, X509 *x);
// Fills NotAfter of |x| in |t|. This function returns 0 if it
// succeeds, or -1.
int get_x509_not_after(time_t &t, X509 *x);
} // namespace tls
} // namespace shrpx

View File

@ -407,6 +407,15 @@ time_t parse_http_date(const StringRef &s) {
#endif // !_WIN32
}
time_t parse_openssl_asn1_time_print(const StringRef &s) {
tm tm{};
auto r = strptime(s.c_str(), "%b %d %H:%M:%S %Y GMT", &tm);
if (r == nullptr) {
return 0;
}
return nghttp2_timegm_without_yday(&tm);
}
char upcase(char c) {
if ('a' <= c && c <= 'z') {
return c - 'a' + 'A';

View File

@ -196,6 +196,11 @@ char *iso8601_date(char *res, int64_t ms);
time_t parse_http_date(const StringRef &s);
// Parses time formatted as "MMM DD HH:MM:SS YYYY [GMT]" (e.g., Feb 3
// 00:55:52 2015 GMT), which is specifically used by OpenSSL
// ASN1_TIME_print().
time_t parse_openssl_asn1_time_print(const StringRef &s);
char upcase(char c);
inline char lowcase(char c) {