Class: R509::CSR

Inherits:
Object
  • Object
show all
Includes:
IOHelpers
Defined in:
lib/r509/csr.rb

Overview

The primary certificate signing request object

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

- (CSR) initialize(opts = {})

A new instance of CSR

Examples:

Generate a 4096-bit RSA key + CSR

:type => :rsa,
:bit_strength => 4096,
:subject => [
  ['CN','somedomain.com'],
  ['O','My Org'],
  ['L','City'],
  ['ST','State'],
  ['C','US']
]

Generate an ECDSA key using the secp384r1 curve parameters + CSR and sign with SHA512

:type => :ec,
:curve_name => 'secp384r1',
:message_digest => 'sha512',
:subject => [
  ['CN','somedomain.com'],
]

Parameters:

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

    a customizable set of options

Options Hash (opts):

  • :csr (String, OpenSSL::X509::Request)

    a csr

  • :type (Symbol)

    :rsa/:dsa/:ec required if not providing existing :csr. Defaults to :rsa

  • :curve_name (String) — default: "secp384r1"

    Only used if :type is :ec

  • :bit_strength (Integer) — default: 2048

    Only used if :type is :rsa or :dsa

  • :message_digest (String)

    Optional digest. sha1, sha224, sha256, sha384, sha512, md5. Defaults to sha1

  • :san_names (Array)

    List of domains, IPs, email addresses, or URIs to encode as subjectAltNames. The type is determined from the structure of the strings via the R509::ASN1.general_name_parser method

  • :subject (R509::Subject, Array, OpenSSL::X509::Name)

    array of subject items

  • :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)



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
87
88
89
90
91
92
# File 'lib/r509/csr.rb', line 39

def initialize(opts={})
  if not opts.kind_of?(Hash)
    raise ArgumentError, 'Must provide a hash of options'
  end
    if opts.has_key?(:subject) and opts.has_key?(:csr)
    raise ArgumentError, "You must provide :subject or :csr, not both"
  end
  @bit_strength = opts[:bit_strength] || 2048
  @curve_name = opts[:curve_name] || "secp384r1"

  if opts.has_key?(:key)
    if opts[:key].kind_of?(R509::PrivateKey)
      @key = opts[:key]
    else
      @key = R509::PrivateKey.new(:key => opts[:key])
    end
  end

  @type = opts[:type] || :rsa
  if not [:rsa,:dsa,:ec].include?(@type) and @key.nil?
    raise ArgumentError, 'Must provide :rsa, :dsa, or :ec as type when key is nil'
  end

  if opts.has_key?(:subject)
    san_names = R509::ASN1.general_name_parser(opts[:san_names] || [])
    create_request(opts[:subject], san_names) #sets @req
  elsif opts.has_key?(:csr)
    if opts.has_key?(:san_names)
      raise ArgumentError, "You can't add domains to an existing CSR"
    end
    parse_csr(opts[:csr])
  else
    raise ArgumentError, "You must provide :subject or :csr"
  end

  if dsa?
    #only DSS1 is acceptable for DSA signing in OpenSSL < 1.0
    #post-1.0 you can sign with anything, but let's be conservative
    #see: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/PKey/DSA.html
    @message_digest = R509::MessageDigest.new('dss1')
  elsif opts.has_key?(:message_digest)
    @message_digest = R509::MessageDigest.new(opts[:message_digest])
  else
    @message_digest = R509::MessageDigest.new('sha1')
  end

  if not opts.has_key?(:csr)
    @req.sign(@key.key, @message_digest.digest)
  end
  if not @key.nil? and not @req.verify(@key.public_key) then
    raise R509Error, 'Key does not match request.'
  end

end

Instance Attribute Details

- (Object) attributes (readonly)

Returns the value of attribute attributes



13
14
15
# File 'lib/r509/csr.rb', line 13

def attributes
  @attributes
end

- (Object) key (readonly)

Returns the value of attribute key



13
14
15
# File 'lib/r509/csr.rb', line 13

def key
  @key
end

- (Object) message_digest (readonly)

Returns the value of attribute message_digest



13
14
15
# File 'lib/r509/csr.rb', line 13

def message_digest
  @message_digest
end

- (Object) req (readonly)

Returns the value of attribute req



13
14
15
# File 'lib/r509/csr.rb', line 13

