~ubuntu-branches/ubuntu/quantal/puppet/quantal-security

« back to all changes in this revision

Viewing changes to .pc/CVE-2011-3872.patch/spec/unit/ssl/certificate_authority_spec.rb

  • Committer: Bazaar Package Importer
  • Author(s): Marc Deslauriers
  • Date: 2011-10-24 15:05:12 UTC
  • Revision ID: james.westby@ubuntu.com-20111024150512-yxqwfdp6hcs6of5l
Tags: 2.7.1-1ubuntu3.2
* SECURITY UPDATE: puppet master impersonation via incorrect certificates
  - debian/patches/CVE-2011-3872.patch: refactor certificate handling.
  - Thanks to upstream for providing the patch.
  - CVE-2011-3872

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env rspec
 
2
require 'spec_helper'
 
3
 
 
4
require 'puppet/ssl/certificate_authority'
 
5
 
 
6
describe Puppet::SSL::CertificateAuthority do
 
7
  after do
 
8
    Puppet::Util::Cacher.expire
 
9
    Puppet.settings.clearused
 
10
  end
 
11
 
 
12
  def stub_ca_host
 
13
    @key = mock 'key'
 
14
    @key.stubs(:content).returns "cakey"
 
15
    @cacert = mock 'certificate'
 
16
    @cacert.stubs(:content).returns "cacertificate"
 
17
 
 
18
    @host = stub 'ssl_host', :key => @key, :certificate => @cacert, :name => Puppet::SSL::Host.ca_name
 
19
  end
 
20
 
 
21
  it "should have a class method for returning a singleton instance" do
 
22
    Puppet::SSL::CertificateAuthority.should respond_to(:instance)
 
23
  end
 
24
 
 
25
  describe "when finding an existing instance" do
 
26
    describe "and the host is a CA host and the run_mode is master" do
 
27
      before do
 
28
        Puppet.settings.stubs(:value).with(:ca).returns true
 
29
        Puppet.run_mode.stubs(:master?).returns true
 
30
 
 
31
        @ca = mock('ca')
 
32
        Puppet::SSL::CertificateAuthority.stubs(:new).returns @ca
 
33
      end
 
34
 
 
35
      it "should return an instance" do
 
36
        Puppet::SSL::CertificateAuthority.instance.should equal(@ca)
 
37
      end
 
38
 
 
39
      it "should always return the same instance" do
 
40
        Puppet::SSL::CertificateAuthority.instance.should equal(Puppet::SSL::CertificateAuthority.instance)
 
41
      end
 
42
    end
 
43
 
 
44
    describe "and the host is not a CA host" do
 
45
      it "should return nil" do
 
46
        Puppet.settings.stubs(:value).with(:ca).returns false
 
47
        Puppet.run_mode.stubs(:master?).returns true
 
48
 
 
49
        ca = mock('ca')
 
50
        Puppet::SSL::CertificateAuthority.expects(:new).never
 
51
        Puppet::SSL::CertificateAuthority.instance.should be_nil
 
52
      end
 
53
    end
 
54
 
 
55
    describe "and the run_mode is not master" do
 
56
      it "should return nil" do
 
57
        Puppet.settings.stubs(:value).with(:ca).returns true
 
58
        Puppet.run_mode.stubs(:master?).returns false
 
59
 
 
60
        ca = mock('ca')
 
61
        Puppet::SSL::CertificateAuthority.expects(:new).never
 
62
        Puppet::SSL::CertificateAuthority.instance.should be_nil
 
63
      end
 
64
    end
 
65
  end
 
66
 
 
67
  describe "when initializing" do
 
68
    before do
 
69
      Puppet.settings.stubs(:use)
 
70
      Puppet.settings.stubs(:value).returns "ca_testing"
 
71
 
 
72
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
 
73
    end
 
74
 
 
75
    it "should always set its name to the value of :certname" do
 
76
      Puppet.settings.expects(:value).with(:certname).returns "ca_testing"
 
77
 
 
78
      Puppet::SSL::CertificateAuthority.new.name.should == "ca_testing"
 
