class R509::Cert::Extensions::BasicConstraints

RFC 5280 Description (see: www.ietf.org/rfc/rfc5280.txt)

The basic constraints extension identifies whether the subject of the certificate is a CA and the maximum depth of valid certification paths that include this certificate.

You can use this extension to parse an existing extension for easy access to the contents or create a new one.

Constants

OID

friendly name for BasicConstraints OID

Attributes

path_length[R]

returns the path length (if present) @return [Integer,nil]

Public Class Methods

new(arg) click to toggle source

This method takes a hash or an existing Extension object to parse @option arg :ca [Boolean] The ca key is required and must be set to true (for an issuing CA) or false (everything else). @option arg :path_length optional [Integer] This option is only allowed if ca is set to TRUE. path_length allows you to define the maximum number of non-self-issued intermediate certificates that may follow this certificate in a valid certification path. For example, if you set this value to 0 then the certificate issued can only issue end entity certificates, not additional subroots. This must be a non-negative integer (>=0). @option arg :critical [Boolean] (true)

Calls superclass method
# File lib/r509/cert/extensions/basic_constraints.rb, line 27
def initialize(arg)
  unless R509::Cert::Extensions.is_extension?(arg)
    arg = build_extension(arg)
  end

  super(arg)
  parse_extension
end

Public Instance Methods

allows_sub_ca?() click to toggle source

Returns true if the path length allows this certificate to be used to create subordinate signing certificates beneath it. Does not check if there is a pathlen restriction in the cert chain above the current cert @return [Boolean]

# File lib/r509/cert/extensions/basic_constraints.rb, line 46
def allows_sub_ca?
  return false unless is_ca?
  return true if @path_length.nil?
  @path_length > 0
end
is_ca?() click to toggle source

Check whether the extension value would make the parent certificate a CA @return [Boolean]

# File lib/r509/cert/extensions/basic_constraints.rb, line 38
def is_ca?
  @is_ca == true
end
to_h() click to toggle source

@return [Hash]

# File lib/r509/cert/extensions/basic_constraints.rb, line 53
def to_h
  hash = { :ca => @is_ca, :critical => self.critical? }
  hash[:path_length] = @path_length unless @path_length.nil? || !is_ca?
  hash
end
to_yaml() click to toggle source

@return [YAML]

# File lib/r509/cert/extensions/basic_constraints.rb, line 60
def to_yaml
  self.to_h.to_yaml
end

Private Instance Methods

build_extension(arg) click to toggle source
# File lib/r509/cert/extensions/basic_constraints.rb, line 84
def build_extension(arg)
  validate_basic_constraints(arg)
  ef = OpenSSL::X509::ExtensionFactory.new
  if arg[:ca] == true
    bc_value = "CA:TRUE"
    unless arg[:path_length].nil?
      bc_value += ",pathlen:#{arg[:path_length]}"
    end
  else
    bc_value = "CA:FALSE"
  end
  critical = R509::Cert::Extensions.calculate_critical(arg[:critical], true)
  ef.create_extension("basicConstraints", bc_value, critical)
end
parse_extension() click to toggle source
# File lib/r509/cert/extensions/basic_constraints.rb, line 66
def parse_extension
  data = R509::ASN1.get_extension_payload(self)
  @is_ca = false
  #   BasicConstraints ::= SEQUENCE {
  #        cA                      BOOLEAN DEFAULT FALSE,
  #        pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
  data.entries.each do |entry|
    if entry.is_a?(OpenSSL::ASN1::Boolean)
      @is_ca = entry.value
    else
      # There are only two kinds of entries permitted so anything
      # else is an integer pathlength. it is in OpenSSL::BN form by default
      # but that's annoying so let's cast it.
      @path_length = entry.value.to_i
    end
  end
end
validate_basic_constraints(constraints) click to toggle source

validates the structure of the certificate policies array

# File lib/r509/cert/extensions/basic_constraints.rb, line 100
def validate_basic_constraints(constraints)
  if constraints.nil? || !constraints.respond_to?(:has_key?) || !constraints.key?(:ca)
    raise ArgumentError, "You must supply a hash with a key named :ca with a boolean value"
  end
  if constraints[:ca].nil? || (!constraints[:ca].is_a?(TrueClass) && !constraints[:ca].is_a?(FalseClass))
    raise ArgumentError, "You must supply true/false for the :ca key when specifying basic constraints"
  end
  if constraints[:ca] == false && constraints[:path_length]
    raise ArgumentError, ":path_length is not allowed when :ca is false"
  end
  if constraints[:ca] == true && constraints[:path_length] && (constraints[:path_length] < 0 || !constraints[:path_length].is_a?(Integer))
    raise ArgumentError, "Path length must be a positive integer (>= 0)"
  end
  constraints
end