forked from vizidrix/goio
-
Notifications
You must be signed in to change notification settings - Fork 0
/
gocert.go
129 lines (115 loc) · 3.41 KB
/
gocert.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package goio
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"net"
"os"
"time"
)
type Cert struct {
privateKey *rsa.PrivateKey
data []byte
}
type CertDefinition struct {
Organization string
Size int
Hosts []string
LifeSpan time.Duration
IsCA bool
}
func intInSlice(value int, list []int) bool {
for _, v := range list {
if v == value {
return true
}
}
return false
}
func NewCertDefinition(organization string, size int, hosts []string, lifespan time.Duration, isCA bool) (*CertDefinition, error) {
if organization == "" {
return nil, errors.New("Invalid RSA organization")
}
validSizes := []int{512, 1024, 2048, 3072, 7680, 15360}
if !intInSlice(size, validSizes) {
return nil, errors.New("Invalid RSA key size")
}
return &CertDefinition{
organization,
size,
hosts,
lifespan,
isCA,
}, nil
}
func MakeCert(organization string, size int, hosts []string, lifespan time.Duration, isCA bool) (*Cert, error) {
var err error
var cert Cert
if cert.privateKey, err = rsa.GenerateKey(rand.Reader, size); err != nil {
return nil, errors.New(fmt.Sprintf("Unable to generate key [%s]\n", err))
}
// Setup certificate expiration
notBefore := time.Now()
notAfter := notBefore.Add(lifespan)
// Setup certificate configuration
template := x509.Certificate{
SerialNumber: new(big.Int).SetInt64(0),
Subject: pkix.Name{
Organization: []string{organization},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
// Separate valid IP addresses from the named hosts provided
for _, host := range hosts {
if ip := net.ParseIP(host); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, host)
}
}
// Append usage for Cert Signing if CA is specified
if isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
// Make certificate blob
if cert.data, err = x509.CreateCertificate(rand.Reader, &template, &template, &cert.privateKey.PublicKey, cert.privateKey); err != nil {
return nil, errors.New(fmt.Sprintf("Unable to create certificate [%s]\n", err))
}
return &cert, nil
}
//"certs/private.pem"
func (cert *Cert) WritePrivate(file string) error {
var target *os.File
var err error
if target, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
return errors.New(fmt.Sprintf("Unable to create private cert file [%s]\n", err))
}
defer target.Close()
if err := pem.Encode(target, &pem.Block{Type: "CERTIFICATE", Bytes: cert.data}); err != nil {
return errors.New(fmt.Sprintf("Unable to encode private cert [%s]\n", err))
}
return nil
}
//"certs/public.pem"
func (cert *Cert) WritePublic(file string) error {
var target *os.File
var err error
if target, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
return errors.New(fmt.Sprintf("Unable to create public cert file [%s]\n", err))
}
defer target.Close()
if err = pem.Encode(target, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(cert.privateKey)}); err != nil {
return errors.New(fmt.Sprintf("Unable to encode public cert [%s]\n", err))
}
return nil
}