79
    end
 
80
 
 
81
    it "should create an SSL::Host instance whose name is the 'ca_name'" do
 
82
      Puppet::SSL::Host.expects(:ca_name).returns "caname"
 
83
 
 
84
      host = stub 'host'
 
85
      Puppet::SSL::Host.expects(:new).with("caname").returns host
 
86
 
 
87
      Puppet::SSL::CertificateAuthority.new
 
88
    end
 
89
 
 
90
    it "should use the :main, :ca, and :ssl settings sections" do
 
91
      Puppet.settings.expects(:use).with(:main, :ssl, :ca)
 
92
      Puppet::SSL::CertificateAuthority.new
 
93
    end
 
94
 
 
95
    it "should create an inventory instance" do
 
96
      Puppet::SSL::Inventory.expects(:new).returns "inventory"
 
97
 
 
98
      Puppet::SSL::CertificateAuthority.new.inventory.should == "inventory"
 
99
    end
 
100
 
 
101
    it "should make sure the CA is set up" do
 
102
      Puppet::SSL::CertificateAuthority.any_instance.expects(:setup)
 
103
 
 
104
      Puppet::SSL::CertificateAuthority.new
 
105
    end
 
106
  end
 
107
 
 
108
  describe "when setting itself up" do
 
109
    it "should generate the CA certificate if it does not have one" do
 
110
      Puppet.settings.stubs :use
 
111
 
 
112
      host = stub 'host'
 
113
      Puppet::SSL::Host.stubs(:new).returns host
 
114
 
 
115
      host.expects(:certificate).returns nil
 
116
 
 
117
      Puppet::SSL::CertificateAuthority.any_instance.expects(:generate_ca_certificate)
 
118
      Puppet::SSL::CertificateAuthority.new
 
119
    end
 
120
  end
 
121
 
 
122
  describe "when retrieving the certificate revocation list" do
 
123
    before do
 
124
      Puppet.settings.stubs(:use)
 
125
      Puppet.settings.stubs(:value).returns "ca_testing"
 
126
      Puppet.settings.stubs(:value).with(:cacrl).returns "/my/crl"
 
127
 
 
128
      cert = stub("certificate", :content => "real_cert")
 
129
      key = stub("key", :content => "real_key")
 
130
      @host = stub 'host', :certificate => cert, :name => "hostname", :key => key
 
131
 
 
132
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
 
133
      @ca = Puppet::SSL::CertificateAuthority.new
 
134
 
 
135
      @ca.stubs(:host).returns @host
 
136
    end
 
137
 
 
138
    it "should return any found CRL instance" do
 
139
      crl = mock 'crl'
 
140
      Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns crl
 
141
      @ca.crl.should equal(crl)
 
142
    end
 
143
 
 
144
    it "should create, generate, and save a new CRL instance of no CRL can be found" do
 
145
      crl = Puppet::SSL::CertificateRevocationList.new("fakename")
 
146
      Puppet::SSL::CertificateRevocationList.indirection.expects(:find).returns nil
 
147
 
 
148
      Puppet::SSL::CertificateRevocationList.expects(:new).returns crl
 
149
 
 
150
      crl.expects(:generate).with(@ca.host.certificate.content, @ca.host.key.content)
 
151
      Puppet::SSL::CertificateRevocationList.indirection.expects(:save).with(crl)
 
152
 
 
153
      @ca.crl.should equal(crl)
 
154
    end
 
155
  end
 
156
 
 
157
  describe "when generating a self-signed CA certificate" do
 
158
    before do
 
159
      Puppet.settings.stubs(:use)
 
160
      Puppet.settings.stubs(:value).returns "ca_testing"
 
161
 
 
162
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:setup)
 
163
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:crl)
 
164
      @ca = Puppet::SSL::CertificateAuthority.new
 
165
 
 
166
      @host = stub 'host', :key => mock("key"), :name => "hostname", :certificate => mock('certificate')
 
167
 
 
168
      Puppet::SSL::CertificateRequest.any_instance.stubs(:generate)
 
169
 
 
170
      @ca.stubs(:host).returns @host
 
