Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add more SSL_ meta vars from the mod_ssl family #107

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion lib/webrick/https.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,43 @@ def parse_uri(str, scheme="https")

alias orig_meta_vars meta_vars

# This method provides the metavariables defined by
# the Apache mod_ssl module, which add SSL/TLS support to CGI.
# To browse the current documentation, see below:
# http://www.modssl.org/docs/2.8/ssl_reference.html#ToC25

def meta_vars
meta = orig_meta_vars
if server_cert
meta["HTTPS"] = "on"
meta["SSL_SERVER_CERT"] = @server_cert.to_pem
meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""

if @client_cert
meta["SSL_CLIENT_M_VERSION"] = @client_cert.version
meta["SSL_CLIENT_M_SERIAL"] = @client_cert.serial
meta["SSL_CLIENT_S_DN"] = @client_cert.subject.to_s
meta["SSL_CLIENT_I_DN"] = @client_cert.issuer.to_s
meta["SSL_CLIENT_V_START"] = @client_cert.not_before.httpdate
meta["SSL_CLIENT_V_END"] = @client_cert.not_after.httpdate
meta["SSL_CLIENT_V_REMAIN"] = (@client_cert.not_after - @client_cert.not_before) / 60 / 60 / 24
meta["SSL_CLIENT_A_SIG"] = @client_cert.signature_algorithm
meta["SSL_CLIENT_A_KEY"] = @client_cert.public_key.oid
meta["SSL_CLIENT_CERT"] = @client_cert.to_pem
meta["SSL_CLIENT_VERIFY"] = if @socket.context.verify_mode == OpenSSL::SSL::VERIFY_NONE
"NONE"
elsif @socket.verify_result == OpenSSL::X509::V_OK
"SUCCESS"
else
"FAILED"
end
end
HoneyryderChuck marked this conversation as resolved.
Show resolved Hide resolved

if @client_cert_chain
@client_cert_chain.each_with_index{|cert, i|
meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
}
end

meta["SSL_CIPHER"] = @cipher[0]
meta["SSL_PROTOCOL"] = @cipher[1]
meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s
Expand Down
85 changes: 85 additions & 0 deletions test/webrick/test_https.rb
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,89 @@ def test_check_ssl_virtual
end
}
end

def test_ssl_meta_vars
# CA cert
ca_cert, ca_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=ca", "is CA")
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = ca_cert
ef.issuer_certificate = ca_cert
ca_cert.extensions = [
ef.create_extension("basicConstraints", "CA:TRUE", true),
ef.create_extension("keyUsage", "keyCertSign, cRLSign", true),
ef.create_extension("subjectKeyIdentifier", "hash", false)
]
ca_cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
ca_cert.sign(ca_key, "SHA256")

# Client cert
client_cert, client_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=client", "is client")
client_cert.issuer = ca_cert.issuer
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = client_cert
ef.issuer_certificate = ca_cert
client_cert.extensions = [
ef.create_extension("basicConstraints", "CA:FALSE", true),
ef.create_extension("keyUsage", "digitalSignature", true),
ef.create_extension("subjectKeyIdentifier", "hash", false),
ef.create_extension("subjectAltName", "DNS:localhost,IP:127.0.0.1", false)
]
client_cert.sign(ca_key, "SHA256")


# Server cert
server_cert, server_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=server", "is server")
server_cert.issuer = ca_cert.issuer
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = server_cert
ef.issuer_certificate = ca_cert
server_cert.extensions = [
ef.create_extension("basicConstraints", "CA:FALSE", true),
ef.create_extension("keyUsage", "digitalSignature", true),
ef.create_extension("subjectKeyIdentifier", "hash", false),
ef.create_extension("subjectAltName", "DNS:localhost,IP:127.0.0.1", false)
]
server_cert.sign(ca_key, "SHA256")

# Client CA Store
ca_client_store = OpenSSL::X509::Store.new
ca_client_store.add_cert(ca_cert)
ca_client_store.add_cert(client_cert)

# Server CA Store
server_ca_store = OpenSSL::X509::Store.new
server_ca_store.add_cert(ca_cert)
server_ca_store.add_cert(server_cert)

config = {
SSLEnable: true,
:SSLCertName => "/CN=localhost",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this key also used the non-hashrocket style? Or is it somehow special?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing special about it, I just copy-pasted as is from the test above. I assumed that consistency wasn't a big issue in this codebase. Perhaps you should consider using rubocop at some point?

SSLCertificate: server_cert,
SSLPrivateKey: server_key,
SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER,
SSLCertificateStore: ca_client_store
}
TestWEBrick.start_httpserver(config){|server, addr, port, log|
env = nil
server.mount_proc("/") {|req, res|
env = req.meta_vars
res.body = "OK"
}

subject = nil
http = Net::HTTP.new(addr, port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_CLIENT_ONCE
http.cert = client_cert
http.key = client_key
http.extra_chain_cert = [ca_cert]
http.cert_store = server_ca_store
req = Net::HTTP::Get.new("/")
body = http.request(req).body
assert_not_nil(env)
assert_equal("SUCCESS", env["SSL_CLIENT_VERIFY"])
assert_equal("/CN=client", env["SSL_CLIENT_S_DN"])
assert_equal(client_cert.to_pem, env["SSL_CLIENT_CERT"])
}
end
end