summaryrefslogtreecommitdiff
path: root/vendor/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb
blob: cb3aaf7b328693986849d2f910c9162c6dbf3d99 (plain)
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
module CertificateAuthority
  class CertificateRevocationList
    include Validations

    attr_accessor :certificates
    attr_accessor :parent
    attr_accessor :crl_body
    attr_accessor :next_update
    attr_accessor :last_update_skew_seconds

    def validate
      errors.add :next_update, "Next update must be a positive value" if self.next_update < 0
      errors.add :parent, "A parent entity must be set" if self.parent.nil?
    end

    def initialize
      self.certificates = []
      self.next_update = 60 * 60 * 4 # 4 hour default
      self.last_update_skew_seconds = 0
    end

    def <<(revocable)
      case revocable
      when Revocable
        raise "Only revoked entities can be added to a CRL" unless revocable.revoked?
        self.certificates << revocable
      when OpenSSL::X509::Certificate
        raise "Not implemented yet"
      else
        raise "#{revocable.class} cannot be included in a CRL"
      end
    end

    def sign!(signing_profile={})
      raise "No parent entity has been set!" if self.parent.nil?
      raise "Invalid CRL" unless self.valid?

      revocations = self.certificates.collect do |revocable|
        revocation = OpenSSL::X509::Revoked.new

        ## We really just need a serial number, now we have to dig it out
        case revocable
        when Certificate
          x509_cert = OpenSSL::X509::Certificate.new(revocable.to_pem)
          revocation.serial = x509_cert.serial
        when SerialNumber
          revocation.serial = revocable.number
        end
        revocation.time = revocable.revoked_at
        revocation
      end

      crl = OpenSSL::X509::CRL.new
      revocations.each do |revocation|
        crl.add_revoked(revocation)
      end

      crl.version = 1
      crl.last_update = Time.now - self.last_update_skew_seconds
      crl.next_update = Time.now + self.next_update

      signing_cert = OpenSSL::X509::Certificate.new(self.parent.to_pem)
      if signing_profile["digest"].nil?
        digest = OpenSSL::Digest.new("SHA512")
      else
        digest = OpenSSL::Digest.new(signing_profile["digest"])
      end
      crl.issuer = signing_cert.subject
      self.crl_body = crl.sign(self.parent.key_material.private_key, digest)

      self.crl_body
    end

    def to_pem
      raise "No signed CRL body" if self.crl_body.nil?
      self.crl_body.to_pem
    end
  end#CertificateRevocationList
end