spec/certificate_authority_spec.rb in r509-0.8.1 vs spec/certificate_authority_spec.rb in r509-0.9
- old
+ new
@@ -1,260 +1,678 @@
require 'spec_helper'
describe R509::CertificateAuthority::Signer do
- before :each do
- @cert = TestFixtures::CERT
- @csr = TestFixtures::CSR
- @csr_invalid_signature = TestFixtures::CSR_INVALID_SIGNATURE
- @csr3 = TestFixtures::CSR3
- @test_ca_config = TestFixtures.test_ca_config
- @ca = R509::CertificateAuthority::Signer.new(@test_ca_config)
- @ca_no_profile = R509::CertificateAuthority::Signer.new(TestFixtures.test_ca_no_profile_config)
- @spki = TestFixtures::SPKI
- end
+ before :each do
+ @csr = TestFixtures::CSR
+ @csr_invalid_signature = TestFixtures::CSR_INVALID_SIGNATURE
+ @csr3 = TestFixtures::CSR3
+ @test_ca_config = TestFixtures.test_ca_config
+ @ca = R509::CertificateAuthority::Signer.new(@test_ca_config)
+ @ca_no_profile = R509::CertificateAuthority::Signer.new(TestFixtures.test_ca_no_profile_config)
+ @spki = TestFixtures::SPKI
+ end
- it "raises an error if you don't pass csr or spki" do
- expect { @ca.sign({ :profile_name => 'server' }) }.to raise_error(ArgumentError, "You must supply either :csr or :spki")
+ it "raises an error if you don't pass csr or spki" do
+ expect { @ca.sign({ :profile_name => 'server' }) }.to raise_error(ArgumentError, "You must supply either :csr or :spki")
+ end
+ it "raises an error if you pass a config that has no private key for ca_cert" do
+ config = R509::Config::CAConfig.new( :ca_cert => R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT) )
+ profile = R509::Config::CAProfile.new
+ config.set_profile("some_profile",profile)
+ expect { R509::CertificateAuthority::Signer.new(config) }.to raise_error(R509::R509Error, "You must have a private key associated with your CA certificate to issue")
+ end
+ it "raises an error if you pass both csr and spki" do
+ csr = R509::CSR.new(:csr => @csr)
+ spki = R509::SPKI.new(:spki => @spki, :subject=>[['CN','test']])
+ expect { @ca.sign({ :spki => spki, :csr => csr, :profile_name => 'server' }) }.to raise_error(ArgumentError, "You can't pass both :csr and :spki")
+ end
+ it "raise an error if you don't pass an R509::SPKI in :spki" do
+ spki = OpenSSL::Netscape::SPKI.new(@spki)
+ expect { @ca.sign({ :spki => spki, :profile_name => 'server' }) }.to raise_error(ArgumentError, 'You must pass an R509::SPKI object for :spki')
+ end
+ it "raise an error if you pass :spki without :subject" do
+ spki = R509::SPKI.new(:spki => @spki)
+ expect { @ca.sign({ :spki => spki, :profile_name => 'server' }) }.to raise_error(ArgumentError, 'You must supply :subject when passing :spki')
+ end
+ it "raise an error if you don't pass an R509::CSR in :csr" do
+ csr = OpenSSL::X509::Request.new(@csr)
+ expect { @ca.sign({ :csr => csr, :profile_name => 'server' }) }.to raise_error(ArgumentError, 'You must pass an R509::CSR object for :csr')
+ end
+ it "raises an error if you have no CAProfile with your CAConfig when attempting to issue a cert" do
+ config = R509::Config::CAConfig.new(
+ :ca_cert => TestFixtures.test_ca_cert
+ )
+ ca = R509::CertificateAuthority::Signer.new(config)
+ expect { ca.sign(:csr => @csr) }.to raise_error(R509::R509Error, 'You must have at least one CAProfile on your CAConfig to issue')
+ end
+ it "properly issues a cert with the default CAProfile configuration" do
+ csr = R509::CSR.new(:subject => [["CN","testy.mctest"]], :bit_strength => 1024)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ expect { ca.sign( :csr => csr, :profile_name => 'default') }.to_not raise_error
+ end
+ it "properly issues server cert using spki" do
+ spki = R509::SPKI.new(:spki => @spki)
+ cert = @ca.sign({ :spki => spki, :profile_name => 'server', :subject=>[['CN','test.local']]})
+ cert.to_pem.should match(/BEGIN CERTIFICATE/)
+ cert.subject.to_s.should == '/CN=test.local'
+ cert.extended_key_usage.web_server_authentication?.should == true
+ end
+ it "properly issues server cert" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ cert = @ca.sign({ :csr => csr, :profile_name => 'server' })
+ cert.to_pem.should match(/BEGIN CERTIFICATE/)
+ cert.subject.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh'
+ cert.extended_key_usage.web_server_authentication?.should == true
+ end
+ it "properly issues cert with all EKUs" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ config = R509::Config::CAConfig.from_yaml("all_eku_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign({ :csr => csr, :profile_name => 'smorgasbord' })
+ cert.extended_key_usage.web_server_authentication?.should == true
+ cert.extended_key_usage.web_client_authentication?.should == true
+ cert.extended_key_usage.code_signing?.should == true
+ cert.extended_key_usage.email_protection?.should == true
+ cert.extended_key_usage.ocsp_signing?.should == true
+ cert.extended_key_usage.time_stamping?.should == true
+ end
+ it "properly issues cert with OCSP noCheck in profile" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ config = R509::Config::CAConfig.from_yaml("ocsp_no_check_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign({ :csr => csr, :profile_name => 'ocsp_no_check_delegate' })
+ cert.ocsp_no_check?.should == true
+ cert.extended_key_usage.ocsp_signing?.should == true
+ end
+ it "does not encode noCheck if not specified by the profile" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ cert = @ca.sign({ :csr => csr, :profile_name => 'server' })
+ cert.ocsp_no_check?.should == false
+ end
+ it "when supplied, uses subject_item_policy to determine allowed subject" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ cert = @ca.sign({ :csr => csr, :profile_name => 'server_with_subject_item_policy' })
+ #profile requires C, ST, CN. O and OU are optional
+ cert.subject.to_s.should == '/C=US/ST=Illinois/O=Paul Kehrer/CN=langui.sh'
+ end
+ it "raises error when issuing cert with csr that does not match subject_item_policy" do
+ csr = R509::CSR.new(:csr => @csr)
+ expect { @ca.sign({ :csr => csr, :profile_name => 'server_with_subject_item_policy' }) }.to raise_error(R509::R509Error, /This profile requires you supply/)
+ end
+ it "issues with specified (dnsName) san domains in array" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ san_names = ['langui.sh','domain2.com']
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :subject => csr.subject, :san_names => san_names )
+ cert.san.dns_names.should == ['langui.sh','domain2.com']
+ end
+ it "issues with empty san_names array" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :subject => csr.subject, :san_names => [] )
+ cert.san.should be_nil
+ end
+ it "issues with specified (directoryName and dnsName) san domains in array" do
+ name = [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']]
+ csr = R509::CSR.new(:subject => name, :bit_strength => 1024)
+ san_names = ['langui.sh','domain2.com',name]
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :subject => csr.subject, :san_names => san_names )
+ cert.san.dns_names.should == ['langui.sh','domain2.com']
+ cert.san.directory_names.size.should == 1
+ cert.san.directory_names[0].to_s.should == "/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh"
+ end
+ it "issues with specified san domains in R509::ASN1::GeneralNames object" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :bit_strength => 1024)
+ san_names = R509::ASN1.general_name_parser(['langui.sh','domain2.com'])
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :subject => csr.subject, :san_names => san_names )
+ cert.san.dns_names.should == ['langui.sh','domain2.com']
+ end
+ it "issues with san domains from csr" do
+ csr = R509::CSR.new(:csr => @csr)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server')
+ cert.san.dns_names.should == ['test.local','additionaldomains.com','saniam.com']
+ end
+ it "issues a csr made via array" do
+ csr = R509::CSR.new(:subject => [['CN','langui.sh']], :bit_strength => 1024)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server')
+ cert.subject.to_s.should == '/CN=langui.sh'
+ end
+ it "overrides a CSR's subject with :subject" do
+ csr = R509::CSR.new(:csr => @csr)
+ subject = csr.subject
+ subject.CN = "someotherdomain.com"
+ subject.delete("O")
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :subject => subject )
+ cert.subject.to_s.should == '/CN=someotherdomain.com'
+ end
+ it "tests that policy identifiers are properly encoded" do
+ csr = R509::CSR.new(:csr => @csr)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server')
+ cert.certificate_policies.should_not be_nil
+ cert.certificate_policies.policies.count.should == 1
+ cert.certificate_policies.policies[0].policy_identifier.should == "2.16.840.1.12345.1.2.3.4.1"
+ cert.certificate_policies.policies[0].policy_qualifiers.cps_uris.should == ["http://example.com/cps", "http://other.com/cps"]
+ cert.certificate_policies.policies[0].policy_qualifiers.user_notices.count.should == 1
+ un = cert.certificate_policies.policies[0].policy_qualifiers.user_notices[0]
+ un.notice_reference.notice_numbers.should == [1,2,3,4]
+ un.notice_reference.organization.should == 'my org'
+ un.explicit_text.should == "thing"
+ end
+ it "multiple policy identifiers are properly encoded" do
+ csr = R509::CSR.new(:csr => @csr)
+ config = R509::Config::CAConfig.from_yaml("multi_policy_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'server')
+ cert.certificate_policies.should_not be_nil
+ cert.certificate_policies.policies.count.should == 2
+ p0 = cert.certificate_policies.policies[0]
+ p0.policy_identifier.should == "2.16.840.1.99999.21.234"
+ p0.policy_qualifiers.cps_uris.should == ["http://example.com/cps", "http://haha.com"]
+ p0.policy_qualifiers.user_notices.count.should == 1
+ un0 = p0.policy_qualifiers.user_notices[0]
+ un0.notice_reference.notice_numbers.should == [1,2,3]
+ un0.notice_reference.organization.should == "my org"
+ un0.explicit_text.should == "this is a great thing"
+ p1 = cert.certificate_policies.policies[1]
+ p1.policy_identifier.should == "2.16.840.1.99999.21.235"
+ p1.policy_qualifiers.cps_uris.should == ["http://example.com/cps2"]
+ p1.policy_qualifiers.user_notices.count.should == 2
+ un1 = p1.policy_qualifiers.user_notices[0]
+ un1.notice_reference.notice_numbers.should == [3,2,1]
+ un1.notice_reference.organization.should == "another org"
+ un1.explicit_text.should == 'this is a bad thing'
+ un2 = p1.policy_qualifiers.user_notices[1]
+ un2.notice_reference.should be_nil
+ un2.explicit_text.should == "another user notice"
+ end
+ it "issues a certificate with an authority key identifier" do
+ csr = R509::CSR.new(:csr => @csr)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server')
+ cert.authority_key_identifier.should_not be_nil
+ end
+ context "inhibitAnyPolicy" do
+ it "issues without inhibit any policy when not present" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.inhibit_any_policy.should == nil
end
- it "raises an error if you pass a config that has no private key for ca_cert" do
- config = R509::Config::CaConfig.new( :ca_cert => R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT) )
- profile = R509::Config::CaProfile.new
- config.set_profile("some_profile",profile)
- expect { R509::CertificateAuthority::Signer.new(config) }.to raise_error(R509::R509Error, "You must have a private key associated with your CA certificate to issue")
+ it "issues with inhibit any policy when present" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:inhibit_any_policy => 1)
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.inhibit_any_policy.skip_certs.should == 1
end
- it "raises an error if you pass both csr and spki" do
- csr = R509::Csr.new(:csr => @csr)
- spki = R509::Spki.new(:spki => @spki, :subject=>[['CN','test']])
- expect { @ca.sign({ :spki => spki, :csr => csr, :profile_name => 'server' }) }.to raise_error(ArgumentError, "You can't pass both :csr and :spki")
+ end
+ context "policyConstraints" do
+ it "issues without policy constraints when not present" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.policy_constraints.should == nil
end
- it "raise an error if you don't pass an R509::Spki in :spki" do
- spki = OpenSSL::Netscape::SPKI.new(@spki)
- expect { @ca.sign({ :spki => spki, :profile_name => 'server' }) }.to raise_error(ArgumentError, 'You must pass an R509::Spki object for :spki')
+ it "issues with require_explicit_policy" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:policy_constraints => {"require_explicit_policy" => 3})
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.policy_constraints.require_explicit_policy.should == 3
+ cert.policy_constraints.inhibit_policy_mapping.should == nil
end
- it "raise an error if you don't pass an R509::Csr in :csr" do
- csr = OpenSSL::X509::Request.new(@csr)
- expect { @ca.sign({ :csr => csr, :profile_name => 'server' }) }.to raise_error(ArgumentError, 'You must pass an R509::Csr object for :csr')
+ it "issues with inhibit_policy_mapping" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:policy_constraints => {"inhibit_policy_mapping" => 3})
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.policy_constraints.require_explicit_policy.should == nil
+ cert.policy_constraints.inhibit_policy_mapping.should == 3
end
- it "raises an error if you have no CaProfiles with your CaConfig when attempting to issue a cert" do
- config = R509::Config::CaConfig.new(
- :ca_cert => TestFixtures.test_ca_cert
- )
- ca = R509::CertificateAuthority::Signer.new(config)
- expect { ca.sign(:csr => @csr) }.to raise_error(R509::R509Error, 'You must have at least one CaProfile on your CaConfig to issue')
+ it "issues with both require and inhibit" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:policy_constraints => {"require_explicit_policy" => 3, "inhibit_policy_mapping" => 2})
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.policy_constraints.require_explicit_policy.should == 3
+ cert.policy_constraints.inhibit_policy_mapping.should == 2
end
- it "properly issues server cert using spki" do
- spki = R509::Spki.new(:spki => @spki, :subject=>[['CN','test.local']])
- cert = @ca.sign({ :spki => spki, :profile_name => 'server' })
- cert.to_pem.should match(/BEGIN CERTIFICATE/)
- cert.subject.to_s.should == '/CN=test.local'
- extended_key_usage = cert.extensions['extendedKeyUsage']
- extended_key_usage['value'].should == 'TLS Web Server Authentication'
+ end
+ context "nameConstraints" do
+ it "issues with no constraints if not present in profile" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.name_constraints.should be_nil
end
- it "properly issues server cert" do
- csr = R509::Csr.new(:cert => @cert, :bit_strength => 1024)
- cert = @ca.sign({ :csr => csr, :profile_name => 'server' })
- cert.to_pem.should match(/BEGIN CERTIFICATE/)
- cert.subject.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh'
- extended_key_usage = cert.extensions['extendedKeyUsage']
- extended_key_usage['value'].should == 'TLS Web Server Authentication'
+ it "issues with permitted constraints" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:name_constraints => { "permitted" => [ { "type" => "DNS", "value" => "domain.com" } , { "type" => "IP", "value" => "ff::/ff:ff:ff:ff:ff:ff:ff:ff" } ] } )
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.name_constraints.permitted_names[0].type.should == :dNSName
+ cert.name_constraints.permitted_names[0].value.should == 'domain.com'
+ cert.name_constraints.permitted_names[1].type.should == :iPAddress
+ cert.name_constraints.permitted_names[1].value.should == 'ff::/ff:ff:ff:ff:ff:ff:ff:ff'
end
- it "when supplied, uses subject_item_policy to determine allowed subject" do
- csr = R509::Csr.new(:cert => @cert, :bit_strength => 512)
- cert = @ca.sign({ :csr => csr, :profile_name => 'server_with_subject_item_policy' })
- #profile requires C, ST, CN. O and OU are optional
- cert.subject.to_s.should == '/C=US/ST=Illinois/O=Paul Kehrer/CN=langui.sh'
+ it "issues with excluded constraints" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:name_constraints => { "excluded" => [ { "type" => "dirName", "value" => [["CN","domain.com"]] }, { "type" => "URI", "value" => ".domain.com" } ] } )
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.name_constraints.excluded_names[0].type.should == :directoryName
+ cert.name_constraints.excluded_names[0].value.to_s.should == '/CN=domain.com'
+ cert.name_constraints.excluded_names[1].type.should == :uniformResourceIdentifier
+ cert.name_constraints.excluded_names[1].value.to_s.should == '.domain.com'
end
- it "raises error when issuing cert with csr that does not match subject_item_policy" do
- csr = R509::Csr.new(:csr => @csr)
- expect { @ca.sign({ :csr => csr, :profile_name => 'server_with_subject_item_policy' }) }.to raise_error(R509::R509Error, /This profile requires you supply/)
+ it "issues with both constraints" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new(:name_constraints => { "permitted" => [ { "type" => "DNS", "value" => "domain.com" } ], "excluded" => [ { "type" => "dirName", "value" => [["CN","domain.com"]] } ] } )
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.name_constraints.permitted_names[0].type.should == :dNSName
+ cert.name_constraints.permitted_names[0].value.should == 'domain.com'
+ cert.name_constraints.excluded_names[0].type.should == :directoryName
+ cert.name_constraints.excluded_names[0].value.to_s.should == '/CN=domain.com'
end
- it "issues with specified san domains" do
- csr = R509::Csr.new(:cert => @cert, :bit_strength => 1024)
- data_hash = csr.to_hash
- data_hash[:san_names] = ['langui.sh','domain2.com']
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :data_hash => data_hash )
- cert.san_names.should == ['langui.sh','domain2.com']
+ end
+ context "authorityInfoAccess" do
+ it "issues a certificate with a ca_issuers_location and ocsp_location" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ca_issuers_location = ['http://domain.com/ca.html']
+ config.ocsp_location = ['http://ocsp.domain.com','http://ocsp.other.com']
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.authority_info_access.ca_issuers.uris.should == ["http://domain.com/ca.html"]
+ cert.authority_info_access.ocsp.uris.should == ["http://ocsp.domain.com","http://ocsp.other.com"]
end
- it "issues with san domains from csr" do
- csr = R509::Csr.new(:csr => @csr)
- cert = @ca.sign(:csr => csr, :profile_name => 'server')
- cert.san_names.should == ['test.local','additionaldomains.com','saniam.com']
+ it "issues a certificate with a ca_issuers_location and ocsp_location (dirName,URI,DNS)" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ca_issuers_location = ['http://domain.com/ca.html','domain.com',R509::Subject.new([['CN','myDir'],['C','US']])]
+ config.ocsp_location = ['http://ocsp.domain.com/','ocsp.domain.com',R509::Subject.new([['CN','ocsp'],['L','Locality']])]
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.authority_info_access.ca_issuers.uris.should == ["http://domain.com/ca.html"]
+ cert.authority_info_access.ca_issuers.dns_names.should == ['domain.com']
+ cert.authority_info_access.ca_issuers.directory_names[0].to_s.should == '/CN=myDir/C=US'
+ cert.authority_info_access.ocsp.uris.should == ["http://ocsp.domain.com/"]
+ cert.authority_info_access.ocsp.dns_names.should == ["ocsp.domain.com"]
+ cert.authority_info_access.ocsp.directory_names[0].to_s.should == '/CN=ocsp/L=Locality'
end
- it "issues a csr made via array" do
- csr = R509::Csr.new(:subject => [['CN','langui.sh']], :bit_strength => 1024)
- cert = @ca.sign(:csr => csr, :profile_name => 'server')
- cert.subject.to_s.should == '/CN=langui.sh'
+ it "issues a certificate with a ca_issuers_location and no ocsp_location" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ca_issuers_location = ['http://domain.com/ca.html']
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign(:csr => csr, :profile_name => 'default')
+ cert.authority_info_access.ca_issuers.uris.should == ["http://domain.com/ca.html"]
+ cert.authority_info_access.ocsp.uris.should == []
end
- it "issues a cert with the subject array provided" do
- csr = R509::Csr.new(:csr => @csr)
- data_hash = csr.to_hash
- data_hash[:subject]['CN'] = "someotherdomain.com"
- data_hash[:subject].delete("O")
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :data_hash => data_hash )
- cert.subject.to_s.should == '/CN=someotherdomain.com'
+ it "issues a certificate with multiple ca_issuer_locations" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ca_issuers_location = ["http://somelocation.com/c.html","http://other.com/d.html"]
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.authority_info_access.ocsp.uris.should == []
+ cert.authority_info_access.ca_issuers.uris.should == ["http://somelocation.com/c.html","http://other.com/d.html"]
end
- it "tests that policy identifiers are properly encoded" do
- csr = R509::Csr.new(:csr => @csr)
- cert = @ca.sign(:csr => csr, :profile_name => 'server')
- cert.extensions['certificatePolicies']['value'].should == "Policy: 2.16.840.1.12345.1.2.3.4.1\n CPS: http://example.com/cps\n"
+ it "issues a certificate with ocsp_location" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ocsp_location = ["http://myocsp.jb.net"]
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.authority_info_access.ca_issuers.uris.should == []
+ cert.authority_info_access.ocsp.uris.should == ["http://myocsp.jb.net"]
end
- it "multiple policy identifiers are properly encoded" do
- csr = R509::Csr.new(:csr => @csr)
- config = R509::Config::CaConfig.from_yaml("multi_policy_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
- ca = R509::CertificateAuthority::Signer.new(config)
- cert = ca.sign(:csr => csr, :profile_name => 'server')
- cert.extensions['certificatePolicies']['value'].should == "Policy: 2.16.840.1.9999999999.3.0\nPolicy: 2.16.840.1.9999999999.1.2.3.4.1\n CPS: http://example.com/cps\n"
+ it "issues a certificate with an empty array for ocsp_location" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ocsp_location = []
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.authority_info_access.should be_nil
end
- it "tests basic constraints CA:TRUE and pathlen:0 on a subroot" do
- csr = R509::Csr.new(:csr => @csr)
- cert = @ca.sign(:csr => csr, :profile_name => 'subroot')
- cert.extensions['basicConstraints']['value'].should == 'CA:TRUE, pathlen:0'
+ it "issues a certificate with an empty array for ca_issuers_location" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.ca_issuers_location = []
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.authority_info_access.should be_nil
end
- it "issues with md5" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'md5')
- cert.cert.signature_algorithm.should == 'md5WithRSAEncryption'
+ end
+ it "issues a certificate with no CDP" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.crl_distribution_points.should == nil
+ end
+ it "issues a certificate with an empty array for CDP" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.cdp_location = []
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.crl_distribution_points.should be_nil
+ end
+ it "issues a certificate with a single CDP" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.cdp_location = ["http://mycdp.com/x.crl"]
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.crl_distribution_points.crl.uris.should == ["http://mycdp.com/x.crl"]
+ end
+ it "issues a certificate with multiple CDPs" do
+ csr = R509::CSR.new(:csr => @csr)
+ ca_cert = R509::Cert.new( :cert => TestFixtures::TEST_CA_CERT, :key => TestFixtures::TEST_CA_KEY )
+ config = R509::Config::CAConfig.new(:ca_cert => ca_cert)
+ config.cdp_location = ["http://mycdp.com/x.crl","http://anothercrl.com/x.crl"]
+ profile = R509::Config::CAProfile.new
+ config.set_profile("default",profile)
+ ca = R509::CertificateAuthority::Signer.new(config)
+ cert = ca.sign( :csr => csr, :profile_name => 'default')
+ cert.crl_distribution_points.crl.uris.should == ["http://mycdp.com/x.crl","http://anothercrl.com/x.crl"]
+ end
+ it "tests basic constraints CA:TRUE and pathlen:0 on a subroot" do
+ csr = R509::CSR.new(:csr => @csr)
+ cert = @ca.sign(:csr => csr, :profile_name => 'subroot')
+ cert.basic_constraints.is_ca?.should == true
+ cert.basic_constraints.path_length.should == 0
+ end
+ it "issues with md5" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'md5')
+ cert.cert.signature_algorithm.should == 'md5WithRSAEncryption'
+ end
+ it "issues with sha1" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha1')
+ cert.cert.signature_algorithm.should == 'sha1WithRSAEncryption'
+ end
+ it "issues with sha224" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha224')
+ cert.cert.signature_algorithm.should == 'sha224WithRSAEncryption'
+ end
+ it "issues with sha256" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha256')
+ cert.cert.signature_algorithm.should == 'sha256WithRSAEncryption'
+ end
+ it "issues with sha384" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha384')
+ cert.cert.signature_algorithm.should == 'sha384WithRSAEncryption'
+ end
+ it "issues with sha512" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha512')
+ cert.cert.signature_algorithm.should == 'sha512WithRSAEncryption'
+ end
+ it "issues with invalid hash (sha1 fallback)" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'invalid')
+ cert.cert.signature_algorithm.should == 'sha1WithRSAEncryption'
+ end
+ it "generates random serial when serial is not specified and uses microtime as part of the serial to prevent collision" do
+ now = Time.now
+ Time.stub!(:now).and_return(now)
+ time = now.to_i.to_s
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => "server")
+ cert.serial.to_s.size.should >= 45
+ cert.serial.to_s.index(time).should_not be_nil
+ end
+ it "accepts specified serial number" do
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => "server", :serial => 12345)
+ cert.serial.should == 12345
+ end
+ it "has default notBefore/notAfter dates" do
+ not_before = (Time.now - (6 * 60 * 60)).utc
+ not_after = (Time.now - (6 * 60 * 60) + (365 * 24 * 60 * 60)).utc
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => "server")
+ cert.cert.not_before.year.should == not_before.year
+ cert.cert.not_before.month.should == not_before.month
+ cert.cert.not_before.day.should == not_before.day
+ cert.cert.not_before.hour.should == not_before.hour
+ cert.cert.not_before.min.should == not_before.min
+ cert.cert.not_after.year.should == not_after.year
+ cert.cert.not_after.month.should == not_after.month
+ cert.cert.not_after.day.should == not_after.day
+ cert.cert.not_after.hour.should == not_after.hour
+ cert.cert.not_after.min.should == not_after.min
+ end
+ it "allows you to specify notBefore/notAfter dates" do
+ not_before = Time.now - 5 * 60 * 60
+ not_after = Time.now + 5 * 60 * 60
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = @ca.sign(:csr => csr, :profile_name => "server", :not_before => not_before, :not_after => not_after)
+ cert.cert.not_before.ctime.should == not_before.utc.ctime
+ cert.cert.not_after.ctime.should == not_after.utc.ctime
+ end
+ it "issues a certificate from a root that does not have a subjectKeyIdentifier" do
+ config = R509::Config::CAConfig.from_yaml("missing_key_identifier_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ ca = R509::CertificateAuthority::Signer.new(config)
+ csr = R509::CSR.new(:csr => @csr3)
+ cert = ca.sign(:csr => csr, :profile_name => "server")
+ cert.authority_key_identifier.should == nil
+ cert.extended_key_usage.web_server_authentication?.should == true
+ end
+ it "raises error unless you provide a proper config (or nil)" do
+ expect { R509::CertificateAuthority::Signer.new('invalid') }.to raise_error(R509::R509Error, 'config must be a kind of R509::Config::CAConfig or nil (for self-sign only)')
+ end
+ it "raises error when providing invalid ca profile" do
+ csr = R509::CSR.new(:csr => @csr)
+ expect { @ca.sign(:csr => csr, :profile_name => 'invalid') }.to raise_error(R509::R509Error, "unknown profile 'invalid'")
+ end
+ it "raises error when attempting to issue CSR with invalid signature" do
+ csr = R509::CSR.new(:csr => @csr_invalid_signature)
+ expect { @ca.sign(:csr => csr, :profile_name => 'server') }.to raise_error(R509::R509Error, 'Certificate request signature is invalid.')
+ end
+ it "raises error when passing non-hash to selfsign method" do
+ expect { @ca.selfsign(@csr) }.to raise_error(ArgumentError, "You must pass a hash of options consisting of at minimum :csr")
+ end
+ it "raises error when passing invalid data for san_names" do
+ csr = R509::CSR.new(
+ :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
+ :bit_strength => 1024
+ )
+ san_names = "invalid"
+ expect { @ca.selfsign(:csr => csr, :san_names => san_names) }.to raise_error(ArgumentError,'When passing SAN names it must be provided as either an array of strings or an R509::ASN1::GeneralNames object')
+ end
+ it "issues a self-signed certificate with custom fields" do
+ not_before = Time.now.to_i
+ not_after = Time.now.to_i+3600*24*7300
+ csr = R509::CSR.new(
+ :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
+ :bit_strength => 1024
+ )
+ san_names = R509::ASN1.general_name_parser(['sanname1','sanname2'])
+ cert = @ca.selfsign(
+ :csr => csr,
+ :serial => 3,
+ :not_before => not_before,
+ :not_after => not_after,
+ :message_digest => 'sha256',
+ :san_names => san_names
+ )
+ cert.public_key.to_s.should == csr.public_key.to_s
+ cert.signature_algorithm.should == 'sha256WithRSAEncryption'
+ cert.serial.should == 3
+ cert.not_before.to_i.should == not_before
+ cert.not_after.to_i.should == not_after
+ cert.subject.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
+ cert.issuer.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
+ cert.basic_constraints.is_ca?.should == true
+ cert.san.dns_names.should include('sanname1','sanname2')
+ end
+ it "issues a self-signed certificate with san names provided as an array" do
+ not_before = Time.now.to_i
+ not_after = Time.now.to_i+3600*24*7300
+ csr = R509::CSR.new(
+ :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
+ :bit_strength => 1024
+ )
+ san_names = ['sanname1','sanname2']
+ cert = @ca.selfsign(
+ :csr => csr,
+ :not_before => not_before,
+ :not_after => not_after,
+ :message_digest => 'sha256',
+ :san_names => san_names
+ )
+ cert.san.dns_names.should include('sanname1','sanname2')
+ end
+ it "issues self-signed certificate with SAN in CSR" do
+ csr = R509::CSR.new(
+ :subject => [['CN','My Self Sign']],
+ :san_names => ['sanname1','sanname2'],
+ :bit_strength => 1024
+ )
+ cert = @ca.selfsign(
+ :csr => csr
+ )
+ cert.san.dns_names.should include('sanname1','sanname2')
+ cert.subject.to_s.should == '/CN=My Self Sign'
+ cert.issuer.to_s.should == '/CN=My Self Sign'
+ cert.public_key.to_s.should == csr.public_key.to_s
+ end
+ it "issues a self-signed certificate with defaults" do
+ csr = R509::CSR.new(
+ :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
+ :bit_strength => 1024
+ )
+ cert = @ca.selfsign(
+ :csr => csr
+ )
+ cert.public_key.to_s.should == csr.public_key.to_s
+ cert.signature_algorithm.should == 'sha1WithRSAEncryption'
+ (cert.not_after.to_i-cert.not_before.to_i).should == 31536000
+ cert.subject.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
+ cert.issuer.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
+ cert.basic_constraints.is_ca?.should == true
+ end
+ it "raises an error if attempting to self-sign without a key" do
+ csr = R509::CSR.new(:csr => @csr3)
+ expect { @ca.selfsign( :csr => csr ) }.to raise_error(ArgumentError, "CSR must also have a private key to self sign")
+ end
+ it "raises an error if you call sign without passing a config to the object" do
+ ca_signer = R509::CertificateAuthority::Signer.new
+ csr = R509::CSR.new(:csr => @csr3)
+ expect { ca_signer.sign(:csr => csr, :profile_name => "server") }.to raise_error(R509::R509Error, "When instantiating the signer without a config you can only call #selfsign")
+ end
+
+ context "issuing off an elliptic curve CA", :ec => true do
+ before :all do
+ @test_ca_ec = R509::Config::CAConfig.from_yaml("test_ca_ec", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_ec.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ @ca_ec = R509::CertificateAuthority::Signer.new(@test_ca_ec)
end
- it "issues with sha1" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha1')
- cert.cert.signature_algorithm.should == 'sha1WithRSAEncryption'
+
+ it "properly issues server cert" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :type => :ec)
+ cert = @ca_ec.sign( :csr => csr, :profile_name => 'server' )
+ cert.to_pem.should match(/BEGIN CERTIFICATE/)
+ cert.subject.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh'
+ cert.signature_algorithm.should == 'ecdsa-with-SHA384'
+ cert.key_algorithm.should == :ec
+ cert.extended_key_usage.web_server_authentication?.should == true
end
- it "issues with sha256" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha256')
- cert.cert.signature_algorithm.should == 'sha256WithRSAEncryption'
+ it "properly issues server cert using spki" do
+ spki = R509::SPKI.new(:spki => @spki)
+ cert = @ca_ec.sign( :spki => spki, :profile_name => 'server', :subject=>[['CN','test.local']] )
+ cert.to_pem.should match(/BEGIN CERTIFICATE/)
+ cert.subject.to_s.should == '/CN=test.local'
+ cert.signature_algorithm.should == 'ecdsa-with-SHA384'
+ cert.key_algorithm.should == :rsa #weird right?! it's because the spki is RSA even though the signature is from an EC root
+ cert.extended_key_usage.web_server_authentication?.should == true
end
- it "issues with sha512" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'sha512')
- cert.cert.signature_algorithm.should == 'sha512WithRSAEncryption'
+ end
+
+ context "issuing off a DSA CA" do
+ before :all do
+ @test_ca_dsa = R509::Config::CAConfig.from_yaml("test_ca_dsa", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_dsa.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
+ @ca_dsa = R509::CertificateAuthority::Signer.new(@test_ca_dsa)
end
- it "issues with invalid hash (sha1 fallback)" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => 'server', :message_digest => 'invalid')
- cert.cert.signature_algorithm.should == 'sha1WithRSAEncryption'
+
+ it "properly issues server cert" do
+ csr = R509::CSR.new(:subject => [['C','US'],['ST','Illinois'],['L','Chicago'],['O','Paul Kehrer'],['CN','langui.sh']], :type => :dsa, :bit_strength => 1024)
+ cert = @ca_dsa.sign( :csr => csr, :profile_name => 'server' )
+ cert.to_pem.should match(/BEGIN CERTIFICATE/)
+ cert.subject.to_s.should == '/C=US/ST=Illinois/L=Chicago/O=Paul Kehrer/CN=langui.sh'
+ cert.signature_algorithm.should == 'dsaWithSHA1'
+ cert.key_algorithm.should == :dsa
+ cert.extended_key_usage.web_server_authentication?.should == true
end
- it "generates random serial when serial is not specified and uses microtime as part of the serial to prevent collision" do
- now = Time.now
- Time.stub!(:now).and_return(now)
- time = now.to_i.to_s
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => "server")
- cert.serial.to_s.size.should >= 45
- cert.serial.to_s.index(time).should_not be_nil
- end
- it "accepts specified serial number" do
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => "server", :serial => 12345)
- cert.serial.should == 12345
- end
- it "has default notBefore/notAfter dates" do
- not_before = (Time.now - (6 * 60 * 60)).utc
- not_after = (Time.now - (6 * 60 * 60) + (365 * 24 * 60 * 60)).utc
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => "server")
- cert.cert.not_before.year.should == not_before.year
- cert.cert.not_before.month.should == not_before.month
- cert.cert.not_before.day.should == not_before.day
- cert.cert.not_before.hour.should == not_before.hour
- cert.cert.not_before.min.should == not_before.min
- cert.cert.not_after.year.should == not_after.year
- cert.cert.not_after.month.should == not_after.month
- cert.cert.not_after.day.should == not_after.day
- cert.cert.not_after.hour.should == not_after.hour
- cert.cert.not_after.min.should == not_after.min
- end
- it "allows you to specify notBefore/notAfter dates" do
- not_before = Time.now - 5 * 60 * 60
- not_after = Time.now + 5 * 60 * 60
- csr = R509::Csr.new(:csr => @csr3)
- cert = @ca.sign(:csr => csr, :profile_name => "server", :not_before => not_before, :not_after => not_after)
- cert.cert.not_before.ctime.should == not_before.utc.ctime
- cert.cert.not_after.ctime.should == not_after.utc.ctime
- end
- it "issues a certificate from a root that does not have a subjectKeyIdentifier" do
- config = R509::Config::CaConfig.from_yaml("missing_key_identifier_ca", File.read("#{File.dirname(__FILE__)}/fixtures/config_test_various.yaml"), {:ca_root_path => "#{File.dirname(__FILE__)}/fixtures"})
- ca = R509::CertificateAuthority::Signer.new(config)
- csr = R509::Csr.new(:csr => @csr3)
- cert = ca.sign(:csr => csr, :profile_name => "server")
- cert.extensions['authorityKeyIdentifier'].should == nil
- cert.extended_key_usage.web_server_authentication?.should == true
- end
- it "raises error unless you provide a proper config (or nil)" do
- expect { R509::CertificateAuthority::Signer.new('invalid') }.to raise_error(R509::R509Error, 'config must be a kind of R509::Config::CaConfig or nil (for self-sign only)')
- end
- it "raises error when providing invalid ca profile" do
- csr = R509::Csr.new(:csr => @csr)
- expect { @ca.sign(:csr => csr, :profile_name => 'invalid') }.to raise_error(R509::R509Error, "unknown profile 'invalid'")
- end
- it "raises error when attempting to issue CSR with invalid signature" do
- csr = R509::Csr.new(:csr => @csr_invalid_signature)
- expect { @ca.sign(:csr => csr, :profile_name => 'server') }.to raise_error(R509::R509Error, 'Certificate request signature is invalid.')
- end
- it "raises error when passing non-hash to selfsign method" do
- expect { @ca.selfsign(@csr) }.to raise_error(ArgumentError, "You must pass a hash of options consisting of at minimum :csr")
- end
- it "issues a self-signed certificate with custom fields" do
- not_before = Time.now.to_i
- not_after = Time.now.to_i+3600*24*7300
- csr = R509::Csr.new(
- :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
- :bit_strength => 1024
- )
- cert = @ca.selfsign(
- :csr => csr,
- :serial => 3,
- :not_before => not_before,
- :not_after => not_after,
- :message_digest => 'sha256',
- :san_names => ['sanname1','sanname2']
- )
- cert.public_key.to_s.should == csr.public_key.to_s
- cert.signature_algorithm.should == 'sha256WithRSAEncryption'
- cert.serial.should == 3
- cert.not_before.to_i.should == not_before
- cert.not_after.to_i.should == not_after
- cert.subject.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
- cert.issuer.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
- cert.extensions['basicConstraints']['value'].should == 'CA:TRUE'
- cert.san_names.should include('sanname1','sanname2')
- end
- it "issues self-signed certificate with SAN in CSR" do
- csr = R509::Csr.new(
- :subject => [['CN','My Self Sign']],
- :san_names => ['sanname1','sanname2'],
- :bit_strength => 1024
- )
- cert = @ca.selfsign(
- :csr => csr
- )
- cert.san_names.should include('sanname1','sanname2')
- cert.subject.to_s.should == '/CN=My Self Sign'
- cert.issuer.to_s.should == '/CN=My Self Sign'
- cert.public_key.to_s.should == csr.public_key.to_s
- end
- it "issues a self-signed certificate with defaults" do
- csr = R509::Csr.new(
- :subject => [['C','US'],['O','r509 LLC'],['CN','r509 Self-Signed CA Test']],
- :bit_strength => 1024
- )
- cert = @ca.selfsign(
- :csr => csr
- )
- cert.public_key.to_s.should == csr.public_key.to_s
- cert.signature_algorithm.should == 'sha1WithRSAEncryption'
- (cert.not_after.to_i-cert.not_before.to_i).should == 31536000
- cert.subject.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
- cert.issuer.to_s.should == '/C=US/O=r509 LLC/CN=r509 Self-Signed CA Test'
- cert.extensions['basicConstraints']['value'].should == 'CA:TRUE'
- end
- it "raises an error if attempting to self-sign without a key" do
- csr = R509::Csr.new(:csr => @csr3)
- expect { @ca.selfsign( :csr => csr ) }.to raise_error(ArgumentError, "CSR must also have a private key to self sign")
- end
- it "raises an error if you call sign without passing a config to the object" do
- ca_signer = R509::CertificateAuthority::Signer.new
- csr = R509::Csr.new(:csr => @csr3)
- expect { ca_signer.sign(:csr => csr, :profile_name => "server") }.to raise_error(R509::R509Error, "When instantiating the signer without a config you can only call #selfsign")
- end
+ end
end