Class: OmfCommon::Auth::Certificate
- Inherits:
-
Object
- Object
- OmfCommon::Auth::Certificate
- Defined in:
- omf_common/lib/omf_common/auth/certificate.rb
Constant Summary
- DEF_DOMAIN_NAME =
'acme'
- DEF_DURATION =
3600
- BEGIN_CERT =
"-----BEGIN CERTIFICATE-----\n"
- END_CERT =
"\n-----END CERTIFICATE-----\n"
- BEGIN_KEY =
"-----BEGIN RSA PRIVATE KEY-----\n"
- END_KEY =
"\n-----END RSA PRIVATE KEY-----\n"
- @@def_x509_name_prefix =
[['C', 'US'], ['ST', 'CA'], ['O', 'ACME'], ['OU', 'Roadrunner']]
- @@def_email_domain =
'acme.org'
Instance Attribute Summary (collapse)
-
- (Object) addresses
readonly
:addresses_raw, :addresses_string.
-
- (Object) digest
readonly
Returns the value of attribute digest.
-
- (Object) key
Returns the value of attribute key.
-
- (Object) resource_id
:addresses_raw, :addresses_string.
-
- (Object) subject
readonly
Returns the value of attribute subject.
Class Method Summary (collapse)
- + (Object) _create_digest
-
+ (Object) _create_key(size = 2048)
Returns an array with a new RSA key and a SHA1 digest.
-
+ (cert, key) _create_x509_cert(subject, key, digest = nil, issuer = nil, not_before = Time.now, duration = DEF_DURATION, addresses = [])
Create a X509 certificate.
- + (Object) create_for_resource(resource_id, resource_type, issuer, opts = {})
-
+ (Certificate) create_from_pem(pem_s)
Return a newly create certificate with properties token from 'pem' encoded string.
- + (Object) create_root(opts = {})
- + (Object) default_domain(country, state, organisation, org_unit)
- + (Object) default_email_domain(email_domain)
Instance Method Summary (collapse)
- - (Object) _extract_addresses(cert)
- - (Boolean) can_sign?
- - (Boolean) cert_expired?
- - (Object) create_for_resource(resource_id, resource_type, opts = {})
-
- (Object) create_for_user(name, opts = {})
See #create_for_resource for documentation on 'opts'.
-
- (Object) describe
Return a hash of some of the key properties of this cert.
-
- (Certificate) initialize(opts)
constructor
A new instance of Certificate.
- - (Boolean) root_ca?
- - (Object) to_pem
- - (Object) to_pem_compact
- - (Object) to_pem_with_key
-
- (Object) to_s
Will return one of the following.
-
- (Object) to_x509
Return the X509 certificate.
- - (Boolean) valid?
- - (Object) verify_cert
Constructor Details
- (Certificate) initialize(opts)
Returns a new instance of Certificate
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 214 def initialize(opts) if @cert = opts[:cert] @subject = @cert.subject end @resource_id = opts[:resource_id] _extract_addresses(@cert) unless @subject ||= opts[:subject] name = opts[:name] type = opts[:type] domain = opts[:domain] @subject = _create_name(name, type, domain) end if key = opts[:key] @digest = opts[:digest] || self.class._create_digest end if @cert self.key = key if key # this verifies that key is the right one for this cert else #@cert ||= _create_x509_cert(@address, @subject, @key, @digest)[:cert] @cert = self.class._create_x509_cert(@subject, key, @digest)[:cert] @key = key end end |
Instance Attribute Details
- (Object) addresses (readonly)
:addresses_raw, :addresses_string
210 211 212 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 210 def addresses @addresses end |
- (Object) digest (readonly)
Returns the value of attribute digest
211 212 213 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 211 def digest @digest end |
- (Object) key
Returns the value of attribute key
211 212 213 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 211 def key @key end |
- (Object) resource_id
:addresses_raw, :addresses_string
210 211 212 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 210 def resource_id @resource_id end |
- (Object) subject (readonly)
Returns the value of attribute subject
211 212 213 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 211 def subject @subject end |
Class Method Details
+ (Object) _create_digest
152 153 154 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 152 def self._create_digest OpenSSL::Digest::SHA1.new end |
+ (Object) _create_key(size = 2048)
Returns an array with a new RSA key and a SHA1 digest
148 149 150 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 148 def self._create_key(size = 2048) [OpenSSL::PKey::RSA.new(size), OpenSSL::Digest::SHA1.new] end |
+ (cert, key) _create_x509_cert(subject, key, digest = nil, issuer = nil, not_before = Time.now, duration = DEF_DURATION, addresses = [])
Create a X509 certificate
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 163 def self._create_x509_cert(subject, key, digest = nil, issuer = nil, not_before = Time.now, duration = DEF_DURATION, addresses = []) if key.nil? key, digest = _create_key() else digest = _create_digest end cert = OpenSSL::X509::Certificate.new cert.version = 2 # TODO change serial to non-sequential secure random numbers for production use cert.serial = UUIDTools::UUID.random_create.to_i cert.subject = subject cert.public_key = key.public_key cert.not_before = not_before cert.not_after = not_before + duration.to_i #extensions << ["subjectAltName", "URI:http://foo.com/users/dc766130, URI:frcp:dc766130-c822-11e0-901e-000c29f89f7b@foo.com", false] issuer_cert = issuer ? issuer.to_x509 : cert ef = OpenSSL::X509::ExtensionFactory.new ef.subject_certificate = cert ef.issuer_certificate = issuer_cert unless addresses.empty? cert.add_extension(ef.create_extension("subjectAltName", addresses.join(','), false)) end if issuer cert.issuer = issuer.subject cert.sign(issuer.key, issuer.digest) else # self signed cert.issuer = subject # Not exactly sure if that's the right extensions to add. Copied from # http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/X509/Certificate.html cert.add_extension(ef.create_extension("basicConstraints", "CA:TRUE", true)) cert.add_extension(ef.create_extension("keyUsage", "keyCertSign, cRLSign", true)) cert.add_extension(ef.create_extension("subjectKeyIdentifier", "hash", false)) cert.add_extension(ef.create_extension("authorityKeyIdentifier", "keyid:always", false)) # Signing the cert should be ABSOLUTELY the last step cert.sign(key, digest) end { cert: cert, key: key } end |
+ (Object) create_for_resource(resource_id, resource_type, issuer, opts = {})
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 56 def self.create_for_resource(resource_id, resource_type, issuer, opts = {}) xname = @@def_x509_name_prefix.dup xname << ['CN', opts[:cn] || resource_id] subject = OpenSSL::X509::Name.new(xname) if key = opts[:key] digest = _create_digest else key, digest = _create_key() end addresses = opts[:addresses] || [] addresses << "URI:uuid:#{opts[:resource_uuid]}" if opts[:resource_uuid] email_domain = opts[:email] ? opts[:email].split('@')[1] : @@def_email_domain addresses << (opts[:geni_uri] || "URI:urn:publicid:IDN+#{email_domain}+#{resource_type}+#{resource_id}") if frcp_uri = opts[:frcp_uri] unless frcp_uri.to_s.start_with? 'URI' frcp_uri = "URI:frcp:#{frcp_uri}" end addresses << frcp_uri end # opts[:frcp_uri] || "URI:frcp:#{user_id}@#{opts[:frcp_domain] || @@def_email_domain}", # opts[:http_uri] || "URI:http://#{opts[:http_prefix] || @@def_email_domain}/users/#{user_id}" not_before = opts[:not_before] || Time.now duration = opts[:duration] || 3600 c = _create_x509_cert(subject, key, digest, issuer, not_before, duration, addresses) c[:addresses] = addresses c[:resource_id] = resource_id c[:subject] = subject self.new c end |
+ (Certificate) create_from_pem(pem_s)
Return a newly create certificate with properties token from 'pem' encoded string.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 106 def self.create_from_pem(pem_s) state = :seeking cert_pem = [] key_pem = [] end_regexp = /^-*END/ pem_s.each_line do |line| state = :seeking if line.match(end_regexp) case state when :seeking case line when /^-*BEGIN CERTIFICATE/ state = :cert when /^-*BEGIN RSA PRIVATE KEY/ state = :key end when :cert cert_pem << line when :key key_pem << line else raise "BUG: Unknown state '#{state}'" end end # Some command list generated cert can use \r\n as newline char cert_pem = cert_pem.join() unless cert_pem =~ /^-----BEGIN CERTIFICATE-----/ cert_pem = "#{BEGIN_CERT}#{cert_pem.chomp}#{END_CERT}" end opts = {} opts[:cert] = OpenSSL::X509::Certificate.new(cert_pem) if key_pem.size > 0 key_pem = key_pem.join() unless key_pem =~ /^-----BEGIN RSA PRIVATE KEY-----/ key_pem = "#{BEGIN_KEY}#{key_pem.chomp}#{END_KEY}" end opts[:key] = OpenSSL::PKey::RSA.new(key_pem) end self.new(opts) end |
+ (Object) create_root(opts = {})
88 89 90 91 92 93 94 95 96 97 98 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 88 def self.create_root(opts = {}) email = opts[:email] ||= "sa@#{@@def_email_domain}" opts = { addresses: [ "email:#{email}" ] }.merge(opts) cert = create_for_resource('sa', :authority, nil, opts) CertificateStore.instance.register_trusted(cert) cert end |
+ (Object) default_domain(country, state, organisation, org_unit)
27 28 29 30 31 32 33 34 35 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 27 def self.default_domain(country, state, organisation, org_unit) @@def_x509_name_prefix = [ ['C', c = country.upcase], ['ST', st = state.upcase], ['O', o = organisation], ['OU', ou = org_unit] ] "/C=#{c}/ST=#{st}/O=#{o}/OU=#{ou}" end |
+ (Object) default_email_domain(email_domain)
37 38 39 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 37 def self.default_email_domain(email_domain) @@def_email_domain = email_domain end |
Instance Method Details
- (Object) _extract_addresses(cert)
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 351 def _extract_addresses(cert) addr = @addresses = {} return unless cert ext = cert.extensions.find { |ext| ext.oid == 'subjectAltName' } return unless ext @address_string = ext.value @addresses_raw = ext.value.split(',').compact @addresses_raw.each do |addr_s| parts = addr_s.split(':') #puts ">>>>>> #{parts}" case parts[0].strip when 'email' addr[:email] = parts[1] when 'URI' if parts[1] == 'urn' parts[2] == 'publicid' ? addr[:geni] = parts[3][4 .. -1] : addr[parts[2].to_sym] = parts[3] else addr[parts[1].to_sym] = parts[2] end else warn "Unknown address type '#{parts[0]}'" end end end |
- (Boolean) can_sign?
295 296 297 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 295 def can_sign? !cert_expired? && !@key.nil? && @key.private? end |
- (Boolean) cert_expired?
243 244 245 246 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 243 def cert_expired? error "Certificate expired!" unless valid? !valid? end |
- (Object) create_for_resource(resource_id, resource_type, opts = {})
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 255 def create_for_resource(resource_id, resource_type, opts = {}) unless valid? raise CertificateNoLongerValidException.new end resource_id ||= UUIDTools::UUID.random_create() unless opts[:resource_uuid] if resource_id.is_a? UUIDTools::UUID opts[:resource_uuid] = resource_id else opts[:resource_uuid] = UUIDTools::UUID.random_create() end end unless opts[:cn] opts[:cn] = "#{resource_id}/type=#{resource_type}" (opts[:cn] += "/uuid=#{opts[:resource_uuid]}") unless resource_id.is_a? UUIDTools::UUID end cert = self.class.create_for_resource(resource_id, resource_type, self, opts) CertificateStore.instance.register(cert) cert end |
- (Object) create_for_user(name, opts = {})
See #create_for_resource for documentation on 'opts'
277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 277 def create_for_user(name, opts = {}) unless valid? raise CertificateNoLongerValidException.new end email = opts[:email] || "#{name}@#{@@def_email_domain}" user_id = opts[:user_id] || UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, email) opts[:cn] = "#{user_id}/emailAddress=#{email}" opts[:addresses] = [ "email:#{email}", ] create_for_resource(user_id, :user, opts) end |
- (Object) describe
Return a hash of some of the key properties of this cert. To get the full monty, use 'openssl x509 -in xxx.pem -text'
326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 326 def describe { subject: subject, issuer: @cert.issuer, addresses: addresses, can_sign: can_sign?, root_ca: root_ca?, valid: valid?, valid_period: [@cert.not_before, @cert.not_after] } #(@cert.methods - Object.new.methods).sort end |
- (Boolean) root_ca?
299 300 301 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 299 def root_ca? subject == @cert.issuer end |
- (Object) to_pem
303 304 305 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 303 def to_pem to_x509.to_pem end |
- (Object) to_pem_compact
311 312 313 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 311 def to_pem_compact to_pem.lines.to_a[1 ... -1].join.strip end |
- (Object) to_pem_with_key
307 308 309 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 307 def to_pem_with_key to_x509.to_pem + @key.to_pem end |
- (Object) to_s
Will return one of the following
:HS256, :HS384, :HS512, :RS256, :RS384, :RS512, :ES256, :ES384, :ES512
def key_algorithm
end
347 348 349 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 347 def to_s "#<#{self.class} subj=#{@subject} can-sign=#{@key != nil}>" end |
- (Object) to_x509
Return the X509 certificate. If it hasn't been passed in, return a self-signed one
291 292 293 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 291 def to_x509() @cert end |
- (Boolean) valid?
238 239 240 241 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 238 def valid? now = Time.new (@cert.not_before <= now && now <= @cert.not_after) end |
- (Object) verify_cert
315 316 317 318 319 320 321 |
# File 'omf_common/lib/omf_common/auth/certificate.rb', line 315 def verify_cert if @cert.issuer == self.subject # self signed cert @cert.verify(@cert.public_key) else @cert.verify(CertificateStore.instance.cert_for(@cert.issuer).to_x509.public_key) end end |