def req
  @req
end

- (Object) san (readonly)

Returns the value of attribute san



13
14
15
# File 'lib/r509/csr.rb', line 13

def san
  @san
end

- (Object) subject (readonly)

Returns the value of attribute subject



13
14
15
# File 'lib/r509/csr.rb', line 13

def subject
  @subject
end

Class Method Details

+ (R509::CSR) load_from_file(filename)

Helper method to quickly load a CSR from the filesystem

Parameters:

  • filename (String)

    Path to file you want to load

Returns:



98
99
100
# File 'lib/r509/csr.rb', line 98

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

Instance Method Details

- (Integer) bit_strength

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

Returns:

  • (Integer)

    the integer bit strength.



179
180
181
182
183
184
185
186
187
# File 'lib/r509/csr.rb', line 179

def bit_strength
  if self.rsa?
    return @req.public_key.n.num_bits
  elsif self.dsa?
    return @req.public_key.p.num_bits
  elsif self.ec?
    raise R509::R509Error, 'Bit strength is not available for EC at this time.'
  end
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



193
194
195
196
197
198
199
# File 'lib/r509/csr.rb', line 193

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

- (Boolean) dsa?

Returns whether the public key is DSA

Returns:

  • (Boolean)

    true if the public key is DSA, false otherwise



166
167
168
# File 'lib/r509/csr.rb', line 166

def dsa?
  @req.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



173
174
175
# File 'lib/r509/csr.rb', line 173

def ec?
  @req.public_key.kind_of?(OpenSSL::PKey::EC)
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



116
117
118
119
120
121
122
# File 'lib/r509/csr.rb', line 116

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

- (Symbol) key_algorithm

Returns key algorithm (RSA/DSA/EC)

Returns:

  • (Symbol)

    value of the key algorithm. :rsa, :dsa, :ec



223
224
225
226
227
228
229
230
231
# File 'lib/r509/csr.rb', line 223

def key_algorithm
  if @req.public_key.kind_of? OpenSSL::PKey::RSA then
    :rsa
  elsif @req.public_key.kind_of? OpenSSL::PKey::DSA then
    :dsa
  elsif @req.public_key.kind_of? OpenSSL::PKey::EC then
    :ec
  end
end

- (OpenSSL::PKey::RSA, ...) public_key

Public key

Returns:

  • (OpenSSL::PKey::RSA, OpenSSL::PKey::DSA, OpenSSL::PKey::EC)

    public key



103
104
105
106
107
# File 'lib/r509/csr.rb', line 103

def public_key
  if(@req.kind_of?(OpenSSL::X509::Request)) then
    @req.public_key
  end
end

- (Boolean) rsa?

Returns whether the public key is RSA

Returns:

  • (Boolean)

    true if the public key is RSA, false otherwise



159
160
161
# File 'lib/r509/csr.rb', line 159

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

- (String) signature_algorithm

Returns signature algorithm

Returns:

  • (String)

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



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

def signature_algorithm
  @req.signature_algorithm
end

- (String) subject_component(short_name)

Returns subject component

Returns:

  • (String)

    value of the subject component requested



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

def subject_component short_name
  @req.subject.to_a.each do |element|
    if element[0].downcase == short_name.downcase then
      return element[1]
    end
  end
  nil
end

- (String) to_der

Converts the CSR into the DER format

Returns:

  • (String)

    the CSR converted into DER format.



136
137
138
# File 'lib/r509/csr.rb', line 136

def to_der
  @req.to_der
end

- (String) to_pem Also known as: to_s

Converts the CSR into the PEM format

Returns:

  • (String)

    the CSR converted into PEM format.



127
128
129
# File 'lib/r509/csr.rb', line 127

def to_pem
  @req.to_pem
end

- (Boolean) verify_signature

Verifies the integrity of the signature on the request

Returns:

  • (Boolean)


111
112
113
# File 'lib/r509/csr.rb', line 111

def verify_signature
  @req.verify(public_key)
end

- (Object) write_der(filename_or_io)

Writes the CSR 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.



152
153
154
# File 'lib/r509/csr.rb', line 152

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

- (Object) write_pem(filename_or_io)

Writes the CSR 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.



144
145
146
# File 'lib/r509/csr.rb', line 144

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