171
    end
 
172
 
 
173
    it "should create and store a password at :capass" do
 
174
      Puppet.settings.expects(:value).with(:capass).returns "/path/to/pass"
 
175
 
 
176
      FileTest.expects(:exist?).with("/path/to/pass").returns false
 
177
 
 
178
      fh = mock 'filehandle'
 
179
      Puppet.settings.expects(:write).with(:capass).yields fh
 
180
 
 
181
      fh.expects(:print).with { |s| s.length > 18 }
 
182
 
 
183
      @ca.stubs(:sign)
 
184
 
 
185
      @ca.generate_ca_certificate
 
186
    end
 
187
 
 
188
    it "should generate a key if one does not exist" do
 
189
      @ca.stubs :generate_password
 
190
      @ca.stubs :sign
 
191
 
 
192
      @ca.host.expects(:key).returns nil
 
193
      @ca.host.expects(:generate_key)
 
194
 
 
195
      @ca.generate_ca_certificate
 
196
    end
 
197
 
 
198
    it "should create and sign a self-signed cert using the CA name" do
 
199
      request = mock 'request'
 
200
      Puppet::SSL::CertificateRequest.expects(:new).with(@ca.host.name).returns request
 
201
      request.expects(:generate).with(@ca.host.key)
 
202
 
 
203
      @ca.expects(:sign).with(@host.name, :ca, request)
 
204
 
 
205
      @ca.stubs :generate_password
 
206
 
 
207
      @ca.generate_ca_certificate
 
208
    end
 
209
 
 
210
    it "should generate its CRL" do
 
211
      @ca.stubs :generate_password
 
212
      @ca.stubs :sign
 
213
 
 
214
      @ca.host.expects(:key).returns nil
 
215
      @ca.host.expects(:generate_key)
 
216
 
 
217
      @ca.expects(:crl)
 
218
 
 
219
      @ca.generate_ca_certificate
 
220
    end
 
221
  end
 
222
 
 
223
  describe "when signing" do
 
224
    before do
 
225
      Puppet.settings.stubs(:use)
 
226
 
 
227
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
 
228
 
 
229
      stub_ca_host
 
230
 
 
231
      Puppet::SSL::Host.expects(:new).with(Puppet::SSL::Host.ca_name).returns @host
 
232
 
 
233
      @ca = Puppet::SSL::CertificateAuthority.new
 
234
 
 
235
      @name = "myhost"
 
236
      @real_cert = stub 'realcert', :sign => nil
 
237
      @cert = Puppet::SSL::Certificate.new(@name)
 
238
      @cert.content = @real_cert
 
239
 
 
240
      Puppet::SSL::Certificate.stubs(:new).returns @cert
 
241
 
 
242
      @cert.stubs(:content=)
 
243
      Puppet::SSL::Certificate.indirection.stubs(:save)
 
244
 
 
245
      # Stub out the factory
 
246
      @factory = stub 'factory', :result => "my real cert"
 
247
      Puppet::SSL::CertificateFactory.stubs(:new).returns @factory
 
248
 
 
249
      @request = stub 'request', :content => "myrequest", :name => @name
 
250
 
 
251
      # And the inventory
 
252
      @inventory = stub 'inventory', :add => nil
 
253
      @ca.stubs(:inventory).returns @inventory
 
254
 
 
255
      Puppet::SSL::CertificateRequest.indirection.stubs(:destroy)
 
256
    end
 
257
 
 
258
    describe "and calculating the next certificate serial number" do
 
259
      before do
 
260
        @path = "/path/to/serial"
 
261
        Puppet.settings.stubs(:value).with(:serial).returns @path
 
262
 
 
263
        @filehandle = stub 'filehandle', :<< => @filehandle
 
264
        Puppet.settings.stubs(:readwritelock).with(:serial).yields @filehandle
 
265
      end
 
266
 
 
267
      it "should default to 0x1 for the first serial number" do
 
268
        @ca.next_serial.should == 0x1
 
269
      end
 
270
 
 
271
      it "should return the current content of the serial file" do
 
