1 package main
2
3 import (
4 "fmt"
5 "io/fs"
6 "strings"
7 "testing"
8
9 "github.com/letsencrypt/boulder/test"
10 )
11
12 func TestLoadPubKey(t *testing.T) {
13 _, _, err := loadPubKey("../../test/test-root.pubkey.pem")
14 test.AssertNotError(t, err, "should not have errored")
15
16 _, _, err = loadPubKey("../../test/hierarchy/int-e1.key.pem")
17 test.AssertError(t, err, "should have failed trying to parse a private key")
18
19 _, _, err = loadPubKey("/path/that/will/not/ever/exist/ever")
20 test.AssertError(t, err, "should have failed opening public key at non-existent path")
21 test.AssertErrorIs(t, err, fs.ErrNotExist)
22
23 _, _, err = loadPubKey("../../test/hierarchy/int-e1.cert.pem")
24 test.AssertError(t, err, "should have failed when trying to parse a certificate")
25 }
26
27 func TestCheckOutputFileSucceeds(t *testing.T) {
28 dir := t.TempDir()
29 err := checkOutputFile(dir+"/example", "foo")
30 if err != nil {
31 t.Fatal(err)
32 }
33 }
34
35 func TestCheckOutputFileEmpty(t *testing.T) {
36 err := checkOutputFile("", "foo")
37 if err == nil {
38 t.Fatal("expected error, got none")
39 }
40 if err.Error() != "outputs.foo is required" {
41 t.Fatalf("wrong error: %s", err)
42 }
43 }
44
45 func TestCheckOutputFileExists(t *testing.T) {
46 dir := t.TempDir()
47 filename := dir + "/example"
48 err := writeFile(filename, []byte("hi"))
49 if err != nil {
50 t.Fatal(err)
51 }
52 err = checkOutputFile(filename, "foo")
53 if err == nil {
54 t.Fatal("expected error, got none")
55 }
56 if !strings.Contains(err.Error(), "already exists") {
57 t.Fatalf("wrong error: %s", err)
58 }
59 }
60
61 func TestKeyGenConfigValidate(t *testing.T) {
62 cases := []struct {
63 name string
64 config keyGenConfig
65 expectedError string
66 }{
67 {
68 name: "no key.type",
69 config: keyGenConfig{},
70 expectedError: "key.type is required",
71 },
72 {
73 name: "bad key.type",
74 config: keyGenConfig{
75 Type: "doop",
76 },
77 expectedError: "key.type can only be 'rsa' or 'ecdsa'",
78 },
79 {
80 name: "bad key.rsa-mod-length",
81 config: keyGenConfig{
82 Type: "rsa",
83 RSAModLength: 1337,
84 },
85 expectedError: "key.rsa-mod-length can only be 2048 or 4096",
86 },
87 {
88 name: "key.type is rsa but key.ecdsa-curve is present",
89 config: keyGenConfig{
90 Type: "rsa",
91 RSAModLength: 2048,
92 ECDSACurve: "bad",
93 },
94 expectedError: "if key.type = 'rsa' then key.ecdsa-curve is not used",
95 },
96 {
97 name: "bad key.ecdsa-curve",
98 config: keyGenConfig{
99 Type: "ecdsa",
100 ECDSACurve: "bad",
101 },
102 expectedError: "key.ecdsa-curve can only be 'P-224', 'P-256', 'P-384', or 'P-521'",
103 },
104 {
105 name: "key.type is ecdsa but key.rsa-mod-length is present",
106 config: keyGenConfig{
107 Type: "ecdsa",
108 RSAModLength: 2048,
109 ECDSACurve: "P-256",
110 },
111 expectedError: "if key.type = 'ecdsa' then key.rsa-mod-length is not used",
112 },
113 {
114 name: "good rsa config",
115 config: keyGenConfig{
116 Type: "rsa",
117 RSAModLength: 2048,
118 },
119 },
120 {
121 name: "good ecdsa config",
122 config: keyGenConfig{
123 Type: "ecdsa",
124 ECDSACurve: "P-256",
125 },
126 },
127 }
128 for _, tc := range cases {
129 t.Run(tc.name, func(t *testing.T) {
130 err := tc.config.validate()
131 if err != nil && err.Error() != tc.expectedError {
132 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
133 } else if err == nil && tc.expectedError != "" {
134 t.Fatalf("validate didn't fail, wanted: %q", err)
135 }
136 })
137 }
138 }
139
140 func TestRootConfigValidate(t *testing.T) {
141 cases := []struct {
142 name string
143 config rootConfig
144 expectedError string
145 }{
146 {
147 name: "no pkcs11.module",
148 config: rootConfig{},
149 expectedError: "pkcs11.module is required",
150 },
151 {
152 name: "no pkcs11.store-key-with-label",
153 config: rootConfig{
154 PKCS11: PKCS11KeyGenConfig{
155 Module: "module",
156 },
157 },
158 expectedError: "pkcs11.store-key-with-label is required",
159 },
160 {
161 name: "bad key fields",
162 config: rootConfig{
163 PKCS11: PKCS11KeyGenConfig{
164 Module: "module",
165 StoreLabel: "label",
166 },
167 },
168 expectedError: "key.type is required",
169 },
170 {
171 name: "no outputs.public-key-path",
172 config: rootConfig{
173 PKCS11: PKCS11KeyGenConfig{
174 Module: "module",
175 StoreLabel: "label",
176 },
177 Key: keyGenConfig{
178 Type: "rsa",
179 RSAModLength: 2048,
180 },
181 },
182 expectedError: "outputs.public-key-path is required",
183 },
184 {
185 name: "no outputs.certificate-path",
186 config: rootConfig{
187 PKCS11: PKCS11KeyGenConfig{
188 Module: "module",
189 StoreLabel: "label",
190 },
191 Key: keyGenConfig{
192 Type: "rsa",
193 RSAModLength: 2048,
194 },
195 Outputs: struct {
196 PublicKeyPath string `yaml:"public-key-path"`
197 CertificatePath string `yaml:"certificate-path"`
198 }{
199 PublicKeyPath: "path",
200 },
201 },
202 expectedError: "outputs.certificate-path is required",
203 },
204 {
205 name: "bad certificate-profile",
206 config: rootConfig{
207 PKCS11: PKCS11KeyGenConfig{
208 Module: "module",
209 StoreLabel: "label",
210 },
211 Key: keyGenConfig{
212 Type: "rsa",
213 RSAModLength: 2048,
214 },
215 Outputs: struct {
216 PublicKeyPath string `yaml:"public-key-path"`
217 CertificatePath string `yaml:"certificate-path"`
218 }{
219 PublicKeyPath: "path",
220 CertificatePath: "path",
221 },
222 },
223 expectedError: "not-before is required",
224 },
225 {
226 name: "good config",
227 config: rootConfig{
228 PKCS11: PKCS11KeyGenConfig{
229 Module: "module",
230 StoreLabel: "label",
231 },
232 Key: keyGenConfig{
233 Type: "rsa",
234 RSAModLength: 2048,
235 },
236 Outputs: struct {
237 PublicKeyPath string `yaml:"public-key-path"`
238 CertificatePath string `yaml:"certificate-path"`
239 }{
240 PublicKeyPath: "path",
241 CertificatePath: "path",
242 },
243 CertProfile: certProfile{
244 NotBefore: "a",
245 NotAfter: "b",
246 SignatureAlgorithm: "c",
247 CommonName: "d",
248 Organization: "e",
249 Country: "f",
250 },
251 SkipLints: []string{
252 "e_ext_authority_key_identifier_missing",
253 "e_ext_authority_key_identifier_no_key_identifier",
254 "e_sub_ca_aia_missing",
255 "e_sub_ca_certificate_policies_missing",
256 "e_sub_ca_crl_distribution_points_missing",
257 "n_ca_digital_signature_not_set",
258 "n_mp_allowed_eku",
259 "n_sub_ca_eku_missing",
260 "w_sub_ca_aia_does_not_contain_issuing_ca_url",
261 },
262 },
263 },
264 }
265 for _, tc := range cases {
266 t.Run(tc.name, func(t *testing.T) {
267 err := tc.config.validate()
268 if err != nil && err.Error() != tc.expectedError {
269 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
270 } else if err == nil && tc.expectedError != "" {
271 t.Fatalf("validate didn't fail, wanted: %q", err)
272 }
273 })
274 }
275 }
276
277 func TestIntermediateConfigValidate(t *testing.T) {
278 cases := []struct {
279 name string
280 config intermediateConfig
281 expectedError string
282 }{
283 {
284 name: "no pkcs11.module",
285 config: intermediateConfig{},
286 expectedError: "pkcs11.module is required",
287 },
288 {
289 name: "no pkcs11.signing-key-label",
290 config: intermediateConfig{
291 PKCS11: PKCS11SigningConfig{
292 Module: "module",
293 },
294 },
295 expectedError: "pkcs11.signing-key-label is required",
296 },
297 {
298 name: "no inputs.public-key-path",
299 config: intermediateConfig{
300 PKCS11: PKCS11SigningConfig{
301 Module: "module",
302 SigningLabel: "label",
303 },
304 },
305 expectedError: "inputs.public-key-path is required",
306 },
307 {
308 name: "no inputs.issuer-certificate-path",
309 config: intermediateConfig{
310 PKCS11: PKCS11SigningConfig{
311 Module: "module",
312 SigningLabel: "label",
313 },
314 Inputs: struct {
315 PublicKeyPath string `yaml:"public-key-path"`
316 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
317 }{
318 PublicKeyPath: "path",
319 },
320 },
321 expectedError: "inputs.issuer-certificate is required",
322 },
323 {
324 name: "no outputs.certificate-path",
325 config: intermediateConfig{
326 PKCS11: PKCS11SigningConfig{
327 Module: "module",
328 SigningLabel: "label",
329 },
330 Inputs: struct {
331 PublicKeyPath string `yaml:"public-key-path"`
332 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
333 }{
334 PublicKeyPath: "path",
335 IssuerCertificatePath: "path",
336 },
337 },
338 expectedError: "outputs.certificate-path is required",
339 },
340 {
341 name: "bad certificate-profile",
342 config: intermediateConfig{
343 PKCS11: PKCS11SigningConfig{
344 Module: "module",
345 SigningLabel: "label",
346 },
347 Inputs: struct {
348 PublicKeyPath string `yaml:"public-key-path"`
349 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
350 }{
351 PublicKeyPath: "path",
352 IssuerCertificatePath: "path",
353 },
354 Outputs: struct {
355 CertificatePath string `yaml:"certificate-path"`
356 }{
357 CertificatePath: "path",
358 },
359 },
360 expectedError: "not-before is required",
361 },
362 {
363 name: "too many policy OIDs",
364 config: intermediateConfig{
365 PKCS11: PKCS11SigningConfig{
366 Module: "module",
367 SigningLabel: "label",
368 },
369 Inputs: struct {
370 PublicKeyPath string `yaml:"public-key-path"`
371 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
372 }{
373 PublicKeyPath: "path",
374 IssuerCertificatePath: "path",
375 },
376 Outputs: struct {
377 CertificatePath string `yaml:"certificate-path"`
378 }{
379 CertificatePath: "path",
380 },
381 CertProfile: certProfile{
382 NotBefore: "a",
383 NotAfter: "b",
384 SignatureAlgorithm: "c",
385 CommonName: "d",
386 Organization: "e",
387 Country: "f",
388 OCSPURL: "g",
389 CRLURL: "h",
390 IssuerURL: "i",
391 Policies: []policyInfoConfig{{OID: "2.23.140.1.2.1"}, {OID: "6.6.6"}},
392 },
393 SkipLints: []string{},
394 },
395 expectedError: "policy should be exactly BRs domain-validated for subordinate CAs",
396 },
397 {
398 name: "too few policy OIDs",
399 config: intermediateConfig{
400 PKCS11: PKCS11SigningConfig{
401 Module: "module",
402 SigningLabel: "label",
403 },
404 Inputs: struct {
405 PublicKeyPath string `yaml:"public-key-path"`
406 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
407 }{
408 PublicKeyPath: "path",
409 IssuerCertificatePath: "path",
410 },
411 Outputs: struct {
412 CertificatePath string `yaml:"certificate-path"`
413 }{
414 CertificatePath: "path",
415 },
416 CertProfile: certProfile{
417 NotBefore: "a",
418 NotAfter: "b",
419 SignatureAlgorithm: "c",
420 CommonName: "d",
421 Organization: "e",
422 Country: "f",
423 OCSPURL: "g",
424 CRLURL: "h",
425 IssuerURL: "i",
426 Policies: []policyInfoConfig{},
427 },
428 SkipLints: []string{},
429 },
430 expectedError: "policy should be exactly BRs domain-validated for subordinate CAs",
431 },
432 {
433 name: "good config",
434 config: intermediateConfig{
435 PKCS11: PKCS11SigningConfig{
436 Module: "module",
437 SigningLabel: "label",
438 },
439 Inputs: struct {
440 PublicKeyPath string `yaml:"public-key-path"`
441 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
442 }{
443 PublicKeyPath: "path",
444 IssuerCertificatePath: "path",
445 },
446 Outputs: struct {
447 CertificatePath string `yaml:"certificate-path"`
448 }{
449 CertificatePath: "path",
450 },
451 CertProfile: certProfile{
452 NotBefore: "a",
453 NotAfter: "b",
454 SignatureAlgorithm: "c",
455 CommonName: "d",
456 Organization: "e",
457 Country: "f",
458 OCSPURL: "g",
459 CRLURL: "h",
460 IssuerURL: "i",
461 Policies: []policyInfoConfig{{OID: "2.23.140.1.2.1"}},
462 },
463 SkipLints: []string{},
464 },
465 },
466 }
467 for _, tc := range cases {
468 t.Run(tc.name, func(t *testing.T) {
469 err := tc.config.validate(intermediateCert)
470 if err != nil && err.Error() != tc.expectedError {
471 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
472 } else if err == nil && tc.expectedError != "" {
473 t.Fatalf("validate didn't fail, wanted: %q", err)
474 }
475 })
476 }
477 }
478
479 func TestCrossCertConfigValidate(t *testing.T) {
480 cases := []struct {
481 name string
482 config crossCertConfig
483 expectedError string
484 }{
485 {
486 name: "no pkcs11.module",
487 config: crossCertConfig{},
488 expectedError: "pkcs11.module is required",
489 },
490 {
491 name: "no pkcs11.signing-key-label",
492 config: crossCertConfig{
493 PKCS11: PKCS11SigningConfig{
494 Module: "module",
495 },
496 },
497 expectedError: "pkcs11.signing-key-label is required",
498 },
499 {
500 name: "no inputs.public-key-path",
501 config: crossCertConfig{
502 PKCS11: PKCS11SigningConfig{
503 Module: "module",
504 SigningLabel: "label",
505 },
506 },
507 expectedError: "inputs.public-key-path is required",
508 },
509 {
510 name: "no inputs.issuer-certificate-path",
511 config: crossCertConfig{
512 PKCS11: PKCS11SigningConfig{
513 Module: "module",
514 SigningLabel: "label",
515 },
516 Inputs: struct {
517 PublicKeyPath string `yaml:"public-key-path"`
518 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
519 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
520 }{
521 PublicKeyPath: "path",
522 CertificateToCrossSignPath: "path",
523 },
524 },
525 expectedError: "inputs.issuer-certificate is required",
526 },
527 {
528 name: "no inputs.certificate-to-cross-sign-path",
529 config: crossCertConfig{
530 PKCS11: PKCS11SigningConfig{
531 Module: "module",
532 SigningLabel: "label",
533 },
534 Inputs: struct {
535 PublicKeyPath string `yaml:"public-key-path"`
536 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
537 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
538 }{
539 PublicKeyPath: "path",
540 IssuerCertificatePath: "path",
541 },
542 },
543 expectedError: "inputs.certificate-to-cross-sign-path is required",
544 },
545 {
546 name: "no outputs.certificate-path",
547 config: crossCertConfig{
548 PKCS11: PKCS11SigningConfig{
549 Module: "module",
550 SigningLabel: "label",
551 },
552 Inputs: struct {
553 PublicKeyPath string `yaml:"public-key-path"`
554 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
555 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
556 }{
557 PublicKeyPath: "path",
558 IssuerCertificatePath: "path",
559 CertificateToCrossSignPath: "path",
560 },
561 },
562 expectedError: "outputs.certificate-path is required",
563 },
564 {
565 name: "bad certificate-profile",
566 config: crossCertConfig{
567 PKCS11: PKCS11SigningConfig{
568 Module: "module",
569 SigningLabel: "label",
570 },
571 Inputs: struct {
572 PublicKeyPath string `yaml:"public-key-path"`
573 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
574 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
575 }{
576 PublicKeyPath: "path",
577 IssuerCertificatePath: "path",
578 CertificateToCrossSignPath: "path",
579 },
580 Outputs: struct {
581 CertificatePath string `yaml:"certificate-path"`
582 }{
583 CertificatePath: "path",
584 },
585 },
586 expectedError: "not-before is required",
587 },
588 {
589 name: "too many policy OIDs",
590 config: crossCertConfig{
591 PKCS11: PKCS11SigningConfig{
592 Module: "module",
593 SigningLabel: "label",
594 },
595 Inputs: struct {
596 PublicKeyPath string `yaml:"public-key-path"`
597 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
598 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
599 }{
600 PublicKeyPath: "path",
601 IssuerCertificatePath: "path",
602 CertificateToCrossSignPath: "path",
603 },
604 Outputs: struct {
605 CertificatePath string `yaml:"certificate-path"`
606 }{
607 CertificatePath: "path",
608 },
609 CertProfile: certProfile{
610 NotBefore: "a",
611 NotAfter: "b",
612 SignatureAlgorithm: "c",
613 CommonName: "d",
614 Organization: "e",
615 Country: "f",
616 OCSPURL: "g",
617 CRLURL: "h",
618 IssuerURL: "i",
619 Policies: []policyInfoConfig{{OID: "2.23.140.1.2.1"}, {OID: "6.6.6"}},
620 },
621 SkipLints: []string{},
622 },
623 expectedError: "policy should be exactly BRs domain-validated for subordinate CAs",
624 },
625 {
626 name: "too few policy OIDs",
627 config: crossCertConfig{
628 PKCS11: PKCS11SigningConfig{
629 Module: "module",
630 SigningLabel: "label",
631 },
632 Inputs: struct {
633 PublicKeyPath string `yaml:"public-key-path"`
634 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
635 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
636 }{
637 PublicKeyPath: "path",
638 IssuerCertificatePath: "path",
639 CertificateToCrossSignPath: "path",
640 },
641 Outputs: struct {
642 CertificatePath string `yaml:"certificate-path"`
643 }{
644 CertificatePath: "path",
645 },
646 CertProfile: certProfile{
647 NotBefore: "a",
648 NotAfter: "b",
649 SignatureAlgorithm: "c",
650 CommonName: "d",
651 Organization: "e",
652 Country: "f",
653 OCSPURL: "g",
654 CRLURL: "h",
655 IssuerURL: "i",
656 Policies: []policyInfoConfig{},
657 },
658 SkipLints: []string{},
659 },
660 expectedError: "policy should be exactly BRs domain-validated for subordinate CAs",
661 },
662 {
663 name: "good config",
664 config: crossCertConfig{
665 PKCS11: PKCS11SigningConfig{
666 Module: "module",
667 SigningLabel: "label",
668 },
669 Inputs: struct {
670 PublicKeyPath string `yaml:"public-key-path"`
671 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
672 CertificateToCrossSignPath string `yaml:"certificate-to-cross-sign-path"`
673 }{
674 PublicKeyPath: "path",
675 IssuerCertificatePath: "path",
676 CertificateToCrossSignPath: "path",
677 },
678 Outputs: struct {
679 CertificatePath string `yaml:"certificate-path"`
680 }{
681 CertificatePath: "path",
682 },
683 CertProfile: certProfile{
684 NotBefore: "a",
685 NotAfter: "b",
686 SignatureAlgorithm: "c",
687 CommonName: "d",
688 Organization: "e",
689 Country: "f",
690 OCSPURL: "g",
691 CRLURL: "h",
692 IssuerURL: "i",
693 Policies: []policyInfoConfig{{OID: "2.23.140.1.2.1"}},
694 },
695 SkipLints: []string{},
696 },
697 },
698 }
699 for _, tc := range cases {
700 t.Run(tc.name, func(t *testing.T) {
701 err := tc.config.validate()
702 if err != nil && err.Error() != tc.expectedError {
703 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
704 } else if err == nil && tc.expectedError != "" {
705 t.Fatalf("validate didn't fail, wanted: %q", err)
706 }
707 })
708 }
709 }
710
711 func TestCSRConfigValidate(t *testing.T) {
712 cases := []struct {
713 name string
714 config csrConfig
715 expectedError string
716 }{
717 {
718 name: "no pkcs11.module",
719 config: csrConfig{},
720 expectedError: "pkcs11.module is required",
721 },
722 {
723 name: "no pkcs11.signing-key-label",
724 config: csrConfig{
725 PKCS11: PKCS11SigningConfig{
726 Module: "module",
727 },
728 },
729 expectedError: "pkcs11.signing-key-label is required",
730 },
731 {
732 name: "no inputs.public-key-path",
733 config: csrConfig{
734 PKCS11: PKCS11SigningConfig{
735 Module: "module",
736 SigningLabel: "label",
737 },
738 },
739 expectedError: "inputs.public-key-path is required",
740 },
741 {
742 name: "no outputs.csr-path",
743 config: csrConfig{
744 PKCS11: PKCS11SigningConfig{
745 Module: "module",
746 SigningLabel: "label",
747 },
748 Inputs: struct {
749 PublicKeyPath string `yaml:"public-key-path"`
750 }{
751 PublicKeyPath: "path",
752 },
753 },
754 expectedError: "outputs.csr-path is required",
755 },
756 {
757 name: "bad certificate-profile",
758 config: csrConfig{
759 PKCS11: PKCS11SigningConfig{
760 Module: "module",
761 SigningLabel: "label",
762 },
763 Inputs: struct {
764 PublicKeyPath string `yaml:"public-key-path"`
765 }{
766 PublicKeyPath: "path",
767 },
768 Outputs: struct {
769 CSRPath string `yaml:"csr-path"`
770 }{
771 CSRPath: "path",
772 },
773 },
774 expectedError: "common-name is required",
775 },
776 {
777 name: "good config",
778 config: csrConfig{
779 PKCS11: PKCS11SigningConfig{
780 Module: "module",
781 SigningLabel: "label",
782 },
783 Inputs: struct {
784 PublicKeyPath string `yaml:"public-key-path"`
785 }{
786 PublicKeyPath: "path",
787 },
788 Outputs: struct {
789 CSRPath string `yaml:"csr-path"`
790 }{
791 CSRPath: "path",
792 },
793 CertProfile: certProfile{
794 CommonName: "d",
795 Organization: "e",
796 Country: "f",
797 },
798 },
799 },
800 }
801 for _, tc := range cases {
802 t.Run(tc.name, func(t *testing.T) {
803 err := tc.config.validate()
804 if err != nil && err.Error() != tc.expectedError {
805 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
806 } else if err == nil && tc.expectedError != "" {
807 t.Fatalf("validate didn't fail, wanted: %q", err)
808 }
809 })
810 }
811 }
812
813 func TestKeyConfigValidate(t *testing.T) {
814 cases := []struct {
815 name string
816 config keyConfig
817 expectedError string
818 }{
819 {
820 name: "no pkcs11.module",
821 config: keyConfig{},
822 expectedError: "pkcs11.module is required",
823 },
824 {
825 name: "no pkcs11.store-key-with-label",
826 config: keyConfig{
827 PKCS11: PKCS11KeyGenConfig{
828 Module: "module",
829 },
830 },
831 expectedError: "pkcs11.store-key-with-label is required",
832 },
833 {
834 name: "bad key fields",
835 config: keyConfig{
836 PKCS11: PKCS11KeyGenConfig{
837 Module: "module",
838 StoreLabel: "label",
839 },
840 },
841 expectedError: "key.type is required",
842 },
843 {
844 name: "no outputs.public-key-path",
845 config: keyConfig{
846 PKCS11: PKCS11KeyGenConfig{
847 Module: "module",
848 StoreLabel: "label",
849 },
850 Key: keyGenConfig{
851 Type: "rsa",
852 RSAModLength: 2048,
853 },
854 },
855 expectedError: "outputs.public-key-path is required",
856 },
857 {
858 name: "good config",
859 config: keyConfig{
860 PKCS11: PKCS11KeyGenConfig{
861 Module: "module",
862 StoreLabel: "label",
863 },
864 Key: keyGenConfig{
865 Type: "rsa",
866 RSAModLength: 2048,
867 },
868 Outputs: struct {
869 PublicKeyPath string `yaml:"public-key-path"`
870 PKCS11ConfigPath string `yaml:"pkcs11-config-path"`
871 }{
872 PublicKeyPath: "path",
873 PKCS11ConfigPath: "path.json",
874 },
875 },
876 },
877 }
878 for _, tc := range cases {
879 t.Run(tc.name, func(t *testing.T) {
880 err := tc.config.validate()
881 if err != nil && err.Error() != tc.expectedError {
882 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
883 } else if err == nil && tc.expectedError != "" {
884 t.Fatalf("validate didn't fail, wanted: %q", err)
885 }
886 })
887 }
888 }
889
890 func TestOCSPRespConfig(t *testing.T) {
891 cases := []struct {
892 name string
893 config ocspRespConfig
894 expectedError string
895 }{
896 {
897 name: "no pkcs11.module",
898 config: ocspRespConfig{},
899 expectedError: "pkcs11.module is required",
900 },
901 {
902 name: "no pkcs11.signing-key-label",
903 config: ocspRespConfig{
904 PKCS11: PKCS11SigningConfig{
905 Module: "module",
906 },
907 },
908 expectedError: "pkcs11.signing-key-label is required",
909 },
910 {
911 name: "no inputs.certificate-path",
912 config: ocspRespConfig{
913 PKCS11: PKCS11SigningConfig{
914 Module: "module",
915 SigningLabel: "label",
916 },
917 },
918 expectedError: "inputs.certificate-path is required",
919 },
920 {
921 name: "no inputs.issuer-certificate-path",
922 config: ocspRespConfig{
923 PKCS11: PKCS11SigningConfig{
924 Module: "module",
925 SigningLabel: "label",
926 },
927 Inputs: struct {
928 CertificatePath string `yaml:"certificate-path"`
929 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
930 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
931 }{
932 CertificatePath: "path",
933 },
934 },
935 expectedError: "inputs.issuer-certificate-path is required",
936 },
937 {
938 name: "no outputs.response-path",
939 config: ocspRespConfig{
940 PKCS11: PKCS11SigningConfig{
941 Module: "module",
942 SigningLabel: "label",
943 },
944 Inputs: struct {
945 CertificatePath string `yaml:"certificate-path"`
946 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
947 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
948 }{
949 CertificatePath: "path",
950 IssuerCertificatePath: "path",
951 },
952 },
953 expectedError: "outputs.response-path is required",
954 },
955 {
956 name: "no ocsp-profile.this-update",
957 config: ocspRespConfig{
958 PKCS11: PKCS11SigningConfig{
959 Module: "module",
960 SigningLabel: "label",
961 },
962 Inputs: struct {
963 CertificatePath string `yaml:"certificate-path"`
964 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
965 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
966 }{
967 CertificatePath: "path",
968 IssuerCertificatePath: "path",
969 },
970 Outputs: struct {
971 ResponsePath string `yaml:"response-path"`
972 }{
973 ResponsePath: "path",
974 },
975 },
976 expectedError: "ocsp-profile.this-update is required",
977 },
978 {
979 name: "no ocsp-profile.next-update",
980 config: ocspRespConfig{
981 PKCS11: PKCS11SigningConfig{
982 Module: "module",
983 SigningLabel: "label",
984 },
985 Inputs: struct {
986 CertificatePath string `yaml:"certificate-path"`
987 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
988 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
989 }{
990 CertificatePath: "path",
991 IssuerCertificatePath: "path",
992 },
993 Outputs: struct {
994 ResponsePath string `yaml:"response-path"`
995 }{
996 ResponsePath: "path",
997 },
998 OCSPProfile: struct {
999 ThisUpdate string `yaml:"this-update"`
1000 NextUpdate string `yaml:"next-update"`
1001 Status string `yaml:"status"`
1002 }{
1003 ThisUpdate: "this-update",
1004 },
1005 },
1006 expectedError: "ocsp-profile.next-update is required",
1007 },
1008 {
1009 name: "no ocsp-profile.status",
1010 config: ocspRespConfig{
1011 PKCS11: PKCS11SigningConfig{
1012 Module: "module",
1013 SigningLabel: "label",
1014 },
1015 Inputs: struct {
1016 CertificatePath string `yaml:"certificate-path"`
1017 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1018 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
1019 }{
1020 CertificatePath: "path",
1021 IssuerCertificatePath: "path",
1022 },
1023 Outputs: struct {
1024 ResponsePath string `yaml:"response-path"`
1025 }{
1026 ResponsePath: "path",
1027 },
1028 OCSPProfile: struct {
1029 ThisUpdate string `yaml:"this-update"`
1030 NextUpdate string `yaml:"next-update"`
1031 Status string `yaml:"status"`
1032 }{
1033 ThisUpdate: "this-update",
1034 NextUpdate: "next-update",
1035 },
1036 },
1037 expectedError: "ocsp-profile.status must be either \"good\" or \"revoked\"",
1038 },
1039 {
1040 name: "good config",
1041 config: ocspRespConfig{
1042 PKCS11: PKCS11SigningConfig{
1043 Module: "module",
1044 SigningLabel: "label",
1045 },
1046 Inputs: struct {
1047 CertificatePath string `yaml:"certificate-path"`
1048 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1049 DelegatedIssuerCertificatePath string `yaml:"delegated-issuer-certificate-path"`
1050 }{
1051 CertificatePath: "path",
1052 IssuerCertificatePath: "path",
1053 },
1054 Outputs: struct {
1055 ResponsePath string `yaml:"response-path"`
1056 }{
1057 ResponsePath: "path",
1058 },
1059 OCSPProfile: struct {
1060 ThisUpdate string `yaml:"this-update"`
1061 NextUpdate string `yaml:"next-update"`
1062 Status string `yaml:"status"`
1063 }{
1064 ThisUpdate: "this-update",
1065 NextUpdate: "next-update",
1066 Status: "good",
1067 },
1068 },
1069 },
1070 }
1071 for _, tc := range cases {
1072 t.Run(tc.name, func(t *testing.T) {
1073 err := tc.config.validate()
1074 if err != nil && err.Error() != tc.expectedError {
1075 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
1076 } else if err == nil && tc.expectedError != "" {
1077 t.Fatalf("validate didn't fail, wanted: %q", err)
1078 }
1079 })
1080 }
1081 }
1082
1083 func TestCRLConfig(t *testing.T) {
1084 cases := []struct {
1085 name string
1086 config crlConfig
1087 expectedError string
1088 }{
1089 {
1090 name: "no pkcs11.module",
1091 config: crlConfig{},
1092 expectedError: "pkcs11.module is required",
1093 },
1094 {
1095 name: "no pkcs11.signing-key-label",
1096 config: crlConfig{
1097 PKCS11: PKCS11SigningConfig{
1098 Module: "module",
1099 },
1100 },
1101 expectedError: "pkcs11.signing-key-label is required",
1102 },
1103 {
1104 name: "no inputs.issuer-certificate-path",
1105 config: crlConfig{
1106 PKCS11: PKCS11SigningConfig{
1107 Module: "module",
1108 SigningLabel: "label",
1109 },
1110 },
1111 expectedError: "inputs.issuer-certificate-path is required",
1112 },
1113 {
1114 name: "no outputs.crl-path",
1115 config: crlConfig{
1116 PKCS11: PKCS11SigningConfig{
1117 Module: "module",
1118 SigningLabel: "label",
1119 },
1120 Inputs: struct {
1121 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1122 }{
1123 IssuerCertificatePath: "path",
1124 },
1125 },
1126 expectedError: "outputs.crl-path is required",
1127 },
1128 {
1129 name: "no crl-profile.this-update",
1130 config: crlConfig{
1131 PKCS11: PKCS11SigningConfig{
1132 Module: "module",
1133 SigningLabel: "label",
1134 },
1135 Inputs: struct {
1136 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1137 }{
1138 IssuerCertificatePath: "path",
1139 },
1140 Outputs: struct {
1141 CRLPath string `yaml:"crl-path"`
1142 }{
1143 CRLPath: "path",
1144 },
1145 },
1146 expectedError: "crl-profile.this-update is required",
1147 },
1148 {
1149 name: "no crl-profile.next-update",
1150 config: crlConfig{
1151 PKCS11: PKCS11SigningConfig{
1152 Module: "module",
1153 SigningLabel: "label",
1154 },
1155 Inputs: struct {
1156 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1157 }{
1158 IssuerCertificatePath: "path",
1159 },
1160 Outputs: struct {
1161 CRLPath string `yaml:"crl-path"`
1162 }{
1163 CRLPath: "path",
1164 },
1165 CRLProfile: struct {
1166 ThisUpdate string `yaml:"this-update"`
1167 NextUpdate string `yaml:"next-update"`
1168 Number int64 `yaml:"number"`
1169 RevokedCertificates []struct {
1170 CertificatePath string `yaml:"certificate-path"`
1171 RevocationDate string `yaml:"revocation-date"`
1172 RevocationReason int `yaml:"revocation-reason"`
1173 } `yaml:"revoked-certificates"`
1174 }{
1175 ThisUpdate: "this-update",
1176 },
1177 },
1178 expectedError: "crl-profile.next-update is required",
1179 },
1180 {
1181 name: "no crl-profile.number",
1182 config: crlConfig{
1183 PKCS11: PKCS11SigningConfig{
1184 Module: "module",
1185 SigningLabel: "label",
1186 },
1187 Inputs: struct {
1188 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1189 }{
1190 IssuerCertificatePath: "path",
1191 },
1192 Outputs: struct {
1193 CRLPath string `yaml:"crl-path"`
1194 }{
1195 CRLPath: "path",
1196 },
1197 CRLProfile: struct {
1198 ThisUpdate string `yaml:"this-update"`
1199 NextUpdate string `yaml:"next-update"`
1200 Number int64 `yaml:"number"`
1201 RevokedCertificates []struct {
1202 CertificatePath string `yaml:"certificate-path"`
1203 RevocationDate string `yaml:"revocation-date"`
1204 RevocationReason int `yaml:"revocation-reason"`
1205 } `yaml:"revoked-certificates"`
1206 }{
1207 ThisUpdate: "this-update",
1208 NextUpdate: "next-update",
1209 },
1210 },
1211 expectedError: "crl-profile.number must be non-zero",
1212 },
1213 {
1214 name: "no crl-profile.revoked-certificates.certificate-path",
1215 config: crlConfig{
1216 PKCS11: PKCS11SigningConfig{
1217 Module: "module",
1218 SigningLabel: "label",
1219 },
1220 Inputs: struct {
1221 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1222 }{
1223 IssuerCertificatePath: "path",
1224 },
1225 Outputs: struct {
1226 CRLPath string `yaml:"crl-path"`
1227 }{
1228 CRLPath: "path",
1229 },
1230 CRLProfile: struct {
1231 ThisUpdate string `yaml:"this-update"`
1232 NextUpdate string `yaml:"next-update"`
1233 Number int64 `yaml:"number"`
1234 RevokedCertificates []struct {
1235 CertificatePath string `yaml:"certificate-path"`
1236 RevocationDate string `yaml:"revocation-date"`
1237 RevocationReason int `yaml:"revocation-reason"`
1238 } `yaml:"revoked-certificates"`
1239 }{
1240 ThisUpdate: "this-update",
1241 NextUpdate: "next-update",
1242 Number: 1,
1243 RevokedCertificates: []struct {
1244 CertificatePath string `yaml:"certificate-path"`
1245 RevocationDate string `yaml:"revocation-date"`
1246 RevocationReason int `yaml:"revocation-reason"`
1247 }{{}},
1248 },
1249 },
1250 expectedError: "crl-profile.revoked-certificates.certificate-path is required",
1251 },
1252 {
1253 name: "no crl-profile.revoked-certificates.revocation-date",
1254 config: crlConfig{
1255 PKCS11: PKCS11SigningConfig{
1256 Module: "module",
1257 SigningLabel: "label",
1258 },
1259 Inputs: struct {
1260 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1261 }{
1262 IssuerCertificatePath: "path",
1263 },
1264 Outputs: struct {
1265 CRLPath string `yaml:"crl-path"`
1266 }{
1267 CRLPath: "path",
1268 },
1269 CRLProfile: struct {
1270 ThisUpdate string `yaml:"this-update"`
1271 NextUpdate string `yaml:"next-update"`
1272 Number int64 `yaml:"number"`
1273 RevokedCertificates []struct {
1274 CertificatePath string `yaml:"certificate-path"`
1275 RevocationDate string `yaml:"revocation-date"`
1276 RevocationReason int `yaml:"revocation-reason"`
1277 } `yaml:"revoked-certificates"`
1278 }{
1279 ThisUpdate: "this-update",
1280 NextUpdate: "next-update",
1281 Number: 1,
1282 RevokedCertificates: []struct {
1283 CertificatePath string `yaml:"certificate-path"`
1284 RevocationDate string `yaml:"revocation-date"`
1285 RevocationReason int `yaml:"revocation-reason"`
1286 }{{
1287 CertificatePath: "path",
1288 }},
1289 },
1290 },
1291 expectedError: "crl-profile.revoked-certificates.revocation-date is required",
1292 },
1293 {
1294 name: "no revocation reason",
1295 config: crlConfig{
1296 PKCS11: PKCS11SigningConfig{
1297 Module: "module",
1298 SigningLabel: "label",
1299 },
1300 Inputs: struct {
1301 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1302 }{
1303 IssuerCertificatePath: "path",
1304 },
1305 Outputs: struct {
1306 CRLPath string `yaml:"crl-path"`
1307 }{
1308 CRLPath: "path",
1309 },
1310 CRLProfile: struct {
1311 ThisUpdate string `yaml:"this-update"`
1312 NextUpdate string `yaml:"next-update"`
1313 Number int64 `yaml:"number"`
1314 RevokedCertificates []struct {
1315 CertificatePath string `yaml:"certificate-path"`
1316 RevocationDate string `yaml:"revocation-date"`
1317 RevocationReason int `yaml:"revocation-reason"`
1318 } `yaml:"revoked-certificates"`
1319 }{
1320 ThisUpdate: "this-update",
1321 NextUpdate: "next-update",
1322 Number: 1,
1323 RevokedCertificates: []struct {
1324 CertificatePath string `yaml:"certificate-path"`
1325 RevocationDate string `yaml:"revocation-date"`
1326 RevocationReason int `yaml:"revocation-reason"`
1327 }{{
1328 CertificatePath: "path",
1329 RevocationDate: "date",
1330 }},
1331 },
1332 },
1333 expectedError: "crl-profile.revoked-certificates.revocation-reason is required",
1334 },
1335 {
1336 name: "good",
1337 config: crlConfig{
1338 PKCS11: PKCS11SigningConfig{
1339 Module: "module",
1340 SigningLabel: "label",
1341 },
1342 Inputs: struct {
1343 IssuerCertificatePath string `yaml:"issuer-certificate-path"`
1344 }{
1345 IssuerCertificatePath: "path",
1346 },
1347 Outputs: struct {
1348 CRLPath string `yaml:"crl-path"`
1349 }{
1350 CRLPath: "path",
1351 },
1352 CRLProfile: struct {
1353 ThisUpdate string `yaml:"this-update"`
1354 NextUpdate string `yaml:"next-update"`
1355 Number int64 `yaml:"number"`
1356 RevokedCertificates []struct {
1357 CertificatePath string `yaml:"certificate-path"`
1358 RevocationDate string `yaml:"revocation-date"`
1359 RevocationReason int `yaml:"revocation-reason"`
1360 } `yaml:"revoked-certificates"`
1361 }{
1362 ThisUpdate: "this-update",
1363 NextUpdate: "next-update",
1364 Number: 1,
1365 RevokedCertificates: []struct {
1366 CertificatePath string `yaml:"certificate-path"`
1367 RevocationDate string `yaml:"revocation-date"`
1368 RevocationReason int `yaml:"revocation-reason"`
1369 }{{
1370 CertificatePath: "path",
1371 RevocationDate: "date",
1372 RevocationReason: 1,
1373 }},
1374 },
1375 },
1376 },
1377 }
1378 for _, tc := range cases {
1379 t.Run(tc.name, func(t *testing.T) {
1380 err := tc.config.validate()
1381 if err != nil && err.Error() != tc.expectedError {
1382 t.Fatalf("Unexpected error, wanted: %q, got: %q", tc.expectedError, err)
1383 } else if err == nil && tc.expectedError != "" {
1384 t.Fatalf("validate didn't fail, wanted: %q", err)
1385 }
1386 })
1387 }
1388 }
1389
1390 func TestSignAndWriteNoLintCert(t *testing.T) {
1391 _, err := signAndWriteCert(nil, nil, nil, nil, nil, "")
1392 test.AssertError(t, err, "should have failed because no lintCert was provided")
1393 test.AssertDeepEquals(t, err, fmt.Errorf("linting was not performed prior to issuance"))
1394 }
1395
View as plain text