Class: R509::Cert

Inherits:
Object
  • Object
show all
Includes:
IOHelpers
Defined in:
lib/r509/cert.rb,
lib/r509/cert/extensions.rb

Overview

The primary certificate object.

Defined Under Namespace

Modules: Extensions

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from IOHelpers

#read_data, read_data, #write_data, write_data

Constructor Details

- (Cert) initialize(opts = {})

A new instance of Cert

Parameters:

  • opts (Hash) (defaults to: {})

    a customizable set of options

Options Hash (opts):

  • :cert (String, OpenSSL::X509::Certificate)

    a cert

  • :key (R509::PrivateKey, String)

    optional private key to supply. either an unencrypted PEM/DER string or an R509::PrivateKey object (use the latter if you need password/hardware support)

  • :pkcs12 (String)

    a PKCS12 object containing both key and cert

  • :password (String)

    password for PKCS12 or private key (if supplied)



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
# File 'lib/r509/cert.rb', line 17

def initialize(opts={})
  if not opts.kind_of?(Hash)
    raise ArgumentError, 'Must provide a hash of options'
  end
  if opts.has_key?(:pkcs12) and ( opts.has_key?(:key) or opts.has_key?(:cert) )
    raise ArgumentError, "When providing pkcs12, do not pass cert or key"
  elsif opts.has_key?(:pkcs12)
    pkcs12 = OpenSSL::PKCS12.new( opts[:pkcs12], opts[:password] )
    parse_certificate(pkcs12.certificate)
    @key = R509::PrivateKey.new( :key => pkcs12.key )
  elsif not opts.has_key?(:cert)
    raise ArgumentError, 'Must provide :cert or :pkcs12'
  else
    csr_check(opts[:cert])
    parse_certificate(opts[:cert])
  end

  if opts.has_key?(:key)
    if opts[:key].kind_of?(R509::PrivateKey)
      @key = opts[:key]
    else
      @key = R509::PrivateKey.new( :key => opts[:key], :password => opts[:password] )
    end
  end
  if not @key.nil?
    if not @cert.public_key.to_der == @key.public_key.to_der then
      raise R509Error, 'Key does not match cert.'
    end
  end
end

Instance Attribute Details

- (Object) cert (readonly)

Returns the value of attribute cert



11
12
13
# File 'lib/r509/cert.rb', line 11

def cert
  @cert
end

- (Object) key (readonly)

Returns the value of attribute key



11
12
13
# File 'lib/r509/cert.rb', line 11

def key
  @key
end

Class Method Details

+ (R509::Cert) load_from_file(filename)

Helper method to quickly load a cert from the filesystem

Parameters:

  • filename (String)

    Path to file you want to load

Returns:



52
53
54
# File 'lib/r509/cert.rb', line 52

def self.load_from_file( filename )
  return R509::Cert.new(:cert => IOHelpers.read_data(filename) )
end

Instance Method Details

- (R509::Cert::Extensions::AuthorityInfoAccess) authority_info_access

Returns this object's AuthorityInfoAccess extension as an R509 extension

if this cert does not have a AuthorityInfoAccess extension.

Returns:



408
409
410
# File 'lib/r509/cert.rb', line 408

def authority_info_access
  return r509_extensions[R509::Cert::Extensions::AuthorityInfoAccess]
end

- (R509::Cert::Extensions::AuthorityKeyIdentifier) authority_key_identifier

Returns this object's AuthorityKeyIdentifier extension as an R509 extension

if this cert does not have a AuthorityKeyIdentifier extension.

Returns:



392
393
394
# File 'lib/r509/cert.rb', line 392

def authority_key_identifier
  return r509_extensions[R509::Cert::Extensions::AuthorityKeyIdentifier]
end

- (R509::Cert::Extensions::BasicConstraints) basic_constraints

Returns this object's BasicConstraints extension as an R509 extension

if this cert does not have a BasicConstraints extension.

Returns:



360
361
362
# File 'lib/r509/cert.rb', line 360

def basic_constraints
  return r509_extensions[R509::Cert::Extensions::BasicConstraints]
end

- (Integer) bit_strength

Returns the bit strength of the key used to create the certificate

Returns:

  • (Integer)

    integer value of bit strength



237
238
239
240
241
242
243
244
245
# File 'lib/r509/cert.rb', line 237

def bit_strength
  if self.rsa?
    return @cert.public_key.n.num_bits
  elsif self.dsa?
    return @cert.public_key.p.num_bits
  elsif self.ec?
    raise R509::R509Error, 'Bit strength is not available for EC at this time.'
  end