272
        FileTest.stubs(:exist?).with(@path).returns true
 
273
        File.expects(:read).with(@path).returns "0002"
 
274
 
 
275
        @ca.next_serial.should == 2
 
276
      end
 
277
 
 
278
      it "should write the next serial number to the serial file as hex" do
 
279
        @filehandle.expects(:<<).with("0002")
 
280
 
 
281
        @ca.next_serial
 
282
      end
 
283
 
 
284
      it "should lock the serial file while writing" do
 
285
        Puppet.settings.expects(:readwritelock).with(:serial)
 
286
 
 
287
        @ca.next_serial
 
288
      end
 
289
    end
 
290
 
 
291
    describe "its own certificate" do
 
292
      before do
 
293
        @serial = 10
 
294
        @ca.stubs(:next_serial).returns @serial
 
295
      end
 
296
 
 
297
      it "should not look up a certificate request for the host" do
 
298
        Puppet::SSL::CertificateRequest.indirection.expects(:find).never
 
299
 
 
300
        @ca.sign(@name, :ca, @request)
 
301
      end
 
302
 
 
303
      it "should use a certificate type of :ca" do
 
304
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
305
          args[0] == :ca
 
306
        end.returns @factory
 
307
        @ca.sign(@name, :ca, @request)
 
308
      end
 
309
 
 
310
      it "should pass the provided CSR as the CSR" do
 
311
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
312
          args[1] == "myrequest"
 
313
        end.returns @factory
 
314
        @ca.sign(@name, :ca, @request)
 
315
      end
 
316
 
 
317
      it "should use the provided CSR's content as the issuer" do
 
318
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
319
          args[2] == "myrequest"
 
320
        end.returns @factory
 
321
        @ca.sign(@name, :ca, @request)
 
322
      end
 
323
 
 
324
      it "should pass the next serial as the serial number" do
 
325
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
326
          args[3] == @serial
 
327
        end.returns @factory
 
328
        @ca.sign(@name, :ca, @request)
 
329
      end
 
330
 
 
331
      it "should save the resulting certificate" do
 
332
        Puppet::SSL::Certificate.indirection.expects(:save).with(@cert)
 
333
 
 
334
        @ca.sign(@name, :ca, @request)
 
335
      end
 
336
    end
 
337
 
 
338
    describe "another host's certificate" do
 
339
      before do
 
340
        @serial = 10
 
341
        @ca.stubs(:next_serial).returns @serial
 
342
 
 
343
        Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
 
344
        Puppet::SSL::CertificateRequest.indirection.stubs :save
 
345
      end
 
346
 
 
347
      it "should use a certificate type of :server" do
 
348
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
349
          args[0] == :server
 
350
        end.returns @factory
 
351
 
 
352
        @ca.sign(@name)
 
353
      end
 
354
 
 
355
      it "should use look up a CSR for the host in the :ca_file terminus" do
 
356
        Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns @request
 
357
 
 
358
        @ca.sign(@name)
 
359
      end
 
360
 
 
361
      it "should fail if no CSR can be found for the host" do
 
362
        Puppet::SSL::CertificateRequest.indirection.expects(:find).with(@name).returns nil
 
363
 
 
364
        lambda { @ca.sign(@name) }.should raise_error(ArgumentError)
 
365
      end
 
366
 
 
367
      it "should use the CA certificate as the issuer" do
 
368
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
369
          args[2] == @cacert.content
 
370
        end.returns @factory
 
371
        @ca.sign(@name)
 
372
      end
 
373
 
 
374
      it "should pass the next serial as the serial number" do
 
375
        Puppet::SSL::CertificateFactory.expects(:new).with do |*args|
 
376
          args[3] == @serial
 
377
        end.returns @factory
 
378
        @ca.sign(@name)
 
379
      end
 
380
 
 
381
      it "should sign the resulting certificate using its real key and a digest" do
 
382
        digest = mock 'digest'
 
383
        OpenSSL::Digest::SHA1.expects(:new).returns digest
 
384
 
 
385
        key = stub 'key', :content => "real_key"
 
