1package plugin
2
3import (
4	"bytes"
5	"crypto/ecdsa"
6	"crypto/elliptic"
7	"crypto/rand"
8	"crypto/x509"
9	"crypto/x509/pkix"
10	"encoding/pem"
11	"math/big"
12	"time"
13)
14
15// generateCert generates a temporary certificate for plugin authentication. The
16// certificate and private key are returns in PEM format.
17func generateCert() (cert []byte, privateKey []byte, err error) {
18	key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
19	if err != nil {
20		return nil, nil, err
21	}
22
23	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
24	sn, err := rand.Int(rand.Reader, serialNumberLimit)
25	if err != nil {
26		return nil, nil, err
27	}
28
29	host := "localhost"
30
31	template := &x509.Certificate{
32		Subject: pkix.Name{
33			CommonName:   host,
34			Organization: []string{"HashiCorp"},
35		},
36		DNSNames: []string{host},
37		ExtKeyUsage: []x509.ExtKeyUsage{
38			x509.ExtKeyUsageClientAuth,
39			x509.ExtKeyUsageServerAuth,
40		},
41		KeyUsage:              x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign,
42		BasicConstraintsValid: true,
43		SerialNumber:          sn,
44		NotBefore:             time.Now().Add(-30 * time.Second),
45		NotAfter:              time.Now().Add(262980 * time.Hour),
46		IsCA:                  true,
47	}
48
49	der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
50	if err != nil {
51		return nil, nil, err
52	}
53
54	var certOut bytes.Buffer
55	if err := pem.Encode(&certOut, &pem.Block{Type: "CERTIFICATE", Bytes: der}); err != nil {
56		return nil, nil, err
57	}
58
59	keyBytes, err := x509.MarshalECPrivateKey(key)
60	if err != nil {
61		return nil, nil, err
62	}
63
64	var keyOut bytes.Buffer
65	if err := pem.Encode(&keyOut, &pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes}); err != nil {
66		return nil, nil, err
67	}
68
69	cert = certOut.Bytes()
70	privateKey = keyOut.Bytes()
71
72	return cert, privateKey, nil
73}
74