require 'spec_helper' shared_examples_for "a correct R509 BasicConstraints object" do |critical| before :all do extension_name = "basicConstraints" klass = R509::Cert::Extensions::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 (critical:#{critical})" do expect(@r509_ext.is_ca?).to eq(@is_ca) end it "the path length should be correct (critical:#{critical})" do expect(@r509_ext.path_length).to eq(@pathlen) end it "allows_sub_ca? should correctly report whether its path length allows it to issue CA certs (critical:#{critical})" do expect(@r509_ext.allows_sub_ca?).to eq(@allows_sub_ca) end it "reports #critical? properly" do expect(@r509_ext.critical?).to eq(critical) end end describe R509::Cert::Extensions::BasicConstraints do context "validate basic constraints structure" do it "must be a hash with key :ca" do expect { R509::Cert::Extensions::BasicConstraints.new('string') }.to raise_error(ArgumentError, "You must supply a hash with a key named :ca with a boolean value") expect { R509::Cert::Extensions::BasicConstraints.new({}) }.to raise_error(ArgumentError, "You must supply a hash with a key named :ca with a boolean value") end it "must have true or false for the ca key value" do expect { R509::Cert::Extensions::BasicConstraints.new(:ca => 'truestring') }.to raise_error(ArgumentError, "You must supply true/false for the :ca key when specifying basic constraints") end it "must not pass a path_length if ca is false" do expect { R509::Cert::Extensions::BasicConstraints.new(:ca => false, :path_length => 5) }.to raise_error(ArgumentError, ":path_length is not allowed when :ca is false") end it "must pass a non-negative integer to path_length" do expect { R509::Cert::Extensions::BasicConstraints.new(:ca => true, :path_length => -1.5) }.to raise_error(ArgumentError, "Path length must be a positive integer (>= 0)") expect { R509::Cert::Extensions::BasicConstraints.new(:ca => true, :path_length => 1.5) }.to raise_error(ArgumentError, "Path length must be a positive integer (>= 0)") end end context "BasicConstraints" do context "creation & yaml generation" do context "CA:true without pathlen" do before :all do @args = { :ca => true, :critical => true } @bc = R509::Cert::Extensions::BasicConstraints.new(@args) end it "creates extension" do expect(@bc.is_ca?).to be true expect(@bc.path_length).to be_nil end it "builds yaml" do expect(YAML.load(@bc.to_yaml)).to eq(@args) end end context "CA:TRUE with path_length" do before :all do @args = { :ca => true, :path_length => 3, :critical => true } @bc = R509::Cert::Extensions::BasicConstraints.new(@args) end it "creates extension" do expect(@bc.is_ca?).to be true expect(@bc.path_length).to eq(3) end it "builds yaml" do expect(YAML.load(@bc.to_yaml)).to eq(@args) end end context "CA:FALSE" do before :all do @args = { :ca => false, :critical => true } @bc = R509::Cert::Extensions::BasicConstraints.new(@args) end it "creates extension" do expect(@bc.is_ca?).to be false expect(@bc.path_length).to be_nil end it "builds yaml" do expect(YAML.load(@bc.to_yaml)).to eq(@args) end end context "default criticality" do before :all do @args = { :ca => false } @bc = R509::Cert::Extensions::BasicConstraints.new(@args) end it "creates extension" do expect(@bc.critical?).to be true end it "builds yaml" do expect(YAML.load(@bc.to_yaml)).to eq(@args.merge(:critical => true)) end end context "non-default criticality" do before :all do @args = { :ca => false, :critical => false } @bc = R509::Cert::Extensions::BasicConstraints.new(@args) end it "creates extension" do expect(@bc.critical?).to be false end it "builds yaml" do expect(YAML.load(@bc.to_yaml)).to eq(@args) end end it "errors when supplying path_length if CA:FALSE" do expect do R509::Cert::Extensions::BasicConstraints.new(:ca => false, :path_length => 4) end.to raise_error(ArgumentError, ":path_length is not allowed when :ca is false") end end 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 BasicConstraints object", false it_should_behave_like "a correct R509 BasicConstraints object", true end context "with constraints for a CA certificate with no path length" do before :all do @extension_value = "CA:TRUE" @is_ca = true @pathlen = nil @allows_sub_ca = true end it_should_behave_like "a correct R509 BasicConstraints object", false it_should_behave_like "a correct R509 BasicConstraints object", true 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 BasicConstraints object", false it_should_behave_like "a correct R509 BasicConstraints object", true 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 BasicConstraints object", false it_should_behave_like "a correct R509 BasicConstraints object", true end end end