end

- (R509::Cert::Extensions::CrlDistributionPoints) crl_distribution_points

Returns this object's CrlDistributionPoints extension as an R509 extension

if this cert does not have a CrlDistributionPoints extension.

Returns:



416
417
418
# File 'lib/r509/cert.rb', line 416

def crl_distribution_points
  return r509_extensions[R509::Cert::Extensions::CrlDistributionPoints]
end

- (String) curve_name

Returns the short name of the elliptic curve used to generate the public key if the key is EC. If not, raises an error.

Returns:

  • (String)

    elliptic curve name



251
252
253
254
255
256
257
# File 'lib/r509/cert.rb', line 251

def curve_name
  if self.ec?
    @cert.public_key.group.curve_name
  else
    raise R509::R509Error, 'Curve name is only available with EC certs'
  end
end

- (Boolean) dsa?

Returns whether the public key is DSA

Returns:

  • (Boolean)

    true if the public key is DSA, false otherwise



223
224
225
# File 'lib/r509/cert.rb', line 223

def dsa?
  @cert.public_key.kind_of?(OpenSSL::PKey::DSA)
end

- (Boolean) ec?

Returns whether the public key is EC

Returns:

  • (Boolean)

    true if the public key is EC, false otherwise



230
231
232
# File 'lib/r509/cert.rb', line 230

def ec?
  @cert.public_key.kind_of?(OpenSSL::PKey::EC)
end

- (R509::Cert::Extensions::ExtendedKeyUsage) extended_key_usage

Returns this object's ExtendedKeyUsage extension as an R509 extension

if this cert does not have a ExtendedKeyUsage extension.

Returns:



376
377
378
# File 'lib/r509/cert.rb', line 376

def extended_key_usage
  return r509_extensions[R509::Cert::Extensions::ExtendedKeyUsage]
end

- (Array) extensions

Return the certificate extensions

Returns:

  • (Array)

    an array of hashes representing the extensions in the cert



318
319
320
321
322
323
324
325
326
327
# File 'lib/r509/cert.rb', line 318

def extensions
  if @extensions.nil?
    @extensions = Hash.new
    @cert.extensions.each { |extension|
      hash = {'value' => extension.value, 'critical' => extension.critical?}
      @extensions[extension.oid] = hash
    }
  end
  @extensions
end

- (String) fingerprint(algorithm = 'sha1')

Returns the certificate fingerprint with the specified algorithm (default sha1)

Parameters:

  • algorithm (String) (defaults to: 'sha1')

    Which algorithm to use for the fingerprint. See R509::MessageDigest for supported algorithm names

Returns:

  • (String)

    hex digest of the certificate



129
130
131
132
133
134
# File 'lib/r509/cert.rb', line 129

def fingerprint(algorithm='sha1')
  message_digest = R509::MessageDigest.new(algorithm)
  md = message_digest.digest
  md.update(@cert.to_der)
  md.to_s
end

- (Boolean) has_private_key?

Boolean of whether the object contains a private key

Returns:

  • (Boolean)

    Boolean of whether the object contains a private key



168
169
170
171
172
173
174
# File 'lib/r509/cert.rb', line 168

def has_private_key?
  if not @key.nil?
    true
  else
    false
  end
end

- (Boolean) is_revoked_by_crl?(r509_crl)

Checks the given CRL for this certificate's serial number. Note that this does NOT check to verify that the CRL you're checking is signed by the same CA as the cert so do that check yourself

Parameters:

  • r509_crl (R509::Crl)

    A CRL from the CA that issued this certificate.

Returns:

  • (Boolean)


311
312
313
# File 'lib/r509/cert.rb', line 311

def is_revoked_by_crl?( r509_crl )
  return r509_crl.revoked?( self.serial )
end

- (OpenSSL::X509::Name) issuer

Returns the issuer

Returns:

  • (OpenSSL::X509::Name)

    issuer object. Can be parsed as string easily



109
110
111
# File 'lib/r509/cert.rb', line 109

def issuer
  @cert.issuer
end

- (String) issuer_cn

The common name (CN) component of the issuer

Returns:

  • (String)

    The common name (CN) component of the issuer



114
115
116
117
118
119
120
121
122
123
# File 'lib/r509/cert.rb', line 114

