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