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