From: Tom Hughes Date: Tue, 10 Mar 2020 20:15:09 +0000 (+0000) Subject: Enhance certificate checks to check for revoked certificates X-Git-Url: https://git.openstreetmap.org./chef.git/commitdiff_plain/df1d0086a51812d2df25229130c98bf09dd9dcdc?hp=f114d89e96ae821cc1ca40155b95473b1404cfa3 Enhance certificate checks to check for revoked certificates --- diff --git a/cookbooks/letsencrypt/files/default/bin/check-certificate b/cookbooks/letsencrypt/files/default/bin/check-certificate index 73bd8a658..f24681589 100755 --- a/cookbooks/letsencrypt/files/default/bin/check-certificate +++ b/cookbooks/letsencrypt/files/default/bin/check-certificate @@ -2,6 +2,7 @@ require "socket" require "openssl" +require "net/http" host = ARGV.shift address = ARGV.shift @@ -23,6 +24,8 @@ end if ssl certificate = ssl.peer_cert + chain = ssl.peer_cert_chain.drop(1) + issuer = chain.first if Time.now < certificate.not_before puts "Certificate #{domains.first} on #{host} not valid until #{certificate.not_before}" @@ -30,6 +33,43 @@ if ssl puts "Certificate #{domains.first} on #{host} expires at #{certificate.not_after}" end + digest = OpenSSL::Digest::SHA1.new + certificate_id = OpenSSL::OCSP::CertificateId.new(certificate, issuer, digest) + ocsp_request = OpenSSL::OCSP::Request.new.add_certid(certificate_id) + + authority_info_access = certificate.extensions.find { |ext| ext.oid == "authorityInfoAccess" } + ocsp = authority_info_access.value.split("\n").find { |desc| desc.start_with?("OCSP") } + ocsp_uri = URI(ocsp.sub(/^.* URI:/, "")) + + http_response = Net::HTTP.start(ocsp_uri.hostname, ocsp_uri.port) do |http| + path = ocsp_uri.path + path = "/" if path.empty? + http.post(path, ocsp_request.to_der, "Content-Type" => "application/ocsp-request") + end + + basic_response = OpenSSL::OCSP::Response.new(http_response.body).basic + + store = OpenSSL::X509::Store.new + store.set_default_paths + + unless basic_response.verify(chain, store) + raise "OCSP response is not signed by a trusted certificate" + end + + single_response = basic_response.find_response(certificate_id) + + unless single_response + raise "OCSP response does not have the status for the certificate" + end + + unless single_response.check_validity + raise "OCSP response is not valid" + end + + if single_response.cert_status == OpenSSL::OCSP::V_CERTSTATUS_REVOKED + puts "Certificate #{domains.first} on #{host} has been revoked" + end + subject_alt_name = certificate.extensions.find { |ext| ext.oid == "subjectAltName" } if subject_alt_name.nil?