1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
require 'time'
module Serverspec::Type
class X509Certificate < Base
def certificate?
(run_openssl_command_with("-noout").exit_status == 0)
end
def subject
normalize_dn(run_openssl_command_with("-subject -noout").stdout.chomp.gsub(/^subject= */,''))
end
def issuer
normalize_dn(run_openssl_command_with("-issuer -noout").stdout.chomp.gsub(/^issuer= */,''))
end
def email
run_openssl_command_with("-email -noout").stdout.chomp
end
def fingerprint
run_openssl_command_with("-fingerprint -noout").stdout.chomp
end
def alias
run_openssl_command_with("-alias -noout").stdout.chomp
end
# Modern openssl use following output format for key length:
# Public-Key: (4096 bit)
# while ancient (0.9.8 for example) use
# RSA Public Key: (2048 bit)
def keylength
len_str = run_openssl_command_with("-text -noout | grep -E 'Public(-| )Key: \\([[:digit:]]+ bit\\)'").stdout.chomp
len_str.gsub(/^.*\(/,'').gsub(/ bit\)$/,'').to_i
end
def has_purpose?(p)
grep_str = "#{p} : Yes"
( run_openssl_command_with("-purpose -noout | grep -wq \"#{grep_str}\"").
exit_status == 0 )
end
def valid?
runner_res = run_openssl_command_with("-startdate -enddate -noout")
return false if runner_res.exit_status != 0
date_map = parse_dates_str_to_map(runner_res.stdout)
now = Time.now
( now >= date_map[:notBefore] && now <= date_map[:notAfter])
end
def validity_in_days
runner_res = run_openssl_command_with("-enddate -noout")
return 0 if runner_res.exit_status != 0
date_map = parse_dates_str_to_map(runner_res.stdout)
diff = date_map[:notAfter] - Time.now
( diff/(60*60*24) )
end
def subject_alt_names
text = run_openssl_command_with('-text -noout').stdout
# X509v3 Subject Alternative Name:
# DNS:*.example.com, DNS:www.example.net, IP:192.0.2.10
if text =~ /^ *X509v3 Subject Alternative Name:.*\n *(.*)$/
$1.split(/, +/)
end
end
private
def run_openssl_command_with(param_str)
@runner.run_command("openssl x509 -in #{name} #{param_str}")
end
def parse_dates_str_to_map(dates_str)
dates_str.split("\n").inject({}) do |res,line|
kv_arr = line.split '='
time = Time.strptime(kv_arr[1],'%b %e %T %Y %Z') rescue Time.parse(kv_arr[1] || '')
res.merge({ kv_arr[0].to_sym => time })
end
end
# Normalize output between openssl versions.
def normalize_dn(dn)
return dn unless dn.start_with?('/')
# normalize openssl < 1.1 to >= 1.1 output
dn[1..-1].split('/').join(', ').gsub('=', ' = ')
end
end
end
|