386
        @ca.host.stubs(:key).returns key
 
387
 
 
388
        @cert.content.expects(:sign).with("real_key", digest)
 
389
        @ca.sign(@name)
 
390
      end
 
391
 
 
392
      it "should save the resulting certificate" do
 
393
        Puppet::SSL::Certificate.indirection.stubs(:save).with(@cert)
 
394
        @ca.sign(@name)
 
395
      end
 
396
 
 
397
      it "should remove the host's certificate request" do
 
398
        Puppet::SSL::CertificateRequest.indirection.expects(:destroy).with(@name)
 
399
 
 
400
        @ca.sign(@name)
 
401
      end
 
402
    end
 
403
 
 
404
    it "should create a certificate instance with the content set to the newly signed x509 certificate" do
 
405
      @serial = 10
 
406
      @ca.stubs(:next_serial).returns @serial
 
407
 
 
408
      Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
 
409
      Puppet::SSL::Certificate.indirection.stubs :save
 
410
      Puppet::SSL::Certificate.expects(:new).with(@name).returns @cert
 
411
 
 
412
      @ca.sign(@name)
 
413
    end
 
414
 
 
415
    it "should return the certificate instance" do
 
416
      @ca.stubs(:next_serial).returns @serial
 
417
      Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
 
418
      Puppet::SSL::Certificate.indirection.stubs :save
 
419
      @ca.sign(@name).should equal(@cert)
 
420
    end
 
421
 
 
422
    it "should add the certificate to its inventory" do
 
423
      @ca.stubs(:next_serial).returns @serial
 
424
      @inventory.expects(:add).with(@cert)
 
425
 
 
426
      Puppet::SSL::CertificateRequest.indirection.stubs(:find).with(@name).returns @request
 
427
      Puppet::SSL::Certificate.indirection.stubs :save
 
428
      @ca.sign(@name)
 
429
    end
 
430
 
 
431
    it "should have a method for triggering autosigning of available CSRs" do
 
432
      @ca.should respond_to(:autosign)
 
433
    end
 
434
 
 
435
    describe "when autosigning certificates" do
 
436
      it "should do nothing if autosign is disabled" do
 
437
        Puppet.settings.expects(:value).with(:autosign).returns 'false'
 
438
 
 
439
        Puppet::SSL::CertificateRequest.indirection.expects(:search).never
 
440
        @ca.autosign
 
441
      end
 
442
 
 
443
      it "should do nothing if no autosign.conf exists" do
 
444
        Puppet.settings.expects(:value).with(:autosign).returns '/auto/sign'
 
445
        FileTest.expects(:exist?).with("/auto/sign").returns false
 
446
 
 
447
        Puppet::SSL::CertificateRequest.indirection.expects(:search).never
 
448
        @ca.autosign
 
449
      end
 
450
 
 
451
      describe "and autosign is enabled and the autosign.conf file exists" do
 
452
        before do
 
453
          Puppet.settings.stubs(:value).with(:autosign).returns '/auto/sign'
 
454
          FileTest.stubs(:exist?).with("/auto/sign").returns true
 
455
          File.stubs(:readlines).with("/auto/sign").returns ["one\n", "two\n"]
 
456
 
 
457
          Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns []
 
458
 
 
459
          @store = stub 'store', :allow => nil
 
460
          Puppet::Network::AuthStore.stubs(:new).returns @store
 
461
        end
 
462
 
 
463
        describe "when creating the AuthStore instance to verify autosigning" do
 
464
          it "should create an AuthStore with each line in the configuration file allowed to be autosigned" do
 
465
            Puppet::Network::AuthStore.expects(:new).returns @store
 
466
 
 
467
            @store.expects(:allow).with("one")
 
468
            @store.expects(:allow).with("two")
 
469
 
 
470
            @ca.autosign
 
471
          end
 
472
 
 
473
          it "should reparse the autosign configuration on each call" do
 
474
            Puppet::Network::AuthStore.expects(:new).times(2).returns @store
 
475
 
 
476
            @ca.autosign
 
477
            @ca.autosign
 
