nghttpx: Add client fingerprint and subject name to mruby env
This commit is contained in:
parent
c573c80bd3
commit
9f80a82c1a
|
@ -368,6 +368,14 @@ respectively.
|
||||||
|
|
||||||
Return the TLS SNI value which client sent in this connection.
|
Return the TLS SNI value which client sent in this connection.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_fingerprint
|
||||||
|
|
||||||
|
Return the SHA-256 fingerprint of a client certificate.
|
||||||
|
|
||||||
|
.. rb:attr_reader:: tls_client_subject_name
|
||||||
|
|
||||||
|
Return the subject name of a client certificate.
|
||||||
|
|
||||||
.. rb:class:: Request
|
.. rb:class:: Request
|
||||||
|
|
||||||
Object to represent request from client. The modification to
|
Object to represent request from client. The modification to
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "shrpx_mruby.h"
|
#include "shrpx_mruby.h"
|
||||||
#include "shrpx_mruby_module.h"
|
#include "shrpx_mruby_module.h"
|
||||||
#include "shrpx_log.h"
|
#include "shrpx_log.h"
|
||||||
|
#include "shrpx_tls.h"
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
|
@ -140,6 +141,61 @@ mrb_value env_get_tls_sni(mrb_state *mrb, mrb_value self) {
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
mrb_value env_get_tls_client_fingerprint(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_str_new_static(mrb, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto x = SSL_get_peer_certificate(ssl);
|
||||||
|
if (!x) {
|
||||||
|
return mrb_str_new_static(mrb, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fingerprint is SHA-256, so we need 32 bytes buffer.
|
||||||
|
std::array<uint8_t, 32> buf;
|
||||||
|
auto slen = tls::get_x509_fingerprint(buf.data(), buf.size(), x);
|
||||||
|
if (slen == -1) {
|
||||||
|
mrb_raise(mrb, E_RUNTIME_ERROR, "could not compute client fingerprint");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Use template version of format_hex
|
||||||
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
auto f = util::format_hex(balloc,
|
||||||
|
StringRef{std::begin(buf), std::begin(buf) + slen});
|
||||||
|
return mrb_str_new(mrb, f.c_str(), f.size());
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
mrb_value env_get_tls_client_subject_name(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_str_new_static(mrb, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto x = SSL_get_peer_certificate(ssl);
|
||||||
|
if (!x) {
|
||||||
|
return mrb_str_new_static(mrb, "", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &balloc = downstream->get_block_allocator();
|
||||||
|
auto name = tls::get_x509_subject_name(balloc, x);
|
||||||
|
return mrb_str_new(mrb, name.c_str(), name.size());
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
void init_env_class(mrb_state *mrb, RClass *module) {
|
void init_env_class(mrb_state *mrb, RClass *module) {
|
||||||
auto env_class =
|
auto env_class =
|
||||||
mrb_define_class_under(mrb, module, "Env", mrb->object_class);
|
mrb_define_class_under(mrb, module, "Env", mrb->object_class);
|
||||||
|
@ -159,6 +215,10 @@ void init_env_class(mrb_state *mrb, RClass *module) {
|
||||||
MRB_ARGS_NONE());
|
MRB_ARGS_NONE());
|
||||||
mrb_define_method(mrb, env_class, "tls_sni", env_get_tls_sni,
|
mrb_define_method(mrb, env_class, "tls_sni", env_get_tls_sni,
|
||||||
MRB_ARGS_NONE());
|
MRB_ARGS_NONE());
|
||||||
|
mrb_define_method(mrb, env_class, "tls_client_fingerprint",
|
||||||
|
env_get_tls_client_fingerprint, MRB_ARGS_NONE());
|
||||||
|
mrb_define_method(mrb, env_class, "tls_client_subject_name",
|
||||||
|
env_get_tls_client_subject_name, MRB_ARGS_NONE());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mruby
|
} // namespace mruby
|
||||||
|
|
|
@ -1920,6 +1920,37 @@ int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t get_x509_fingerprint(uint8_t *dst, size_t dstlen, X509 *x) {
|
||||||
|
assert(dstlen >= 32);
|
||||||
|
unsigned int len = dstlen;
|
||||||
|
if (X509_digest(x, EVP_sha256(), dst, &len) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringRef get_x509_subject_name(BlockAllocator &balloc, X509 *x) {
|
||||||
|
auto nm = X509_get_subject_name(x);
|
||||||
|
|
||||||
|
auto b = BIO_new(BIO_s_mem());
|
||||||
|
if (!b) {
|
||||||
|
return StringRef{};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not documented, but it seems that X509_NAME_print_ex returns the
|
||||||
|
// number of bytes written into b.
|
||||||
|
auto slen = X509_NAME_print_ex(b, nm, 0, XN_FLAG_RFC2253);
|
||||||
|
if (slen <= 0) {
|
||||||
|
return StringRef{};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto iov = make_byte_ref(balloc, slen + 1);
|
||||||
|
BIO_read(b, iov.base, slen);
|
||||||
|
BIO_free(b);
|
||||||
|
iov.base[slen] = '\0';
|
||||||
|
return StringRef{iov.base, static_cast<size_t>(slen)};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace tls
|
} // namespace tls
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
|
@ -269,6 +269,15 @@ int proto_version_from_string(const StringRef &v);
|
||||||
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
int verify_ocsp_response(SSL_CTX *ssl_ctx, const uint8_t *ocsp_resp,
|
||||||
size_t ocsp_resplen);
|
size_t ocsp_resplen);
|
||||||
|
|
||||||
|
// Stores SHA-256 fingerprint of |x| in |dst| of length |dstlen|.
|
||||||
|
// |dstlen| must be larger than 32 bytes. This function returns the
|
||||||
|
// number of bytes written in |dst|, or -1.
|
||||||
|
ssize_t get_x509_fingerprint(uint8_t *dst, size_t dstlen, X509 *x);
|
||||||
|
|
||||||
|
// Returns subject name of |x|. If this function fails to get subject
|
||||||
|
// name, it returns an empty string.
|
||||||
|
StringRef get_x509_subject_name(BlockAllocator &balloc, X509 *x);
|
||||||
|
|
||||||
} // namespace tls
|
} // namespace tls
|
||||||
|
|
||||||
} // namespace shrpx
|
} // namespace shrpx
|
||||||
|
|
Loading…
Reference in New Issue