blob: 39a0b0e69e84c3c327515b0511c761155bbd61af [file] [log] [blame]
Serge Bazanski999e1db2021-11-30 20:37:38 +01001package pki
2
3import (
4 "context"
5 "crypto/x509"
6 "testing"
7
8 "go.etcd.io/etcd/integration"
9
10 "source.monogon.dev/metropolis/node/core/consensus/client"
11)
12
13// TestRevoke exercises the CRL revocation and watching functionality of a CA
14// certificate.
15func TestRevoke(t *testing.T) {
16 cluster := integration.NewClusterV3(nil, &integration.ClusterConfig{
17 Size: 1,
18 })
19 cl := client.NewLocal(cluster.Client(0))
20 defer cluster.Terminate(nil)
21 ctx, ctxC := context.WithCancel(context.Background())
22 defer ctxC()
23 ns := Namespaced("/test-managed/")
24
25 ca := &Certificate{
26 Namespace: &ns,
27 Issuer: SelfSigned,
28 Name: "ca",
29 Template: CA("Test CA"),
30 }
31 sub := &Certificate{
32 Namespace: &ns,
33 Issuer: ca,
34 Name: "sub",
35 Template: Server([]string{"server"}, nil),
36 }
37
38 caCertBytes, err := ca.Ensure(ctx, cl)
39 if err != nil {
40 t.Fatalf("Ensuring ca certificate failed: %v", err)
41 }
42 caCert, err := x509.ParseCertificate(caCertBytes)
43 if err != nil {
44 t.Fatalf("Loading newly emitted CA certificate failed: %v", err)
45 }
46
47 subCertBytes, err := sub.Ensure(ctx, cl)
48 if err != nil {
49 t.Fatalf("Ensuring sub certificate failed: %v", err)
50 }
51 subCert, err := x509.ParseCertificate(subCertBytes)
52 if err != nil {
53 t.Fatalf("Loading newly emitted sub certificate failed: %v", err)
54 }
55
56 // Ensure CRL is correctly signed and that subCert is not yet on it.
57 crlW := ca.WatchCRL(cl)
58 crl, err := crlW.Get(ctx)
59 if err != nil {
60 t.Fatalf("Retrieving initial CRL failed: %v", err)
61 }
62 if err := caCert.CheckCRLSignature(crl.List); err != nil {
63 t.Fatalf("Initial CRL not signed by CA: %v", err)
64 }
65 for _, el := range crl.List.TBSCertList.RevokedCertificates {
66 if el.SerialNumber.Cmp(subCert.SerialNumber) == 0 {
67 t.Fatalf("Newly emitted certificate is already on CRL.")
68 }
69 }
70
71 // Emit yet another certificate. Also shouldn't be on CRL.
72 bad := &Certificate{
73 Namespace: &ns,
74 Issuer: ca,
75 Name: "bad",
76 Template: Server([]string{"badserver"}, nil),
77 }
78 badCertBytes, err := bad.Ensure(ctx, cl)
79 if err != nil {
80 t.Fatalf("Ensuring bad certificate failed: %v", err)
81 }
82 badCert, err := x509.ParseCertificate(badCertBytes)
83 if err != nil {
84 t.Fatalf("Loading newly emitted bad certificate failed: %v", err)
85 }
86 for _, el := range crl.List.TBSCertList.RevokedCertificates {
87 if el.SerialNumber.Cmp(badCert.SerialNumber) == 0 {
88 t.Fatalf("Newly emitted bad certificate is already on CRL.")
89 }
90 }
91
92 // Revoke bad certificate. Should now be present in CRL.
93 if err := ca.Revoke(ctx, cl, "badserver"); err != nil {
94 t.Fatalf("Revoke failed: %v", err)
95 }
96 // Get in a loop until found.
97 for {
98 crl, err = crlW.Get(ctx)
99 if err != nil {
100 t.Fatalf("Get failed: %v", err)
101 }
102 found := false
103 for _, el := range crl.List.TBSCertList.RevokedCertificates {
104 if el.SerialNumber.Cmp(badCert.SerialNumber) == 0 {
105 found = true
106 }
107 if el.SerialNumber.Cmp(subCert.SerialNumber) == 0 {
108 t.Errorf("Found non-revoked cert in CRL")
109 }
110 }
111 if found {
112 break
113 }
114 }
115 // Now revoke first certificate. Both should be now present in CRL.
116 if err := ca.Revoke(ctx, cl, "server"); err != nil {
117 t.Fatalf("Revoke failed: %v", err)
118 }
119 // Get in a loop until found.
120 for {
121 crl, err = crlW.Get(ctx)
122 if err != nil {
123 t.Fatalf("Get failed: %v", err)
124 }
125 foundSub := false
126 foundBad := false
127 for _, el := range crl.List.TBSCertList.RevokedCertificates {
128 if el.SerialNumber.Cmp(badCert.SerialNumber) == 0 {
129 foundBad = true
130 }
131 if el.SerialNumber.Cmp(subCert.SerialNumber) == 0 {
132 foundSub = true
133 }
134 }
135 if foundBad && foundSub {
136 break
137 }
138 }
139}