class R509::CRL::Administrator

Used to manage revocations and generate CRLs

Attributes

config[R]
crl_number[R]

Public Class Methods

new(config, reader_writer = R509::CRL::FileReaderWriter.new) click to toggle source

@param config [R509::Config::CAConfig] @param reader_writer [R509::CRL::ReaderWriter] A subclass off the R509::CRL::ReaderWriter. Defaults to an instance of R509::CRL::FileReaderWriter.

# File lib/r509/crl/administrator.rb, line 17
def initialize(config, reader_writer = R509::CRL::FileReaderWriter.new)
  @config = config
  unless @config.is_a?(R509::Config::CAConfig)
    raise R509Error, "config must be a kind of R509::Config::CAConfig"
  end

  unless reader_writer.is_a?(R509::CRL::ReaderWriter)
    raise ArgumentError, "argument reader_writer must be a subclass of R509::CRL::ReaderWriter"
  end
  @rw = reader_writer
  @rw.crl_list_file = @config.crl_list_file if @rw.respond_to?(:crl_list_file=)
  @rw.crl_number_file = @config.crl_number_file if @rw.respond_to?(:crl_number_file=)
  @crl_number = @rw.read_number
  @revoked_certs = {}
  @rw.read_list do |serial, reason, revoke_time|
    revoke_cert(serial, reason, revoke_time, false)
  end

  @crl_md = R509::MessageDigest.new(@config.crl_md)
end

Public Instance Methods

generate_crl(last_update = Time.at(Time.now.to_i) - @config.crl_start_skew_seconds, next_update = Time.at(Time.now) + @config.crl_validity_hours * 3600) click to toggle source

Generate the CRL @param last_update [Time] the lastUpdate for the CRL @param next_update [Time] the nextUpdate for the CRL

@return [R509::CRL::SignedList] signed CRL

# File lib/r509/crl/administrator.rb, line 104
def generate_crl(last_update = Time.at(Time.now.to_i) - @config.crl_start_skew_seconds, next_update = Time.at(Time.now) + @config.crl_validity_hours * 3600)
  # Time.at(Time.now.to_i) removes sub-second precision. Subsecond precision is irrelevant
  # for CRL update times and makes testing harder.
  crl = create_crl_object(last_update, next_update)

  self.revoked_certs.each do |serial, reason, revoke_time|
    revoked = OpenSSL::X509::Revoked.new
    revoked.serial = OpenSSL::BN.new serial.to_s
    revoked.time = Time.at(revoke_time)
    unless reason.nil?
      enum = OpenSSL::ASN1::Enumerated(reason)
      ext = OpenSSL::X509::Extension.new("CRLReason", enum)
      revoked.add_extension(ext)
    end
    # now add it to the crl
    crl.add_revoked(revoked)
  end

  crl.sign(@config.crl_cert.key.key, @crl_md.digest)
  R509::CRL::SignedList.new(crl)
end
revoke_cert(serial, reason = nil, revoke_time = Time.now.to_i, write = true) click to toggle source

Adds a certificate to the revocation list. After calling you must call generate_crl to sign a new CRL

@param serial [Integer] serial number of the certificate to revoke @param reason [Integer,nil] reason for revocation @param revoke_time [Integer] @param write [Boolean] whether or not to write the revocation event. Should only be false if you're doing an initial load

reason codes defined by rfc 5280

CRLReason ::= ENUMERATED {

unspecified       (0),
keyCompromise       (1),
cACompromise        (2),
affiliationChanged    (3),
superseded        (4),
cessationOfOperation    (5),
certificateHold     (6),
removeFromCRL       (8),
privilegeWithdrawn    (9),
aACompromise       (10) }
# File lib/r509/crl/administrator.rb, line 71
def revoke_cert(serial, reason = nil, revoke_time = Time.now.to_i, write = true)
  unless reason.nil?
    if !reason.is_a?(Integer) || !reason.between?(0, 10) || reason == 7
      raise ArgumentError, "Revocation reason must be integer 0-10 (excluding 7) or nil"
    end
  end

  serial = serial.to_i
  revoke_time = revoke_time.to_i
  if revoked?(serial)
    raise R509::R509Error, "Cannot revoke a previously revoked certificate"
  end
  @revoked_certs[serial] = { :reason => reason, :revoke_time => revoke_time }
  if write == true
    @rw.write_list_entry(serial, revoke_time, reason)
  end
  nil
end
revoked?(serial) click to toggle source

Indicates whether the serial number has been revoked, or not.

@param [Integer] serial The serial number we want to check @return [Boolean] True if the serial number was revoked. False, otherwise.

# File lib/r509/crl/administrator.rb, line 42
def revoked?(serial)
  @revoked_certs.key?(serial.to_i)
end
revoked_cert(serial) click to toggle source

@return [Array] serial, reason, revoke_time tuple

# File lib/r509/crl/administrator.rb, line 47
def revoked_cert(serial)
  @revoked_certs[serial]
end
revoked_certs() click to toggle source

@return [Array<Array>] Returns an array of serial, reason, revoke_time

tuples.
# File lib/r509/crl/administrator.rb, line 128
def revoked_certs
  ret = []
  @revoked_certs.keys.sort.each do |serial|
    ret << [serial, @revoked_certs[serial][:reason], @revoked_certs[serial][:revoke_time]]
  end
  ret
end
unrevoke_cert(serial) click to toggle source

Remove serial from revocation list. After unrevoking you must call generate_crl to sign a new CRL

@param serial [Integer] serial number of the certificate to remove from revocation

# File lib/r509/crl/administrator.rb, line 93
def unrevoke_cert(serial)
  @revoked_certs.delete(serial)
  @rw.remove_list_entry(serial)
  nil
end

Private Instance Methods

create_crl_object(last_update, next_update) click to toggle source
# File lib/r509/crl/administrator.rb, line 138
def create_crl_object(last_update, next_update)
  crl = OpenSSL::X509::CRL.new
  crl.version = 1
  crl.last_update = last_update
  crl.next_update = next_update
  crl.issuer = @config.crl_cert.subject.name
  ef = OpenSSL::X509::ExtensionFactory.new
  ef.issuer_certificate = @config.crl_cert.cert
  ef.crl = crl
  crl_number = increment_crl_number
  crlnum = OpenSSL::ASN1::Integer(crl_number)
  crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum))
  extensions = []
  extensions << ["authorityKeyIdentifier", "keyid", false]
  extensions.each do |oid, value, critical|
    crl.add_extension(ef.create_extension(oid, value, critical))
  end
  crl
end
increment_crl_number() click to toggle source

Increments the crl_number. @return [Integer] the new CRL number

# File lib/r509/crl/administrator.rb, line 161
def increment_crl_number
  @crl_number += 1
  @rw.write_number(@crl_number)
  @crl_number
end