Class: AuthorityChecker

Inherits:
Object
  • Object
show all
Defined in:
lib/sslackey/authority_checker.rb

Constant Summary collapse

REVOCATION_RESPONSES =
[:successful, :unknown, :revoked]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(trusted_certs_path) ⇒ AuthorityChecker

Returns a new instance of AuthorityChecker.



6
7
8
9
# File 'lib/sslackey/authority_checker.rb', line 6

def initialize(trusted_certs_path)
  @trusted_certs_file_path = trusted_certs_path

end

Instance Attribute Details

#trusted_certs_file_pathObject

Returns the value of attribute trusted_certs_file_path.



4
5
6
# File 'lib/sslackey/authority_checker.rb', line 4

def trusted_certs_file_path
  @trusted_certs_file_path
end

Class Method Details

.parse_authority_info_access(ocsp_string) ⇒ Object



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/sslackey/authority_checker.rb', line 40

def self.parse_authority_info_access(ocsp_string)
  ocsp_string.each_line do |line|
    if line.index(/OCSP/)
      urls = line.scan(/URI:.*/)
      url = urls[0]
      url.slice!(/URI:/)
      return url
    end
  end
  return nil
end

.parse_crl_distribution_points(crl_string) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/sslackey/authority_checker.rb', line 52

def self.parse_crl_distribution_points(crl_string)
  crl_string.each_line do |line|
    urls = line.scan(/URI:.*/)
    crl_url = urls[0]
    crl_url.slice!(/URI:/)
    return crl_url
  end
end

Instance Method Details

#create_response_file(file_name) ⇒ Object



91
92
93
# File 'lib/sslackey/authority_checker.rb', line 91

def create_response_file(file_name)
  Tempfile.new(file_name)
end

#fetch_crl_content(crl_url) ⇒ Object



106
107
108
# File 'lib/sslackey/authority_checker.rb', line 106

def fetch_crl_content(crl_url)
  `curl -s '#{crl_url}'`
end

#generate_ocsp_response(issuer_file_path, certificate_file_path, output_file_path, ocsp_url) ⇒ Object



72
73
74
# File 'lib/sslackey/authority_checker.rb', line 72

def generate_ocsp_response(issuer_file_path, certificate_file_path, output_file_path, ocsp_url)
  `openssl ocsp -no_nonce -CAfile #{trusted_certs_file_path} -issuer #{issuer_file_path} -cert #{certificate_file_path} -respout #{output_file_path} -url #{ocsp_url}`
end

#perform_crl_check(certificate, crl_url) ⇒ Object



95
96
97
98
99
100
101
102
103
104
# File 'lib/sslackey/authority_checker.rb', line 95

def perform_crl_check(certificate, crl_url)
  content = fetch_crl_content(crl_url)
  crl = OpenSSL::X509::CRL.new(content)

  revoked_matches = crl.revoked.select { |elem| elem.serial == certificate.serial }

  return :revoked unless revoked_matches.empty?

  :successful
end

#perform_ocsp_check(certificate, issuer_certificate, ocsp_url) ⇒ Object



62
63
64
65
66
67
68
69
70
# File 'lib/sslackey/authority_checker.rb', line 62

def perform_ocsp_check(certificate, issuer_certificate, ocsp_url)
  certificate_file = write_certificate_file(certificate, "provider")
  issuer_file = write_certificate_file(issuer_certificate, "issuer")
  output_file = create_response_file("ocsp_output")

  generate_ocsp_response(issuer_file.path, certificate_file.path, output_file.path, ocsp_url)

  read_ocsp_response(output_file).to_sym
end

#read_ocsp_response(output_file) ⇒ Object



76
77
78
79
80
81
# File 'lib/sslackey/authority_checker.rb', line 76

def read_ocsp_response(output_file)
  output_file.rewind
  response = OpenSSL::OCSP::Response.new(output_file.read)
  output_file.close
  response.status_string
end

#validate(certificate, issuer_certificate) ⇒ Object



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
# File 'lib/sslackey/authority_checker.rb', line 11

def validate(certificate, issuer_certificate)
  ocsp_url = nil
  crl_url = nil

  certificate.extensions.each do |extension|
    props = extension.to_h
    if props["oid"] == "authorityInfoAccess"
      ocsp_url = AuthorityChecker.parse_authority_info_access(props["value"])
      LOGGER.debug("got an ocsp url: #{ocsp_url}") if defined? LOGGER
    end

    if props["oid"] == "crlDistributionPoints"
      crl_url = AuthorityChecker.parse_crl_distribution_points(props["value"])
      LOGGER.debug("got an crl url: #{crl_url}") if defined? LOGGER
    end
  end
  if ocsp_url
    response = perform_ocsp_check(certificate, issuer_certificate, ocsp_url)
  elsif crl_url
    response = perform_crl_check(certificate, crl_url)
  else
    raise "Could not find valid oscp or crl extension to check against in certificate #{certificate.subject}"
  end

  raise "Unknown revocation response #{response}" unless AuthorityChecker::REVOCATION_RESPONSES.include?(response)

  response
end

#write_certificate_file(certificate, file_name) ⇒ Object



83
84
85
86
87
88
89
# File 'lib/sslackey/authority_checker.rb', line 83

def write_certificate_file(certificate, file_name)
  file = Tempfile.new(file_name)
  file.write(certificate)
  file.rewind
  file.close
  file
end