def issuer_cn
  return nil if self.issuer.nil?

  self.issuer.to_a.each do |part, value, length|
    return value if part.upcase == 'CN'
  end

  # return nil if we didn't find a CN part
  return nil
end

- (String) key_algorithm

Returns key algorithm (RSA, DSA, EC)

Returns:

  • (String)

    value of the key algorithm. RSA, DSA, EC



269
270
271
272
273
274
275
276
277
# File 'lib/r509/cert.rb', line 269

def key_algorithm
  if self.rsa?
    "RSA"
  elsif self.dsa?
    "DSA"
  elsif self.ec?
    "EC"
  end
end

- (R509::Cert::Extensions::KeyUsage) key_usage

Returns this object's KeyUsage extension as an R509 extension

if this cert does not have a KeyUsage extension.

Returns:



368
369
370
# File 'lib/r509/cert.rb', line 368

def key_usage
  return r509_extensions[R509::Cert::Extensions::KeyUsage]
end

- (Time) not_after

Returns ending (notAfter) of certificate validity period

Returns:

  • (Time)

    time object



95
96
97
# File 'lib/r509/cert.rb', line 95

def not_after
  @cert.not_after
end

- (Time) not_before

Returns beginning (notBefore) of certificate validity period

Returns:

  • (Time)

    time object



81
82
83
# File 'lib/r509/cert.rb', line 81

def not_before
  @cert.not_before
end

- (OpenSSL::PKey::RSA) public_key

Returns the certificate public key

Returns:

  • (OpenSSL::PKey::RSA)

    public key object



102
103
104
# File 'lib/r509/cert.rb', line 102

def public_key
  @cert.public_key
end

- (Hash) r509_extensions

Returns the certificate extensions as a hash of R509::Cert::Extensions specific objects.

