mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
e8d25b30f3
Add Client Side Certificate Auth feature and handling to puma's MiniSSL. Also exposes SSL errors to puma/apps. compatibility notes: MRI only shell example: puma -b 'ssl://127.0.0.1:9292?key=path_to_key&cert=path_to_cert&ca=path_to_ca&verify_mode=force_peer' code example: (examples/client_side_ssl) app = proc {|env| p env['puma.peercert']; [200, {}, ["hey"]] } events = SSLEvents.new($stdout, $stderr) server = Puma::Server.new(app, events) admin_context = Puma::MiniSSL::Context.new admin_context.key = KEY_PATH admin_context.cert = CERT_PATH admin_context.ca = CA_CERT_PATH admin_context.verify_mode = Puma::MiniSSL::VERIFY_PEER | Puma::MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT server.add_ssl_listener("0.0.0.0", ADMIN_PORT, admin_context) server.min_threads = MIN_THREADS server.max_threads = MAX_THREADS server.persistent_timeout = IDLE_TIMEOUT server.run.join additional credits: Andy Alness <andy.alness@gmail.com>
78 lines
2.7 KiB
Ruby
78 lines
2.7 KiB
Ruby
require "bundler/setup"
|
|
require "puma"
|
|
require "puma/minissl"
|
|
|
|
case ARGV[0]
|
|
|
|
when "s"
|
|
|
|
app = proc {|env|
|
|
p env['puma.peercert']
|
|
[200, {}, [ env['puma.peercert'] ]]
|
|
}
|
|
events = Puma::Events.new($stdout, $stderr)
|
|
server = Puma::Server.new(app, events)
|
|
|
|
context = Puma::MiniSSL::Context.new
|
|
context.key = "certs/server.key"
|
|
context.cert = "certs/server.crt"
|
|
context.ca = "certs/ca.crt"
|
|
#context.verify_mode = Puma::MiniSSL::VERIFY_NONE
|
|
#context.verify_mode = Puma::MiniSSL::VERIFY_PEER
|
|
context.verify_mode = Puma::MiniSSL::VERIFY_PEER | Puma::MiniSSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
|
|
|
server.add_ssl_listener("127.0.0.1", 4000, context)
|
|
|
|
server.run
|
|
sleep
|
|
#server.stop(true)
|
|
|
|
when "g"
|
|
|
|
def issue_cert(dn, key, serial, not_before, not_after, extensions, issuer, issuer_key, digest)
|
|
cert = OpenSSL::X509::Certificate.new
|
|
issuer = cert unless issuer
|
|
issuer_key = key unless issuer_key
|
|
cert.version = 2
|
|
cert.serial = serial
|
|
cert.subject = dn
|
|
cert.issuer = issuer.subject
|
|
cert.public_key = key.public_key
|
|
cert.not_before = not_before
|
|
cert.not_after = not_after
|
|
ef = OpenSSL::X509::ExtensionFactory.new
|
|
ef.subject_certificate = cert
|
|
ef.issuer_certificate = issuer
|
|
extensions.each{|oid, value, critical|
|
|
cert.add_extension(ef.create_extension(oid, value, critical))
|
|
}
|
|
cert.sign(issuer_key, digest)
|
|
cert
|
|
end
|
|
|
|
@ca_key = OpenSSL::PKey::RSA.generate(2048)
|
|
@svr_key = OpenSSL::PKey::RSA.generate(2048)
|
|
@cli_key = OpenSSL::PKey::RSA.generate(2048)
|
|
@ca = OpenSSL::X509::Name.parse("/DC=net/DC=client-cbhq/CN=CA")
|
|
@svr = OpenSSL::X509::Name.parse("/DC=net/DC=client-cbhq/CN=localhost")
|
|
@cli = OpenSSL::X509::Name.parse("/DC=net/DC=client-cbhq/CN=localhost")
|
|
now = Time.at(Time.now.to_i)
|
|
ca_exts = [
|
|
["basicConstraints","CA:TRUE",true],
|
|
["keyUsage","cRLSign,keyCertSign",true],
|
|
]
|
|
ee_exts = [
|
|
#["keyUsage","keyEncipherment,digitalSignature",true],
|
|
["keyUsage","keyEncipherment,dataEncipherment,digitalSignature",true],
|
|
]
|
|
@ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600_000, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new)
|
|
@svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800_000, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
|
|
@cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800_000, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
|
|
|
|
File.open("ca.crt","wb"){|f| f.print @ca_cert.to_pem }
|
|
File.open("ca.key","wb"){|f| f.print @ca_key.to_pem }
|
|
File.open("server.crt","wb"){|f| f.print @svr_cert.to_pem }
|
|
File.open("server.key","wb"){|f| f.print @svr_key.to_pem }
|
|
File.open("client1.crt","wb"){|f| f.print @cli_cert.to_pem }
|
|
File.open("client1.key","wb"){|f| f.print @cli_key.to_pem }
|
|
end
|