Land #4239 - Support SSL intermediate certs
commit
f2add929d7
|
@ -99,6 +99,93 @@ module Rex::Socket::SslTcpServer
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Parse a certificate in unified PEM format that contains a private key and
|
||||
# one or more certificates. The first certificate is the primary, while any
|
||||
# additional certificates are treated as intermediary certificates. This emulates
|
||||
# the behavior of web servers like nginx.
|
||||
#
|
||||
# @param [String] ssl_cert
|
||||
# @return [String, String, Array]
|
||||
def self.ssl_parse_pem(ssl_cert)
|
||||
cert = nil
|
||||
key = nil
|
||||
chain = nil
|
||||
|
||||
certs = []
|
||||
ssl_cert.scan(/-----BEGIN\s*[^\-]+-----+\r?\n[^\-]*-----END\s*[^\-]+-----\r?\n?/nm).each do |pem|
|
||||
if pem =~ /PRIVATE KEY/
|
||||
key = OpenSSL::PKey::RSA.new(pem)
|
||||
elsif pem =~ /CERTIFICATE/
|
||||
certs << OpenSSL::X509::Certificate.new(pem)
|
||||
end
|
||||
end
|
||||
|
||||
cert = certs.shift
|
||||
if certs.length > 0
|
||||
chain = certs
|
||||
end
|
||||
|
||||
[key, cert, chain]
|
||||
end
|
||||
|
||||
#
|
||||
# Shim for the ssl_parse_pem module method
|
||||
#
|
||||
def ssl_parse_pem(ssl_cert)
|
||||
Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
|
||||
end
|
||||
|
||||
#
|
||||
# Generate a realistic-looking but obstensibly fake SSL
|
||||
# certificate.
|
||||
#
|
||||
# @return [String, String, Array]
|
||||
def self.ssl_generate_certificate
|
||||
key = OpenSSL::PKey::RSA.new(1024){ }
|
||||
cert = OpenSSL::X509::Certificate.new
|
||||
cert.version = 2
|
||||
cert.serial = rand(0xFFFFFFFF)
|
||||
subject = OpenSSL::X509::Name.new([
|
||||
["C","US"],
|
||||
['ST', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
issuer = OpenSSL::X509::Name.new([
|
||||
["C","US"],
|
||||
['ST', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
|
||||
cert.subject = subject
|
||||
cert.issuer = issuer
|
||||
cert.not_before = Time.now - (3600 * 365)
|
||||
cert.not_after = Time.now + (3600 * 365)
|
||||
cert.public_key = key.public_key
|
||||
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
||||
cert.extensions = [
|
||||
ef.create_extension("basicConstraints","CA:FALSE"),
|
||||
ef.create_extension("subjectKeyIdentifier","hash"),
|
||||
ef.create_extension("extendedKeyUsage","serverAuth"),
|
||||
ef.create_extension("keyUsage","keyEncipherment,dataEncipherment,digitalSignature")
|
||||
]
|
||||
ef.issuer_certificate = cert
|
||||
cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
|
||||
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
||||
|
||||
[key, cert, nil]
|
||||
end
|
||||
|
||||
#
|
||||
# Shim for the ssl_generate_certificate module method
|
||||
#
|
||||
def ssl_generate_certificate
|
||||
Rex::Socket::SslTcpServer.ssl_generate_certificate
|
||||
end
|
||||
|
||||
#
|
||||
# Create a new ssl context. If +ssl_cert+ is not given, generates a new
|
||||
|
@ -107,54 +194,19 @@ module Rex::Socket::SslTcpServer
|
|||
# @param [Rex::Socket::Parameters] params
|
||||
# @return [::OpenSSL::SSL::SSLContext]
|
||||
def makessl(params)
|
||||
ssl_cert = params.ssl_cert
|
||||
if ssl_cert
|
||||
cert = OpenSSL::X509::Certificate.new(ssl_cert)
|
||||
key = OpenSSL::PKey::RSA.new(ssl_cert)
|
||||
else
|
||||
key = OpenSSL::PKey::RSA.new(1024){ }
|
||||
cert = OpenSSL::X509::Certificate.new
|
||||
cert.version = 2
|
||||
cert.serial = rand(0xFFFFFFFF)
|
||||
# name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
|
||||
subject = OpenSSL::X509::Name.new([
|
||||
["C","US"],
|
||||
['ST', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
issuer = OpenSSL::X509::Name.new([
|
||||
["C","US"],
|
||||
['ST', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
|
||||
cert.subject = subject
|
||||
cert.issuer = issuer
|
||||
cert.not_before = Time.now - (3600 * 365)
|
||||
cert.not_after = Time.now + (3600 * 365)
|
||||
cert.public_key = key.public_key
|
||||
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
||||
cert.extensions = [
|
||||
ef.create_extension("basicConstraints","CA:FALSE"),
|
||||
ef.create_extension("subjectKeyIdentifier","hash"),
|
||||
ef.create_extension("extendedKeyUsage","serverAuth"),
|
||||
ef.create_extension("keyUsage","keyEncipherment,dataEncipherment,digitalSignature")
|
||||
]
|
||||
ef.issuer_certificate = cert
|
||||
cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
|
||||
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
||||
if params.ssl_cert
|
||||
key, cert, chain = ssl_parse_pem(params.ssl_cert)
|
||||
else
|
||||
key, cert, chain = ssl_generate_certificate
|
||||
end
|
||||
|
||||
ctx = OpenSSL::SSL::SSLContext.new()
|
||||
ctx.key = key
|
||||
ctx.cert = cert
|
||||
ctx.extra_chain_cert = chain
|
||||
ctx.options = 0
|
||||
|
||||
|
||||
# Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
|
||||
if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
|
||||
# enable/disable the SSL/TLS-level compression
|
||||
|
|
Loading…
Reference in New Issue