Class: R509::PrivateKey

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

Overview

private key management

Constant Summary collapse

KNOWN_TYPES =

a list of key types

["RSA", "DSA", "EC"]
DEFAULT_TYPE =

the default type

"RSA"
DEFAULT_STRENGTH =

default bit length for DSA/RSA

2048
DEFAULT_CURVE =

default curve name for EC

"secp384r1"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IOHelpers

#read_data, read_data, write_data, #write_data

Constructor Details

#initialize(opts = {}) ⇒ PrivateKey

Returns a new instance of PrivateKey.

Parameters:

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

    a customizable set of options

Options Hash (opts):

  • :type (Symbol)

    Defaults to R509::PrivateKey::DEFAULT_TYPE. Allows R509::PrivateKey::KNOWN_TYPES.

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

    Only used if :type is EC

  • :bit_length (Integer) — default: 2048

    Only used if :type is RSA or DSA

  • :bit_strength (Integer) — default: 2048

    Deprecated, identical to bit_length.

  • :password (String)
  • :key (String, OpenSSL::PKey::RSA, OpenSSL::PKey::DSA, OpenSSL::PKey::EC)
  • :engine (OpenSSL::Engine)
  • :key_name (string) — default: used with engine


27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/r509/private_key.rb', line 27

def initialize(opts = {})
  unless opts.is_a?(Hash)
    raise ArgumentError, 'Must provide a hash of options'
  end
  validate_engine(opts)

  if opts.key?(:key)
    validate_key(opts)
  else
    generate_key(opts)
  end
end

Class Method Details

.load_from_file(filename, password = nil) ⇒ R509::PrivateKey

Helper method to quickly load a private key from the filesystem

Parameters:

  • filename (String)

    Path to file you want to load

Returns:



44
45
46
# File 'lib/r509/private_key.rb', line 44

def self.load_from_file(filename, password = nil)
  R509::PrivateKey.new(:key => IOHelpers.read_data(filename), :password => password)
end

Instance Method Details

#bit_lengthInteger Also known as: bit_strength

Returns the bit length of the key

Returns:

  • (Integer)


51
52
53
54
55
56
57
58
59
# File 'lib/r509/private_key.rb', line 51

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

#curve_nameString

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

Returns:

  • (String)

    elliptic curve name



66
67
68
69
70
71
72
# File 'lib/r509/private_key.rb', line 66

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

#dsa?Boolean

Returns whether the key is DSA

Returns:

  • (Boolean)

    true if the key is DSA, false otherwise



183
184
185
# File 'lib/r509/private_key.rb', line 183

def dsa?
  self.key.is_a?(OpenSSL::PKey::DSA)
end

#ec?Boolean

Returns whether the key is EC

Returns:

  • (Boolean)

    true if the key is EC, false otherwise



190
191
192
# File 'lib/r509/private_key.rb', line 190

def ec?
  self.key.is_a?(OpenSSL::PKey::EC)
end

#in_hardware?Boolean

Returns whether the key is resident in hardware or not.

Returns:

  • (Boolean)

    whether the key is resident in hardware or not



84
85
86
87
88
89
90
# File 'lib/r509/private_key.rb', line 84

def in_hardware?
  if @engine
    true
  else
    false
  end
end

#keyOpenSSL::PKey::RSA, ...

Returns this method may return the PKey object itself or a handle to the private key in the HSM (which will not show the private key, just public).

Returns:

  • (OpenSSL::PKey::RSA, OpenSSL::PKey::DSA, OpenSSL::Engine pkey)

    this method may return the PKey object itself or a handle to the private key in the HSM (which will not show the private key, just public)



75
76
77
78
79
80
81
# File 'lib/r509/private_key.rb', line 75

def key
  if in_hardware?
    @engine.load_private_key(@key_name)
  else
    @key
  end
end

#public_keyOpenSSL::PKey::RSA, ... Also known as: to_s

Returns public key.

Returns:



93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/r509/private_key.rb', line 93

def public_key
  if self.ec?
    # OpenSSL::PKey::EC.public_key returns an OpenSSL::PKey::EC::Point, which isn't consistent
    # with the way OpenSSL::PKey::RSA/DSA do it. We could return the original PKey::EC object
    # but if we do that then it has the private_key as well. Here's a ghetto workaround.
    # We have to supply the curve name to the temporary key object or else #public_key= fails
    curve_name = self.key.group.curve_name
    temp_key = OpenSSL::PKey::EC.new(curve_name)
    temp_key.public_key = self.key.public_key
    temp_key
  else
    self.key.public_key
  end
end

#rsa?Boolean

Returns whether the key is RSA

Returns:

  • (Boolean)

    true if the key is RSA, false otherwise



176
177
178
# File 'lib/r509/private_key.rb', line 176

def rsa?
  self.key.is_a?(OpenSSL::PKey::RSA)
end

#to_derString

Converts the key into the DER format

Returns:

  • (String)

    the key converted into DER format.



138
139
140
141
142
143
# File 'lib/r509/private_key.rb', line 138

def to_der
  if in_hardware?
    raise R509::R509Error, "This method cannot be called when using keys in hardware"
  end
  self.key.to_der
end

#to_encrypted_pem(cipher, password) ⇒ String

Converts the key into encrypted PEM format

full list of available ciphers can be obtained with OpenSSL::Cipher.ciphers (common ones are des3, aes256, aes128)

Parameters:

  • cipher (String, OpenSSL::Cipher)

    to use for encryption

  • password (String)

    password

Returns:

  • (String)

    the key converted into encrypted PEM format.



127
128
129
130
131
132
133
# File 'lib/r509/private_key.rb', line 127

def to_encrypted_pem(cipher, password)
  if in_hardware?
    raise R509::R509Error, "This method cannot be called when using keys in hardware"
  end
  cipher = OpenSSL::Cipher::Cipher.new(cipher)
  self.key.to_pem(cipher, password)
end

#to_pemString

Converts the key into the PEM format

Returns:

  • (String)

    the key converted into PEM format.



113
114
115
116
117
118
# File 'lib/r509/private_key.rb', line 113

def to_pem
  if in_hardware?
    raise R509::R509Error, "This method cannot be called when using keys in hardware"
  end
  self.key.to_pem
end

#write_der(filename_or_io) ⇒ Object

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



169
170
171
# File 'lib/r509/private_key.rb', line 169

def write_der(filename_or_io)
  write_data(filename_or_io, self.to_der)
end

#write_encrypted_pem(filename_or_io, cipher, password) ⇒ Object

Writes the key into encrypted PEM format with specified cipher

full list of available ciphers can be obtained with OpenSSL::Cipher.ciphers (common ones are des3, aes256, aes128)

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.

  • cipher (String, OpenSSL::Cipher)

    to use for encryption

  • password (String)

    password



161
162
163
# File 'lib/r509/private_key.rb', line 161

def write_encrypted_pem(filename_or_io, cipher, password)
  write_data(filename_or_io, to_encrypted_pem(cipher, password))
end

#write_pem(filename_or_io) ⇒ Object

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



149
150
151
# File 'lib/r509/private_key.rb', line 149

def write_pem(filename_or_io)
  write_data(filename_or_io, self.to_pem)
end