478
          end
 
479
 
 
480
          it "should ignore comments" do
 
481
            File.stubs(:readlines).with("/auto/sign").returns ["one\n", "#two\n"]
 
482
 
 
483
            @store.expects(:allow).with("one")
 
484
            @ca.autosign
 
485
          end
 
486
 
 
487
          it "should ignore blank lines" do
 
488
            File.stubs(:readlines).with("/auto/sign").returns ["one\n", "\n"]
 
489
 
 
490
            @store.expects(:allow).with("one")
 
491
            @ca.autosign
 
492
          end
 
493
        end
 
494
 
 
495
        it "should sign all CSRs whose hostname matches the autosign configuration" do
 
496
          csr1 = mock 'csr1'
 
497
          csr2 = mock 'csr2'
 
498
          Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2]
 
499
        end
 
500
 
 
501
        it "should not sign CSRs whose hostname does not match the autosign configuration" do
 
502
          csr1 = mock 'csr1'
 
503
          csr2 = mock 'csr2'
 
504
          Puppet::SSL::CertificateRequest.indirection.stubs(:search).returns [csr1, csr2]
 
505
        end
 
506
      end
 
507
    end
 
508
  end
 
509
 
 
510
  describe "when managing certificate clients" do
 
511
    before do
 
512
      Puppet.settings.stubs(:use)
 
513
 
 
514
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:password?).returns true
 
515
 
 
516
      stub_ca_host
 
517
 
 
518
      Puppet::SSL::Host.expects(:new).returns @host
 
519
      Puppet::SSL::CertificateAuthority.any_instance.stubs(:host).returns @host
 
520
 
 
521
      @cacert = mock 'certificate'
 
522
      @cacert.stubs(:content).returns "cacertificate"
 
523
      @ca = Puppet::SSL::CertificateAuthority.new
 
524
    end
 
525
 
 
526
    it "should have a method for acting on the SSL files" do
 
527
      @ca.should respond_to(:apply)
 
528
    end
 
529
 
 
530
    describe "when applying a method to a set of hosts" do
 
531
      it "should fail if no subjects have been specified" do
 
532
        lambda { @ca.apply(:generate) }.should raise_error(ArgumentError)
 
533
      end
 
534
 
 
535
      it "should create an Interface instance with the specified method and the options" do
 
536
        Puppet::SSL::CertificateAuthority::Interface.expects(:new).with(:generate, :to => :host).returns(stub('applier', :apply => nil))
 
537
        @ca.apply(:generate, :to => :host)
 
538
      end
 
539
 
 
540
      it "should apply the Interface with itself as the argument" do
 
541
        applier = stub('applier')
 
542
        applier.expects(:apply).with(@ca)
 
543
        Puppet::SSL::CertificateAuthority::Interface.expects(:new).returns applier
 
544
        @ca.apply(:generate, :to => :ca_testing)
 
545
      end
 
546
    end
 
547
 
 
548
    it "should be able to list waiting certificate requests" do
 
549
      req1 = stub 'req1', :name => "one"
 
550
      req2 = stub 'req2', :name => "two"
 
551
      Puppet::SSL::CertificateRequest.indirection.expects(:search).with("*").returns [req1, req2]
 
552
 
 
553
      @ca.waiting?.should == %w{one two}
 
554
    end
 
555
 
 
556
    it "should delegate removing hosts to the Host class" do
 
557
      Puppet::SSL::Host.expects(:destroy).with("myhost")
 
558
 
 
559
      @ca.destroy("myhost")
 
560
    end
 
561
 
 
562
    it "should be able to verify certificates" do
 
563
      @ca.should respond_to(:verify)
 
564
    end
 
565
 
 
566
    it "should list certificates as the sorted list of all existing signed certificates" do
 
567
      cert1 = stub 'cert1', :name => "cert1"
 
568
      cert2 = stub 'cert2', :name => "cert2"
 
569
      Puppet::SSL::Certificate.indirection.expects(:search).with("*").returns [cert1, cert2]
 
570
      @ca.list.should == %w{cert1 cert2}
 
