93 lines
2.1 KiB
Ruby
93 lines
2.1 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
require 'openssl'
|
|
|
|
module Rex
|
|
module Parser
|
|
|
|
###
|
|
#
|
|
# This class parses the contents of a PEM-encoded X509 certificate file containing
|
|
# a private key, a public key, and any appended glue certificates.
|
|
#
|
|
###
|
|
class X509Certificate
|
|
|
|
#
|
|
# 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.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
|
|
|
|
#
|
|
# Parse a certificate in unified PEM format from a file
|
|
#
|
|
# @param [String] ssl_cert_file
|
|
# @return [String, String, Array]
|
|
def self.parse_pem_file(ssl_cert_file)
|
|
data = ''
|
|
::File.open(ssl_cert_file, 'rb') do |fd|
|
|
data << fd.read(fd.stat.size)
|
|
end
|
|
parse_pem(data)
|
|
end
|
|
|
|
#
|
|
# Parse a certificate in unified PEM format and retrieve
|
|
# the SHA1 hash.
|
|
#
|
|
# @param [String] ssl_cert
|
|
# @return [String]
|
|
def self.get_cert_hash(ssl_cert)
|
|
hcert = parse_pem(ssl_cert)
|
|
|
|
unless hcert and hcert[0] and hcert[1]
|
|
raise ArgumentError, "Could not parse a private key and certificate"
|
|
end
|
|
|
|
Rex::Text.sha1_raw(hcert[1].to_der)
|
|
end
|
|
|
|
#
|
|
# Parse a file that contains a certificate in unified PEM
|
|
# format and retrieve the SHA1 hash.
|
|
#
|
|
# @param [String] ssl_cert_file
|
|
# @return [String]
|
|
def self.get_cert_file_hash(ssl_cert_file)
|
|
data = ''
|
|
::File.open(ssl_cert_file, 'rb') do |fd|
|
|
data << fd.read(fd.stat.size)
|
|
end
|
|
get_cert_hash(data)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
end
|