diff options
Diffstat (limited to 'vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb')
-rw-r--r-- | vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb b/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb new file mode 100644 index 0000000..e101f98 --- /dev/null +++ b/vendor/certificate_authority/lib/certificate_authority/ocsp_handler.rb @@ -0,0 +1,144 @@ +module CertificateAuthority + class OCSPResponseBuilder + attr_accessor :ocsp_response + attr_accessor :verification_mechanism + attr_accessor :ocsp_request_reader + attr_accessor :parent + attr_accessor :next_update + + GOOD = OpenSSL::OCSP::V_CERTSTATUS_GOOD + REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED + + NO_REASON=0 + KEY_COMPROMISED=OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE + UNSPECIFIED=OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED + + def build_response() + raise "Requires a parent for signing" if @parent.nil? + if @verification_mechanism.nil? + ## If no verification callback is provided we're marking it GOOD + @verification_mechanism = lambda {|cert_id| [GOOD,NO_REASON] } + end + + @ocsp_request_reader.ocsp_request.certid.each do |cert_id| + result,reason = verification_mechanism.call(cert_id.serial) + + ## cert_id, status, reason, rev_time, this update, next update, ext + ## - unit of time is seconds + ## - rev_time is currently set to "now" + @ocsp_response.add_status(cert_id, + result, reason, + 0, 0, @next_update, nil) + end + + @ocsp_response.sign(OpenSSL::X509::Certificate.new(@parent.to_pem), @parent.key_material.private_key, nil, nil) + OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, @ocsp_response) + end + + def self.from_request_reader(request_reader,verification_mechanism=nil) + response_builder = OCSPResponseBuilder.new + response_builder.ocsp_request_reader = request_reader + + ocsp_response = OpenSSL::OCSP::BasicResponse.new + ocsp_response.copy_nonce(request_reader.ocsp_request) + response_builder.ocsp_response = ocsp_response + response_builder.next_update = 60*15 #Default of 15 minutes + response_builder + end + end + + class OCSPRequestReader + attr_accessor :raw_ocsp_request + attr_accessor :ocsp_request + + def serial_numbers + @ocsp_request.certid.collect do |cert_id| + cert_id.serial + end + end + + def self.from_der(request_body) + reader = OCSPRequestReader.new + reader.raw_ocsp_request = request_body + reader.ocsp_request = OpenSSL::OCSP::Request.new(request_body) + + reader + end + end + + ## DEPRECATED + class OCSPHandler + include ActiveModel::Validations + + attr_accessor :ocsp_request + attr_accessor :certificate_ids + + attr_accessor :certificates + attr_accessor :parent + + attr_accessor :ocsp_response_body + + validate do |crl| + errors.add :parent, "A parent entity must be set" if parent.nil? + end + validate :all_certificates_available + + def initialize + self.certificates = {} + end + + def <<(cert) + self.certificates[cert.serial_number.number.to_s] = cert + end + + def extract_certificate_serials + openssl_request = OpenSSL::OCSP::Request.new(@ocsp_request) + + self.certificate_ids = openssl_request.certid.collect do |cert_id| + cert_id.serial + end + + self.certificate_ids + end + + + def response + raise "Invalid response" unless valid? + + openssl_ocsp_response = OpenSSL::OCSP::BasicResponse.new + openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request) + openssl_ocsp_response.copy_nonce(openssl_ocsp_request) + + openssl_ocsp_request.certid.each do |cert_id| + certificate = self.certificates[cert_id.serial.to_s] + + openssl_ocsp_response.add_status(cert_id, + OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0, + 0, 0, 30, nil) + end + + + openssl_ocsp_response.sign(OpenSSL::X509::Certificate.new(self.parent.to_pem), self.parent.key_material.private_key, nil, nil) + final_response = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, openssl_ocsp_response) + self.ocsp_response_body = final_response + self.ocsp_response_body + end + + def to_der + raise "No signed OCSP response body available" if self.ocsp_response_body.nil? + self.ocsp_response_body.to_der + end + + private + + def all_certificates_available + openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request) + + openssl_ocsp_request.certid.each do |cert_id| + certificate = self.certificates[cert_id.serial.to_s] + errors.add(:base, "Certificate #{cert_id.serial} has not been added yet") if certificate.nil? + end + end + + end +end |