571
    end
 
572
 
 
573
    describe "and printing certificates" do
 
574
      it "should return nil if the certificate cannot be found" do
 
575
        Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
 
576
        @ca.print("myhost").should be_nil
 
577
      end
 
578
 
 
579
      it "should print certificates by calling :to_text on the host's certificate" do
 
580
        cert1 = stub 'cert1', :name => "cert1", :to_text => "mytext"
 
581
        Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns cert1
 
582
        @ca.print("myhost").should == "mytext"
 
583
      end
 
584
    end
 
585
 
 
586
    describe "and fingerprinting certificates" do
 
587
      before :each do
 
588
        @cert = stub 'cert', :name => "cert", :fingerprint => "DIGEST"
 
589
        Puppet::SSL::Certificate.indirection.stubs(:find).with("myhost").returns @cert
 
590
        Puppet::SSL::CertificateRequest.indirection.stubs(:find).with("myhost")
 
591
      end
 
592
 
 
593
      it "should raise an error if the certificate or CSR cannot be found" do
 
594
        Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
 
595
        Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns nil
 
596
        lambda { @ca.fingerprint("myhost") }.should raise_error
 
597
      end
 
598
 
 
599
      it "should try to find a CSR if no certificate can be found" do
 
600
        Puppet::SSL::Certificate.indirection.expects(:find).with("myhost").returns nil
 
601
        Puppet::SSL::CertificateRequest.indirection.expects(:find).with("myhost").returns @cert
 
602
        @cert.expects(:fingerprint)
 
603
        @ca.fingerprint("myhost")
 
604
      end
 
605
 
 
606
      it "should delegate to the certificate fingerprinting" do
 
607
        @cert.expects(:fingerprint)
 
608
        @ca.fingerprint("myhost")
 
609
      end
 
610
 
 
611
      it "should propagate the digest algorithm to the certificate fingerprinting system" do
 
612
        @cert.expects(:fingerprint).with(:digest)
 
613
        @ca.fingerprint("myhost", :digest)
 
614
      end
 
615
    end
 
616
 
 
617
    describe "and verifying certificates" do
 
618
      before do
 
619
        @store = stub 'store', :verify => true, :add_file => nil, :purpose= => nil, :add_crl => true, :flags= => nil
 
620
 
 
621
        OpenSSL::X509::Store.stubs(:new).returns @store
 
622
 
 
623
        Puppet.settings.stubs(:value).returns "crtstuff"
 
624
 
 
625
        @cert = stub 'cert', :content => "mycert"
 
626
        Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
 
627
 
 
628
        @crl = stub('crl', :content => "mycrl")
 
629
 
 
630
        @ca.stubs(:crl).returns @crl
 
631
      end
 
632
 
 
633
      it "should fail if the host's certificate cannot be found" do
 
634
        Puppet::SSL::Certificate.indirection.expects(:find).with("me").returns(nil)
 
635
 
 
636
        lambda { @ca.verify("me") }.should raise_error(ArgumentError)
 
637
      end
 
638
 
 
639
      it "should create an SSL Store to verify" do
 
640
        OpenSSL::X509::Store.expects(:new).returns @store
 
641
 
 
642
        @ca.verify("me")
 
643
      end
 
644
 
 
645
      it "should add the CA Certificate to the store" do
 
646
        Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
 
647
        @store.expects(:add_file).with "/ca/cert"
 
648
 
 
649
        @ca.verify("me")
 
650
      end
 
651
 
 
652
      it "should add the CRL to the store if the crl is enabled" do
 
653
        @store.expects(:add_crl).with "mycrl"
 
654
 
 
655
        @ca.verify("me")
 
656
      end
 
657
 
 
658
      it "should set the store purpose to OpenSSL::X509::PURPOSE_SSL_CLIENT" do
 
659
        Puppet.settings.stubs(:value).with(:cacert).returns "/ca/cert"
 
660
        @store.expects(:add_file).with "/ca/cert"
 
661
 
 
662
        @ca.verify("me")
 
663
      end
 
664
 
 
665
      it "should set the store flags to check the crl" do
 
