/
certs.go
106 lines (91 loc) · 2.92 KB
/
certs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package certs
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"log"
"math/big"
"net"
"time"
)
// ref: https://ericchiang.github.io/post/go-tls/
// CertTemplate is a helper function to create a cert template with a serial number and other required fields
func CertTemplate() (*x509.Certificate, error) {
// generate a random serial number (a real cert authority would have some logic behind this)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
log.Println("failed to generate serial number: ", err)
return nil, errors.New("failed to generate serial number: " + err.Error())
}
tmpl := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{Organization: []string{"Yhat, Inc."}},
SignatureAlgorithm: x509.SHA256WithRSA,
NotBefore: time.Now(),
NotAfter: time.Now().Add(time.Hour), // valid for an hour
BasicConstraintsValid: true,
}
return &tmpl, nil
}
func createCert(template, parent *x509.Certificate, pub interface{}, parentPriv interface{}) (
cert *x509.Certificate, certpem []byte, err error) {
certDER, err := x509.CreateCertificate(rand.Reader, template, parent, pub, parentPriv)
if err != nil {
log.Println(err)
return
}
// parse the resulting certificate so we can use it again
cert, err = x509.ParseCertificate(certDER)
if err != nil {
log.Println(err)
return
}
// PEM encode the certificate (this is a standard TLS encoding)
b := pem.Block{Type: "CERTIFICATE", Bytes: certDER}
certpem = pem.EncodeToMemory(&b)
return
}
// GenCert generates a new certificate
func GenCert() (string, string, tls.Certificate, error) {
// generate a new key-pair
var keypem []byte
var tlscert tls.Certificate
certTemplate, err := CertTemplate()
if err != nil {
log.Println(err)
return "", "", tlscert, err
}
key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
log.Println(err)
return "", "", tlscert, err
}
certTemplate.KeyUsage = x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature
certTemplate.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}
certTemplate.IPAddresses = []net.IP{net.ParseIP("127.0.0.1")}
cert, certpem, err := createCert(certTemplate, certTemplate, &key.PublicKey, key)
if err != nil {
log.Println(err)
return "", "", tlscert, err
}
log.Printf("%s\n", certpem)
log.Printf("%#x\n", cert.Signature)
// PEM encode the private key
keypem = pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key),
})
// Create a TLS cert using the private key and certificate
tlscert, err = tls.X509KeyPair(certpem, keypem)
if err != nil {
log.Println(err)
return "", "", tlscert, err
}
certString := fmt.Sprintf("%s", certpem)
return string(keypem), certString, tlscert, nil
}