1package cert
2
3import (
4	"crypto/ecdsa"
5	"crypto/ed25519"
6	"crypto/elliptic"
7	"crypto/rand"
8	"crypto/rsa"
9	"crypto/x509"
10	"encoding/asn1"
11	"encoding/pem"
12	"math/big"
13	"time"
14
15	"github.com/v2fly/v2ray-core/v4/common"
16)
17
18//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen
19
20type Certificate struct {
21	// Cerificate in ASN.1 DER format
22	Certificate []byte
23	// Private key in ASN.1 DER format
24	PrivateKey []byte
25}
26
27func ParseCertificate(certPEM []byte, keyPEM []byte) (*Certificate, error) {
28	certBlock, _ := pem.Decode(certPEM)
29	if certBlock == nil {
30		return nil, newError("failed to decode certificate")
31	}
32	keyBlock, _ := pem.Decode(keyPEM)
33	if keyBlock == nil {
34		return nil, newError("failed to decode key")
35	}
36	return &Certificate{
37		Certificate: certBlock.Bytes,
38		PrivateKey:  keyBlock.Bytes,
39	}, nil
40}
41
42func (c *Certificate) ToPEM() ([]byte, []byte) {
43	return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: c.Certificate}),
44		pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: c.PrivateKey})
45}
46
47type Option func(*x509.Certificate)
48
49func Authority(isCA bool) Option {
50	return func(cert *x509.Certificate) {
51		cert.IsCA = isCA
52	}
53}
54
55func NotBefore(t time.Time) Option {
56	return func(c *x509.Certificate) {
57		c.NotBefore = t
58	}
59}
60
61func NotAfter(t time.Time) Option {
62	return func(c *x509.Certificate) {
63		c.NotAfter = t
64	}
65}
66
67func DNSNames(names ...string) Option {
68	return func(c *x509.Certificate) {
69		c.DNSNames = names
70	}
71}
72
73func CommonName(name string) Option {
74	return func(c *x509.Certificate) {
75		c.Subject.CommonName = name
76	}
77}
78
79func KeyUsage(usage x509.KeyUsage) Option {
80	return func(c *x509.Certificate) {
81		c.KeyUsage = usage
82	}
83}
84
85func Organization(org string) Option {
86	return func(c *x509.Certificate) {
87		c.Subject.Organization = []string{org}
88	}
89}
90
91func MustGenerate(parent *Certificate, opts ...Option) *Certificate {
92	cert, err := Generate(parent, opts...)
93	common.Must(err)
94	return cert
95}
96
97func publicKey(priv interface{}) interface{} {
98	switch k := priv.(type) {
99	case *rsa.PrivateKey:
100		return &k.PublicKey
101	case *ecdsa.PrivateKey:
102		return &k.PublicKey
103	case ed25519.PrivateKey:
104		return k.Public().(ed25519.PublicKey)
105	default:
106		return nil
107	}
108}
109
110func Generate(parent *Certificate, opts ...Option) (*Certificate, error) {
111	var (
112		pKey      interface{}
113		parentKey interface{}
114		err       error
115	)
116	// higher signing performance than RSA2048
117	selfKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
118	if err != nil {
119		return nil, newError("failed to generate self private key").Base(err)
120	}
121	parentKey = selfKey
122	if parent != nil {
123		if _, e := asn1.Unmarshal(parent.PrivateKey, &ecPrivateKey{}); e == nil {
124			pKey, err = x509.ParseECPrivateKey(parent.PrivateKey)
125		} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs8{}); e == nil {
126			pKey, err = x509.ParsePKCS8PrivateKey(parent.PrivateKey)
127		} else if _, e := asn1.Unmarshal(parent.PrivateKey, &pkcs1PrivateKey{}); e == nil {
128			pKey, err = x509.ParsePKCS1PrivateKey(parent.PrivateKey)
129		}
130		if err != nil {
131			return nil, newError("failed to parse parent private key").Base(err)
132		}
133		parentKey = pKey
134	}
135
136	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
137	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
138	if err != nil {
139		return nil, newError("failed to generate serial number").Base(err)
140	}
141
142	template := &x509.Certificate{
143		SerialNumber:          serialNumber,
144		NotBefore:             time.Now().Add(time.Hour * -1),
145		NotAfter:              time.Now().Add(time.Hour),
146		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
147		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
148		BasicConstraintsValid: true,
149	}
150
151	for _, opt := range opts {
152		opt(template)
153	}
154
155	parentCert := template
156	if parent != nil {
157		pCert, err := x509.ParseCertificate(parent.Certificate)
158		if err != nil {
159			return nil, newError("failed to parse parent certificate").Base(err)
160		}
161		parentCert = pCert
162	}
163
164	derBytes, err := x509.CreateCertificate(rand.Reader, template, parentCert, publicKey(selfKey), parentKey)
165	if err != nil {
166		return nil, newError("failed to create certificate").Base(err)
167	}
168
169	privateKey, err := x509.MarshalPKCS8PrivateKey(selfKey)
170	if err != nil {
171		return nil, newError("Unable to marshal private key").Base(err)
172	}
173
174	return &Certificate{
175		Certificate: derBytes,
176		PrivateKey:  privateKey,
177	}, nil
178}
179