spec/cert/extensions_spec.rb in r509-0.8.1 vs spec/cert/extensions_spec.rb in r509-0.9

- old
+ new

@@ -2,631 +2,1094 @@ include R509::Cert::Extensions shared_examples_for "a correctly implemented wrap_openssl_extensions" do before :each do - @r509_extensions = R509::Cert::Extensions.wrap_openssl_extensions( @openssl_extensions ) - - @r509_classes = [ BasicConstraints, KeyUsage, ExtendedKeyUsage, - SubjectKeyIdentifier, AuthorityKeyIdentifier, - SubjectAlternativeName, AuthorityInfoAccess, - CrlDistributionPoints ] + @r509_extensions = R509::Cert::Extensions.wrap_openssl_extensions( @openssl_extensions ) + + @r509_classes = [ BasicConstraints, KeyUsage, ExtendedKeyUsage, + SubjectKeyIdentifier, AuthorityKeyIdentifier, + SubjectAlternativeName, AuthorityInfoAccess, + CRLDistributionPoints, OCSPNoCheck ] end - + it "should not have returned values that aren't R509 extensions" do - classes = @r509_extensions.values.map { |ext| ext.class } - non_r509_classes = classes.reject { |ext_class| @r509_classes.include?(ext_class) } - non_r509_classes.should == [] + classes = @r509_extensions.values.map { |ext| ext.class } + non_r509_classes = classes.reject { |ext_class| @r509_classes.include?(ext_class) } + non_r509_classes.should == [] end - + it "should have returned the right number of extensions" do - @r509_extensions.count.should == @wrappable_extensions.count + @r509_extensions.count.should == @wrappable_extensions.count end - + it "should not have returned keys improperly mapped to values" do - incorrect_mappings = @r509_extensions.select { |key_class,ext| ext.class != key_class } - incorrect_mappings = {} if incorrect_mappings == [] # compatibility for old versions of Ruby - incorrect_mappings.should == {} + incorrect_mappings = @r509_extensions.select { |key_class,ext| ext.class != key_class } + incorrect_mappings = {} if incorrect_mappings == [] # compatibility for old versions of Ruby + incorrect_mappings.should == {} end - + it "should not have failed to map an implemented extension" do - missing_extensions = [] - @wrappable_extensions.each do |openssl_ext| - if (@r509_extensions.select {|r509_class,r509_ext| r509_ext.oid == openssl_ext.oid}) == {} - missing_extensions << openssl_ext.oid - end + missing_extensions = [] + @wrappable_extensions.each do |openssl_ext| + if (@r509_extensions.select {|r509_class,r509_ext| r509_ext.oid == openssl_ext.oid}) == {} + missing_extensions << openssl_ext.oid end - - missing_extensions.should == [] + end + + missing_extensions.should == [] end end shared_examples_for "a correctly implemented get_unknown_extensions" do it "should not have returned values that are R509 extensions" do - R509::Cert::Extensions.get_unknown_extensions( @openssl_extensions ).should == @unknown_extensions + R509::Cert::Extensions.get_unknown_extensions( @openssl_extensions ).should == @unknown_extensions end end -shared_examples_for "a correct R509 BasicConstraints object" do - before :all do - extension_name = "basicConstraints" - klass = BasicConstraints - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 BasicConstraints object" do |critical| + before :all do + extension_name = "basicConstraints" + klass = BasicConstraints + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value , critical) + @r509_ext = klass.new( openssl_ext ) + end - it "is_ca? should correctly report whether it's a CA certificate" do - @r509_ext.is_ca?.should == @is_ca - end + it "is_ca? should correctly report whether it's a CA certificate (critical:#{critical})" do + @r509_ext.is_ca?.should == @is_ca + end - it "the path length should be correct" do - @r509_ext.path_length.should == @pathlen - end + it "the path length should be correct (critical:#{critical})" do + @r509_ext.path_length.should == @pathlen + end - it "allows_sub_ca? should correctly report whether its path length allows it to issue CA certs" do - @r509_ext.allows_sub_ca?.should == @allows_sub_ca - end + it "allows_sub_ca? should correctly report whether its path length allows it to issue CA certs (critical:#{critical})" do + @r509_ext.allows_sub_ca?.should == @allows_sub_ca + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end -shared_examples_for "a correct R509 KeyUsage object" do - before :all do - extension_name = "keyUsage" - klass = KeyUsage - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 KeyUsage object" do |critical| + before :each do + extension_name = "keyUsage" + klass = KeyUsage + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value, critical ) + @r509_ext = klass.new( openssl_ext ) + end - it "allowed_uses should be non-nil" do - @r509_ext.allowed_uses.should_not == nil - end + it "allowed_uses should be non-nil critical:#{critical}" do + @r509_ext.allowed_uses.should_not == nil + end - it "allowed_uses should be correct" do - @r509_ext.allowed_uses.should == @allowed_uses - end + it "allowed_uses should be correct critical:#{critical}" do + @r509_ext.allowed_uses.should == @allowed_uses + end - it "the individual allowed-use functions should be correct" do - @r509_ext.digital_signature?.should == @allowed_uses.include?( KeyUsage::AU_DIGITAL_SIGNATURE ) - @r509_ext.non_repudiation?.should == @allowed_uses.include?( KeyUsage::AU_NON_REPUDIATION ) - @r509_ext.key_encipherment?.should == @allowed_uses.include?( KeyUsage::AU_KEY_ENCIPHERMENT ) - @r509_ext.data_encipherment?.should == @allowed_uses.include?( KeyUsage::AU_DATA_ENCIPHERMENT ) - @r509_ext.key_agreement?.should == @allowed_uses.include?( KeyUsage::AU_KEY_AGREEMENT ) - @r509_ext.certificate_sign?.should == @allowed_uses.include?( KeyUsage::AU_CERTIFICATE_SIGN ) - @r509_ext.crl_sign?.should == @allowed_uses.include?( KeyUsage::AU_CRL_SIGN ) - @r509_ext.encipher_only?.should == @allowed_uses.include?( KeyUsage::AU_ENCIPHER_ONLY ) - @r509_ext.decipher_only?.should == @allowed_uses.include?( KeyUsage::AU_DECIPHER_ONLY ) + it "the individual allowed-use functions should be correct critical:#{critical}" do + @r509_ext.digital_signature?.should == @allowed_uses.include?( KeyUsage::AU_DIGITAL_SIGNATURE ) + @r509_ext.non_repudiation?.should == @allowed_uses.include?( KeyUsage::AU_NON_REPUDIATION ) + @r509_ext.key_encipherment?.should == @allowed_uses.include?( KeyUsage::AU_KEY_ENCIPHERMENT ) + @r509_ext.data_encipherment?.should == @allowed_uses.include?( KeyUsage::AU_DATA_ENCIPHERMENT ) + @r509_ext.key_agreement?.should == @allowed_uses.include?( KeyUsage::AU_KEY_AGREEMENT ) + @r509_ext.key_cert_sign?.should == @allowed_uses.include?( KeyUsage::AU_KEY_CERT_SIGN ) + @r509_ext.crl_sign?.should == @allowed_uses.include?( KeyUsage::AU_CRL_SIGN ) + @r509_ext.encipher_only?.should == @allowed_uses.include?( KeyUsage::AU_ENCIPHER_ONLY ) + @r509_ext.decipher_only?.should == @allowed_uses.include?( KeyUsage::AU_DECIPHER_ONLY ) + end + + it "the #allows? method should work critical:#{critical}" do + @allowed_uses.each do |au| + @r509_ext.allows?(au).should == true end + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end -shared_examples_for "a correct R509 ExtendedKeyUsage object" do - before :all do - extension_name = "extendedKeyUsage" - klass = ExtendedKeyUsage - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 ExtendedKeyUsage object" do |critical| + before :all do + extension_name = "extendedKeyUsage" + klass = ExtendedKeyUsage + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value , critical ) + @r509_ext = klass.new( openssl_ext ) + end - it "allowed_uses should be non-nil" do - @r509_ext.allowed_uses.should_not == nil - end + it "allowed_uses should be non-nil critical:#{critical}" do + @r509_ext.allowed_uses.should_not == nil + end - it "allowed_uses should be correct" do - @r509_ext.allowed_uses.should == @allowed_uses - end + it "allowed_uses should be correct critical:#{critical}" do + @r509_ext.allowed_uses.should == @allowed_uses + end - it "the individual allowed-use functions should be correct" do - @r509_ext.web_server_authentication?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_WEB_SERVER_AUTH ) - @r509_ext.web_client_authentication?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_WEB_CLIENT_AUTH ) - @r509_ext.code_signing?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_CODE_SIGNING ) - @r509_ext.email_protection?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_EMAIL_PROTECTION ) + it "the individual allowed-use functions should be correct critical:#{critical}" do + @r509_ext.web_server_authentication?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_WEB_SERVER_AUTH ) + @r509_ext.web_client_authentication?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_WEB_CLIENT_AUTH ) + @r509_ext.code_signing?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_CODE_SIGNING ) + @r509_ext.email_protection?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_EMAIL_PROTECTION ) + @r509_ext.ocsp_signing?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_OCSP_SIGNING ) + @r509_ext.time_stamping?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_TIME_STAMPING ) + @r509_ext.any_extended_key_usage?.should == @allowed_uses.include?( ExtendedKeyUsage::AU_ANY_EXTENDED_KEY_USAGE ) + end + + it "the #allows? method should work critical:#{critical}" do + @allowed_uses.each do |au| + @r509_ext.allows?(au).should == true end + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end shared_examples_for "a correct R509 SubjectKeyIdentifier object" do - before :all do - extension_name = "subjectKeyIdentifier" - klass = SubjectKeyIdentifier - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end + before :all do + extension_name = "subjectKeyIdentifier" + klass = SubjectKeyIdentifier + openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) + @r509_ext = klass.new( openssl_ext ) + end - it "key should be correct" do - @r509_ext.key.should == @key - end + it "key should be correct" do + @r509_ext.key.should == @key + end end shared_examples_for "a correct R509 AuthorityKeyIdentifier object" do - before :all do - extension_name = "authorityKeyIdentifier" - klass = AuthorityKeyIdentifier - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end + before :all do + extension_name = "authorityKeyIdentifier" + klass = AuthorityKeyIdentifier + ef = OpenSSL::X509::ExtensionFactory.new + ef.issuer_certificate = OpenSSL::X509::Certificate.new TestFixtures::TEST_CA_CERT + openssl_ext = ef.create_extension( "authorityKeyIdentifier", @extension_value ) + @r509_ext = klass.new( openssl_ext ) + end - #TODO + it "has the expected type" do + @r509_ext.oid.should == "authorityKeyIdentifier" + end + + it "contains the key identifier" do + @r509_ext.key_identifier.should == "79:75:BB:84:3A:CB:2C:DE:7A:09:BE:31:1B:43:BC:1C:2A:4D:53:58" + end + it "parses the authority cert issuer and serial number" do + @r509_ext.authority_cert_issuer.value.to_s.should == "/C=US/ST=Illinois/L=Chicago/O=Ruby CA Project/CN=Test CA" + @r509_ext.authority_cert_serial_number.should == 'FF:D9:C7:0B:87:37:D1:94' + end end -shared_examples_for "a correct R509 SubjectAlternativeName object" do - before :all do - extension_name = "subjectAltName" - klass = SubjectAlternativeName - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 SubjectAlternativeName object" do |critical| + before :all do + extension_name = "subjectAltName" + klass = SubjectAlternativeName + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(@conf) + openssl_ext = ef.create_extension( extension_name, @extension_value , critical ) + @r509_ext = klass.new( openssl_ext ) + end - it "dns_names should be correct" do - @r509_ext.dns_names.should == @dns_names - end + it "dns_names should be correct critical:#{critical}" do + @r509_ext.dns_names.should == @dns_names + end - it "ip_addresses should be correct" do - @r509_ext.ip_addresses.should == @ip_addresses - end + it "ip_addresses should be correct critical:#{critical}" do + @r509_ext.ip_addresses.should == @ip_addresses + end - it "uris should be correct" do - @r509_ext.uris.should == @uris - end + it "rfc_822names should be correct critical:#{critical}" do + @r509_ext.rfc_822_names.should == @rfc_822_names + end + + it "uris should be correct critical:#{critical}" do + @r509_ext.uris.should == @uris + end + + it "dirNames should be correct critical:#{critical}" do + @r509_ext.directory_names.size.should == @directory_names.size + end + + it "ordered should be correct critical:#{critical}" do + @r509_ext.names.size.should == @dns_names.size + @ip_addresses.size + @rfc_822_names.size + @uris.size + @directory_names.size + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end -shared_examples_for "a correct R509 AuthorityInfoAccess object" do - before :all do - extension_name = "authorityInfoAccess" - klass = AuthorityInfoAccess - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 AuthorityInfoAccess object" do |critical| + before :all do + extension_name = "authorityInfoAccess" + klass = AuthorityInfoAccess + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value, critical ) + @r509_ext = klass.new( openssl_ext ) + end - it "ca_issuers_uri should be correct" do - @r509_ext.ca_issuers_uris.should == @ca_issuers_uris - end + it "ca_issuers_uri should be correct critical:#{critical}" do + @r509_ext.ca_issuers.uris.should == @ca_issuers_uris + end - it "ocsp_uri should be correct" do - @r509_ext.ocsp_uris.should == @ocsp_uris - end + it "ocsp_uri should be correct critical:#{critical}" do + @r509_ext.ocsp.uris.should == @ocsp_uris + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end -shared_examples_for "a correct R509 CrlDistributionPoints object" do - before :all do - extension_name = "crlDistributionPoints" - klass = CrlDistributionPoints - openssl_ext = OpenSSL::X509::Extension.new( extension_name, @extension_value ) - @r509_ext = klass.new( openssl_ext ) - end +shared_examples_for "a correct R509 CRLDistributionPoints object" do |critical| + before :all do + extension_name = "crlDistributionPoints" + klass = CRLDistributionPoints + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value , critical ) + @r509_ext = klass.new( openssl_ext ) + end - it "crl_uri should be correct" do - @r509_ext.crl_uris.should == @crl_uris - end + it "crl_uri should be correct critical:#{critical}" do + @r509_ext.crl.uris.should == @crl_uris + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end end +shared_examples_for "a correct R509 OCSPNoCheck object" do |critical| + before :all do + extension_name = "noCheck" + klass = OCSPNoCheck + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, "irrelevant", critical) + @r509_ext = klass.new( openssl_ext ) + end -describe R509::Cert::Extensions do - include R509::Cert::Extensions - - context "Class functions" do - context "#wrap_openssl_extensions and #get_unknown_extensions" do - context "with no extensions" do - before :each do - @wrappable_extensions = [] - @unknown_extensions = [] - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with one implemented extension" do - before :each do - @wrappable_extensions = [] - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:0" ) - - @unknown_extensions = [] - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with all implemented extensions" do - before :each do - @wrappable_extensions = [] - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:0" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "keyUsage", KeyUsage::AU_DIGITAL_SIGNATURE ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "extendedKeyUsage", ExtendedKeyUsage::AU_WEB_SERVER_AUTH ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "subjectKeyIdentifier", "00:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF:00:11:22" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "authorityKeyIdentifier", "keyid:always" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "subjectAltName", "DNS:www.test.local" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "authorityInfoAccess", "CA Issuers - URI:http://www.test.local" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "crlDistributionPoints", "URI:http://www.test.local" ) - - @unknown_extensions = [] - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with an unimplemented extension" do - before :each do - @wrappable_extensions = [] - - @unknown_extensions = [] - @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with implemented and unimplemented extensions" do - before :each do - @wrappable_extensions = [] - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:0" ) - - @unknown_extensions = [] - @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with multiple extensions of an implemented type" do - before :each do - @wrappable_extensions = [] - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:0" ) - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:1" ) - - @unknown_extensions = [] - @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it "should raise an ArgumentError for #wrap_openssl_extensions" do - expect { - R509::Cert::Extensions.wrap_openssl_extensions( @openssl_extensions ) - }.to raise_error(ArgumentError) - end - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - - context "with multiple extensions of an unimplemented type" do - before :each do - @wrappable_extensions = [] - @wrappable_extensions << OpenSSL::X509::Extension.new( "basicConstraints", "CA:TRUE;pathlen:0" ) - - @unknown_extensions = [] - @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) - @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www2.test.local" ) - - @openssl_extensions = @wrappable_extensions + @unknown_extensions - end - - it_should_behave_like "a correctly implemented wrap_openssl_extensions" - it_should_behave_like "a correctly implemented get_unknown_extensions" - end - end + it "has the expected type" do + @r509_ext.oid.should == "noCheck" + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end +end + +shared_examples_for "a correct R509 CertificatePolicies object" do + before :all do + klass = CertificatePolicies + openssl_ext = OpenSSL::X509::Extension.new @policy_data + @r509_ext = klass.new( openssl_ext ) + end + + it "should correctly parse the data" do + @r509_ext.policies.count.should == 1 + @r509_ext.policies[0].policy_identifier.should == "2.16.840.1.12345.1.2.3.4.1" + @r509_ext.policies[0].policy_qualifiers.cps_uris.should == ["http://example.com/cps", "http://other.com/cps"] + end +end + +shared_examples_for "a correct R509 InhibitAnyPolicy object" do |critical| + before :all do + extension_name = "inhibitAnyPolicy" + klass = InhibitAnyPolicy + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @skip_certs.to_s,critical) + @r509_ext = klass.new( openssl_ext ) + end + + it "should parse the integer value out of the extension" do + @r509_ext.skip_certs.should == @skip_certs + end + + it "reports #critical? properly" do + @r509_ext.critical?.should == critical + end +end + +shared_examples_for "a correct R509 PolicyConstraints object" do |critical| + before :all do + extension_name = "policyConstraints" + klass = PolicyConstraints + ef = OpenSSL::X509::ExtensionFactory.new + openssl_ext = ef.create_extension( extension_name, @extension_value, critical) + @r509_ext = klass.new( openssl_ext ) + end + + it "should have the expected require policy" do + @r509_ext.require_explicit_policy.should == @require_explicit_policy + end + it "should have the expected inhibit mapping" do + @r509_ext.inhibit_policy_mapping.should == @inhibit_policy_mapping + end +end + +shared_examples_for "a correct R509 NameConstraints object" do |critical| + before :all do + extension_name = "nameConstraints" + klass = NameConstraints + ef = OpenSSL::X509::ExtensionFactory.new + ef.config = OpenSSL::Config.parse(@conf) + openssl_ext = ef.create_extension( extension_name, @extension_value, critical) + @r509_ext = klass.new( openssl_ext ) + end + + it "should have the permitted names" do + @permitted_names.each_with_index do |name,index| + @r509_ext.permitted_names[index].tag.should == name[:tag] + @r509_ext.permitted_names[index].value.should == name[:value] end + end + it "should have the excluded names" do + @excluded_names.each_with_index do |name,index| + @r509_ext.excluded_names[index].tag.should == name[:tag] + @r509_ext.excluded_names[index].value.should == name[:value] + end + end +end - context "BasicConstraints" do - context "with constraints for a CA certificate" do - before :all do - @extension_value = "CA:TRUE;pathlen:1" - @is_ca = true - @pathlen = 1 - @allows_sub_ca = true - end +describe R509::Cert::Extensions do + include R509::Cert::Extensions - it_should_behave_like "a correct R509 BasicConstraints object" + context "Class functions" do + context "#wrap_openssl_extensions and #get_unknown_extensions" do + context "with no extensions" do + before :each do + @wrappable_extensions = [] + @unknown_extensions = [] + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - context "with constraints for a sub-CA certificate" do - before :all do - @extension_value = "CA:TRUE;pathlen:0" - @is_ca = true - @pathlen = 0 - @allows_sub_ca = false - end + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 BasicConstraints object" + context "with one implemented extension" do + before :each do + @wrappable_extensions = [] + ef = OpenSSL::X509::ExtensionFactory.new + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:0" ) + + @unknown_extensions = [] + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - context "with constraints for a non-CA certificate" do - before :all do - @extension_value = "CA:FALSE" - @is_ca = false - @pathlen = nil - @allows_sub_ca = false - end + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 BasicConstraints object" + context "with all implemented extensions" do + before :each do + @wrappable_extensions = [] + ef = OpenSSL::X509::ExtensionFactory.new + ef.issuer_certificate = OpenSSL::X509::Certificate.new TestFixtures::TEST_CA_CERT + ef.subject_certificate = OpenSSL::X509::Certificate.new TestFixtures::TEST_CA_CERT + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:0", true ) + @wrappable_extensions << ef.create_extension( "keyUsage", KeyUsage::AU_DIGITAL_SIGNATURE ) + @wrappable_extensions << ef.create_extension( "extendedKeyUsage", ExtendedKeyUsage::AU_WEB_SERVER_AUTH ) + @wrappable_extensions << ef.create_extension( "subjectKeyIdentifier", "hash" ) + @wrappable_extensions << ef.create_extension( "authorityKeyIdentifier", "keyid:always" ) + @wrappable_extensions << ef.create_extension( "subjectAltName", "DNS:www.test.local" ) + @wrappable_extensions << ef.create_extension( "authorityInfoAccess", "caIssuers;URI:http://www.test.local" ) + @wrappable_extensions << ef.create_extension( "crlDistributionPoints", "URI:http://www.test.local" ) + + @unknown_extensions = [] + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - end - context "KeyUsage" do - context "with one allowed use" do - before :all do - @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE ] - @extension_value = @allowed_uses.join( ", " ) - end + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 KeyUsage object" + context "with an unimplemented extension" do + before :each do + @wrappable_extensions = [] + + @unknown_extensions = [] + @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - context "with some allowed uses" do - before :all do - # this spec and the one below alternate the uses - @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE, KeyUsage::AU_KEY_ENCIPHERMENT, KeyUsage::AU_KEY_AGREEMENT, KeyUsage::AU_CRL_SIGN, KeyUsage::AU_DECIPHER_ONLY ] - @extension_value = @allowed_uses.join( ", " ) - end + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 KeyUsage object" + context "with implemented and unimplemented extensions" do + before :each do + @wrappable_extensions = [] + ef = OpenSSL::X509::ExtensionFactory.new + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:0" ) + + @unknown_extensions = [] + @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - context "with some different allowed uses" do - before :all do - @allowed_uses = [ KeyUsage::AU_NON_REPUDIATION, KeyUsage::AU_DATA_ENCIPHERMENT, KeyUsage::AU_CERTIFICATE_SIGN, KeyUsage::AU_ENCIPHER_ONLY ] - @extension_value = @allowed_uses.join( ", " ) - end + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 KeyUsage object" + context "with multiple extensions of an implemented type" do + before :each do + @wrappable_extensions = [] + ef = OpenSSL::X509::ExtensionFactory.new + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:0" ) + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:1" ) + + @unknown_extensions = [] + @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end - context "with all allowed uses" do - before :all do - @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE, KeyUsage::AU_KEY_ENCIPHERMENT, - KeyUsage::AU_KEY_AGREEMENT, KeyUsage::AU_CRL_SIGN, KeyUsage::AU_DECIPHER_ONLY, - KeyUsage::AU_NON_REPUDIATION, KeyUsage::AU_DATA_ENCIPHERMENT, - KeyUsage::AU_CERTIFICATE_SIGN, KeyUsage::AU_ENCIPHER_ONLY ] - @extension_value = @allowed_uses.join( ", " ) - end + it "should raise an ArgumentError for #wrap_openssl_extensions" do + expect { + R509::Cert::Extensions.wrap_openssl_extensions( @openssl_extensions ) + }.to raise_error(ArgumentError) + end + it_should_behave_like "a correctly implemented get_unknown_extensions" + end - it_should_behave_like "a correct R509 KeyUsage object" + context "with multiple extensions of an unimplemented type" do + before :each do + @wrappable_extensions = [] + ef = OpenSSL::X509::ExtensionFactory.new + @wrappable_extensions << ef.create_extension( "basicConstraints", "CA:TRUE,pathlen:0" ) + + @unknown_extensions = [] + @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www.test.local" ) + @unknown_extensions << OpenSSL::X509::Extension.new( "issuerAltName", "DNS:www2.test.local" ) + + @openssl_extensions = @wrappable_extensions + @unknown_extensions end + + it_should_behave_like "a correctly implemented wrap_openssl_extensions" + it_should_behave_like "a correctly implemented get_unknown_extensions" + end end + end - context "ExtendedKeyUsage" do - context "with one allowed use" do - before :all do - @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH ] - @extension_value = @allowed_uses.join( ", " ) - end + context "BasicConstraints" do + context "with constraints for a CA certificate" do + before :all do + @extension_value = "CA:TRUE,pathlen:3" + @is_ca = true + @pathlen = 3 + @allows_sub_ca = true + end - it_should_behave_like "a correct R509 ExtendedKeyUsage object" - end + it_should_behave_like "a correct R509 BasicConstraints object", false + it_should_behave_like "a correct R509 BasicConstraints object", true + end - context "with some allowed uses" do - before :all do - # this spec and the one below alternate the uses - @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH, ExtendedKeyUsage::AU_CODE_SIGNING ] - @extension_value = @allowed_uses.join( ", " ) - end + context "with constraints for a sub-CA certificate" do + before :all do + @extension_value = "CA:TRUE,pathlen:0" + @is_ca = true + @pathlen = 0 + @allows_sub_ca = false + end - it_should_behave_like "a correct R509 ExtendedKeyUsage object" - end + it_should_behave_like "a correct R509 BasicConstraints object", false + it_should_behave_like "a correct R509 BasicConstraints object", true + end - context "with some different allowed uses" do - before :all do - @allowed_uses = [ ExtendedKeyUsage::AU_WEB_CLIENT_AUTH, ExtendedKeyUsage::AU_EMAIL_PROTECTION ] - @extension_value = @allowed_uses.join( ", " ) - end + context "with constraints for a non-CA certificate" do + before :all do + @extension_value = "CA:FALSE" + @is_ca = false + @pathlen = nil + @allows_sub_ca = false + end - it_should_behave_like "a correct R509 ExtendedKeyUsage object" - end + it_should_behave_like "a correct R509 BasicConstraints object", false + it_should_behave_like "a correct R509 BasicConstraints object", true + end + end - context "with all allowed uses" do - before :all do - @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH, ExtendedKeyUsage::AU_CODE_SIGNING, - ExtendedKeyUsage::AU_WEB_CLIENT_AUTH, ExtendedKeyUsage::AU_EMAIL_PROTECTION ] - @extension_value = @allowed_uses.join( ", " ) - end + context "KeyUsage" do + context "with one allowed use" do + before :all do + @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 ExtendedKeyUsage object" - end + it_should_behave_like "a correct R509 KeyUsage object", false + it_should_behave_like "a correct R509 KeyUsage object", true end - context "SubjectKeyIdentifier" do - before :all do - @extension_value = "00:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF:00:11:22" - @key = @extension_value - end + context "with some allowed uses" do + before :all do + # this spec and the one below alternate the uses + @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE, KeyUsage::AU_KEY_ENCIPHERMENT, KeyUsage::AU_KEY_AGREEMENT, KeyUsage::AU_CRL_SIGN, KeyUsage::AU_DECIPHER_ONLY ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectKeyIdentifier object" + it_should_behave_like "a correct R509 KeyUsage object", false + it_should_behave_like "a correct R509 KeyUsage object", true end - context "AuthorityKeyIdentifier" do - before :all do - @extension_value = "keyid:always" - end + context "with some different allowed uses" do + before :all do + @allowed_uses = [ KeyUsage::AU_NON_REPUDIATION, KeyUsage::AU_DATA_ENCIPHERMENT, KeyUsage::AU_KEY_CERT_SIGN, KeyUsage::AU_ENCIPHER_ONLY ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 AuthorityKeyIdentifier object" + it_should_behave_like "a correct R509 KeyUsage object", false + it_should_behave_like "a correct R509 KeyUsage object", true end - context "SubjectAlternativeName" do - context "with a DNS alternative name only" do - before :all do - @dns_names = ["www.test.local"] - @ip_addresses = [] - @uris = [] - @extension_value = "DNS:#{@dns_names.join(",DNS:")}" - end + context "with all allowed uses" do + before :all do + @allowed_uses = [ KeyUsage::AU_DIGITAL_SIGNATURE, KeyUsage::AU_NON_REPUDIATION, + KeyUsage::AU_KEY_ENCIPHERMENT, KeyUsage::AU_DATA_ENCIPHERMENT, + KeyUsage::AU_KEY_AGREEMENT, KeyUsage::AU_KEY_CERT_SIGN, + KeyUsage::AU_CRL_SIGN, KeyUsage::AU_ENCIPHER_ONLY, + KeyUsage::AU_DECIPHER_ONLY ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 KeyUsage object", false + it_should_behave_like "a correct R509 KeyUsage object", true + end + end - context "with multiple DNS alternative names only" do - before :all do - @dns_names = ["www.test.local", "www2.test.local"] - @ip_addresses = [] - @uris = [] - @extension_value = "DNS:#{@dns_names.join(",DNS:")}" - end + context "ExtendedKeyUsage" do + context "with one allowed use" do + before :all do + @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 ExtendedKeyUsage object", false + it_should_behave_like "a correct R509 ExtendedKeyUsage object", true + end - context "with an IP address alternative name only" do - before :all do - @dns_names = [] - @ip_addresses = ["10.1.2.3"] - @uris = [] - @extension_value = "IP:#{@ip_addresses.join(",IP:")}" - end + context "with some allowed uses" do + before :all do + # this spec and the one below alternate the uses + @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH, ExtendedKeyUsage::AU_CODE_SIGNING ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 ExtendedKeyUsage object", false + it_should_behave_like "a correct R509 ExtendedKeyUsage object", true + end - context "with multiple IP address alternative names only" do - before :all do - @dns_names = [] - @ip_addresses = ["10.1.2.3", "10.1.2.4"] - @uris = [] - @extension_value = "IP:#{@ip_addresses.join(",IP:")}" - end + context "with some different allowed uses" do + before :all do + @allowed_uses = [ ExtendedKeyUsage::AU_WEB_CLIENT_AUTH, ExtendedKeyUsage::AU_EMAIL_PROTECTION ] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 ExtendedKeyUsage object", false + it_should_behave_like "a correct R509 ExtendedKeyUsage object", true + end - context "with a URI alternative name only" do - before :all do - @dns_names = [] - @ip_addresses = [] - @uris = ["http://www.test.local"] - @extension_value = "URI:#{@uris.join(",URI:")}" - end + context "with all allowed uses" do + before :all do + @allowed_uses = [ ExtendedKeyUsage::AU_WEB_SERVER_AUTH, ExtendedKeyUsage::AU_CODE_SIGNING, + ExtendedKeyUsage::AU_WEB_CLIENT_AUTH, ExtendedKeyUsage::AU_EMAIL_PROTECTION, + ExtendedKeyUsage::AU_TIME_STAMPING, ExtendedKeyUsage::AU_OCSP_SIGNING, + ExtendedKeyUsage::AU_ANY_EXTENDED_KEY_USAGE] + @extension_value = @allowed_uses.join( ", " ) + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 ExtendedKeyUsage object", false + it_should_behave_like "a correct R509 ExtendedKeyUsage object", true + end + end - context "with multiple URI alternative names only" do - before :all do - @dns_names = [] - @ip_addresses = [] - @uris = ["http://www.test.local","http://www2.test.local"] - @extension_value = "URI:#{@uris.join(",URI:")}" - end + context "SubjectKeyIdentifier" do + before :all do + @extension_value = "00:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF:00:11:22" + @key = @extension_value + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 SubjectKeyIdentifier object" + end - context "with multiple different alternative names" do - before :all do - @dns_names = ["www.test.local"] - @ip_addresses = ["10.1.2.3"] - @uris = ["http://www.test.local"] - @extension_value = "DNS:#{@dns_names.join(",DNS:")},IP:#{@ip_addresses.join(",IP:")},URI:#{@uris.join(",URI:")}" - end + context "AuthorityKeyIdentifier" do + before :all do + @extension_value = "keyid:always,issuer:always" + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 AuthorityKeyIdentifier object" + end - context "with multiple different alternative names with trailing newlines" do - before :all do - @dns_names = ["www.test.local"] - @ip_addresses = ["10.1.2.3"] - @uris = ["http://www.test.local"] - @extension_value = "DNS:#{@dns_names.join("\n,DNS:")}\n,IP:#{@ip_addresses.join("\n,IP:")}\n,URI:#{@uris.join("\n,URI:")}\n" - end + context "SubjectAlternativeName" do + context "with an unimplemented GeneralName type" do + it "errors as expected" do + ef = OpenSSL::X509::ExtensionFactory.new + ext = ef.create_extension("subjectAltName","otherName:1.2.3.4;IA5STRING:Hello World") + expect { R509::Cert::Extensions::SubjectAlternativeName.new ext }.to raise_error(R509::R509Error, 'Unimplemented GeneralName tag: 0. At this time R509 does not support GeneralName types other than rfc822Name, dNSName, uniformResourceIdentifier, iPAddress, and directoryName') + end + end + context "with a DNS alternative name only" do + before :all do + @dns_names = ["www.test.local"] + @ip_addresses = [] + @uris = [] + @rfc_822_names = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - it_should_behave_like "a correct R509 SubjectAlternativeName object" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true end - context "AuthorityInfoAccess" do - context "with a CA Issuers URI only" do - before :all do - @ca_issuers_uris = ["http://www.test.local/ca.cert"] - @ocsp_uris = [] - @extension_value = "CA Issuers - URI:#{@ca_issuers_uris.join(",URI:")}" - end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with multiple DNS alternative names only" do + before :all do + @dns_names = ["www.test.local", "www2.test.local"] + @ip_addresses = [] + @uris = [] + @rfc_822_names = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - context "with multiple CA Issuers URIs only" do - before :all do - @ca_issuers_uris = ["http://www.test.local/ca.cert", "http://www.test.local/subca.cert"] - @ocsp_uris = [] - @extension_value = "CA Issuers - URI:#{@ca_issuers_uris.join(",CA Issuers - URI:")}" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with an IP address alternative name only" do + before :all do + @dns_names = [] + @ip_addresses = ["203.1.2.3"] + @rfc_822_names = [] + @uris = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - context "with an OCSP URI only" do - before :all do - @ca_issuers_uris = [] - @ocsp_uris = ["http://www.test.local"] - @extension_value = "OCSP - URI:#{@ocsp_uris.join(",URI:")}" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with multiple IP address alternative names only" do + before :all do + @dns_names = [] + @ip_addresses = ["10.1.2.3", "10.1.2.4"] + @uris = [] + @rfc_822_names = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - context "with multiple OCSP URIs only" do - before :all do - @ca_issuers_uris = [] - @ocsp_uris = ["http://www.test.local", "http://www2.test.local"] - @extension_value = "OCSP - URI:#{@ocsp_uris.join(",OCSP - URI:")}" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with an rfc822Name alternative name only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = ["some@guy.com"] + @uris = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - context "with both a CA Issuers URI and an OCSP URI" do - before :all do - @ca_issuers_uris = ["http://www.test.local/ca.cert"] - @ocsp_uris = ["http://www.test.local"] - @extension_value = "CA Issuers - URI:#{@ca_issuers_uris.join(",CA Issuers - URI:")},OCSP - URI:#{@ocsp_uris.join(",URI:")}" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with multiple rfc822Name alternative names only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = ["some@guy.com","other@guy.com"] + @uris = [] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - context "with both a CA Issuers URI and an OCSP URI with trailing newlines" do - before :all do - @ca_issuers_uris = ["http://www.test.local/ca.cert"] - @ocsp_uris = ["http://www.test.local"] - @extension_value = "CA Issuers - URI:#{@ca_issuers_uris.join("\n,CA Issuers - URI:")}\n,OCSP - URI:#{@ocsp_uris.join("\n,URI:")}\n" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - it_should_behave_like "a correct R509 AuthorityInfoAccess object" - end + context "with a URI alternative name only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = [] + @uris = ["http://www.test.local"] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end + + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true end - context "CrlDistributionPoints" do - context "wtih a single CRL URI" do - before :all do - @crl_uris = ["http://www.test.local/ca.crl"] - @extension_value = "URI:#{@crl_uris.join(",URI:")}" - end + context "with multiple URI alternative names only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = [] + @uris = ["http://www.test.local","http://www2.test.local"] + @directory_names = [] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - it_should_behave_like "a correct R509 CrlDistributionPoints object" - end + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end - context "wtih multiple CRL URIs" do - before :all do - @crl_uris = ["http://www.test.local/ca.crl", "http://www.test.local/subca.crl"] - @extension_value = "URI:#{@crl_uris.join(",URI:")}" - end + context "with a directoryName alternative name only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = [] + @uris = [] + @directory_names = [ + [['CN','langui.sh'],['O','org'],['L','locality']] + ] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end - it_should_behave_like "a correct R509 CrlDistributionPoints object" + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end + + context "with multiple directoryName alternative names only" do + before :all do + @dns_names = [] + @ip_addresses = [] + @rfc_822_names = [] + @uris = [] + @directory_names = [ + [['CN','langui.sh'],['O','org'],['L','locality']], + [['CN','otherdomain.com'],['O','org-like']] + ] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end + + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end + + context "with multiple different alternative names" do + before :all do + @dns_names = ["www.test.local"] + @ip_addresses = ["10.1.2.3"] + @rfc_822_names = ["myemail@email.com"] + @uris = ["http://www.test.local"] + @directory_names = [ + [['CN','langui.sh'],['O','org'],['L','locality']] + ] + total = [@dns_names,@ip_addresses,@uris,@rfc_822_names,@directory_names].flatten(1) + gns = R509::ASN1.general_name_parser(total) + serialized = gns.serialize_names + @conf = serialized[:conf] + @extension_value = serialized[:extension_string] + end + + it_should_behave_like "a correct R509 SubjectAlternativeName object", false + it_should_behave_like "a correct R509 SubjectAlternativeName object", true + end + end + context "AuthorityInfoAccess" do + context "with a CA Issuers URI only" do + before :all do + @ca_issuers_uris = ["http://www.test.local/ca.cert"] + @ocsp_uris = [] + @extension_value = "caIssuers;URI:#{@ca_issuers_uris.join(",caIssuers;URI:")}" + end + + it_should_behave_like "a correct R509 AuthorityInfoAccess object", false + it_should_behave_like "a correct R509 AuthorityInfoAccess object", true + end + + context "with multiple CA Issuers URIs only" do + before :all do + @ca_issuers_uris = ["http://www.test.local/ca.cert", "http://www.test.local/subca.cert"] + @ocsp_uris = [] + @extension_value = "caIssuers;URI:#{@ca_issuers_uris.join(",caIssuers;URI:")}" + end + + it_should_behave_like "a correct R509 AuthorityInfoAccess object", false + it_should_behave_like "a correct R509 AuthorityInfoAccess object", true + end + + context "with an OCSP URI only" do + before :all do + @ca_issuers_uris = [] + @ocsp_uris = ["http://www.test.local"] + @extension_value = "OCSP;URI:#{@ocsp_uris.join(",OCSP;URI:")}" + end + + it_should_behave_like "a correct R509 AuthorityInfoAccess object", false + it_should_behave_like "a correct R509 AuthorityInfoAccess object", true + end + + context "with multiple OCSP URIs only" do + before :all do + @ca_issuers_uris = [] + @ocsp_uris = ["http://www.test.local", "http://www2.test.local"] + @extension_value = "OCSP;URI:#{@ocsp_uris.join(",OCSP;URI:")}" + end + + it_should_behave_like "a correct R509 AuthorityInfoAccess object", false + it_should_behave_like "a correct R509 AuthorityInfoAccess object", true + end + + context "with both a CA Issuers URI and an OCSP URI" do + before :all do + @ca_issuers_uris = ["http://www.test.local/ca.cert"] + @ocsp_uris = ["http://www.test.local"] + @extension_value = "caIssuers;URI:#{@ca_issuers_uris.join(",caIssuers;URI:")},OCSP;URI:#{@ocsp_uris.join(",OCSP;URI:")}" + end + + it_should_behave_like "a correct R509 AuthorityInfoAccess object", false + it_should_behave_like "a correct R509 AuthorityInfoAccess object", true + end + end + + context "CRLDistributionPoints" do + context "with a single CRL URI" do + before :all do + @crl_uris = ["http://www.test.local/ca.crl"] + @extension_value = "URI:#{@crl_uris.join(",URI:")}" + end + + it_should_behave_like "a correct R509 CRLDistributionPoints object", false + it_should_behave_like "a correct R509 CRLDistributionPoints object", true + end + + context "with multiple CRL URIs" do + before :all do + @crl_uris = ["http://www.test.local/ca.crl", "http://www.test.local/subca.crl"] + @extension_value = "URI:#{@crl_uris.join(",URI:")}" + end + + it_should_behave_like "a correct R509 CRLDistributionPoints object", false + it_should_behave_like "a correct R509 CRLDistributionPoints object", true + end + end + + context "OCSPNoCheck" do + it_should_behave_like "a correct R509 OCSPNoCheck object", false + it_should_behave_like "a correct R509 OCSPNoCheck object", true + end + + context "CertificatePolicies" do + before :all do + @policy_data = "0\x81\x90\x06\x03U\x1D \x04\x81\x880\x81\x850\x81\x82\x06\v`\x86H\x01\xE09\x01\x02\x03\x04\x010s0\"\x06\b+\x06\x01\x05\x05\a\x02\x01\x16\x16http://example.com/cps0 \x06\b+\x06\x01\x05\x05\a\x02\x01\x16\x14http://other.com/cps0+\x06\b+\x06\x01\x05\x05\a\x02\x020\x1F0\x16\x16\x06my org0\f\x02\x01\x01\x02\x01\x02\x02\x01\x03\x02\x01\x04\x1A\x05thing" + end + + it_should_behave_like "a correct R509 CertificatePolicies object" + end + + context "InhibitAnyPolicy" do + before :all do + @skip_certs = 3 + end + + it_should_behave_like "a correct R509 InhibitAnyPolicy object", false + it_should_behave_like "a correct R509 InhibitAnyPolicy object", true + end + + context "PolicyConstraints" do + context "with just require" do + before :all do + @require_explicit_policy = 2 + @inhibit_policy_mapping = nil + @extension_value = "requireExplicitPolicy:#{@require_explicit_policy}" + end + it_should_behave_like "a correct R509 PolicyConstraints object", false + it_should_behave_like "a correct R509 PolicyConstraints object", true + end + context "with just inhibit" do + before :all do + @require_explicit_policy = nil + @inhibit_policy_mapping = 3 + @extension_value = "inhibitPolicyMapping:#{@inhibit_policy_mapping}" + end + it_should_behave_like "a correct R509 PolicyConstraints object", false + it_should_behave_like "a correct R509 PolicyConstraints object", true + end + context "with both require and inhibit" do + before :all do + @require_explicit_policy = 2 + @inhibit_policy_mapping = 3 + @extension_value = "requireExplicitPolicy:#{@require_explicit_policy},inhibitPolicyMapping:#{@inhibit_policy_mapping}" + end + it_should_behave_like "a correct R509 PolicyConstraints object", false + it_should_behave_like "a correct R509 PolicyConstraints object", true + end + + end + + context "NameConstraints" do + context "with one permitted name" do + before :all do + @excluded_names = [] + @permitted_names = [{:tag => 2, :value => ".whatever.com"}] + gns = R509::ASN1::GeneralNames.new + @permitted_names.each do |name| + gns.add_item(name) end + @conf = [] + permitted = gns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "permitted;" + serialized[:extension_string] + }.join(",") + @extension_value = permitted + @conf = @conf.join("\n") + end - context "wtih multiple CRL URIs and trailing newlines" do - before :all do - @crl_uris = ["http://www.test.local/ca.crl", "http://www.test.local/subca.crl"] - @extension_value = "URI:#{@crl_uris.join("\n,URI:")}\n" - end + it_should_behave_like "a correct R509 NameConstraints object", false + it_should_behave_like "a correct R509 NameConstraints object", true + end + context "with multiple permitted names" do + before :all do + @excluded_names = [] + @permitted_names = [{:tag => 2, :value => ".whatever.com"}, {:tag => 1, :value => "user@emaildomain.com" } ] + gns = R509::ASN1::GeneralNames.new + @permitted_names.each do |name| + gns.add_item(name) + end + @conf = [] + permitted = gns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "permitted;" + serialized[:extension_string] + }.join(",") + @extension_value = permitted + @conf = @conf.join("\n") + end - it_should_behave_like "a correct R509 CrlDistributionPoints object" + it_should_behave_like "a correct R509 NameConstraints object", false + it_should_behave_like "a correct R509 NameConstraints object", true + end + context "with one excluded name" do + before :all do + @permitted_names = [] + @excluded_names = [{:tag => 7, :value => "127.0.0.1/255.255.255.255"}] + egns = R509::ASN1::GeneralNames.new + @excluded_names.each do |name| + egns.add_item(name) end + @conf = [] + excluded = egns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "excluded;" + serialized[:extension_string] + }.join(",") + @extension_value = excluded + @conf = @conf.join("\n") + end + + it_should_behave_like "a correct R509 NameConstraints object", false + it_should_behave_like "a correct R509 NameConstraints object", true end + context "with multiple excluded names" do + before :all do + @permitted_names = [] + @excluded_names = [{:tag => 7, :value => "127.0.0.1/255.255.255.255"}, {:tag => 1, :value => "emaildomain.com" } ] + @permitted_names = [] + egns = R509::ASN1::GeneralNames.new + @excluded_names.each do |name| + egns.add_item(name) + end + @conf = [] + excluded = egns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "excluded;" + serialized[:extension_string] + }.join(",") + @extension_value = excluded + @conf = @conf.join("\n") + end + it_should_behave_like "a correct R509 NameConstraints object", false + it_should_behave_like "a correct R509 NameConstraints object", true + end + context "with both permitted and excluded names" do + before :all do + @excluded_names = [{:tag => 7, :value => "127.0.0.1/255.255.255.255"}, {:tag => 1, :value => "emaildomain.com" } ] + @permitted_names = [{:tag => 2, :value => ".whatever.com"}, {:tag => 1, :value => "user@emaildomain.com"} ] + gns = R509::ASN1::GeneralNames.new + @permitted_names.each do |name| + gns.add_item(name) + end + @conf = [] + permitted = gns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "permitted;" + serialized[:extension_string] + }.join(",") + egns = R509::ASN1::GeneralNames.new + @excluded_names.each do |name| + egns.add_item(name) + end + excluded = egns.names.map { |name| + serialized = name.serialize_name + @conf << serialized[:conf] + "excluded;" + serialized[:extension_string] + }.join(",") + @extension_value = permitted + "," + excluded + @conf = @conf.join("\n") + end + + it_should_behave_like "a correct R509 NameConstraints object", false + it_should_behave_like "a correct R509 NameConstraints object", true + end + end end