1package cert
2
3import (
4	"context"
5	"crypto/ecdsa"
6	"crypto/elliptic"
7	"crypto/rand"
8	"crypto/rsa"
9	"crypto/tls"
10	"crypto/x509"
11	"crypto/x509/pkix"
12	"encoding/pem"
13	"fmt"
14	"io"
15	"io/ioutil"
16	"math/big"
17	mathrand "math/rand"
18	"net"
19	"net/http"
20	"net/url"
21	"os"
22	"path/filepath"
23	"reflect"
24	"testing"
25	"time"
26
27	"github.com/go-test/deep"
28	"github.com/hashicorp/go-sockaddr"
29
30	"golang.org/x/net/http2"
31
32	cleanhttp "github.com/hashicorp/go-cleanhttp"
33	log "github.com/hashicorp/go-hclog"
34	"github.com/hashicorp/vault/api"
35	vaulthttp "github.com/hashicorp/vault/http"
36
37	rootcerts "github.com/hashicorp/go-rootcerts"
38	"github.com/hashicorp/vault/builtin/logical/pki"
39	logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical"
40	"github.com/hashicorp/vault/sdk/framework"
41	"github.com/hashicorp/vault/sdk/helper/certutil"
42	"github.com/hashicorp/vault/sdk/helper/tokenutil"
43	"github.com/hashicorp/vault/sdk/logical"
44	"github.com/hashicorp/vault/vault"
45	"github.com/mitchellh/mapstructure"
46)
47
48const (
49	serverCertPath = "test-fixtures/cacert.pem"
50	serverKeyPath  = "test-fixtures/cakey.pem"
51	serverCAPath   = serverCertPath
52
53	testRootCACertPath1 = "test-fixtures/testcacert1.pem"
54	testRootCAKeyPath1  = "test-fixtures/testcakey1.pem"
55	testCertPath1       = "test-fixtures/testissuedcert4.pem"
56	testKeyPath1        = "test-fixtures/testissuedkey4.pem"
57	testIssuedCertCRL   = "test-fixtures/issuedcertcrl"
58
59	testRootCACertPath2 = "test-fixtures/testcacert2.pem"
60	testRootCAKeyPath2  = "test-fixtures/testcakey2.pem"
61	testRootCertCRL     = "test-fixtures/cacert2crl"
62)
63
64func generateTestCertAndConnState(t *testing.T, template *x509.Certificate) (string, tls.ConnectionState, error) {
65	t.Helper()
66	tempDir, err := ioutil.TempDir("", "vault-cert-auth-test-")
67	if err != nil {
68		t.Fatal(err)
69	}
70	t.Logf("test %s, temp dir %s", t.Name(), tempDir)
71	caCertTemplate := &x509.Certificate{
72		Subject: pkix.Name{
73			CommonName: "localhost",
74		},
75		DNSNames:              []string{"localhost"},
76		IPAddresses:           []net.IP{net.ParseIP("127.0.0.1")},
77		KeyUsage:              x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign),
78		SerialNumber:          big.NewInt(mathrand.Int63()),
79		NotBefore:             time.Now().Add(-30 * time.Second),
80		NotAfter:              time.Now().Add(262980 * time.Hour),
81		BasicConstraintsValid: true,
82		IsCA:                  true,
83	}
84	caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
85	if err != nil {
86		t.Fatal(err)
87	}
88	caBytes, err := x509.CreateCertificate(rand.Reader, caCertTemplate, caCertTemplate, caKey.Public(), caKey)
89	if err != nil {
90		t.Fatal(err)
91	}
92	caCert, err := x509.ParseCertificate(caBytes)
93	if err != nil {
94		t.Fatal(err)
95	}
96	caCertPEMBlock := &pem.Block{
97		Type:  "CERTIFICATE",
98		Bytes: caBytes,
99	}
100	err = ioutil.WriteFile(filepath.Join(tempDir, "ca_cert.pem"), pem.EncodeToMemory(caCertPEMBlock), 0o755)
101	if err != nil {
102		t.Fatal(err)
103	}
104	marshaledCAKey, err := x509.MarshalECPrivateKey(caKey)
105	if err != nil {
106		t.Fatal(err)
107	}
108	caKeyPEMBlock := &pem.Block{
109		Type:  "EC PRIVATE KEY",
110		Bytes: marshaledCAKey,
111	}
112	err = ioutil.WriteFile(filepath.Join(tempDir, "ca_key.pem"), pem.EncodeToMemory(caKeyPEMBlock), 0o755)
113	if err != nil {
114		t.Fatal(err)
115	}
116
117	key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
118	if err != nil {
119		t.Fatal(err)
120	}
121	certBytes, err := x509.CreateCertificate(rand.Reader, template, caCert, key.Public(), caKey)
122	if err != nil {
123		t.Fatal(err)
124	}
125	certPEMBlock := &pem.Block{
126		Type:  "CERTIFICATE",
127		Bytes: certBytes,
128	}
129	err = ioutil.WriteFile(filepath.Join(tempDir, "cert.pem"), pem.EncodeToMemory(certPEMBlock), 0o755)
130	if err != nil {
131		t.Fatal(err)
132	}
133	marshaledKey, err := x509.MarshalECPrivateKey(key)
134	if err != nil {
135		t.Fatal(err)
136	}
137	keyPEMBlock := &pem.Block{
138		Type:  "EC PRIVATE KEY",
139		Bytes: marshaledKey,
140	}
141	err = ioutil.WriteFile(filepath.Join(tempDir, "key.pem"), pem.EncodeToMemory(keyPEMBlock), 0o755)
142	if err != nil {
143		t.Fatal(err)
144	}
145	connInfo, err := testConnState(filepath.Join(tempDir, "cert.pem"), filepath.Join(tempDir, "key.pem"), filepath.Join(tempDir, "ca_cert.pem"))
146	return tempDir, connInfo, err
147}
148
149// Unlike testConnState, this method does not use the same 'tls.Config' objects for
150// both dialing and listening. Instead, it runs the server without specifying its CA.
151// But the client, presents the CA cert of the server to trust the server.
152// The client can present a cert and key which is completely independent of server's CA.
153// The connection state returned will contain the certificate presented by the client.
154func connectionState(serverCAPath, serverCertPath, serverKeyPath, clientCertPath, clientKeyPath string) (tls.ConnectionState, error) {
155	serverKeyPair, err := tls.LoadX509KeyPair(serverCertPath, serverKeyPath)
156	if err != nil {
157		return tls.ConnectionState{}, err
158	}
159	// Prepare the listener configuration with server's key pair
160	listenConf := &tls.Config{
161		Certificates: []tls.Certificate{serverKeyPair},
162		ClientAuth:   tls.RequestClientCert,
163	}
164
165	clientKeyPair, err := tls.LoadX509KeyPair(clientCertPath, clientKeyPath)
166	if err != nil {
167		return tls.ConnectionState{}, err
168	}
169	// Load the CA cert required by the client to authenticate the server.
170	rootConfig := &rootcerts.Config{
171		CAFile: serverCAPath,
172	}
173	serverCAs, err := rootcerts.LoadCACerts(rootConfig)
174	if err != nil {
175		return tls.ConnectionState{}, err
176	}
177	// Prepare the dial configuration that the client uses to establish the connection.
178	dialConf := &tls.Config{
179		Certificates: []tls.Certificate{clientKeyPair},
180		RootCAs:      serverCAs,
181	}
182
183	// Start the server.
184	list, err := tls.Listen("tcp", "127.0.0.1:0", listenConf)
185	if err != nil {
186		return tls.ConnectionState{}, err
187	}
188	defer list.Close()
189
190	// Accept connections.
191	serverErrors := make(chan error, 1)
192	connState := make(chan tls.ConnectionState)
193	go func() {
194		defer close(connState)
195		serverConn, err := list.Accept()
196		if err != nil {
197			serverErrors <- err
198			close(serverErrors)
199			return
200		}
201		defer serverConn.Close()
202
203		// Read the ping
204		buf := make([]byte, 4)
205		_, err = serverConn.Read(buf)
206		if (err != nil) && (err != io.EOF) {
207			serverErrors <- err
208			close(serverErrors)
209			return
210		}
211		close(serverErrors)
212		connState <- serverConn.(*tls.Conn).ConnectionState()
213	}()
214
215	// Establish a connection from the client side and write a few bytes.
216	clientErrors := make(chan error, 1)
217	go func() {
218		addr := list.Addr().String()
219		conn, err := tls.Dial("tcp", addr, dialConf)
220		if err != nil {
221			clientErrors <- err
222			close(clientErrors)
223			return
224		}
225		defer conn.Close()
226
227		// Write ping
228		_, err = conn.Write([]byte("ping"))
229		if err != nil {
230			clientErrors <- err
231		}
232		close(clientErrors)
233	}()
234
235	for err = range clientErrors {
236		if err != nil {
237			return tls.ConnectionState{}, fmt.Errorf("error in client goroutine:%v", err)
238		}
239	}
240
241	for err = range serverErrors {
242		if err != nil {
243			return tls.ConnectionState{}, fmt.Errorf("error in server goroutine:%v", err)
244		}
245	}
246	// Grab the current state
247	return <-connState, nil
248}
249
250func TestBackend_PermittedDNSDomainsIntermediateCA(t *testing.T) {
251	// Enable PKI secret engine and Cert auth method
252	coreConfig := &vault.CoreConfig{
253		DisableMlock: true,
254		DisableCache: true,
255		Logger:       log.NewNullLogger(),
256		CredentialBackends: map[string]logical.Factory{
257			"cert": Factory,
258		},
259		LogicalBackends: map[string]logical.Factory{
260			"pki": pki.Factory,
261		},
262	}
263	cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
264		HandlerFunc: vaulthttp.Handler,
265	})
266	cluster.Start()
267	defer cluster.Cleanup()
268	cores := cluster.Cores
269	vault.TestWaitActive(t, cores[0].Core)
270	client := cores[0].Client
271
272	var err error
273
274	// Mount /pki as a root CA
275	err = client.Sys().Mount("pki", &api.MountInput{
276		Type: "pki",
277		Config: api.MountConfigInput{
278			DefaultLeaseTTL: "16h",
279			MaxLeaseTTL:     "32h",
280		},
281	})
282	if err != nil {
283		t.Fatal(err)
284	}
285
286	// Set the cluster's certificate as the root CA in /pki
287	pemBundleRootCA := string(cluster.CACertPEM) + string(cluster.CAKeyPEM)
288	_, err = client.Logical().Write("pki/config/ca", map[string]interface{}{
289		"pem_bundle": pemBundleRootCA,
290	})
291	if err != nil {
292		t.Fatal(err)
293	}
294
295	// Mount /pki2 to operate as an intermediate CA
296	err = client.Sys().Mount("pki2", &api.MountInput{
297		Type: "pki",
298		Config: api.MountConfigInput{
299			DefaultLeaseTTL: "16h",
300			MaxLeaseTTL:     "32h",
301		},
302	})
303	if err != nil {
304		t.Fatal(err)
305	}
306
307	// Create a CSR for the intermediate CA
308	secret, err := client.Logical().Write("pki2/intermediate/generate/internal", nil)
309	if err != nil {
310		t.Fatal(err)
311	}
312	intermediateCSR := secret.Data["csr"].(string)
313
314	// Sign the intermediate CSR using /pki
315	secret, err = client.Logical().Write("pki/root/sign-intermediate", map[string]interface{}{
316		"permitted_dns_domains": ".myvault.com",
317		"csr":                   intermediateCSR,
318	})
319	if err != nil {
320		t.Fatal(err)
321	}
322	intermediateCertPEM := secret.Data["certificate"].(string)
323
324	// Configure the intermediate cert as the CA in /pki2
325	_, err = client.Logical().Write("pki2/intermediate/set-signed", map[string]interface{}{
326		"certificate": intermediateCertPEM,
327	})
328	if err != nil {
329		t.Fatal(err)
330	}
331
332	// Create a role on the intermediate CA mount
333	_, err = client.Logical().Write("pki2/roles/myvault-dot-com", map[string]interface{}{
334		"allowed_domains":  "myvault.com",
335		"allow_subdomains": "true",
336		"max_ttl":          "5m",
337	})
338	if err != nil {
339		t.Fatal(err)
340	}
341
342	// Issue a leaf cert using the intermediate CA
343	secret, err = client.Logical().Write("pki2/issue/myvault-dot-com", map[string]interface{}{
344		"common_name": "cert.myvault.com",
345		"format":      "pem",
346		"ip_sans":     "127.0.0.1",
347	})
348	if err != nil {
349		t.Fatal(err)
350	}
351	leafCertPEM := secret.Data["certificate"].(string)
352	leafCertKeyPEM := secret.Data["private_key"].(string)
353
354	// Enable the cert auth method
355	err = client.Sys().EnableAuthWithOptions("cert", &api.EnableAuthOptions{
356		Type: "cert",
357	})
358	if err != nil {
359		t.Fatal(err)
360	}
361
362	// Set the intermediate CA cert as a trusted certificate in the backend
363	_, err = client.Logical().Write("auth/cert/certs/myvault-dot-com", map[string]interface{}{
364		"display_name": "myvault.com",
365		"policies":     "default",
366		"certificate":  intermediateCertPEM,
367	})
368	if err != nil {
369		t.Fatal(err)
370	}
371
372	// Create temporary files for CA cert, client cert and client cert key.
373	// This is used to configure TLS in the api client.
374	caCertFile, err := ioutil.TempFile("", "caCert")
375	if err != nil {
376		t.Fatal(err)
377	}
378	defer os.Remove(caCertFile.Name())
379	if _, err := caCertFile.Write([]byte(cluster.CACertPEM)); err != nil {
380		t.Fatal(err)
381	}
382	if err := caCertFile.Close(); err != nil {
383		t.Fatal(err)
384	}
385
386	leafCertFile, err := ioutil.TempFile("", "leafCert")
387	if err != nil {
388		t.Fatal(err)
389	}
390	defer os.Remove(leafCertFile.Name())
391	if _, err := leafCertFile.Write([]byte(leafCertPEM)); err != nil {
392		t.Fatal(err)
393	}
394	if err := leafCertFile.Close(); err != nil {
395		t.Fatal(err)
396	}
397
398	leafCertKeyFile, err := ioutil.TempFile("", "leafCertKey")
399	if err != nil {
400		t.Fatal(err)
401	}
402	defer os.Remove(leafCertKeyFile.Name())
403	if _, err := leafCertKeyFile.Write([]byte(leafCertKeyPEM)); err != nil {
404		t.Fatal(err)
405	}
406	if err := leafCertKeyFile.Close(); err != nil {
407		t.Fatal(err)
408	}
409
410	// This function is a copy-pasta from the NewTestCluster, with the
411	// modification to reconfigure the TLS on the api client with the leaf
412	// certificate generated above.
413	getAPIClient := func(port int, tlsConfig *tls.Config) *api.Client {
414		transport := cleanhttp.DefaultPooledTransport()
415		transport.TLSClientConfig = tlsConfig.Clone()
416		if err := http2.ConfigureTransport(transport); err != nil {
417			t.Fatal(err)
418		}
419		client := &http.Client{
420			Transport: transport,
421			CheckRedirect: func(*http.Request, []*http.Request) error {
422				// This can of course be overridden per-test by using its own client
423				return fmt.Errorf("redirects not allowed in these tests")
424			},
425		}
426		config := api.DefaultConfig()
427		if config.Error != nil {
428			t.Fatal(config.Error)
429		}
430		config.Address = fmt.Sprintf("https://127.0.0.1:%d", port)
431		config.HttpClient = client
432
433		// Set the above issued certificates as the client certificates
434		config.ConfigureTLS(&api.TLSConfig{
435			CACert:     caCertFile.Name(),
436			ClientCert: leafCertFile.Name(),
437			ClientKey:  leafCertKeyFile.Name(),
438		})
439
440		apiClient, err := api.NewClient(config)
441		if err != nil {
442			t.Fatal(err)
443		}
444		return apiClient
445	}
446
447	// Create a new api client with the desired TLS configuration
448	newClient := getAPIClient(cores[0].Listeners[0].Address.Port, cores[0].TLSConfig)
449
450	secret, err = newClient.Logical().Write("auth/cert/login", map[string]interface{}{
451		"name": "myvault-dot-com",
452	})
453	if err != nil {
454		t.Fatal(err)
455	}
456	if secret.Auth == nil || secret.Auth.ClientToken == "" {
457		t.Fatalf("expected a successful authentication")
458	}
459}
460
461func TestBackend_NonCAExpiry(t *testing.T) {
462	var resp *logical.Response
463	var err error
464
465	// Create a self-signed certificate and issue a leaf certificate using the
466	// CA cert
467	template := &x509.Certificate{
468		SerialNumber: big.NewInt(1234),
469		Subject: pkix.Name{
470			CommonName:         "localhost",
471			Organization:       []string{"hashicorp"},
472			OrganizationalUnit: []string{"vault"},
473		},
474		BasicConstraintsValid: true,
475		NotBefore:             time.Now().Add(-30 * time.Second),
476		NotAfter:              time.Now().Add(50 * time.Second),
477		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
478		KeyUsage:              x509.KeyUsage(x509.KeyUsageCertSign | x509.KeyUsageCRLSign),
479	}
480
481	// Set IP SAN
482	parsedIP := net.ParseIP("127.0.0.1")
483	if parsedIP == nil {
484		t.Fatalf("failed to create parsed IP")
485	}
486	template.IPAddresses = []net.IP{parsedIP}
487
488	// Private key for CA cert
489	caPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)
490	if err != nil {
491		t.Fatal(err)
492	}
493
494	// Marshalling to be able to create PEM file
495	caPrivateKeyBytes := x509.MarshalPKCS1PrivateKey(caPrivateKey)
496
497	caPublicKey := &caPrivateKey.PublicKey
498
499	template.IsCA = true
500
501	caCertBytes, err := x509.CreateCertificate(rand.Reader, template, template, caPublicKey, caPrivateKey)
502	if err != nil {
503		t.Fatal(err)
504	}
505
506	caCert, err := x509.ParseCertificate(caCertBytes)
507	if err != nil {
508		t.Fatal(err)
509	}
510
511	parsedCaBundle := &certutil.ParsedCertBundle{
512		Certificate:      caCert,
513		CertificateBytes: caCertBytes,
514		PrivateKeyBytes:  caPrivateKeyBytes,
515		PrivateKeyType:   certutil.RSAPrivateKey,
516	}
517
518	caCertBundle, err := parsedCaBundle.ToCertBundle()
519	if err != nil {
520		t.Fatal(err)
521	}
522
523	caCertFile, err := ioutil.TempFile("", "caCert")
524	if err != nil {
525		t.Fatal(err)
526	}
527
528	defer os.Remove(caCertFile.Name())
529
530	if _, err := caCertFile.Write([]byte(caCertBundle.Certificate)); err != nil {
531		t.Fatal(err)
532	}
533	if err := caCertFile.Close(); err != nil {
534		t.Fatal(err)
535	}
536
537	caKeyFile, err := ioutil.TempFile("", "caKey")
538	if err != nil {
539		t.Fatal(err)
540	}
541
542	defer os.Remove(caKeyFile.Name())
543
544	if _, err := caKeyFile.Write([]byte(caCertBundle.PrivateKey)); err != nil {
545		t.Fatal(err)
546	}
547	if err := caKeyFile.Close(); err != nil {
548		t.Fatal(err)
549	}
550
551	// Prepare template for non-CA cert
552
553	template.IsCA = false
554	template.SerialNumber = big.NewInt(5678)
555
556	template.KeyUsage = x509.KeyUsage(x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign)
557	issuedPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048)
558	if err != nil {
559		t.Fatal(err)
560	}
561
562	issuedPrivateKeyBytes := x509.MarshalPKCS1PrivateKey(issuedPrivateKey)
563
564	issuedPublicKey := &issuedPrivateKey.PublicKey
565
566	// Keep a short certificate lifetime so logins can be tested both when
567	// cert is valid and when it gets expired
568	template.NotBefore = time.Now().Add(-2 * time.Second)
569	template.NotAfter = time.Now().Add(3 * time.Second)
570
571	issuedCertBytes, err := x509.CreateCertificate(rand.Reader, template, caCert, issuedPublicKey, caPrivateKey)
572	if err != nil {
573		t.Fatal(err)
574	}
575
576	issuedCert, err := x509.ParseCertificate(issuedCertBytes)
577	if err != nil {
578		t.Fatal(err)
579	}
580
581	parsedIssuedBundle := &certutil.ParsedCertBundle{
582		Certificate:      issuedCert,
583		CertificateBytes: issuedCertBytes,
584		PrivateKeyBytes:  issuedPrivateKeyBytes,
585		PrivateKeyType:   certutil.RSAPrivateKey,
586	}
587
588	issuedCertBundle, err := parsedIssuedBundle.ToCertBundle()
589	if err != nil {
590		t.Fatal(err)
591	}
592
593	issuedCertFile, err := ioutil.TempFile("", "issuedCert")
594	if err != nil {
595		t.Fatal(err)
596	}
597
598	defer os.Remove(issuedCertFile.Name())
599
600	if _, err := issuedCertFile.Write([]byte(issuedCertBundle.Certificate)); err != nil {
601		t.Fatal(err)
602	}
603	if err := issuedCertFile.Close(); err != nil {
604		t.Fatal(err)
605	}
606
607	issuedKeyFile, err := ioutil.TempFile("", "issuedKey")
608	if err != nil {
609		t.Fatal(err)
610	}
611
612	defer os.Remove(issuedKeyFile.Name())
613
614	if _, err := issuedKeyFile.Write([]byte(issuedCertBundle.PrivateKey)); err != nil {
615		t.Fatal(err)
616	}
617	if err := issuedKeyFile.Close(); err != nil {
618		t.Fatal(err)
619	}
620
621	config := logical.TestBackendConfig()
622	storage := &logical.InmemStorage{}
623	config.StorageView = storage
624
625	b, err := Factory(context.Background(), config)
626	if err != nil {
627		t.Fatal(err)
628	}
629
630	// Register the Non-CA certificate of the client key pair
631	certData := map[string]interface{}{
632		"certificate":  issuedCertBundle.Certificate,
633		"policies":     "abc",
634		"display_name": "cert1",
635		"ttl":          10000,
636	}
637	certReq := &logical.Request{
638		Operation: logical.UpdateOperation,
639		Path:      "certs/cert1",
640		Storage:   storage,
641		Data:      certData,
642	}
643
644	resp, err = b.HandleRequest(context.Background(), certReq)
645	if err != nil || (resp != nil && resp.IsError()) {
646		t.Fatalf("err:%v resp:%#v", err, resp)
647	}
648
649	// Create connection state using the certificates generated
650	connState, err := connectionState(caCertFile.Name(), caCertFile.Name(), caKeyFile.Name(), issuedCertFile.Name(), issuedKeyFile.Name())
651	if err != nil {
652		t.Fatalf("error testing connection state:%v", err)
653	}
654
655	loginReq := &logical.Request{
656		Operation: logical.UpdateOperation,
657		Storage:   storage,
658		Path:      "login",
659		Connection: &logical.Connection{
660			ConnState: &connState,
661		},
662	}
663
664	// Login when the certificate is still valid. Login should succeed.
665	resp, err = b.HandleRequest(context.Background(), loginReq)
666	if err != nil || (resp != nil && resp.IsError()) {
667		t.Fatalf("err:%v resp:%#v", err, resp)
668	}
669
670	// Wait until the certificate expires
671	time.Sleep(5 * time.Second)
672
673	// Login attempt after certificate expiry should fail
674	resp, err = b.HandleRequest(context.Background(), loginReq)
675	if err == nil {
676		t.Fatalf("expected error due to expired certificate")
677	}
678}
679
680func TestBackend_RegisteredNonCA_CRL(t *testing.T) {
681	config := logical.TestBackendConfig()
682	storage := &logical.InmemStorage{}
683	config.StorageView = storage
684
685	b, err := Factory(context.Background(), config)
686	if err != nil {
687		t.Fatal(err)
688	}
689
690	nonCACert, err := ioutil.ReadFile(testCertPath1)
691	if err != nil {
692		t.Fatal(err)
693	}
694
695	// Register the Non-CA certificate of the client key pair
696	certData := map[string]interface{}{
697		"certificate":  nonCACert,
698		"policies":     "abc",
699		"display_name": "cert1",
700		"ttl":          10000,
701	}
702	certReq := &logical.Request{
703		Operation: logical.UpdateOperation,
704		Path:      "certs/cert1",
705		Storage:   storage,
706		Data:      certData,
707	}
708
709	resp, err := b.HandleRequest(context.Background(), certReq)
710	if err != nil || (resp != nil && resp.IsError()) {
711		t.Fatalf("err:%v resp:%#v", err, resp)
712	}
713
714	// Connection state is presenting the client Non-CA cert and its key.
715	// This is exactly what is registered at the backend.
716	connState, err := connectionState(serverCAPath, serverCertPath, serverKeyPath, testCertPath1, testKeyPath1)
717	if err != nil {
718		t.Fatalf("error testing connection state:%v", err)
719	}
720	loginReq := &logical.Request{
721		Operation: logical.UpdateOperation,
722		Storage:   storage,
723		Path:      "login",
724		Connection: &logical.Connection{
725			ConnState: &connState,
726		},
727	}
728	// Login should succeed.
729	resp, err = b.HandleRequest(context.Background(), loginReq)
730	if err != nil || (resp != nil && resp.IsError()) {
731		t.Fatalf("err:%v resp:%#v", err, resp)
732	}
733
734	// Register a CRL containing the issued client certificate used above.
735	issuedCRL, err := ioutil.ReadFile(testIssuedCertCRL)
736	if err != nil {
737		t.Fatal(err)
738	}
739	crlData := map[string]interface{}{
740		"crl": issuedCRL,
741	}
742	crlReq := &logical.Request{
743		Operation: logical.UpdateOperation,
744		Storage:   storage,
745		Path:      "crls/issuedcrl",
746		Data:      crlData,
747	}
748	resp, err = b.HandleRequest(context.Background(), crlReq)
749	if err != nil || (resp != nil && resp.IsError()) {
750		t.Fatalf("err:%v resp:%#v", err, resp)
751	}
752
753	// Attempt login with the same connection state but with the CRL registered
754	resp, err = b.HandleRequest(context.Background(), loginReq)
755	if err != nil {
756		t.Fatal(err)
757	}
758	if resp == nil || !resp.IsError() {
759		t.Fatalf("expected failure due to revoked certificate")
760	}
761}
762
763func TestBackend_CRLs(t *testing.T) {
764	config := logical.TestBackendConfig()
765	storage := &logical.InmemStorage{}
766	config.StorageView = storage
767
768	b, err := Factory(context.Background(), config)
769	if err != nil {
770		t.Fatal(err)
771	}
772
773	clientCA1, err := ioutil.ReadFile(testRootCACertPath1)
774	if err != nil {
775		t.Fatal(err)
776	}
777	// Register the CA certificate of the client key pair
778	certData := map[string]interface{}{
779		"certificate":  clientCA1,
780		"policies":     "abc",
781		"display_name": "cert1",
782		"ttl":          10000,
783	}
784
785	certReq := &logical.Request{
786		Operation: logical.UpdateOperation,
787		Path:      "certs/cert1",
788		Storage:   storage,
789		Data:      certData,
790	}
791
792	resp, err := b.HandleRequest(context.Background(), certReq)
793	if err != nil || (resp != nil && resp.IsError()) {
794		t.Fatalf("err:%v resp:%#v", err, resp)
795	}
796
797	// Connection state is presenting the client CA cert and its key.
798	// This is exactly what is registered at the backend.
799	connState, err := connectionState(serverCAPath, serverCertPath, serverKeyPath, testRootCACertPath1, testRootCAKeyPath1)
800	if err != nil {
801		t.Fatalf("error testing connection state:%v", err)
802	}
803	loginReq := &logical.Request{
804		Operation: logical.UpdateOperation,
805		Storage:   storage,
806		Path:      "login",
807		Connection: &logical.Connection{
808			ConnState: &connState,
809		},
810	}
811	resp, err = b.HandleRequest(context.Background(), loginReq)
812	if err != nil || (resp != nil && resp.IsError()) {
813		t.Fatalf("err:%v resp:%#v", err, resp)
814	}
815
816	// Now, without changing the registered client CA cert, present from
817	// the client side, a cert issued using the registered CA.
818	connState, err = connectionState(serverCAPath, serverCertPath, serverKeyPath, testCertPath1, testKeyPath1)
819	if err != nil {
820		t.Fatalf("error testing connection state: %v", err)
821	}
822	loginReq.Connection.ConnState = &connState
823
824	// Attempt login with the updated connection
825	resp, err = b.HandleRequest(context.Background(), loginReq)
826	if err != nil || (resp != nil && resp.IsError()) {
827		t.Fatalf("err:%v resp:%#v", err, resp)
828	}
829
830	// Register a CRL containing the issued client certificate used above.
831	issuedCRL, err := ioutil.ReadFile(testIssuedCertCRL)
832	if err != nil {
833		t.Fatal(err)
834	}
835	crlData := map[string]interface{}{
836		"crl": issuedCRL,
837	}
838
839	crlReq := &logical.Request{
840		Operation: logical.UpdateOperation,
841		Storage:   storage,
842		Path:      "crls/issuedcrl",
843		Data:      crlData,
844	}
845	resp, err = b.HandleRequest(context.Background(), crlReq)
846	if err != nil || (resp != nil && resp.IsError()) {
847		t.Fatalf("err:%v resp:%#v", err, resp)
848	}
849
850	// Attempt login with the revoked certificate.
851	resp, err = b.HandleRequest(context.Background(), loginReq)
852	if err != nil {
853		t.Fatal(err)
854	}
855	if resp == nil || !resp.IsError() {
856		t.Fatalf("expected failure due to revoked certificate")
857	}
858
859	// Register a different client CA certificate.
860	clientCA2, err := ioutil.ReadFile(testRootCACertPath2)
861	if err != nil {
862		t.Fatal(err)
863	}
864	certData["certificate"] = clientCA2
865	resp, err = b.HandleRequest(context.Background(), certReq)
866	if err != nil || (resp != nil && resp.IsError()) {
867		t.Fatalf("err:%v resp:%#v", err, resp)
868	}
869
870	// Test login using a different client CA cert pair.
871	connState, err = connectionState(serverCAPath, serverCertPath, serverKeyPath, testRootCACertPath2, testRootCAKeyPath2)
872	if err != nil {
873		t.Fatalf("error testing connection state: %v", err)
874	}
875	loginReq.Connection.ConnState = &connState
876
877	// Attempt login with the updated connection
878	resp, err = b.HandleRequest(context.Background(), loginReq)
879	if err != nil || (resp != nil && resp.IsError()) {
880		t.Fatalf("err:%v resp:%#v", err, resp)
881	}
882
883	// Register a CRL containing the root CA certificate used above.
884	rootCRL, err := ioutil.ReadFile(testRootCertCRL)
885	if err != nil {
886		t.Fatal(err)
887	}
888	crlData["crl"] = rootCRL
889	resp, err = b.HandleRequest(context.Background(), crlReq)
890	if err != nil || (resp != nil && resp.IsError()) {
891		t.Fatalf("err:%v resp:%#v", err, resp)
892	}
893
894	// Attempt login with the same connection state but with the CRL registered
895	resp, err = b.HandleRequest(context.Background(), loginReq)
896	if err != nil {
897		t.Fatal(err)
898	}
899	if resp == nil || !resp.IsError() {
900		t.Fatalf("expected failure due to revoked certificate")
901	}
902}
903
904func testFactory(t *testing.T) logical.Backend {
905	b, err := Factory(context.Background(), &logical.BackendConfig{
906		System: &logical.StaticSystemView{
907			DefaultLeaseTTLVal: 1000 * time.Second,
908			MaxLeaseTTLVal:     1800 * time.Second,
909		},
910		StorageView: &logical.InmemStorage{},
911	})
912	if err != nil {
913		t.Fatalf("error: %s", err)
914	}
915	return b
916}
917
918// Test the certificates being registered to the backend
919func TestBackend_CertWrites(t *testing.T) {
920	// CA cert
921	ca1, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
922	if err != nil {
923		t.Fatalf("err: %v", err)
924	}
925	// Non CA Cert
926	ca2, err := ioutil.ReadFile("test-fixtures/keys/cert.pem")
927	if err != nil {
928		t.Fatalf("err: %v", err)
929	}
930	// Non CA cert without TLS web client authentication
931	ca3, err := ioutil.ReadFile("test-fixtures/noclientauthcert.pem")
932	if err != nil {
933		t.Fatalf("err: %v", err)
934	}
935
936	tc := logicaltest.TestCase{
937		CredentialBackend: testFactory(t),
938		Steps: []logicaltest.TestStep{
939			testAccStepCert(t, "aaa", ca1, "foo", allowed{}, false),
940			testAccStepCert(t, "bbb", ca2, "foo", allowed{}, false),
941			testAccStepCert(t, "ccc", ca3, "foo", allowed{}, true),
942		},
943	}
944	tc.Steps = append(tc.Steps, testAccStepListCerts(t, []string{"aaa", "bbb"})...)
945	logicaltest.Test(t, tc)
946}
947
948// Test a client trusted by a CA
949func TestBackend_basic_CA(t *testing.T) {
950	connState, err := testConnState("test-fixtures/keys/cert.pem",
951		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
952	if err != nil {
953		t.Fatalf("error testing connection state: %v", err)
954	}
955	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
956	if err != nil {
957		t.Fatalf("err: %v", err)
958	}
959	logicaltest.Test(t, logicaltest.TestCase{
960		CredentialBackend: testFactory(t),
961		Steps: []logicaltest.TestStep{
962			testAccStepCert(t, "web", ca, "foo", allowed{}, false),
963			testAccStepLogin(t, connState),
964			testAccStepCertLease(t, "web", ca, "foo"),
965			testAccStepCertTTL(t, "web", ca, "foo"),
966			testAccStepLogin(t, connState),
967			testAccStepCertMaxTTL(t, "web", ca, "foo"),
968			testAccStepLogin(t, connState),
969			testAccStepCertNoLease(t, "web", ca, "foo"),
970			testAccStepLoginDefaultLease(t, connState),
971			testAccStepCert(t, "web", ca, "foo", allowed{names: "*.example.com"}, false),
972			testAccStepLogin(t, connState),
973			testAccStepCert(t, "web", ca, "foo", allowed{names: "*.invalid.com"}, false),
974			testAccStepLoginInvalid(t, connState),
975		},
976	})
977}
978
979// Test CRL behavior
980func TestBackend_Basic_CRLs(t *testing.T) {
981	connState, err := testConnState("test-fixtures/keys/cert.pem",
982		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
983	if err != nil {
984		t.Fatalf("error testing connection state: %v", err)
985	}
986	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
987	if err != nil {
988		t.Fatalf("err: %v", err)
989	}
990	crl, err := ioutil.ReadFile("test-fixtures/root/root.crl")
991	if err != nil {
992		t.Fatalf("err: %v", err)
993	}
994	logicaltest.Test(t, logicaltest.TestCase{
995		CredentialBackend: testFactory(t),
996		Steps: []logicaltest.TestStep{
997			testAccStepCertNoLease(t, "web", ca, "foo"),
998			testAccStepLoginDefaultLease(t, connState),
999			testAccStepAddCRL(t, crl, connState),
1000			testAccStepReadCRL(t, connState),
1001			testAccStepLoginInvalid(t, connState),
1002			testAccStepDeleteCRL(t, connState),
1003			testAccStepLoginDefaultLease(t, connState),
1004		},
1005	})
1006}
1007
1008// Test a self-signed client (root CA) that is trusted
1009func TestBackend_basic_singleCert(t *testing.T) {
1010	connState, err := testConnState("test-fixtures/root/rootcacert.pem",
1011		"test-fixtures/root/rootcakey.pem", "test-fixtures/root/rootcacert.pem")
1012	if err != nil {
1013		t.Fatalf("error testing connection state: %v", err)
1014	}
1015	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1016	if err != nil {
1017		t.Fatalf("err: %v", err)
1018	}
1019	logicaltest.Test(t, logicaltest.TestCase{
1020		CredentialBackend: testFactory(t),
1021		Steps: []logicaltest.TestStep{
1022			testAccStepCert(t, "web", ca, "foo", allowed{}, false),
1023			testAccStepLogin(t, connState),
1024			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com"}, false),
1025			testAccStepLogin(t, connState),
1026			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid"}, false),
1027			testAccStepLoginInvalid(t, connState),
1028			testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.4:invalid"}, false),
1029			testAccStepLoginInvalid(t, connState),
1030		},
1031	})
1032}
1033
1034func TestBackend_common_name_singleCert(t *testing.T) {
1035	connState, err := testConnState("test-fixtures/root/rootcacert.pem",
1036		"test-fixtures/root/rootcakey.pem", "test-fixtures/root/rootcacert.pem")
1037	if err != nil {
1038		t.Fatalf("error testing connection state: %v", err)
1039	}
1040	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1041	if err != nil {
1042		t.Fatalf("err: %v", err)
1043	}
1044	logicaltest.Test(t, logicaltest.TestCase{
1045		CredentialBackend: testFactory(t),
1046		Steps: []logicaltest.TestStep{
1047			testAccStepCert(t, "web", ca, "foo", allowed{}, false),
1048			testAccStepLogin(t, connState),
1049			testAccStepCert(t, "web", ca, "foo", allowed{common_names: "example.com"}, false),
1050			testAccStepLogin(t, connState),
1051			testAccStepCert(t, "web", ca, "foo", allowed{common_names: "invalid"}, false),
1052			testAccStepLoginInvalid(t, connState),
1053			testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.4:invalid"}, false),
1054			testAccStepLoginInvalid(t, connState),
1055		},
1056	})
1057}
1058
1059// Test a self-signed client with custom ext (root CA) that is trusted
1060func TestBackend_ext_singleCert(t *testing.T) {
1061	connState, err := testConnState(
1062		"test-fixtures/root/rootcawextcert.pem",
1063		"test-fixtures/root/rootcawextkey.pem",
1064		"test-fixtures/root/rootcacert.pem",
1065	)
1066	if err != nil {
1067		t.Fatalf("error testing connection state: %v", err)
1068	}
1069	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1070	if err != nil {
1071		t.Fatalf("err: %v", err)
1072	}
1073	logicaltest.Test(t, logicaltest.TestCase{
1074		CredentialBackend: testFactory(t),
1075		Steps: []logicaltest.TestStep{
1076			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:A UTF8String Extension"}, false),
1077			testAccStepLogin(t, connState),
1078			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false),
1079			testAccStepLogin(t, connState),
1080			testAccStepCert(t, "web", ca, "foo", allowed{ext: "1.2.3.45:*"}, false),
1081			testAccStepLoginInvalid(t, connState),
1082			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:The Wrong Value"}, false),
1083			testAccStepLoginInvalid(t, connState),
1084			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false),
1085			testAccStepLoginInvalid(t, connState),
1086			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:"}, false),
1087			testAccStepLoginInvalid(t, connState),
1088			testAccStepCert(t, "web", ca, "foo", allowed{ext: "2.1.1.1:,2.1.1.2:*"}, false),
1089			testAccStepLoginInvalid(t, connState),
1090			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:A UTF8String Extension"}, false),
1091			testAccStepLogin(t, connState),
1092			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false),
1093			testAccStepLogin(t, connState),
1094			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "1.2.3.45:*"}, false),
1095			testAccStepLoginInvalid(t, connState),
1096			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:The Wrong Value"}, false),
1097			testAccStepLoginInvalid(t, connState),
1098			testAccStepCert(t, "web", ca, "foo", allowed{names: "example.com", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false),
1099			testAccStepLoginInvalid(t, connState),
1100			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:A UTF8String Extension"}, false),
1101			testAccStepLoginInvalid(t, connState),
1102			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:A UTF8*"}, false),
1103			testAccStepLoginInvalid(t, connState),
1104			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "1.2.3.45:*"}, false),
1105			testAccStepLoginInvalid(t, connState),
1106			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:The Wrong Value"}, false),
1107			testAccStepLoginInvalid(t, connState),
1108			testAccStepCert(t, "web", ca, "foo", allowed{names: "invalid", ext: "2.1.1.1:*,2.1.1.2:The Wrong Value"}, false),
1109			testAccStepLoginInvalid(t, connState),
1110		},
1111	})
1112}
1113
1114// Test a self-signed client with URI alt names (root CA) that is trusted
1115func TestBackend_dns_singleCert(t *testing.T) {
1116	certTemplate := &x509.Certificate{
1117		Subject: pkix.Name{
1118			CommonName: "example.com",
1119		},
1120		DNSNames:    []string{"example.com"},
1121		IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
1122		ExtKeyUsage: []x509.ExtKeyUsage{
1123			x509.ExtKeyUsageServerAuth,
1124			x509.ExtKeyUsageClientAuth,
1125		},
1126		KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
1127		SerialNumber: big.NewInt(mathrand.Int63()),
1128		NotBefore:    time.Now().Add(-30 * time.Second),
1129		NotAfter:     time.Now().Add(262980 * time.Hour),
1130	}
1131
1132	tempDir, connState, err := generateTestCertAndConnState(t, certTemplate)
1133	if tempDir != "" {
1134		defer os.RemoveAll(tempDir)
1135	}
1136	if err != nil {
1137		t.Fatalf("error testing connection state: %v", err)
1138	}
1139	ca, err := ioutil.ReadFile(filepath.Join(tempDir, "ca_cert.pem"))
1140	if err != nil {
1141		t.Fatalf("err: %v", err)
1142	}
1143
1144	logicaltest.Test(t, logicaltest.TestCase{
1145		CredentialBackend: testFactory(t),
1146		Steps: []logicaltest.TestStep{
1147			testAccStepCert(t, "web", ca, "foo", allowed{dns: "example.com"}, false),
1148			testAccStepLogin(t, connState),
1149			testAccStepCert(t, "web", ca, "foo", allowed{dns: "*ample.com"}, false),
1150			testAccStepLogin(t, connState),
1151			testAccStepCert(t, "web", ca, "foo", allowed{dns: "notincert.com"}, false),
1152			testAccStepLoginInvalid(t, connState),
1153			testAccStepCert(t, "web", ca, "foo", allowed{dns: "abc"}, false),
1154			testAccStepLoginInvalid(t, connState),
1155			testAccStepCert(t, "web", ca, "foo", allowed{dns: "*.example.com"}, false),
1156			testAccStepLoginInvalid(t, connState),
1157		},
1158	})
1159}
1160
1161// Test a self-signed client with URI alt names (root CA) that is trusted
1162func TestBackend_email_singleCert(t *testing.T) {
1163	certTemplate := &x509.Certificate{
1164		Subject: pkix.Name{
1165			CommonName: "example.com",
1166		},
1167		EmailAddresses: []string{"valid@example.com"},
1168		IPAddresses:    []net.IP{net.ParseIP("127.0.0.1")},
1169		ExtKeyUsage: []x509.ExtKeyUsage{
1170			x509.ExtKeyUsageServerAuth,
1171			x509.ExtKeyUsageClientAuth,
1172		},
1173		KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
1174		SerialNumber: big.NewInt(mathrand.Int63()),
1175		NotBefore:    time.Now().Add(-30 * time.Second),
1176		NotAfter:     time.Now().Add(262980 * time.Hour),
1177	}
1178
1179	tempDir, connState, err := generateTestCertAndConnState(t, certTemplate)
1180	if tempDir != "" {
1181		defer os.RemoveAll(tempDir)
1182	}
1183	if err != nil {
1184		t.Fatalf("error testing connection state: %v", err)
1185	}
1186	ca, err := ioutil.ReadFile(filepath.Join(tempDir, "ca_cert.pem"))
1187	if err != nil {
1188		t.Fatalf("err: %v", err)
1189	}
1190
1191	logicaltest.Test(t, logicaltest.TestCase{
1192		CredentialBackend: testFactory(t),
1193		Steps: []logicaltest.TestStep{
1194			testAccStepCert(t, "web", ca, "foo", allowed{emails: "valid@example.com"}, false),
1195			testAccStepLogin(t, connState),
1196			testAccStepCert(t, "web", ca, "foo", allowed{emails: "*@example.com"}, false),
1197			testAccStepLogin(t, connState),
1198			testAccStepCert(t, "web", ca, "foo", allowed{emails: "invalid@notincert.com"}, false),
1199			testAccStepLoginInvalid(t, connState),
1200			testAccStepCert(t, "web", ca, "foo", allowed{emails: "abc"}, false),
1201			testAccStepLoginInvalid(t, connState),
1202			testAccStepCert(t, "web", ca, "foo", allowed{emails: "*.example.com"}, false),
1203			testAccStepLoginInvalid(t, connState),
1204		},
1205	})
1206}
1207
1208// Test a self-signed client with OU (root CA) that is trusted
1209func TestBackend_organizationalUnit_singleCert(t *testing.T) {
1210	connState, err := testConnState(
1211		"test-fixtures/root/rootcawoucert.pem",
1212		"test-fixtures/root/rootcawoukey.pem",
1213		"test-fixtures/root/rootcawoucert.pem",
1214	)
1215	if err != nil {
1216		t.Fatalf("error testing connection state: %v", err)
1217	}
1218	ca, err := ioutil.ReadFile("test-fixtures/root/rootcawoucert.pem")
1219	if err != nil {
1220		t.Fatalf("err: %v", err)
1221	}
1222	logicaltest.Test(t, logicaltest.TestCase{
1223		CredentialBackend: testFactory(t),
1224		Steps: []logicaltest.TestStep{
1225			testAccStepCert(t, "web", ca, "foo", allowed{organizational_units: "engineering"}, false),
1226			testAccStepLogin(t, connState),
1227			testAccStepCert(t, "web", ca, "foo", allowed{organizational_units: "eng*"}, false),
1228			testAccStepLogin(t, connState),
1229			testAccStepCert(t, "web", ca, "foo", allowed{organizational_units: "engineering,finance"}, false),
1230			testAccStepLogin(t, connState),
1231			testAccStepCert(t, "web", ca, "foo", allowed{organizational_units: "foo"}, false),
1232			testAccStepLoginInvalid(t, connState),
1233		},
1234	})
1235}
1236
1237// Test a self-signed client with URI alt names (root CA) that is trusted
1238func TestBackend_uri_singleCert(t *testing.T) {
1239	u, err := url.Parse("spiffe://example.com/host")
1240	if err != nil {
1241		t.Fatal(err)
1242	}
1243	certTemplate := &x509.Certificate{
1244		Subject: pkix.Name{
1245			CommonName: "example.com",
1246		},
1247		DNSNames:    []string{"example.com"},
1248		IPAddresses: []net.IP{net.ParseIP("127.0.0.1")},
1249		URIs:        []*url.URL{u},
1250		ExtKeyUsage: []x509.ExtKeyUsage{
1251			x509.ExtKeyUsageServerAuth,
1252			x509.ExtKeyUsageClientAuth,
1253		},
1254		KeyUsage:     x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement,
1255		SerialNumber: big.NewInt(mathrand.Int63()),
1256		NotBefore:    time.Now().Add(-30 * time.Second),
1257		NotAfter:     time.Now().Add(262980 * time.Hour),
1258	}
1259
1260	tempDir, connState, err := generateTestCertAndConnState(t, certTemplate)
1261	if tempDir != "" {
1262		defer os.RemoveAll(tempDir)
1263	}
1264	if err != nil {
1265		t.Fatalf("error testing connection state: %v", err)
1266	}
1267	ca, err := ioutil.ReadFile(filepath.Join(tempDir, "ca_cert.pem"))
1268	if err != nil {
1269		t.Fatalf("err: %v", err)
1270	}
1271	logicaltest.Test(t, logicaltest.TestCase{
1272		CredentialBackend: testFactory(t),
1273		Steps: []logicaltest.TestStep{
1274			testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/*"}, false),
1275			testAccStepLogin(t, connState),
1276			testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/host"}, false),
1277			testAccStepLogin(t, connState),
1278			testAccStepCert(t, "web", ca, "foo", allowed{uris: "spiffe://example.com/invalid"}, false),
1279			testAccStepLoginInvalid(t, connState),
1280			testAccStepCert(t, "web", ca, "foo", allowed{uris: "abc"}, false),
1281			testAccStepLoginInvalid(t, connState),
1282			testAccStepCert(t, "web", ca, "foo", allowed{uris: "http://www.google.com"}, false),
1283			testAccStepLoginInvalid(t, connState),
1284		},
1285	})
1286}
1287
1288// Test against a collection of matching and non-matching rules
1289func TestBackend_mixed_constraints(t *testing.T) {
1290	connState, err := testConnState("test-fixtures/keys/cert.pem",
1291		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
1292	if err != nil {
1293		t.Fatalf("error testing connection state: %v", err)
1294	}
1295	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1296	if err != nil {
1297		t.Fatalf("err: %v", err)
1298	}
1299	logicaltest.Test(t, logicaltest.TestCase{
1300		CredentialBackend: testFactory(t),
1301		Steps: []logicaltest.TestStep{
1302			testAccStepCert(t, "1unconstrained", ca, "foo", allowed{}, false),
1303			testAccStepCert(t, "2matching", ca, "foo", allowed{names: "*.example.com,whatever"}, false),
1304			testAccStepCert(t, "3invalid", ca, "foo", allowed{names: "invalid"}, false),
1305			testAccStepLogin(t, connState),
1306			// Assumes CertEntries are processed in alphabetical order (due to store.List), so we only match 2matching if 1unconstrained doesn't match
1307			testAccStepLoginWithName(t, connState, "2matching"),
1308			testAccStepLoginWithNameInvalid(t, connState, "3invalid"),
1309		},
1310	})
1311}
1312
1313// Test an untrusted client
1314func TestBackend_untrusted(t *testing.T) {
1315	connState, err := testConnState("test-fixtures/keys/cert.pem",
1316		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
1317	if err != nil {
1318		t.Fatalf("error testing connection state: %v", err)
1319	}
1320	logicaltest.Test(t, logicaltest.TestCase{
1321		CredentialBackend: testFactory(t),
1322		Steps: []logicaltest.TestStep{
1323			testAccStepLoginInvalid(t, connState),
1324		},
1325	})
1326}
1327
1328func TestBackend_validCIDR(t *testing.T) {
1329	config := logical.TestBackendConfig()
1330	storage := &logical.InmemStorage{}
1331	config.StorageView = storage
1332
1333	b, err := Factory(context.Background(), config)
1334	if err != nil {
1335		t.Fatal(err)
1336	}
1337
1338	connState, err := testConnState("test-fixtures/keys/cert.pem",
1339		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
1340	if err != nil {
1341		t.Fatalf("error testing connection state: %v", err)
1342	}
1343	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1344	if err != nil {
1345		t.Fatalf("err: %v", err)
1346	}
1347
1348	name := "web"
1349	boundCIDRs := []string{"127.0.0.1", "128.252.0.0/16"}
1350
1351	addCertReq := &logical.Request{
1352		Operation: logical.UpdateOperation,
1353		Path:      "certs/" + name,
1354		Data: map[string]interface{}{
1355			"certificate":         string(ca),
1356			"policies":            "foo",
1357			"display_name":        name,
1358			"allowed_names":       "",
1359			"required_extensions": "",
1360			"lease":               1000,
1361			"bound_cidrs":         boundCIDRs,
1362		},
1363		Storage:    storage,
1364		Connection: &logical.Connection{ConnState: &connState},
1365	}
1366
1367	_, err = b.HandleRequest(context.Background(), addCertReq)
1368	if err != nil {
1369		t.Fatal(err)
1370	}
1371
1372	readCertReq := &logical.Request{
1373		Operation:  logical.ReadOperation,
1374		Path:       "certs/" + name,
1375		Storage:    storage,
1376		Connection: &logical.Connection{ConnState: &connState},
1377	}
1378
1379	readResult, err := b.HandleRequest(context.Background(), readCertReq)
1380	cidrsResult := readResult.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)
1381
1382	if cidrsResult[0].String() != boundCIDRs[0] ||
1383		cidrsResult[1].String() != boundCIDRs[1] {
1384		t.Fatalf("bound_cidrs couldn't be set correctly, EXPECTED: %v, ACTUAL: %v", boundCIDRs, cidrsResult)
1385	}
1386
1387	loginReq := &logical.Request{
1388		Operation:       logical.UpdateOperation,
1389		Path:            "login",
1390		Unauthenticated: true,
1391		Data: map[string]interface{}{
1392			"name": name,
1393		},
1394		Storage:    storage,
1395		Connection: &logical.Connection{ConnState: &connState},
1396	}
1397
1398	// override the remote address with an IPV4 that is authorized
1399	loginReq.Connection.RemoteAddr = "127.0.0.1/32"
1400
1401	_, err = b.HandleRequest(context.Background(), loginReq)
1402	if err != nil {
1403		t.Fatal(err.Error())
1404	}
1405}
1406
1407func TestBackend_invalidCIDR(t *testing.T) {
1408	config := logical.TestBackendConfig()
1409	storage := &logical.InmemStorage{}
1410	config.StorageView = storage
1411
1412	b, err := Factory(context.Background(), config)
1413	if err != nil {
1414		t.Fatal(err)
1415	}
1416
1417	connState, err := testConnState("test-fixtures/keys/cert.pem",
1418		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
1419	if err != nil {
1420		t.Fatalf("error testing connection state: %v", err)
1421	}
1422	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1423	if err != nil {
1424		t.Fatalf("err: %v", err)
1425	}
1426
1427	name := "web"
1428
1429	addCertReq := &logical.Request{
1430		Operation: logical.UpdateOperation,
1431		Path:      "certs/" + name,
1432		Data: map[string]interface{}{
1433			"certificate":         string(ca),
1434			"policies":            "foo",
1435			"display_name":        name,
1436			"allowed_names":       "",
1437			"required_extensions": "",
1438			"lease":               1000,
1439			"bound_cidrs":         []string{"127.0.0.1/32", "128.252.0.0/16"},
1440		},
1441		Storage:    storage,
1442		Connection: &logical.Connection{ConnState: &connState},
1443	}
1444
1445	_, err = b.HandleRequest(context.Background(), addCertReq)
1446	if err != nil {
1447		t.Fatal(err)
1448	}
1449
1450	loginReq := &logical.Request{
1451		Operation:       logical.UpdateOperation,
1452		Path:            "login",
1453		Unauthenticated: true,
1454		Data: map[string]interface{}{
1455			"name": name,
1456		},
1457		Storage:    storage,
1458		Connection: &logical.Connection{ConnState: &connState},
1459	}
1460
1461	// override the remote address with an IPV4 that isn't authorized
1462	loginReq.Connection.RemoteAddr = "127.0.0.1/8"
1463
1464	_, err = b.HandleRequest(context.Background(), loginReq)
1465	if err == nil {
1466		t.Fatal("expected \"ERROR: permission denied\"")
1467	}
1468}
1469
1470func testAccStepAddCRL(t *testing.T, crl []byte, connState tls.ConnectionState) logicaltest.TestStep {
1471	return logicaltest.TestStep{
1472		Operation: logical.UpdateOperation,
1473		Path:      "crls/test",
1474		ConnState: &connState,
1475		Data: map[string]interface{}{
1476			"crl": crl,
1477		},
1478	}
1479}
1480
1481func testAccStepReadCRL(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
1482	return logicaltest.TestStep{
1483		Operation: logical.ReadOperation,
1484		Path:      "crls/test",
1485		ConnState: &connState,
1486		Check: func(resp *logical.Response) error {
1487			crlInfo := CRLInfo{}
1488			err := mapstructure.Decode(resp.Data, &crlInfo)
1489			if err != nil {
1490				t.Fatalf("err: %v", err)
1491			}
1492			if len(crlInfo.Serials) != 1 {
1493				t.Fatalf("bad: expected CRL with length 1, got %d", len(crlInfo.Serials))
1494			}
1495			if _, ok := crlInfo.Serials["637101449987587619778072672905061040630001617053"]; !ok {
1496				t.Fatalf("bad: expected serial number not found in CRL")
1497			}
1498			return nil
1499		},
1500	}
1501}
1502
1503func testAccStepDeleteCRL(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
1504	return logicaltest.TestStep{
1505		Operation: logical.DeleteOperation,
1506		Path:      "crls/test",
1507		ConnState: &connState,
1508	}
1509}
1510
1511func testAccStepLogin(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
1512	return testAccStepLoginWithName(t, connState, "")
1513}
1514
1515func testAccStepLoginWithName(t *testing.T, connState tls.ConnectionState, certName string) logicaltest.TestStep {
1516	return logicaltest.TestStep{
1517		Operation:       logical.UpdateOperation,
1518		Path:            "login",
1519		Unauthenticated: true,
1520		ConnState:       &connState,
1521		Check: func(resp *logical.Response) error {
1522			if resp.Auth.TTL != 1000*time.Second {
1523				t.Fatalf("bad lease length: %#v", resp.Auth)
1524			}
1525
1526			if certName != "" && resp.Auth.DisplayName != ("mnt-"+certName) {
1527				t.Fatalf("matched the wrong cert: %#v", resp.Auth.DisplayName)
1528			}
1529
1530			fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
1531			return fn(resp)
1532		},
1533		Data: map[string]interface{}{
1534			"name": certName,
1535		},
1536	}
1537}
1538
1539func testAccStepLoginDefaultLease(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
1540	return logicaltest.TestStep{
1541		Operation:       logical.UpdateOperation,
1542		Path:            "login",
1543		Unauthenticated: true,
1544		ConnState:       &connState,
1545		Check: func(resp *logical.Response) error {
1546			if resp.Auth.TTL != 1000*time.Second {
1547				t.Fatalf("bad lease length: %#v", resp.Auth)
1548			}
1549
1550			fn := logicaltest.TestCheckAuth([]string{"default", "foo"})
1551			return fn(resp)
1552		},
1553	}
1554}
1555
1556func testAccStepLoginInvalid(t *testing.T, connState tls.ConnectionState) logicaltest.TestStep {
1557	return testAccStepLoginWithNameInvalid(t, connState, "")
1558}
1559
1560func testAccStepLoginWithNameInvalid(t *testing.T, connState tls.ConnectionState, certName string) logicaltest.TestStep {
1561	return logicaltest.TestStep{
1562		Operation:       logical.UpdateOperation,
1563		Path:            "login",
1564		Unauthenticated: true,
1565		ConnState:       &connState,
1566		Check: func(resp *logical.Response) error {
1567			if resp.Auth != nil {
1568				return fmt.Errorf("should not be authorized: %#v", resp)
1569			}
1570			return nil
1571		},
1572		Data: map[string]interface{}{
1573			"name": certName,
1574		},
1575		ErrorOk: true,
1576	}
1577}
1578
1579func testAccStepListCerts(
1580	t *testing.T, certs []string) []logicaltest.TestStep {
1581	return []logicaltest.TestStep{
1582		{
1583			Operation: logical.ListOperation,
1584			Path:      "certs",
1585			Check: func(resp *logical.Response) error {
1586				if resp == nil {
1587					return fmt.Errorf("nil response")
1588				}
1589				if resp.Data == nil {
1590					return fmt.Errorf("nil data")
1591				}
1592				if resp.Data["keys"] == interface{}(nil) {
1593					return fmt.Errorf("nil keys")
1594				}
1595				keys := resp.Data["keys"].([]string)
1596				if !reflect.DeepEqual(keys, certs) {
1597					return fmt.Errorf("mismatch: keys is %#v, certs is %#v", keys, certs)
1598				}
1599				return nil
1600			},
1601		}, {
1602			Operation: logical.ListOperation,
1603			Path:      "certs/",
1604			Check: func(resp *logical.Response) error {
1605				if resp == nil {
1606					return fmt.Errorf("nil response")
1607				}
1608				if resp.Data == nil {
1609					return fmt.Errorf("nil data")
1610				}
1611				if resp.Data["keys"] == interface{}(nil) {
1612					return fmt.Errorf("nil keys")
1613				}
1614				keys := resp.Data["keys"].([]string)
1615				if !reflect.DeepEqual(keys, certs) {
1616					return fmt.Errorf("mismatch: keys is %#v, certs is %#v", keys, certs)
1617				}
1618
1619				return nil
1620			},
1621		},
1622	}
1623}
1624
1625type allowed struct {
1626	names                string // allowed names in the certificate, looks at common, name, dns, email [depricated]
1627	common_names         string // allowed common names in the certificate
1628	dns                  string // allowed dns names in the SAN extension of the certificate
1629	emails               string // allowed email names in SAN extension of the certificate
1630	uris                 string // allowed uris in SAN extension of the certificate
1631	organizational_units string // allowed OUs in the certificate
1632	ext                  string // required extensions in the certificate
1633}
1634
1635func testAccStepCert(
1636	t *testing.T, name string, cert []byte, policies string, testData allowed, expectError bool) logicaltest.TestStep {
1637	return logicaltest.TestStep{
1638		Operation: logical.UpdateOperation,
1639		Path:      "certs/" + name,
1640		ErrorOk:   expectError,
1641		Data: map[string]interface{}{
1642			"certificate":                  string(cert),
1643			"policies":                     policies,
1644			"display_name":                 name,
1645			"allowed_names":                testData.names,
1646			"allowed_common_names":         testData.common_names,
1647			"allowed_dns_sans":             testData.dns,
1648			"allowed_email_sans":           testData.emails,
1649			"allowed_uri_sans":             testData.uris,
1650			"allowed_organizational_units": testData.organizational_units,
1651			"required_extensions":          testData.ext,
1652			"lease":                        1000,
1653		},
1654		Check: func(resp *logical.Response) error {
1655			if resp == nil && expectError {
1656				return fmt.Errorf("expected error but received nil")
1657			}
1658			return nil
1659		},
1660	}
1661}
1662
1663func testAccStepCertLease(
1664	t *testing.T, name string, cert []byte, policies string) logicaltest.TestStep {
1665	return logicaltest.TestStep{
1666		Operation: logical.UpdateOperation,
1667		Path:      "certs/" + name,
1668		Data: map[string]interface{}{
1669			"certificate":  string(cert),
1670			"policies":     policies,
1671			"display_name": name,
1672			"lease":        1000,
1673		},
1674	}
1675}
1676
1677func testAccStepCertTTL(
1678	t *testing.T, name string, cert []byte, policies string) logicaltest.TestStep {
1679	return logicaltest.TestStep{
1680		Operation: logical.UpdateOperation,
1681		Path:      "certs/" + name,
1682		Data: map[string]interface{}{
1683			"certificate":  string(cert),
1684			"policies":     policies,
1685			"display_name": name,
1686			"ttl":          "1000s",
1687		},
1688	}
1689}
1690
1691func testAccStepCertMaxTTL(
1692	t *testing.T, name string, cert []byte, policies string) logicaltest.TestStep {
1693	return logicaltest.TestStep{
1694		Operation: logical.UpdateOperation,
1695		Path:      "certs/" + name,
1696		Data: map[string]interface{}{
1697			"certificate":  string(cert),
1698			"policies":     policies,
1699			"display_name": name,
1700			"ttl":          "1000s",
1701			"max_ttl":      "1200s",
1702		},
1703	}
1704}
1705
1706func testAccStepCertNoLease(
1707	t *testing.T, name string, cert []byte, policies string) logicaltest.TestStep {
1708	return logicaltest.TestStep{
1709		Operation: logical.UpdateOperation,
1710		Path:      "certs/" + name,
1711		Data: map[string]interface{}{
1712			"certificate":  string(cert),
1713			"policies":     policies,
1714			"display_name": name,
1715		},
1716	}
1717}
1718
1719func testConnState(certPath, keyPath, rootCertPath string) (tls.ConnectionState, error) {
1720	cert, err := tls.LoadX509KeyPair(certPath, keyPath)
1721	if err != nil {
1722		return tls.ConnectionState{}, err
1723	}
1724	rootConfig := &rootcerts.Config{
1725		CAFile: rootCertPath,
1726	}
1727	rootCAs, err := rootcerts.LoadCACerts(rootConfig)
1728	if err != nil {
1729		return tls.ConnectionState{}, err
1730	}
1731	listenConf := &tls.Config{
1732		Certificates:       []tls.Certificate{cert},
1733		ClientAuth:         tls.RequestClientCert,
1734		InsecureSkipVerify: false,
1735		RootCAs:            rootCAs,
1736	}
1737	dialConf := listenConf.Clone()
1738	// start a server
1739	list, err := tls.Listen("tcp", "127.0.0.1:0", listenConf)
1740	if err != nil {
1741		return tls.ConnectionState{}, err
1742	}
1743	defer list.Close()
1744
1745	// Accept connections.
1746	serverErrors := make(chan error, 1)
1747	connState := make(chan tls.ConnectionState)
1748	go func() {
1749		defer close(connState)
1750		serverConn, err := list.Accept()
1751		serverErrors <- err
1752		if err != nil {
1753			close(serverErrors)
1754			return
1755		}
1756		defer serverConn.Close()
1757
1758		// Read the ping
1759		buf := make([]byte, 4)
1760		_, err = serverConn.Read(buf)
1761		if (err != nil) && (err != io.EOF) {
1762			serverErrors <- err
1763			close(serverErrors)
1764			return
1765		} else {
1766			// EOF is a reasonable error condition, so swallow it.
1767			serverErrors <- nil
1768		}
1769		close(serverErrors)
1770		connState <- serverConn.(*tls.Conn).ConnectionState()
1771	}()
1772
1773	// Establish a connection from the client side and write a few bytes.
1774	clientErrors := make(chan error, 1)
1775	go func() {
1776		addr := list.Addr().String()
1777		conn, err := tls.Dial("tcp", addr, dialConf)
1778		clientErrors <- err
1779		if err != nil {
1780			close(clientErrors)
1781			return
1782		}
1783		defer conn.Close()
1784
1785		// Write ping
1786		_, err = conn.Write([]byte("ping"))
1787		clientErrors <- err
1788		close(clientErrors)
1789	}()
1790
1791	for err = range clientErrors {
1792		if err != nil {
1793			return tls.ConnectionState{}, fmt.Errorf("error in client goroutine:%v", err)
1794		}
1795	}
1796
1797	for err = range serverErrors {
1798		if err != nil {
1799			return tls.ConnectionState{}, fmt.Errorf("error in server goroutine:%v", err)
1800		}
1801	}
1802	// Grab the current state
1803	return <-connState, nil
1804}
1805
1806func Test_Renew(t *testing.T) {
1807	storage := &logical.InmemStorage{}
1808
1809	lb, err := Factory(context.Background(), &logical.BackendConfig{
1810		System: &logical.StaticSystemView{
1811			DefaultLeaseTTLVal: 300 * time.Second,
1812			MaxLeaseTTLVal:     1800 * time.Second,
1813		},
1814		StorageView: storage,
1815	})
1816	if err != nil {
1817		t.Fatalf("error: %s", err)
1818	}
1819
1820	b := lb.(*backend)
1821	connState, err := testConnState("test-fixtures/keys/cert.pem",
1822		"test-fixtures/keys/key.pem", "test-fixtures/root/rootcacert.pem")
1823	if err != nil {
1824		t.Fatalf("error testing connection state: %v", err)
1825	}
1826	ca, err := ioutil.ReadFile("test-fixtures/root/rootcacert.pem")
1827	if err != nil {
1828		t.Fatal(err)
1829	}
1830
1831	req := &logical.Request{
1832		Connection: &logical.Connection{
1833			ConnState: &connState,
1834		},
1835		Storage: storage,
1836		Auth:    &logical.Auth{},
1837	}
1838
1839	fd := &framework.FieldData{
1840		Raw: map[string]interface{}{
1841			"name":        "test",
1842			"certificate": ca,
1843			"policies":    "foo,bar",
1844		},
1845		Schema: pathCerts(b).Fields,
1846	}
1847
1848	resp, err := b.pathCertWrite(context.Background(), req, fd)
1849	if err != nil {
1850		t.Fatal(err)
1851	}
1852
1853	empty_login_fd := &framework.FieldData{
1854		Raw:    map[string]interface{}{},
1855		Schema: pathLogin(b).Fields,
1856	}
1857	resp, err = b.pathLogin(context.Background(), req, empty_login_fd)
1858	if err != nil {
1859		t.Fatal(err)
1860	}
1861	if resp.IsError() {
1862		t.Fatalf("got error: %#v", *resp)
1863	}
1864	req.Auth.InternalData = resp.Auth.InternalData
1865	req.Auth.Metadata = resp.Auth.Metadata
1866	req.Auth.LeaseOptions = resp.Auth.LeaseOptions
1867	req.Auth.Policies = resp.Auth.Policies
1868	req.Auth.TokenPolicies = req.Auth.Policies
1869	req.Auth.Period = resp.Auth.Period
1870
1871	// Normal renewal
1872	resp, err = b.pathLoginRenew(context.Background(), req, empty_login_fd)
1873	if err != nil {
1874		t.Fatal(err)
1875	}
1876	if resp == nil {
1877		t.Fatal("got nil response from renew")
1878	}
1879	if resp.IsError() {
1880		t.Fatalf("got error: %#v", *resp)
1881	}
1882
1883	// Change the policies -- this should fail
1884	fd.Raw["policies"] = "zip,zap"
1885	resp, err = b.pathCertWrite(context.Background(), req, fd)
1886	if err != nil {
1887		t.Fatal(err)
1888	}
1889
1890	resp, err = b.pathLoginRenew(context.Background(), req, empty_login_fd)
1891	if err == nil {
1892		t.Fatal("expected error")
1893	}
1894
1895	// Put the policies back, this should be okay
1896	fd.Raw["policies"] = "bar,foo"
1897	resp, err = b.pathCertWrite(context.Background(), req, fd)
1898	if err != nil {
1899		t.Fatal(err)
1900	}
1901
1902	resp, err = b.pathLoginRenew(context.Background(), req, empty_login_fd)
1903	if err != nil {
1904		t.Fatal(err)
1905	}
1906	if resp == nil {
1907		t.Fatal("got nil response from renew")
1908	}
1909	if resp.IsError() {
1910		t.Fatalf("got error: %#v", *resp)
1911	}
1912
1913	// Add period value to cert entry
1914	period := 350 * time.Second
1915	fd.Raw["period"] = period.String()
1916	resp, err = b.pathCertWrite(context.Background(), req, fd)
1917	if err != nil {
1918		t.Fatal(err)
1919	}
1920
1921	resp, err = b.pathLoginRenew(context.Background(), req, empty_login_fd)
1922	if err != nil {
1923		t.Fatal(err)
1924	}
1925	if resp == nil {
1926		t.Fatal("got nil response from renew")
1927	}
1928	if resp.IsError() {
1929		t.Fatalf("got error: %#v", *resp)
1930	}
1931
1932	if resp.Auth.Period != period {
1933		t.Fatalf("expected a period value of %s in the response, got: %s", period, resp.Auth.Period)
1934	}
1935
1936	// Delete CA, make sure we can't renew
1937	resp, err = b.pathCertDelete(context.Background(), req, fd)
1938	if err != nil {
1939		t.Fatal(err)
1940	}
1941
1942	resp, err = b.pathLoginRenew(context.Background(), req, empty_login_fd)
1943	if err != nil {
1944		t.Fatal(err)
1945	}
1946	if resp == nil {
1947		t.Fatal("got nil response from renew")
1948	}
1949	if !resp.IsError() {
1950		t.Fatal("expected error")
1951	}
1952}
1953
1954func TestBackend_CertUpgrade(t *testing.T) {
1955	s := &logical.InmemStorage{}
1956
1957	config := logical.TestBackendConfig()
1958	config.StorageView = s
1959
1960	ctx := context.Background()
1961
1962	b := Backend()
1963	if b == nil {
1964		t.Fatalf("failed to create backend")
1965	}
1966	if err := b.Setup(ctx, config); err != nil {
1967		t.Fatal(err)
1968	}
1969
1970	foo := &CertEntry{
1971		Policies:   []string{"foo"},
1972		Period:     time.Second,
1973		TTL:        time.Second,
1974		MaxTTL:     time.Second,
1975		BoundCIDRs: []*sockaddr.SockAddrMarshaler{{SockAddr: sockaddr.MustIPAddr("127.0.0.1")}},
1976	}
1977
1978	entry, err := logical.StorageEntryJSON("cert/foo", foo)
1979	if err != nil {
1980		t.Fatal(err)
1981	}
1982	err = s.Put(ctx, entry)
1983	if err != nil {
1984		t.Fatal(err)
1985	}
1986
1987	certEntry, err := b.Cert(ctx, s, "foo")
1988	if err != nil {
1989		t.Fatal(err)
1990	}
1991
1992	exp := &CertEntry{
1993		Policies:   []string{"foo"},
1994		Period:     time.Second,
1995		TTL:        time.Second,
1996		MaxTTL:     time.Second,
1997		BoundCIDRs: []*sockaddr.SockAddrMarshaler{{SockAddr: sockaddr.MustIPAddr("127.0.0.1")}},
1998		TokenParams: tokenutil.TokenParams{
1999			TokenPolicies:   []string{"foo"},
2000			TokenPeriod:     time.Second,
2001			TokenTTL:        time.Second,
2002			TokenMaxTTL:     time.Second,
2003			TokenBoundCIDRs: []*sockaddr.SockAddrMarshaler{{SockAddr: sockaddr.MustIPAddr("127.0.0.1")}},
2004		},
2005	}
2006	if diff := deep.Equal(certEntry, exp); diff != nil {
2007		t.Fatal(diff)
2008	}
2009}
2010