You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cert.rb 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. module CryptCheck
  2. module Tls
  3. class Cert
  4. DEFAULT_CA_DIRECTORIES = [
  5. '/usr/share/ca-certificates/mozilla'
  6. ]
  7. SIGNATURE_ALGORITHMS = %i(md2 mdc2 md4 md5 ripemd160 sha sha1 sha2 rsa dss ecc ghost).freeze
  8. SIGNATURE_ALGORITHMS_X509 = {
  9. 'dsaWithSHA' => %i(sha1 dss),
  10. 'dsaWithSHA1' => %i(sha1 dss),
  11. 'dsaWithSHA1_2' => %i(sha1 dss),
  12. 'dsa_with_SHA224' => %i(sha2 dss),
  13. 'dsa_with_SHA256' => %i(sha2 dss),
  14. 'mdc2WithRSA' => %i(mdc2 rsa),
  15. 'md2WithRSAEncryption' => %i(md2 rsa),
  16. 'md4WithRSAEncryption' => %i(md4, rsa),
  17. 'md5WithRSA' => %i(md5 rsa),
  18. 'md5WithRSAEncryption' => %i(md5 rsa),
  19. 'shaWithRSAEncryption' => %i(sha rsa),
  20. 'sha1WithRSA' => %i(sha1 rsa),
  21. 'sha1WithRSAEncryption' => %i(sha1 rsa),
  22. 'sha224WithRSAEncryption' => %i(sha2 rsa),
  23. 'sha256WithRSAEncryption' => %i(sha2 rsa),
  24. 'sha384WithRSAEncryption' => %i(sha2 rsa),
  25. 'sha512WithRSAEncryption' => %i(sha2 rsa),
  26. 'ripemd160WithRSA' => %i(ripemd160 rsa),
  27. 'ecdsa-with-SHA1' => %i(sha1 ecc),
  28. 'ecdsa-with-SHA224' => %i(sha2 ecc),
  29. 'ecdsa-with-SHA256' => %i(sha2 ecc),
  30. 'ecdsa-with-SHA384' => %i(sha2 ecc),
  31. 'ecdsa-with-SHA512' => %i(sha2 ecc),
  32. 'id_GostR3411_94_with_GostR3410_2001' => %i(ghost),
  33. 'id_GostR3411_94_with_GostR3410_94' => %i(ghost),
  34. 'id_GostR3411_94_with_GostR3410_94_cc' => %i(ghost),
  35. 'id_GostR3411_94_with_GostR3410_2001_cc' => %i(ghost)
  36. }.freeze
  37. WEAK_SIGN = {
  38. critical: %i(mdc2 md2 md4 md5 sha sha1)
  39. }.freeze
  40. SIGNATURE_ALGORITHMS.each do |name|
  41. class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
  42. def #{name}?
  43. SIGNATURE_ALGORITHMS_X509[@cert.signature_algorithm].include? :#{name}
  44. end
  45. RUBY_EVAL
  46. end
  47. def initialize(cert, chain=[])
  48. @cert, @chain = case cert
  49. when ::OpenSSL::X509::Certificate
  50. [cert, chain]
  51. when ::OpenSSL::SSL::SSLSocket
  52. [cert.peer_cert, cert.peer_cert_chain]
  53. end
  54. end
  55. def self.trusted?(cert, chain, roots: DEFAULT_CA_DIRECTORIES)
  56. store = ::OpenSSL::X509::Store.new
  57. store.purpose = ::OpenSSL::X509::PURPOSE_SSL_SERVER
  58. store.add_chains roots
  59. chain.each do |cert|
  60. # Never add other self signed certificates than system CA !
  61. next if cert.subject == cert.issuer
  62. store.add_cert cert rescue nil
  63. end if chain
  64. trusted = store.verify cert
  65. return :trusted if trusted
  66. store.error_string
  67. end
  68. def trusted?(roots: DEFAULT_CA_DIRECTORIES)
  69. Cert.trusted? @cert, @chain, roots: roots
  70. end
  71. def valid?(host)
  72. ::OpenSSL::SSL.verify_certificate_identity @cert, host
  73. end
  74. def fingerprint
  75. @cert.fingerprint
  76. end
  77. def key
  78. @cert.public_key
  79. end
  80. def subject
  81. @cert.subject
  82. end
  83. def serial
  84. @cert.serial
  85. end
  86. def issuer
  87. @cert.issuer
  88. end
  89. def lifetime
  90. { not_before: @cert.not_before, not_after: @cert.not_after }
  91. end
  92. def to_h
  93. {
  94. subject: self.subject.to_s,
  95. serial: self.serial.to_s,
  96. issuer: self.issuer.to_s,
  97. lifetime: self.lifetime,
  98. fingerprint: self.fingerprint,
  99. chain: @chain.collect do |cert|
  100. {
  101. subject: cert.subject.to_s,
  102. serial: cert.serial.to_s,
  103. issuer: cert.issuer.to_s,
  104. fingerprint: cert.fingerprint,
  105. lifetime: { not_before: cert.not_before, not_after: cert.not_after }
  106. }
  107. end,
  108. key: self.key.to_h,
  109. states: self.states
  110. }
  111. end
  112. protected
  113. include State
  114. CHECKS = WEAK_SIGN.collect do |level, hashes|
  115. hashes.collect do |hash|
  116. ["#{hash}_sign".to_sym, level, -> (s) { s.send "#{hash}?" }]
  117. end
  118. end.flatten(1).freeze
  119. def available_checks
  120. CHECKS
  121. end
  122. def children
  123. [self.key]
  124. end
  125. end
  126. end
  127. end