aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2015-11-16 19:44:04 +0900
committerKazuki Yamaguchi <k@rhe.jp>2015-11-16 20:17:11 +0900
commita5aa53a9174f47450582b29cb93cbd162753bf47 (patch)
tree64c717946fb08b64ff289e1de2dbb78b41dbee6a
parentde62f5962e9047e867eb39ef933738ea3b9722c1 (diff)
downloadplum-a5aa53a9174f47450582b29cb93cbd162753bf47.tar.gz
rack/tls_listener: sni
-rw-r--r--examples/rack-example-config.rb21
-rw-r--r--lib/plum/rack/listener.rb24
2 files changed, 37 insertions, 8 deletions
diff --git a/examples/rack-example-config.rb b/examples/rack-example-config.rb
new file mode 100644
index 0000000..d8d3dcb
--- /dev/null
+++ b/examples/rack-example-config.rb
@@ -0,0 +1,21 @@
+log "logs/plum.log"
+debug false
+server_push true
+threaded false # create a new thread per request
+fallback_legacy "127.0.0.1:8080" # forward if client doesn't support HTTP/2
+
+# listeners may be multiple
+listener :unix, { path: "/tmp/plum.sock", mode: 600 }
+listener :tcp, { hostname: "0.0.0.0", port: 80 }
+listener :tls, {
+ hostname: "0.0.0.0",
+ port: 443,
+ certificate: "/path/to/cert", # chained certifcate is acceptable
+ certificate_key: "/path/to/key",
+ sni: {
+ "rhe.jp" => { # SNI, key must be String. If none matches, default certificate (above) is used
+ certificate: "/path/to/rhe.jp/cert",
+ certificate_key: "/path/to/rhe.jp/key"
+ },
+ }
+}
diff --git a/lib/plum/rack/listener.rb b/lib/plum/rack/listener.rb
index c650ff0..1645c57 100644
--- a/lib/plum/rack/listener.rb
+++ b/lib/plum/rack/listener.rb
@@ -41,21 +41,29 @@ module Plum
ctx = OpenSSL::SSL::SSLContext.new
ctx.ssl_version = :TLSv1_2
- ctx.alpn_select_cb = -> protocols {
- if protocols.include?("h2")
- "h2"
+ ctx.alpn_select_cb = -> (protocols) { protocols.include?("h2") ? "h2" : protocols.first }
+ ctx.tmp_ecdh_callback = -> (sock, ise, keyl) { OpenSSL::PKey::EC.new("prime256v1") }
+ *ctx.extra_chain_cert, ctx.cert = parse_chained_cert(cert)
+ ctx.key = OpenSSL::PKey::RSA.new(key)
+ ctx.servername_cb = -> (sock, hostname) {
+ if lc[:sni] && (host = lc[:sni][hostname])
+ new_ctx = ctx.dup
+ *new_ctx.extra_chain_cert, new_ctx.cert = parse_chained_cert(File.read(host[:certificate]))
+ new_ctx.key = OpenSSL::PKey::RSA.new(File.read(host[:certificate_key]))
+ new_ctx
else
- protocols.first
+ ctx
end
}
- ctx.tmp_ecdh_callback = -> (sock, ise, keyl) { OpenSSL::PKey::EC.new("prime256v1") }
- ctx.cert = OpenSSL::X509::Certificate.new(cert)
- ctx.key = OpenSSL::PKey::RSA.new(key)
tcp_server = ::TCPServer.new(lc[:hostname], lc[:port])
@server = OpenSSL::SSL::SSLServer.new(tcp_server, ctx)
@server.start_immediately = false
end
+ def parse_chained_cert(str)
+ str.scan(/-----BEGIN CERTIFICATE.+?END CERTIFICATE-----/m).map { |s| OpenSSL::X509::Certificate.new(s) }
+ end
+
def to_io
@server.to_io
end
@@ -90,7 +98,7 @@ module Plum
cert.sign key, OpenSSL::Digest::SHA1.new
- [cert, key]
+ [cert.to_s, key.to_s]
end
end