R509::Cert::Extensions module, each specific to the extension. The hash is keyed with the R509 extension class. Extensions without an R509 implementation are ignored (see #get_unknown_extensions).

Returns:

  • (Hash)

    A hash, in which the values are classes from the



336
337
338
339
340
341
342
# File 'lib/r509/cert.rb', line 336

def r509_extensions
  if @r509_extensions.nil?
    @r509_extensions = Extensions.wrap_openssl_extensions( self.cert.extensions )
  end

  return @r509_extensions
end

- (Boolean) rsa?

Returns whether the public key is RSA

Returns:

  • (Boolean)

    true if the public key is RSA, false otherwise



216
217
218
# File 'lib/r509/cert.rb', line 216

def rsa?
  @cert.public_key.kind_of?(OpenSSL::PKey::RSA)
end

- (Array) san_names

List of SAN DNS names

Returns:

  • (Array)

    list of SAN DNS names



177
178
179
180
181
182
183
# File 'lib/r509/cert.rb', line 177

def san_names
  if self.subject_alternative_name.nil?
    return []
  else
    return self.subject_alternative_name.dns_names
  end
end

- (Integer) serial

Returns the serial number of the certificate in decimal form

Returns:

  • (Integer)


88
89
90
# File 'lib/r509/cert.rb', line 88

def serial
  @cert.serial.to_i
end

- (String) signature_algorithm

Returns signature algorithm

Returns:

  • (String)

    value of the signature algorithm. E.g. sha1WithRSAEncryption, sha256WithRSAEncryption, md5WithRSAEncryption, et cetera



262
263
264
# File 'lib/r509/cert.rb', line 262

def signature_algorithm
  @cert.signature_algorithm
end

- (OpenSSL::X509::Name) subject

Returns the subject

Returns:

  • (OpenSSL::X509::Name)

    subject object. Can be parsed as string easily



163
164
165
# File 'lib/r509/cert.rb', line 163

def subject
  @cert.subject
end

- (R509::Cert::Extensions::SubjectAlternativeName) subject_alternative_name

Returns this object's SubjectAlternativeName extension as an R509 extension

if this cert does not have a SubjectAlternativeName extension.

Returns:



400
401
402
# File 'lib/r509/cert.rb', line 400

def subject_alternative_name
  return r509_extensions[R509::Cert::Extensions::SubjectAlternativeName]
end

- (String) subject_cn

Returns the CN component, if any, of the subject

Returns:

  • (String)


188
189
190
# File 'lib/r509/cert.rb', line 188

def subject_cn()
  return self.subject_component('CN')
end

- (String) subject_component(short_name)

Returns subject component

Returns:

  • (String)

    value of the subject component requested



195
196
197
198
199
# File 'lib/r509/cert.rb', line 195

def subject_component short_name
  match = @cert.subject.to_a.find { |x| x[0] == short_name }
  return nil if match.nil?
  return match[1]
end

- (R509::Cert::Extensions::SubjectKeyIdentifier) subject_key_identifier

Returns this object's SubjectKeyIdentifier extension as an R509 extension

if this cert does not have a SubjectKeyIdentifier extension.

Returns:



384
385
386
# File 'lib/r509/cert.rb', line 384

def subject_key_identifier
  return r509_extensions[R509::Cert::Extensions::SubjectKeyIdentifier]
end

- (Array) subject_names

Return the CN, as well as all the subject alternative names (SANs).

Returns:

  • (Array)

    the array of names. Returns an empty array if there are no names, at all.



205
206
207
208
209
210
211
# File 'lib/r509/cert.rb', line 205

def subject_names
  ret = []
  ret << subject_cn unless subject_cn.nil?
  ret.concat( self.san_names )

  return ret.sort.uniq
end

- (String) to_der

Converts the Cert into the DER format

Returns:

  • (String)

    the Cert converted into DER format.



72
73
74
75
76
# File 'lib/r509/cert.rb', line 72

def to_der
  if @cert.kind_of?(OpenSSL::X509::Certificate)
    return @cert.to_der
  end
end

- (String) to_pem Also known as: to_s

Converts the Cert into the PEM format

Returns:

  • (String)

    the Cert converted into PEM format.



61
62
63
64
65
# File 'lib/r509/cert.rb', line 61

def to_pem
  if @cert.kind_of?(OpenSSL::X509::Certificate)
    return @cert.to_pem.chomp
  end
end

- (Array) unknown_extensions

Returns an array of OpenSSL::X509::Extension objects representing the extensions that do not have R509 implementations.

Returns:

  • (Array)

    An array of OpenSSL::X509::Extension objects.



348
349
350
# File 'lib/r509/cert.rb', line 348

def unknown_extensions
  return Extensions.get_unknown_extensions( self.cert.extensions )
end

- (Boolean) valid?

Returns whether the current time is between the notBefore and notAfter times in the certificate.

Returns:

  • (Boolean)


140
141
142
# File 'lib/r509/cert.rb', line 140

def valid?
  valid_at?(Time.now)
end

- (Boolean) valid_at?(time)

Returns whether the certificate was between its notBefore and notAfter at the time provided

Parameters:

  • time (Time, Integer)

    Time object or integer timestamp

Returns:

  • (Boolean)


148
149
150
151
152
153
154
155
156
157
158
# File 'lib/r509/cert.rb', line 148

def valid_at?(time)
  if time.kind_of?(Integer)
    time = Time.at(time)
  end

  if (self.not_after < time) or (self.not_before > time)
    false
  else
    true
  end
end

- (Object) write_der(filename_or_io)

Writes the Cert into the DER format

Parameters:

  • filename_or_io (String, #write)

    Either a string of the path for the file that you'd like to write, or an IO-like object.



289
290
291
# File 'lib/r509/cert.rb', line 289

def write_der(filename_or_io)
  write_data(filename_or_io, @cert.to_der)
end

- (Object) write_pem(filename_or_io)

Writes the Cert into the PEM format

Parameters:

  • filename_or_io (String, #write)

    Either a string of the path for the file that you'd like to write, or an IO-like object.



282
283
284
# File 'lib/r509/cert.rb', line 282

def write_pem(filename_or_io)
  write_data(filename_or_io, @cert.to_pem)
end

- (Object) write_pkcs12(filename_or_io, password, friendly_name = 'r509 pkcs12')

Writes cert and key into PKCS12 format using OpenSSL defaults for encryption (des3)

Parameters:

  • filename_or_io (String, #write)

    Either a string of the path for the file that you'd like to write, or an IO-like object.

  • password (String)

    password

  • friendly_name (String) (defaults to: 'r509 pkcs12')

    An optional string to encode in the PKCS12 for friendlyName. defaults to "r509 pkcs12"



298
299
300
301
302
303
304
# File 'lib/r509/cert.rb', line 298

def write_pkcs12(filename_or_io,password,friendly_name='r509 pkcs12')
  if @key.nil?
    raise R509::R509Error, "Writing a PKCS12 requires both key and cert"
  end
  pkcs12 = OpenSSL::PKCS12.create(password,friendly_name,@key.key,@cert)
  write_data(filename_or_io, pkcs12.to_der)
end