aboutsummaryrefslogtreecommitdiff
path: root/vendor/certificate_authority/lib/certificate_authority/extensions.rb
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/certificate_authority/lib/certificate_authority/extensions.rb')
-rw-r--r--vendor/certificate_authority/lib/certificate_authority/extensions.rb447
1 files changed, 406 insertions, 41 deletions
diff --git a/vendor/certificate_authority/lib/certificate_authority/extensions.rb b/vendor/certificate_authority/lib/certificate_authority/extensions.rb
index e5a8e85..89de032 100644
--- a/vendor/certificate_authority/lib/certificate_authority/extensions.rb
+++ b/vendor/certificate_authority/lib/certificate_authority/extensions.rb
@@ -5,6 +5,10 @@ module CertificateAuthority
raise "Implementation required"
end
+ def self.parse(value, critical)
+ raise "Implementation required"
+ end
+
def config_extensions
{}
end
@@ -12,21 +16,40 @@ module CertificateAuthority
def openssl_identifier
raise "Implementation required"
end
+
+ def ==(value)
+ raise "Implementation required"
+ end
end
+ # Specifies whether an X.509v3 certificate can act as a CA, signing other
+ # certificates to be verified. If set, a path length constraint can also be
+ # specified.
+ # Reference: Section 4.2.1.10 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.10
class BasicConstraints
+ OPENSSL_IDENTIFIER = "basicConstraints"
+
include ExtensionAPI
include ActiveModel::Validations
+
+ attr_accessor :critical
attr_accessor :ca
attr_accessor :path_len
+ validates :critical, :inclusion => [true,false]
validates :ca, :inclusion => [true,false]
def initialize
- self.ca = false
+ @critical = false
+ @ca = false
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
end
def is_ca?
- self.ca
+ @ca
end
def path_len=(value)
@@ -34,29 +57,54 @@ module CertificateAuthority
@path_len = value
end
- def openssl_identifier
- "basicConstraints"
+ def to_s
+ res = []
+ res << "CA:#{@ca}"
+ res << "pathlen:#{@path_len}" unless @path_len.nil?
+ res.join(',')
end
- def to_s
- result = ""
- result += "CA:#{self.ca}"
- result += ",pathlen:#{self.path_len}" unless self.path_len.nil?
- result
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.ca = (c.last.upcase == "TRUE") if c.first == "CA"
+ obj.path_len = c.last.to_i if c.first == "pathlen"
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@ca,@path_len]
end
end
+ # Specifies where CRL information be be retrieved. This extension isn't
+ # critical, but is recommended for proper CAs.
+ # Reference: Section 4.2.1.14 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.14
class CrlDistributionPoints
+ OPENSSL_IDENTIFIER = "crlDistributionPoints"
+
include ExtensionAPI
- attr_accessor :uri
+ attr_accessor :critical
+ attr_accessor :uris
def initialize
- # self.uri = "http://moo.crlendPoint.example.com/something.crl"
+ @critical = false
+ @uris = []
end
def openssl_identifier
- "crlDistributionPoints"
+ OPENSSL_IDENTIFIER
end
## NB: At this time it seems OpenSSL's extension handlers don't support
@@ -69,99 +117,302 @@ module CertificateAuthority
}
end
+ # This is for legacy support. Technically it can (and probably should)
+ # be an array. But if someone is calling the old accessor we shouldn't
+ # necessarily break it.
+ def uri=(value)
+ @uris << value
+ end
+
def to_s
- return "" if self.uri.nil?
- "URI:#{self.uri}"
+ res = []
+ @uris.each do |uri|
+ res << "URI:#{uri}"
+ end
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.uris << c.last if c.first == "URI"
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@uri]
end
end
+ # Identifies the public key associated with a given certificate.
+ # Should be required for "CA" certificates.
+ # Reference: Section 4.2.1.2 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.2
class SubjectKeyIdentifier
+ OPENSSL_IDENTIFIER = "subjectKeyIdentifier"
+
include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :identifier
+
+ def initialize
+ @critical = false
+ @identifier = "hash"
+ end
+
def openssl_identifier
- "subjectKeyIdentifier"
+ OPENSSL_IDENTIFIER
end
def to_s
- "hash"
+ res = []
+ res << @identifier
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.identifier = value
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@identifier]
end
end
+ # Identifies the public key associated with a given private key.
+ # Reference: Section 4.2.1.1 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.1
class AuthorityKeyIdentifier
+ OPENSSL_IDENTIFIER = "authorityKeyIdentifier"
+
include ExtensionAPI
+ attr_accessor :critical
+ attr_accessor :identifier
+
+ def initialize
+ @critical = false
+ @identifier = ["keyid", "issuer"]
+ end
+
def openssl_identifier
- "authorityKeyIdentifier"
+ OPENSSL_IDENTIFIER
end
def to_s
- "keyid,issuer"
+ res = []
+ res += @identifier
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.identifier = value.split(/,\s*/).last.chomp
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@identifier]
end
end
+ # Specifies how to access CA information and services for the CA that
+ # issued this certificate.
+ # Generally used to specify OCSP servers.
+ # Reference: Section 4.2.2.1 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.2.1
class AuthorityInfoAccess
+ OPENSSL_IDENTIFIER = "authorityInfoAccess"
+
include ExtensionAPI
+ attr_accessor :critical
attr_accessor :ocsp
+ attr_accessor :ca_issuers
def initialize
- self.ocsp = []
+ @critical = false
+ @ocsp = []
+ @ca_issuers = []
end
def openssl_identifier
- "authorityInfoAccess"
+ OPENSSL_IDENTIFIER
end
def to_s
- return "" if self.ocsp.empty?
- "OCSP;URI:#{self.ocsp}"
+ res = []
+ res += @ocsp.map {|o| "OCSP;URI:#{o}" }
+ res += @ca_issuers.map {|c| "caIssuers;URI:#{c}" }
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split("\n").each do |v|
+ if v.starts_with?("OCSP")
+ obj.ocsp << v.split.last
+ end
+
+ if v.starts_with?("CA Issuers")
+ obj.ca_issuers << v.split.last
+ end
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@ocsp,@ca_issuers]
end
end
+ # Specifies the allowed usage purposes of the keypair specified in this certificate.
+ # Reference: Section 4.2.1.3 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.3
+ #
+ # Note: OpenSSL when parsing an extension will return results in the form
+ # 'Digital Signature', but on signing you have to set it to 'digitalSignature'.
+ # So copying an extension from an imported cert isn't going to work yet.
class KeyUsage
+ OPENSSL_IDENTIFIER = "keyUsage"
+
include ExtensionAPI
+ attr_accessor :critical
attr_accessor :usage
def initialize
- self.usage = ["digitalSignature", "nonRepudiation"]
+ @critical = false
+ @usage = ["digitalSignature", "nonRepudiation"]
end
def openssl_identifier
- "keyUsage"
+ OPENSSL_IDENTIFIER
end
def to_s
- "#{self.usage.join(',')}"
+ res = []
+ res += @usage
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.usage = value.split(/,\s*/)
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@usage]
end
end
+ # Specifies even more allowed usages in addition to what is specified in
+ # the Key Usage extension.
+ # Reference: Section 4.2.1.13 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.13
class ExtendedKeyUsage
+ OPENSSL_IDENTIFIER = "extendedKeyUsage"
+
include ExtensionAPI
+ attr_accessor :critical
attr_accessor :usage
def initialize
- self.usage = ["serverAuth","clientAuth"]
+ @critical = false
+ @usage = ["serverAuth"]
end
def openssl_identifier
- "extendedKeyUsage"
+ OPENSSL_IDENTIFIER
end
def to_s
- "#{self.usage.join(',')}"
+ res = []
+ res += @usage
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.usage = value.split(/,\s*/)
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@usage]
end
end
+ # Specifies additional "names" for which this certificate is valid.
+ # Reference: Section 4.2.1.7 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.7
class SubjectAlternativeName
+ OPENSSL_IDENTIFIER = "subjectAltName"
+
include ExtensionAPI
- attr_accessor :uris, :dns_names, :ips
+ attr_accessor :critical
+ attr_accessor :uris, :dns_names, :ips, :emails
def initialize
- self.uris = []
- self.dns_names = []
- self.ips = []
+ @critical = false
+ @uris = []
+ @dns_names = []
+ @ips = []
+ @emails = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
end
def uris=(value)
@@ -179,22 +430,50 @@ module CertificateAuthority
@ips = value
end
- def openssl_identifier
- "subjectAltName"
+ def emails=(value)
+ raise "Emails must be an array" unless value.is_a?(Array)
+ @emails = value
end
def to_s
- res = self.uris.map {|u| "URI:#{u}" }
- res += self.dns_names.map {|d| "DNS:#{d}" }
- res += self.ips.map {|i| "IP:#{i}" }
+ res = []
+ res += @uris.map {|u| "URI:#{u}" }
+ res += @dns_names.map {|d| "DNS:#{d}" }
+ res += @ips.map {|i| "IP:#{i}" }
+ res += @emails.map {|i| "email:#{i}" }
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.uris << c.last if c.first == "URI"
+ obj.dns_names << c.last if c.first == "DNS"
+ obj.ips << c.last if c.first == "IP"
+ obj.emails << c.last if c.first == "EMAIL"
+ end
+ obj
+ end
- return res.join(',')
+ protected
+ def state
+ [@critical,@uris,@dns_names,@ips,@emails]
end
end
class CertificatePolicies
+ OPENSSL_IDENTIFIER = "certificatePolicies"
+
include ExtensionAPI
+ attr_accessor :critical
attr_accessor :policy_identifier
attr_accessor :cps_uris
##User notice
@@ -203,12 +482,12 @@ module CertificateAuthority
attr_accessor :notice_numbers
def initialize
+ self.critical = false
@contains_data = false
end
-
def openssl_identifier
- "certificatePolicies"
+ OPENSSL_IDENTIFIER
end
def user_notice=(value={})
@@ -258,7 +537,93 @@ module CertificateAuthority
def to_s
return "" unless @contains_data
- "ia5org,@custom_policies"
+ res = []
+ res << "ia5org"
+ res += @config_extensions["custom_policies"] unless @config_extensions.nil?
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.policy_identifier = c.last if c.first == "policyIdentifier"
+ obj.cps_uris << c.last if c.first =~ %r{CPS.\d+}
+ # TODO: explicit_text, organization, notice_numbers
+ end
+ obj
+ end
+ end
+
+ # DEPRECATED
+ # Specifics the purposes for which a certificate can be used.
+ # The basicConstraints, keyUsage, and extendedKeyUsage extensions are now used instead.
+ # https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_Certificate_Type
+ class NetscapeCertificateType
+ OPENSSL_IDENTIFIER = "nsCertType"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :flags
+
+ def initialize
+ self.critical = false
+ self.flags = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += self.flags
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.flags = value.split(/,\s*/)
+ obj
+ end
+ end
+
+ # DEPRECATED
+ # Contains a comment which will be displayed when the certificate is viewed in some browsers.
+ # https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_String_extensions_
+ class NetscapeComment
+ OPENSSL_IDENTIFIER = "nsComment"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :comment
+
+ def initialize
+ self.critical = false
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res << self.comment if self.comment
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.comment = value
+ obj
end
end