blob: d38b559dfaa5f1e74a24d0d088376b8e1b5a432b [file] [log] [blame]
Serge Bazanski52538842021-08-11 16:22:41 +02001package pki
2
3import (
4 "bytes"
5 "context"
6 "crypto/ed25519"
7 "crypto/rand"
8 "crypto/x509"
9 "testing"
10
Lorenz Brund13c1c62022-03-30 19:58:58 +020011 "go.etcd.io/etcd/client/pkg/v3/testutil"
12 "go.etcd.io/etcd/tests/v3/integration"
Serge Bazanski52538842021-08-11 16:22:41 +020013)
14
15// TestManaged ensures Managed Certificates work, including re-ensuring
16// certificates with the same data and issuing subordinate certificates.
17func TestManaged(t *testing.T) {
Lorenz Brund13c1c62022-03-30 19:58:58 +020018 tb, cancel := testutil.NewTestingTBProthesis("pki-managed")
19 defer cancel()
20 cluster := integration.NewClusterV3(tb, &integration.ClusterConfig{
Serge Bazanski52538842021-08-11 16:22:41 +020021 Size: 1,
22 })
23 cl := cluster.Client(0)
Lorenz Brund13c1c62022-03-30 19:58:58 +020024 defer cluster.Terminate(tb)
Serge Bazanski52538842021-08-11 16:22:41 +020025 ctx, ctxC := context.WithCancel(context.Background())
26 defer ctxC()
27 ns := Namespaced("/test-managed/")
28
29 // Test CA certificate issuance.
30 ca := &Certificate{
31 Namespace: &ns,
32 Issuer: SelfSigned,
33 Name: "ca",
34 Template: CA("Test CA"),
35 }
36 caBytes, err := ca.Ensure(ctx, cl)
37 if err != nil {
38 t.Fatalf("Failed to Ensure CA: %v", err)
39 }
40 caCert, err := x509.ParseCertificate(caBytes)
41 if err != nil {
42 t.Fatalf("Failed to parse newly emited CA cert: %v", err)
43 }
44 if !caCert.IsCA {
45 t.Errorf("Newly emitted CA cert is not CA")
46 }
47 if ca.PublicKey == nil {
48 t.Errorf("Newly emitted CA cert has no public key")
49 }
50 if ca.PrivateKey == nil {
51 t.Errorf("Newly emitted CA cert has no public key")
52 }
53
54 // Re-emitting CA certificate with same parameters should return exact same
55 // data.
56 ca2 := &Certificate{
57 Namespace: &ns,
58 Issuer: SelfSigned,
59 Name: "ca",
60 Template: CA("Test CA"),
61 }
62 caBytes2, err := ca2.Ensure(ctx, cl)
63 if err != nil {
64 t.Fatalf("Failed to re-Ensure CA: %v", err)
65 }
66 if !bytes.Equal(caBytes, caBytes2) {
67 t.Errorf("New CA has different x509 certificate")
68 }
69 if !bytes.Equal(ca.PublicKey, ca2.PublicKey) {
70 t.Errorf("New CA has different public key")
71 }
72 if !bytes.Equal(ca.PrivateKey, ca2.PrivateKey) {
73 t.Errorf("New CA has different private key")
74 }
75
76 // Emitting a subordinate certificate should work.
77 client := &Certificate{
78 Namespace: &ns,
79 Issuer: ca2,
80 Name: "client",
81 Template: Client("foo", nil),
82 }
83 clientBytes, err := client.Ensure(ctx, cl)
84 if err != nil {
85 t.Fatalf("Failed to ensure client certificate: %v", err)
86 }
87 clientCert, err := x509.ParseCertificate(clientBytes)
88 if err != nil {
89 t.Fatalf("Failed to parse newly emitted client certificate: %v", err)
90 }
91 if clientCert.IsCA {
92 t.Errorf("New client cert is CA")
93 }
94 if want, got := "foo", clientCert.Subject.CommonName; want != got {
95 t.Errorf("New client CN should be %q, got %q", want, got)
96 }
97 if want, got := caCert.Subject.String(), clientCert.Issuer.String(); want != got {
98 t.Errorf("New client issuer should be %q, got %q", want, got)
99 }
100}
101
102// TestExternal ensures External certificates work correctly, including
103// re-Ensuring certificates with the same public key, and attempting to re-issue
104// the same certificate with a different public key (which should fail).
105func TestExternal(t *testing.T) {
Lorenz Brund13c1c62022-03-30 19:58:58 +0200106 tb, cancel := testutil.NewTestingTBProthesis("pki-managed")
107 defer cancel()
108 cluster := integration.NewClusterV3(tb, &integration.ClusterConfig{
Serge Bazanski52538842021-08-11 16:22:41 +0200109 Size: 1,
110 })
111 cl := cluster.Client(0)
Lorenz Brund13c1c62022-03-30 19:58:58 +0200112 defer cluster.Terminate(tb)
Serge Bazanski52538842021-08-11 16:22:41 +0200113 ctx, ctxC := context.WithCancel(context.Background())
114 defer ctxC()
115 ns := Namespaced("/test-external/")
116
117 ca := &Certificate{
118 Namespace: &ns,
119 Issuer: SelfSigned,
120 Name: "ca",
121 Template: CA("Test CA"),
122 }
123
124 // Issuing an external certificate should work.
125 pk, _, err := ed25519.GenerateKey(rand.Reader)
126 if err != nil {
127 t.Fatalf("GenerateKey: %v", err)
128 }
129 server := &Certificate{
130 Namespace: &ns,
131 Issuer: ca,
132 Name: "server",
133 Template: Server([]string{"server"}, nil),
134 Mode: CertificateExternal,
135 PublicKey: pk,
136 }
137 serverBytes, err := server.Ensure(ctx, cl)
138 if err != nil {
139 t.Fatalf("Failed to Ensure server certificate: %v", err)
140 }
141
142 // Issuing an external certificate with the same name but different public key
143 // should fail.
144 pk2, _, err := ed25519.GenerateKey(rand.Reader)
145 if err != nil {
146 t.Fatalf("GenerateKey: %v", err)
147 }
148 server2 := &Certificate{
149 Namespace: &ns,
150 Issuer: ca,
151 Name: "server",
152 Template: Server([]string{"server"}, nil),
153 Mode: CertificateExternal,
154 PublicKey: pk2,
155 }
156 if _, err := server2.Ensure(ctx, cl); err == nil {
157 t.Fatalf("Issuing server certificate with different public key should have failed")
158 }
159
160 // Issuing the external certificate with the same name and same public key
161 // should work and yield the same x509 bytes.
162 server3 := &Certificate{
163 Namespace: &ns,
164 Issuer: ca,
165 Name: "server",
166 Template: Server([]string{"server"}, nil),
167 Mode: CertificateExternal,
168 PublicKey: pk,
169 }
170 serverBytes3, err := server3.Ensure(ctx, cl)
171 if err != nil {
172 t.Fatalf("Failed to re-Ensure server certificate: %v", err)
173 }
174 if !bytes.Equal(serverBytes, serverBytes3) {
175 t.Errorf("New server certificate has different x509 certificate")
176 }
177}