Skip to content

Commit a767613

Browse files
add more SSL_ meta vars from the mod_ssl family
adding a few more variables when webrick is run in SSL, and mutual tls is in place; in such a case, it's important to send information to the backend whether the certificate has been verified, among others.
1 parent 158a7ef commit a767613

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

lib/webrick/https.rb

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,43 @@ def parse_uri(str, scheme="https")
6464

6565
alias orig_meta_vars meta_vars
6666

67+
# This method provides the metavariables defined by
68+
# the Apache mod_ssl module, which add SSL/TLS support to CGI.
69+
# To browse the current documentation, see below:
70+
# http://www.modssl.org/docs/2.8/ssl_reference.html#ToC25
71+
6772
def meta_vars
6873
meta = orig_meta_vars
6974
if server_cert
7075
meta["HTTPS"] = "on"
7176
meta["SSL_SERVER_CERT"] = @server_cert.to_pem
72-
meta["SSL_CLIENT_CERT"] = @client_cert ? @client_cert.to_pem : ""
77+
78+
if @client_cert
79+
meta["SSL_CLIENT_M_VERSION"] = @client_cert.version
80+
meta["SSL_CLIENT_M_SERIAL"] = @client_cert.serial
81+
meta["SSL_CLIENT_S_DN"] = @client_cert.subject.to_s
82+
meta["SSL_CLIENT_I_DN"] = @client_cert.issuer.to_s
83+
meta["SSL_CLIENT_V_START"] = @client_cert.not_before.httpdate
84+
meta["SSL_CLIENT_V_END"] = @client_cert.not_after.httpdate
85+
meta["SSL_CLIENT_V_REMAIN"] = (@client_cert.not_after - @client_cert.not_before) / 60 / 60 / 24
86+
meta["SSL_CLIENT_A_SIG"] = @client_cert.signature_algorithm
87+
meta["SSL_CLIENT_A_KEY"] = @client_cert.public_key.oid
88+
meta["SSL_CLIENT_CERT"] = @client_cert.to_pem
89+
meta["SSL_CLIENT_VERIFY"] = if @socket.context.verify_mode == OpenSSL::SSL::VERIFY_NONE
90+
"NONE"
91+
elsif @socket.verify_result == OpenSSL::X509::V_OK
92+
"SUCCESS"
93+
else
94+
"FAILED"
95+
end
96+
end
97+
7398
if @client_cert_chain
7499
@client_cert_chain.each_with_index{|cert, i|
75100
meta["SSL_CLIENT_CERT_CHAIN_#{i}"] = cert.to_pem
76101
}
77102
end
103+
78104
meta["SSL_CIPHER"] = @cipher[0]
79105
meta["SSL_PROTOCOL"] = @cipher[1]
80106
meta["SSL_CIPHER_USEKEYSIZE"] = @cipher[2].to_s

test/webrick/test_https.rb

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,89 @@ def test_check_ssl_virtual
109109
end
110110
}
111111
end
112+
113+
def test_ssl_meta_vars
114+
# CA cert
115+
ca_cert, ca_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=ca", "is CA")
116+
ef = OpenSSL::X509::ExtensionFactory.new
117+
ef.subject_certificate = ca_cert
118+
ef.issuer_certificate = ca_cert
119+
ca_cert.extensions = [
120+
ef.create_extension("basicConstraints", "CA:TRUE", true),
121+
ef.create_extension("keyUsage", "keyCertSign, cRLSign", true),
122+
ef.create_extension("subjectKeyIdentifier", "hash", false)
123+
]
124+
ca_cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
125+
ca_cert.sign(ca_key, "SHA256")
126+
127+
# Client cert
128+
client_cert, client_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=client", "is client")
129+
client_cert.issuer = ca_cert.issuer
130+
ef = OpenSSL::X509::ExtensionFactory.new
131+
ef.subject_certificate = client_cert
132+
ef.issuer_certificate = ca_cert
133+
client_cert.extensions = [
134+
ef.create_extension("basicConstraints", "CA:FALSE", true),
135+
ef.create_extension("keyUsage", "digitalSignature", true),
136+
ef.create_extension("subjectKeyIdentifier", "hash", false),
137+
ef.create_extension("subjectAltName", "DNS:localhost,IP:127.0.0.1", false)
138+
]
139+
client_cert.sign(ca_key, "SHA256")
140+
141+
142+
# Server cert
143+
server_cert, server_key = WEBrick::Utils.create_self_signed_cert(2048, "/CN=server", "is server")
144+
server_cert.issuer = ca_cert.issuer
145+
ef = OpenSSL::X509::ExtensionFactory.new
146+
ef.subject_certificate = server_cert
147+
ef.issuer_certificate = ca_cert
148+
server_cert.extensions = [
149+
ef.create_extension("basicConstraints", "CA:FALSE", true),
150+
ef.create_extension("keyUsage", "digitalSignature", true),
151+
ef.create_extension("subjectKeyIdentifier", "hash", false),
152+
ef.create_extension("subjectAltName", "DNS:localhost,IP:127.0.0.1", false)
153+
]
154+
server_cert.sign(ca_key, "SHA256")
155+
156+
# Client CA Store
157+
ca_client_store = OpenSSL::X509::Store.new
158+
ca_client_store.add_cert(ca_cert)
159+
ca_client_store.add_cert(client_cert)
160+
161+
# Server CA Store
162+
server_ca_store = OpenSSL::X509::Store.new
163+
server_ca_store.add_cert(ca_cert)
164+
server_ca_store.add_cert(server_cert)
165+
166+
config = {
167+
SSLEnable: true,
168+
:SSLCertName => "/CN=localhost",
169+
SSLCertificate: server_cert,
170+
SSLPrivateKey: server_key,
171+
SSLVerifyClient: OpenSSL::SSL::VERIFY_PEER,
172+
SSLCertificateStore: ca_client_store
173+
}
174+
TestWEBrick.start_httpserver(config){|server, addr, port, log|
175+
env = nil
176+
server.mount_proc("/") {|req, res|
177+
env = req.meta_vars
178+
res.body = "OK"
179+
}
180+
181+
subject = nil
182+
http = Net::HTTP.new(addr, port)
183+
http.use_ssl = true
184+
http.verify_mode = OpenSSL::SSL::VERIFY_CLIENT_ONCE
185+
http.cert = client_cert
186+
http.key = client_key
187+
http.extra_chain_cert = [ca_cert]
188+
http.cert_store = server_ca_store
189+
req = Net::HTTP::Get.new("/")
190+
body = http.request(req).body
191+
assert_not_nil(env)
192+
assert_equal("SUCCESS", env["SSL_CLIENT_VERIFY"])
193+
assert_equal("/CN=client", env["SSL_CLIENT_S_DN"])
194+
assert_equal(client_cert.to_pem, env["SSL_CLIENT_CERT"])
195+
}
196+
end
112197
end

0 commit comments

Comments
 (0)