Unverified Commit 3c854184 authored by Tim Smith's avatar Tim Smith Committed by GitHub
Browse files

Merge pull request #76 from juju482/master

openssl_x509_crl resource & fixes
parents fc8f79b6 c0792d83
......@@ -11,6 +11,7 @@ This cookbook provides tools for working with the Ruby OpenSSL library. It inclu
- A resource for generating EC public keys.
- A resource for generating x509 certificates.
- A resource for generating x509 requests.
- A resource for generating x509 crl.
- A resource for generating dhparam.pem files.
- An attribute-driven recipe for upgrading OpenSSL packages.
......@@ -101,20 +102,20 @@ Name | Type | Description
`country` | String (Optional) | Value for the `C` ssl field.
`email` | String (Optional) | Value for the `email` ssl field.
`expire` | Integer (Optional) | Value representing the number of days from _now_ through which the issued certificate cert will remain valid. The certificate will expire after this period. _Default: 365
`extensions` | Hash (Optional) | Hash of X509 Extensions entries, in format `{ 'keyUsage' => { 'values' => %w( keyEncipherment digitalSignature), 'critical' => true } }`
`extensions` | Hash (Optional) | Hash of X509 Extensions entries, in format `{ 'keyUsage' => { 'values' => %w( keyEncipherment digitalSignature), 'critical' => true } }` _Default: empty_
`subject_alt_name` | Array (Optional) | Array of _Subject Alternative Name_ entries, in format `DNS:example.com` or `IP:1.2.3.4` _Default: empty_
`key_file` | String (Optional) | The path to a certificate key file on the filesystem. If the `key_file` attribute is specified, the resource will attempt to source a key from this location. If no key file is found, the resource will generate a new key file at this location. If the `key_file` attribute is not specified, the resource will generate a key file in the same directory as the generated certificate, with the same name as the generated certificate.
`key_pass` | String (Optional) | The passphrase for an existing key's passphrase
`key_type` | String (Optional) | The desired type of the generated key (rsa or ec). _Default: ec_
`key_type` | String (Optional) | The desired type of the generated key (rsa or ec). _Default: rsa_
`key_length` | Integer (Optional) | The desired Bit Length of the generated key (if key_type is equal to 'rsa'). _Default: 2048_
`key_curve` | String (Optional) | The desired curve of the generated key (if key_type is equal to 'ec'). Run `openssl ecparam -list_curves` to see available options. _Default: prime256v1
`key_curve` | String (Optional) | The desired curve of the generated key (if key_type is equal to 'ec'). Run `openssl ecparam -list_curves` to see available options. _Default: prime256v1_
`csr_file` | String (Optional) | The path to a X509 Certificate Request (CSR) on the filesystem. If the `csr_file` attribute is specified, the resource will attempt to source a CSR from this location. If no CSR file is found, the resource will generate a Self-Signed Certificate and the certificate fields must be specified (common_name at last).
`ca_cert_file` | String (Optionel) | The path to the CA X509 Certificate on the filesystem. If the `ca_cert_file` attribute is specified, the `ca_key_file` attribute must also be specified, the certificate will be signed with them.
`ca_key_file` | String (Optionel) | The path to the CA private key on the filesystem. If the `ca_key_file` attribute is specified, the `ca_cert_file' attribute must also be specified, the certificate will be signed with them.
`ca_key_pass` | String (Optionel) | The passphrase for CA private key's passphrase
`ca_cert_file` | String (Optional) | The path to the CA X509 Certificate on the filesystem. If the `ca_cert_file` attribute is specified, the `ca_key_file` attribute must also be specified, the certificate will be signed with them.
`ca_key_file` | String (Optional) | The path to the CA private key on the filesystem. If the `ca_key_file` attribute is specified, the `ca_cert_file' attribute must also be specified, the certificate will be signed with them.
`ca_key_pass` | String (Optional) | The passphrase for CA private key's passphrase
`owner` | String (optional) | The owner of all files created by the resource. _Default: "root"_
`group` | String (optional) | The group of all files created by the resource. _Default: "root"_
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0400"_
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0644"_
#### Example Usage
......@@ -160,10 +161,8 @@ When executed, this recipe will generate a key certificate at `/etc/ssl_test/my_
### openssl_x509_request
This resource generates PEM-formatted x509 certificates requests. If no existing key is specified, the resource will automatically generate a passwordless key with the certificate.
#### Properties
Name | Type | Description
......@@ -187,6 +186,8 @@ Name | Type | Desc
#### Example Usage
In this example, an administrator wishes to create a x509 CRL. In order to create the CRL, the administrator crafts this recipe:
```ruby
openssl_x509_request '/etc/ssl_test/my_ec_request.csr' do
common_name 'myecrequest.example.com'
......@@ -198,6 +199,50 @@ end
When executed, this recipe will generate a key certificate at `/etc/httpd/ssl/my_ec_request.key`. It will then use that key to generate a new csr file at `/etc/ssl_test/my_ec_request.csr`.
### openssl_x509_crl
This resource generates PEM-formatted x509 CRL.
#### Properties
Name | Type | Description
--------------------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------
`path` | String (Optional) | Optional path to write the file to if you'd like to specify it here instead of in the resource name
`serial_to_revoke` | String or Integer(Optional) | Serial of the X509 Certificate to revoke
`revokation_reason` | String or Integer(Optional) | [Reason of the revokation]((https://en.wikipedia.org/wiki/Certificate_revocation_list#Reasons_for_revocation)) _Default: 0_
`expire` | Integer (Optional) | Value representing the number of days from _now_ through which the issued CRL will remain valid. The CRL will expire after this period. _Default: 8_
`renewal_threshold` | Integer (Optional) | Number of days before the expiration. It this threshold is reached, the CRL will be renewed _Default: 1_
`ca_cert_file` | String (Required) | The path to the CA X509 Certificate on the filesystem. If the `ca_cert_file` attribute is specified, the `ca_key_file` attribute must also be specified, the CRL will be signed with them.
`ca_key_file` | String (Required) | The path to the CA private key on the filesystem. If the `ca_key_file` attribute is specified, the `ca_cert_file' attribute must also be specified, the CRL will be signed with them.
`ca_key_pass` | String (Optional) | The passphrase for CA private key's passphrase
`owner` | String (optional) | The owner of all files created by the resource. _Default: "root"_
`group` | String (optional) | The group of all files created by the resource. _Default: "root"_
`mode` | String or Integer (Optional) | The permission mode of all files created by the resource. _Default: "0644"_
#### Example Usage
In this example, an administrator wishes to create an empty X509 CRL. In order to create the CRL, the administrator crafts this recipe:
```ruby
openssl_x509_crl '/etc/ssl_test/my_ca.crl' do
ca_cert_file '/etc/ssl_test/my_ca.crt'
ca_key_file '/etc/ssl_test/my_ca.key'
end
```
When executed, this recipe will generate a new CRL file at `/etc/ssl_test/my_ca.crl`.
In this example, an administrator wishes to revoke a certificate in an existing X509 CRL.
```ruby
openssl_x509_crl '/etc/ssl_test/my_ca.crl' do
ca_cert_file '/etc/ssl_test/my_ca.crt'
ca_key_file '/etc/ssl_test/my_ca.key'
serial_to_revoke C7BCB6602A2E4251EF4E2827A228CB52BC0CEA2F
end
```
### openssl_dhparam
This resource generates dhparam.pem files. If a valid dhparam.pem file is found at the specified location, no new file will be created. If a file is found at the specified location but it is not a valid dhparam file, it will be overwritten.
......
......@@ -18,6 +18,8 @@ platforms:
driver:
image: dokken/amazonlinux
pid_one_command: /sbin/init
intermediate_instructions:
- RUN /usr/bin/yum -y install diffutils
- name: debian-8
driver:
......
......@@ -44,10 +44,47 @@ module OpenSSLCookbook
begin
key = OpenSSL::PKey.read key_content, key_password
rescue OpenSSL::PKey::PKeyError
rescue OpenSSL::PKey::PKeyError, ArgumentError
return false
end
key.private?
if key.is_a?(OpenSSL::PKey::EC)
key.private_key?
else
key.private?
end
end
# given a crl file path see if it's actually a crl
# @param [String] crl_file the path to the crlfile
# @return [Boolean] is the key valid?
def crl_file_valid?(crl_file)
begin
OpenSSL::X509::CRL.new ::File.read(crl_file)
rescue OpenSSL::X509::CRLError, Errno::ENOENT
return false
end
true
end
# check is a serial given is revoked in a crl given
# @param [OpenSSL::X509::CRL] crl X509 CRL to check
# @param [String, Integer] serial X509 Certificate Serial Number
# @return [true, false]
def serial_revoked?(crl, serial)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(OpenSSL::X509::CRL)
raise TypeError, 'serial must be a Ruby String or Integer object' unless serial.is_a?(String) || serial.is_a?(Integer)
serial_to_verify = if serial.is_a?(String)
serial.to_i(16)
else
serial
end
status = false
crl.revoked.each do |revoked|
status = true if revoked.serial == serial_to_verify
end
status
end
# generate a dhparam file
......@@ -103,7 +140,7 @@ module OpenSSLCookbook
def gen_ec_priv_key(curve)
raise TypeError, 'curve must be a string' unless curve.is_a?(String)
raise ArgumentError, 'Specified curve is not available on this system' unless curve == 'prime256v1' || curve == 'secp384r1' || curve == 'secp521r1'
OpenSSL::PKey::EC.generate(curve)
OpenSSL::PKey::EC.new(curve).generate_key
end
# generate pem format of the public key given a private key
......@@ -158,6 +195,9 @@ module OpenSSLCookbook
request.subject = subject
request.public_key = key
# Chef 12 backward compatibility
OpenSSL::PKey::EC.send(:alias_method, :private?, :private_key?)
request.sign(key, OpenSSL::Digest::SHA256.new)
request
end
......@@ -198,6 +238,9 @@ module OpenSSLCookbook
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise TypeError, 'key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless key.is_a?(OpenSSL::PKey::EC) || key.is_a?(OpenSSL::PKey::RSA)
raise ArgumentError, 'info must contain a validity' unless info.key?('validity')
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
cert = OpenSSL::X509::Certificate.new
ef = OpenSSL::X509::ExtensionFactory.new
......@@ -213,6 +256,7 @@ module OpenSSLCookbook
ef.issuer_certificate = cert
extension << ef.create_extension('basicConstraints', 'CA:TRUE', true)
else
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(OpenSSL::X509::Certificate)
cert.issuer = info['issuer'].subject
ef.issuer_certificate = info['issuer']
end
......@@ -227,5 +271,113 @@ module OpenSSLCookbook
cert.sign(key, OpenSSL::Digest::SHA256.new)
cert
end
# generate a X509 CRL given a CA
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def gen_x509_crl(ca_private_key, info)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(OpenSSL::PKey::EC) || ca_private_key.is_a?(OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
crl = OpenSSL::X509::CRL.new
ef = OpenSSL::X509::ExtensionFactory.new
crl.version = 1
crl.issuer = info['issuer'].subject
crl.last_update = Time.now
crl.next_update = Time.now + 3600 * 24 * info['validity']
ef.config = OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE)
ef.issuer_certificate = info['issuer']
crl.add_extension OpenSSL::X509::Extension.new('crlNumber', OpenSSL::ASN1::Integer(1))
crl.add_extension ef.create_extension('authorityKeyIdentifier',
'keyid:always,issuer:always')
crl.sign(ca_private_key, OpenSSL::Digest::SHA256.new)
crl
end
# generate the next CRL number available for a X509 CRL given
# @param [OpenSSL::X509::CRL] crl x509 CRL
# @return [Integer]
def get_next_crl_number(crl)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(OpenSSL::X509::CRL)
crlnum = 1
crl.extensions.each do |e|
crlnum = e.value if e.oid == 'crlNumber'
end
crlnum.to_i + 1
end
# add a serial given in the crl given
# @param [Hash] revoke_info serial to revoke & revokation reason
# @param [OpenSSL::X509::CRL] crl X509 CRL
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def revoke_x509_crl(revoke_info, crl, ca_private_key, info)
raise TypeError, 'revoke_info must be a Ruby Hash oject' unless revoke_info.is_a?(Hash)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(OpenSSL::X509::CRL)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(OpenSSL::PKey::EC) || ca_private_key.is_a?(OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'revoke_info must contain a serial and a reason' unless revoke_info.key?('serial') && revoke_info.key?('reason')
raise TypeError, 'revoke_info[\'serial\'] must be a Ruby String or Integer object' unless revoke_info['serial'].is_a?(String) || revoke_info['serial'].is_a?(Integer)
raise TypeError, 'revoke_info[\'reason\'] must be a Ruby Integer object' unless revoke_info['reason'].is_a?(Integer)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
revoked = OpenSSL::X509::Revoked.new
revoked.serial = if revoke_info['serial'].is_a?(String)
revoke_info['serial'].to_i(16)
else
revoke_info['serial']
end
revoked.time = Time.now
ext = OpenSSL::X509::Extension.new('CRLReason',
OpenSSL::ASN1::Enumerated(revoke_info['reason']))
revoked.add_extension(ext)
crl.add_revoked(revoked)
crl = renew_x509_crl(crl, ca_private_key, info)
crl
end
# renew a X509 crl given
# @param [OpenSSL::X509::CRL] crl CRL to renew
# @param [OpenSSL::PKey::EC, OpenSSL::PKey::RSA] ca_private_key private key from the CA
# @param [Hash] info issuer & validity
# @return [OpenSSL::X509::CRL]
def renew_x509_crl(crl, ca_private_key, info)
raise TypeError, 'crl must be a Ruby OpenSSL::X509::CRL object' unless crl.is_a?(OpenSSL::X509::CRL)
raise TypeError, 'ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object' unless ca_private_key.is_a?(OpenSSL::PKey::EC) || ca_private_key.is_a?(OpenSSL::PKey::RSA)
raise TypeError, 'info must be a Ruby Hash' unless info.is_a?(Hash)
raise ArgumentError, 'info must contain a issuer and a validity' unless info.key?('issuer') && info.key?('validity')
raise TypeError, 'info[\'issuer\'] must be a Ruby OpenSSL::X509::Certificate object' unless info['issuer'].is_a?(OpenSSL::X509::Certificate)
raise TypeError, 'info[\'validity\'] must be a Ruby Integer object' unless info['validity'].is_a?(Integer)
crl.last_update = Time.now
crl.next_update = crl.last_update + 3600 * 24 * info['validity']
ef = OpenSSL::X509::ExtensionFactory.new
ef.config = OpenSSL::Config.load(OpenSSL::Config::DEFAULT_CONFIG_FILE)
ef.issuer_certificate = info['issuer']
crl.extensions = [ OpenSSL::X509::Extension.new('crlNumber',
OpenSSL::ASN1::Integer(get_next_crl_number(crl)))]
crl.add_extension ef.create_extension('authorityKeyIdentifier',
'keyid:always,issuer:always')
crl.sign(ca_private_key, OpenSSL::Digest::SHA256.new)
crl
end
end
end
......@@ -13,9 +13,9 @@ default_action :create
action :create do
raise ArgumentError, "You cannot specify both 'private_key_path' and 'private_key_content' properties at the same time." if new_resource.private_key_path && new_resource.private_key_content
raise ArgumentError, "You must specify the private key with either 'private_key_path' or 'private_key_content' properties." unless new_resource.private_key_path || new_resource.private_key_content
raise "#{new_resource.private_key_path} not a valid private RSA key or password is invalid" unless priv_key_file_valid?((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
raise "#{new_resource.private_key_path} not a valid private EC key or password is invalid" unless priv_key_file_valid?((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
ec_key_content = gen_ec_public_key((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
ec_key_content = gen_ec_pub_key((new_resource.private_key_path || new_resource.private_key_content), new_resource.private_key_pass)
file new_resource.name do
action :create
......
include OpenSSLCookbook::Helpers
property :path, String, name_property: true
property :serial_to_revoke, [Integer, String]
property :revocation_reason, Integer, default: 0
property :expire, Integer, default: 8
property :renewal_threshold, Integer, default: 1
property :ca_cert_file, String, required: true
property :ca_key_file, String, required: true
property :ca_key_pass, String
property :owner, String, default: 'root'
property :group, String, default: 'root'
property :mode, String, default: '0644'
action :create do
file new_resource.path do
owner new_resource.owner
group new_resource.group
mode new_resource.mode
content crl.to_pem
action :create
end
end
action_class do
def crl_info
# Will contain issuer & expiration
crl_info = {}
crl_info['issuer'] = OpenSSL::X509::Certificate.new ::File.read(new_resource.ca_cert_file)
crl_info['validity'] = new_resource.expire
crl_info
end
def revoke_info
# Will contain Serial to revoke & reason
revoke_info = {}
revoke_info['serial'] = new_resource.serial_to_revoke
revoke_info['reason'] = new_resource.revocation_reason
revoke_info
end
def ca_private_key
ca_private_key = OpenSSL::PKey.read ::File.read(new_resource.ca_key_file), new_resource.ca_key_pass
ca_private_key
end
def crl
if crl_file_valid?(new_resource.path)
crl = OpenSSL::X509::CRL.new ::File.read(new_resource.path)
else
log "Creating a CRL #{new_resource.path} for CA #{new_resource.ca_cert_file}"
crl = gen_x509_crl(ca_private_key, crl_info)
end
if !new_resource.serial_to_revoke.nil? && serial_revoked?(crl, new_resource.serial_to_revoke) == false
log "Revoking serial #{new_resource.serial_to_revoke} in CRL #{new_resource.path}"
crl = revoke_x509_crl(revoke_info, crl, ca_private_key, crl_info)
elsif crl.next_update <= Time.now + 3600 * 24 * new_resource.renewal_threshold
log "Renewing CRL for CA #{new_resource.ca_cert_file}"
crl = renew_x509_crl(crl, ca_private_key, crl_info)
end
crl
end
end
......@@ -171,6 +171,40 @@ describe OpenSSLCookbook::Helpers do
end
end
describe '#crl_file_valid?' do
require 'tempfile'
before(:each) do
@crlfile = Tempfile.new('crlfile')
end
context 'When the crl file doesnt not exist' do
it 'returns false' do
expect(instance.crl_file_valid?('/tmp/bad_filename')).to be_falsey
end
end
context 'When the crl file does exist, but does not contain a valid CRL' do
it 'returns false' do
@crlfile.write('I_am_not_a_crl_I_am_a_free_man')
@crlfile.close
expect(instance.crl_file_valid?(@crlfile.path)).to be_falsey
end
end
context 'When the crl file does exist, and does contain a vaild CRL' do
it 'returns true' do
@crlfile.write("-----BEGIN X509 CRL-----\nMIIBbjCB0QIBATAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANDQTIXDTE4MDgwMTE3\nMjg1NVoXDTE4MDgwOTE3Mjg1NVowNjA0AhUAx7y2YCouQlHvTignoijLUrwM6i8X\nDTE4MDgwMTE3Mjg1NVowDDAKBgNVHRUEAwoBAKBaMFgwCgYDVR0UBAMCAQQwSgYD\nVR0jBEMwQYAUCqE8XxFIFys0LTVPvsO1UtmrlyOhEqQQMA4xDDAKBgNVBAMMA0NB\nMoIVAPneTuAa1LzrK0wiZrxE8/1lSTp3MAoGCCqGSM49BAMCA4GLADCBhwJBct+Z\nZV3IZkPNevQv2S8lZ6kAMudN8R4QSzIQfM354Uk880RyQStP2S5Mb4gW3aFzwAy2\n/+rbx0bn2WmwoQv17I8CQgDtbvhf9chyPgMwAGCF7al04fve90fU1zRNH0zX1j9H\niDA2q1uBX+3TcTWcN+xgNimeRpvJFJ3uOB6w7jtwqGf1YQ==\n-----END X509 CRL-----\n")
@crlfile.close
expect(instance.crl_file_valid?(@crlfile.path)).to be_truthy
end
end
after(:each) do
@crlfile.unlink
end
end
# Generators
describe '#gen_dhparam' do
context 'When given an invalid key length' do
......@@ -492,4 +526,317 @@ describe OpenSSLCookbook::Helpers do
end
end
end
describe '#get_next_crl_number' do
include OpenSSLCookbook::Helpers
before(:all) do
@crl = OpenSSL::X509::CRL. new "-----BEGIN X509 CRL-----\nMIIBbTCB0QIBATAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANDQTIXDTE4MDgwMjA5\nMzc0OFoXDTE4MDgxMDA5Mzc0OFowNjA0AhUAx7y2YCouQlHvTignoijLUrwM6i8X\nDTE4MDgwMjA5Mzc0OFowDDAKBgNVHRUEAwoBAKBaMFgwCgYDVR0UBAMCAQQwSgYD\nVR0jBEMwQYAUxRlLNQUIOeWVaYm6HS0qFIbNCs2hEqQQMA4xDDAKBgNVBAMMA0NB\nMoIVAN1nyw8cj7IbhRLBu2CfS9Q8ILmDMAoGCCqGSM49BAMCA4GKADCBhgJBNR3o\njo/PzFwFGJKxIMa09pU+jprLG2CWehpZ4tGDjwiDCfZBztkg3H15eu+hyWmDp0U9\neAP5iJHVb12/3KZP0YUCQSgmaoLF68+Gh7ha+hcDjwFhzqdgmh/UlGPaxFBJ1BiQ\nQq9uBn0IT4o7v1Tv2WRZNDk7oiuRaZG+R9IodiZPsGKv\n-----END X509 CRL-----\n"
end
context 'When the CRL given is anything other then a Ruby OpenSSL::X509::CRL object' do
it 'Raises a TypeError' do
expect do
instance.get_next_crl_number('abc')
end.to raise_error(TypeError)
end
end
context 'When given valid parameter to get the next crlNumber' do
it 'Get 5' do
@next_crl = instance.get_next_crl_number(@crl)
expect(@next_crl).to be_kind_of(Integer)
expect(@next_crl == 5).to be_truthy
end
end
end
describe '#serial_revoked?' do
include OpenSSLCookbook::Helpers
before(:all) do
@crl = OpenSSL::X509::CRL. new "-----BEGIN X509 CRL-----\nMIIBbTCB0QIBATAKBggqhkjOPQQDAjAOMQwwCgYDVQQDDANDQTIXDTE4MDgwMjA5\nMzc0OFoXDTE4MDgxMDA5Mzc0OFowNjA0AhUAx7y2YCouQlHvTignoijLUrwM6i8X\nDTE4MDgwMjA5Mzc0OFowDDAKBgNVHRUEAwoBAKBaMFgwCgYDVR0UBAMCAQQwSgYD\nVR0jBEMwQYAUxRlLNQUIOeWVaYm6HS0qFIbNCs2hEqQQMA4xDDAKBgNVBAMMA0NB\nMoIVAN1nyw8cj7IbhRLBu2CfS9Q8ILmDMAoGCCqGSM49BAMCA4GKADCBhgJBNR3o\njo/PzFwFGJKxIMa09pU+jprLG2CWehpZ4tGDjwiDCfZBztkg3H15eu+hyWmDp0U9\neAP5iJHVb12/3KZP0YUCQSgmaoLF68+Gh7ha+hcDjwFhzqdgmh/UlGPaxFBJ1BiQ\nQq9uBn0IT4o7v1Tv2WRZNDk7oiuRaZG+R9IodiZPsGKv\n-----END X509 CRL-----\n"
end
context 'When the CRL given is anything other then a Ruby OpenSSL::X509::CRL object' do
it 'Raises a TypeError' do
expect do
instance.serial_revoked?('abc', 'C7BCB6602A2E4251EF4E2827A228CB52BC0CEA2F')
end.to raise_error(TypeError)
end
end
context 'When the serial given is anything other then a Ruby String or Integer object' do
it 'Raises a TypeError' do
expect do
instance.serial_revoked?(@crl, [])
end.to raise_error(TypeError)
end
end
context 'When given valid parameters to know if the serial is revoked' do
it 'get true' do
@serial_revoked = instance.serial_revoked?(@crl, 'C7BCB6602A2E4251EF4E2827A228CB52BC0CEA2F')
expect(@serial_revoked).to be_kind_of(TrueClass)
end
end
end
describe '#gen_x509_crl' do
include OpenSSLCookbook::Helpers
before(:all) do
# Generating CA
@ca_key = OpenSSL::PKey::RSA.new(2048)
@ca_cert = OpenSSL::X509::Certificate.new
@ca_cert.version = 2
@ca_cert.serial = 1
@ca_cert.subject = OpenSSL::X509::Name.new [%w(CN TestCA)]
@ca_cert.issuer = @ca_cert.subject
@ca_cert.public_key = @ca_key.public_key
@ca_cert.not_before = Time.now
@ca_cert.not_after = @ca_cert.not_before + 365 * 24 * 60 * 60
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = @ca_cert
ef.issuer_certificate = @ca_cert
@ca_cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true))
@ca_cert.add_extension(ef.create_extension('keyUsage', 'keyCertSign, cRLSign', true))
@ca_cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
@ca_cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always', false))
@ca_cert.sign(@ca_key, OpenSSL::Digest::SHA256.new)
@info = { 'validity' => 8, 'issuer' => @ca_cert }
end
context 'When the CA private key given is anything other then a Ruby OpenSSL::PKey::EC object or a OpenSSL::PKey::RSA object' do
it 'Raises a TypeError' do
expect do
instance.gen_x509_crl('abc', @info)
end.to raise_error(TypeError)
end
end
context 'When the info given is anything other then a Ruby Hash' do
it 'Raises a TypeError' do
expect do
instance.gen_x509_crl(@ca_key, 'abc')
end.to raise_error(TypeError)
end
end
context 'When a misformatted info Ruby Hash is given' do
it 'Raises a ArgumentError' do
expect do
instance.gen_x509_crl(@ca_key, 'abc' => 'def', 'validity' => 8)
end.to raise_error(ArgumentError)
end
it 'Raises a TypeError' do
expect do
instance.gen_x509_crl(@ca_key, 'issuer' => 'abc', 'validity' => 8)
end.to raise_error(TypeError)
end
it 'Raises a TypeError' do
expect do
instance.gen_x509_crl(@ca_key, 'issuer' => @ca_cert, 'validity' => 'abc')
end.to raise_error(TypeError)
end
end
context 'When given valid parameters to generate a CRL' do
it 'Generates a valid x509 CRL' do
@x509_crl = instance.gen_x509_crl(@ca_key, @info)
expect(@x509_crl).to be_kind_of(OpenSSL::X509::CRL)
expect(OpenSSL::X509::CRL.new(@x509_crl).verify(@ca_key)).to be_truthy
end
end
end
describe '#renew_x509_crl' do
include OpenSSLCookbook::Helpers
before(:all) do
# Generating CA
@ca_key = OpenSSL::PKey::RSA.new(2048)
@ca_cert = OpenSSL::X509::Certificate.new
@ca_cert.version = 2
@ca_cert.serial = 1
@ca_cert.subject = OpenSSL::X509::Name.new [%w(CN TestCA)]
@ca_cert.issuer = @ca_cert.subject
@ca_cert.public_key = @ca_key.public_key
@ca_cert.not_before = Time.now
@ca_cert.not_after = @ca_cert.not_before + 365 * 24 * 60 * 60
ef = OpenSSL::X509::ExtensionFactory.new
ef.subject_certificate = @ca_cert
ef.issuer_certificate = @ca_cert
@ca_cert.add_extension(ef.create_extension('basicConstraints', 'CA:TRUE', true))
@ca_cert.add_extension(ef.create_extension('keyUsage', 'keyCertSign, cRLSign', true))
@ca_cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
@ca_cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always', false))
@ca_cert.sign(@ca_key, OpenSSL::Digest::SHA256.new)
@info = { 'validity' => 8, 'issuer' => @ca_cert }
@crl = gen_x509_crl(@ca_key, @info)
end
context 'When the CRL given is anything other then a Ruby OpenSSL::X509::CRL object' do
it 'Raises a TypeError' do
expect do
instance.renew_x509_crl('abc', @ca_key, @info)
end.to raise_error(TypeError)
end
end
context 'When the CA private key given is anything other then a Ruby OpenSSL::PKey::EC object or a OpenSSL::PKey::RSA object' do
it 'Raises a TypeError' do
expect do
instance.renew_x509_crl(@crl, 'abc', @info)
end.to raise_error(TypeError)