666
        @store.expects(:flags=).with OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK
 
667
 
 
668
        @ca.verify("me")
 
669
      end
 
670
 
 
671
      it "should use the store to verify the certificate" do
 
672
        @cert.expects(:content).returns "mycert"
 
673
 
 
674
        @store.expects(:verify).with("mycert").returns true
 
675
 
 
676
        @ca.verify("me")
 
677
      end
 
678
 
 
679
      it "should fail if the verification returns false" do
 
680
        @cert.expects(:content).returns "mycert"
 
681
 
 
682
        @store.expects(:verify).with("mycert").returns false
 
683
 
 
684
        lambda { @ca.verify("me") }.should raise_error
 
685
      end
 
686
    end
 
687
 
 
688
    describe "and revoking certificates" do
 
689
      before do
 
690
        @crl = mock 'crl'
 
691
        @ca.stubs(:crl).returns @crl
 
692
 
 
693
        @ca.stubs(:next_serial).returns 10
 
694
 
 
695
        @real_cert = stub 'real_cert', :serial => 15
 
696
        @cert = stub 'cert', :content => @real_cert
 
697
        Puppet::SSL::Certificate.indirection.stubs(:find).returns @cert
 
698
 
 
699
      end
 
700
 
 
701
      it "should fail if the certificate revocation list is disabled" do
 
702
        @ca.stubs(:crl).returns false
 
703
 
 
704
        lambda { @ca.revoke('ca_testing') }.should raise_error(ArgumentError)
 
705
 
 
706
      end
 
707
 
 
708
      it "should delegate the revocation to its CRL" do
 
709
        @ca.crl.expects(:revoke)
 
710
 
 
711
        @ca.revoke('host')
 
712
      end
 
713
 
 
714
      it "should get the serial number from the local certificate if it exists" do
 
715
        @ca.crl.expects(:revoke).with { |serial, key| serial == 15 }
 
716
 
 
717
        Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns @cert
 
718
 
 
719
        @ca.revoke('host')
 
720
      end
 
721
 
 
722
      it "should get the serial number from inventory if no local certificate exists" do
 
723
        real_cert = stub 'real_cert', :serial => 15
 
724
        cert = stub 'cert', :content => real_cert
 
725
        Puppet::SSL::Certificate.indirection.expects(:find).with("host").returns nil
 
726
 
 
727
        @ca.inventory.expects(:serial).with("host").returns 16
 
728
 
 
729
        @ca.crl.expects(:revoke).with { |serial, key| serial == 16 }
 
730
        @ca.revoke('host')
 
731
      end
 
732
    end
 
733
 
 
734
    it "should be able to generate a complete new SSL host" do
 
735
      @ca.should respond_to(:generate)
 
736
    end
 
737
 
 
738
    describe "and generating certificates" do
 
739
      before do
 
740
        @host = stub 'host', :generate_certificate_request => nil
 
741
        Puppet::SSL::Host.stubs(:new).returns @host
 
742
        Puppet::SSL::Certificate.indirection.stubs(:find).returns nil
 
743
 
 
744
        @ca.stubs(:sign)
 
745
      end
 
746
 
 
747
      it "should fail if a certificate already exists for the host" do
 
748
        Puppet::SSL::Certificate.indirection.expects(:find).with("him").returns "something"
 
749
 
 
750
        lambda { @ca.generate("him") }.should raise_error(ArgumentError)
 
751
      end
 
752
 
 
753
      it "should create a new Host instance with the correct name" do
 
754
        Puppet::SSL::Host.expects(:new).with("him").returns @host
 
755
 
 
756
        @ca.generate("him")
 
757
      end
 
758
 
 
759
      it "should use the Host to generate the certificate request" do
 
760
        @host.expects :generate_certificate_request
 
761
 
 
762
        @ca.generate("him")
 
763
      end
 
764
 
 
765
      it "should sign the generated request" do
 
766
        @ca.expects(:sign).with("him")
 
767
 
 
768
        @ca.generate("him")
 
769
      end
 
770
    end
 
771
  end
 
772
end