diff options
author | Luke Kanies <luke@madstop.com> | 2008-03-19 17:30:39 -0500 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2008-04-15 21:34:05 -0500 |
commit | ee07d0b7f198857f700b9ad09713fe6b992ffee8 (patch) | |
tree | 48b5606de64d9c315d56ef1fc0c797045a762188 | |
parent | dc5c73bc72810bf63236581cdc9407b039ea135d (diff) | |
download | puppet-ee07d0b7f198857f700b9ad09713fe6b992ffee8.tar.gz puppet-ee07d0b7f198857f700b9ad09713fe6b992ffee8.tar.xz puppet-ee07d0b7f198857f700b9ad09713fe6b992ffee8.zip |
Adding tests for the certificate serial numbers
-rw-r--r-- | lib/puppet/ssl/certificate_authority.rb | 20 | ||||
-rwxr-xr-x | spec/unit/ssl/certificate_authority.rb | 184 |
2 files changed, 194 insertions, 10 deletions
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb index 971a9965e..19887c70b 100644 --- a/lib/puppet/ssl/certificate_authority.rb +++ b/lib/puppet/ssl/certificate_authority.rb @@ -61,28 +61,28 @@ class Puppet::SSL::CertificateAuthority < Puppet::SSL::Host end # Sign a given certificate request. - def sign(host, cert_type = :service, self_signed = false) - # This is only used by the CA for self-signing. - if host.is_a?(Puppet::SSL::CertificateRequest) - csr = host - host = csr.name + def sign(host, cert_type = :server, self_signing_csr = nil) + + # This is a self-signed certificate + if self_signing_csr + csr = self_signing_csr issuer = csr.content else + raise ArgumentError, "Cannot find CA certificate; cannot sign certificate for %s" % host unless certificate unless csr = Puppet::SSL::CertificateRequest.find(host, :in => :ca_file) - raise Puppet::Error, "Could not find certificate request for %s" % host + raise ArgumentError, "Could not find certificate request for %s" % host end issuer = certificate.content end - raise Puppet::Error, "Certificate request for #{host} does not match its own public key" unless csr.content.verify(csr.content.public_key) - raise ArgumentError, "Cannot find CA certificate; cannot sign certificate for %s" % host unless self_signed or certificate - cert = Puppet::SSL::Certificate.new(host) cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result # Save the now-signed cert, unless it's a self-signed cert, since we # assume it goes somewhere else. - cert.save(:in => :ca_file) unless self_signed + cert.save(:in => :ca_file) unless self_signing_csr + + return cert end # Do all of the initialization necessary to set up our diff --git a/spec/unit/ssl/certificate_authority.rb b/spec/unit/ssl/certificate_authority.rb index b1b33f8b9..8fb23d883 100755 --- a/spec/unit/ssl/certificate_authority.rb +++ b/spec/unit/ssl/certificate_authority.rb @@ -113,4 +113,188 @@ describe Puppet::SSL::CertificateAuthority do end end end + + describe "when signing" do + before do + Puppet.settings.stubs(:value).with(:certname).returns "whatever" + + Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true + + # Set up the CA + @key = mock 'key' + @key.stubs(:content).returns "cakey" + Puppet::SSL::CertificateAuthority.any_instance.stubs(:key).returns @key + @cacert = mock 'certificate' + @cacert.stubs(:content).returns "cacertificate" + Puppet::SSL::CertificateAuthority.any_instance.stubs(:certificate).returns @cacert + @ca = Puppet::SSL::CertificateAuthority.new + + # Stub out the factory + @name = "myhost" + @cert = stub 'certificate', :content => "mycert" + Puppet::SSL::Certificate.stubs(:new).returns @cert + + @cert.stubs(:content=) + + @factory = stub 'factory', :result => "my real cert" + Puppet::SSL::CertificateFactory.stubs(:new).returns @factory + + @request = stub 'request', :content => "myrequest" + end + + describe "and calculating the next certificate serial number" do + before do + @path = "/path/to/serial" + Puppet.settings.stubs(:value).with(:serial).returns @path + + @filehandle = stub 'filehandle', :<< => @filehandle + Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle + end + + it "should default to 0x0 for the first serial number" do + @ca.next_serial.should == 0x0 + end + + it "should return the current content of the serial file" do + FileTest.expects(:exist?).with(@path).returns true + File.expects(:read).with(@path).returns "0002" + + @ca.next_serial.should == 2 + end + + it "should write the next serial number to the serial file as hex" do + @filehandle.expects(:<<).with("0001") + + @ca.next_serial + end + + it "should lock the serial file while writing" do + Puppet.settings.expects(:readwritelock).with(:serial) + + @ca.next_serial + end + end + + describe "its own certificate" do + before do + @serial = 10 + @ca.stubs(:next_serial).returns @serial + end + + it "should not look up a certificate request for the host" do + Puppet::SSL::CertificateRequest.expects(:find).never + + @ca.sign(@name, :ca, @request) + end + + it "should use a certificate type of :ca" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[0] == :ca + end.returns @factory + @ca.sign(@name, :ca, @request) + end + + it "should pass the provided CSR as the CSR" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[1] == "myrequest" + end.returns @factory + @ca.sign(@name, :ca, @request) + end + + it "should use the provided CSR's content as the issuer" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[2] == "myrequest" + end.returns @factory + @ca.sign(@name, :ca, @request) + end + + it "should pass the next serial as the serial number" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[3] == @serial + end.returns @factory + @ca.sign(@name, :ca, @request) + end + + it "should not save the resulting certificate" do + @cert.expects(:save).never + end + end + + describe "another host's certificate" do + before do + @serial = 10 + @ca.stubs(:next_serial).returns @serial + + Puppet::SSL::CertificateRequest.stubs(:find).with(@name, :in => :ca_file).returns @request + @cert.stubs :save + end + + it "should fail if the CA certificate cannot be found" do + @ca.expects(:certificate).returns nil + + Puppet::SSL::CertificateRequest.stubs(:find).returns "csr" + + lambda { @ca.sign("myhost") }.should raise_error(ArgumentError) + end + + it "should use a certificate type of :server" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[0] == :server + end.returns @factory + + @ca.sign(@name) + end + + it "should use look up a CSR for the host in the :ca_file terminus" do + Puppet::SSL::CertificateRequest.expects(:find).with(@name, :in => :ca_file).returns @request + + @ca.sign(@name) + end + + it "should fail if no CSR can be found for the host" do + Puppet::SSL::CertificateRequest.expects(:find).with(@name, :in => :ca_file).returns nil + + lambda { @ca.sign(@name) }.should raise_error(ArgumentError) + end + + it "should use the CA certificate as the issuer" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[2] == @cacert.content + end.returns @factory + @ca.sign(@name) + end + + it "should pass the next serial as the serial number" do + Puppet::SSL::CertificateFactory.expects(:new).with do |*args| + args[3] == @serial + end.returns @factory + @ca.sign(@name) + end + + it "should save the resulting certificate in the :ca_file terminus" do + @cert.expects(:save).with(:in => :ca_file) + @ca.sign(@name) + end + end + + it "should create a certificate instance with the content set to the newly signed x509 certificate" do + @serial = 10 + @ca.stubs(:next_serial).returns @serial + + Puppet::SSL::CertificateRequest.stubs(:find).with(@name, :in => :ca_file).returns @request + @cert.stubs :save + Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert + + @ca.sign(@name) + end + + it "should return the certificate instance" do + @serial = 10 + @ca.stubs(:next_serial).returns @serial + + Puppet::SSL::CertificateRequest.stubs(:find).with(@name, :in => :ca_file).returns @request + @cert.stubs :save + @ca.sign(@name).should equal(@cert) + end + end end |