forked from google/easypki
/
client-auth.go
155 lines (148 loc) · 4.41 KB
/
client-auth.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package main
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"flag"
"io/ioutil"
"log"
"os"
"time"
"github.com/boltdb/bolt"
"github.com/brimworks/easypki/pkg/certificate"
"github.com/brimworks/easypki/pkg/easypki"
"github.com/brimworks/easypki/pkg/store"
"github.com/go-yaml/yaml"
)
func main() {
var (
caName = flag.String("ca_name", "", "Name of the CA which signed the bundle.")
bundleName = flag.String("bundle_name", "", "Name of the bundle to retrieve.")
fullChain = flag.Bool("full_chain", true, "Include chain of trust in certificate output.")
dbPath = flag.String("db_path", "", "Bolt database path.")
configPath = flag.String("config_path", "", "Configuration path to generate PKI.")
)
flag.Parse()
if *dbPath == "" {
log.Fatal("Arg db_path must be set.")
}
if *bundleName == "" && *configPath == "" {
log.Fatal("One of bundle_name or config_path must be set.")
}
db, err := bolt.Open(*dbPath, 0600, nil)
if err != nil {
log.Fatalf("Failed opening bolt database %v: %v", *dbPath, err)
}
defer db.Close()
pki := &easypki.EasyPKI{Store: &store.Bolt{DB: db}}
if *bundleName != "" {
get(pki, *caName, *bundleName, *fullChain)
return
}
build(pki, *configPath)
}
// build create a full PKI based on a yaml configuration.
func build(pki *easypki.EasyPKI, configPath string) {
type configCerts struct {
Name string `yaml:"name"`
CommonName string `yaml:"commonName"`
DNSNames []string `yaml:"dnsNames"`
EmailAddresses []string `yaml:"emailAddresses"`
IsCA bool `yaml:"isCA"`
IsClient bool `yaml:"isClient"`
Signer string `yaml:"signer"`
Expire time.Duration `yaml:"expire"`
}
type config struct {
Subject pkix.Name `yaml:"subject"`
Certs []configCerts `yaml:"certs"`
}
b, err := ioutil.ReadFile(configPath)
if err != nil {
log.Fatalf("Failed reading configuration file %v: %v", configPath, err)
}
conf := &config{}
if err := yaml.Unmarshal(b, conf); err != nil {
log.Fatalf("Failed umarshaling yaml config (%v) %v: %v", configPath, string(b), err)
}
for _, cert := range conf.Certs {
req := &easypki.Request{
Name: cert.Name,
Template: &x509.Certificate{
Subject: conf.Subject,
NotAfter: time.Now().Add(cert.Expire),
IsCA: cert.IsCA,
DNSNames: cert.DNSNames,
EmailAddresses: cert.EmailAddresses,
},
IsClientCertificate: cert.IsClient,
}
if cert.IsCA {
req.Template.MaxPathLen = -1
}
req.Template.Subject.CommonName = cert.CommonName
var signer *certificate.Bundle
if cert.Signer != "" {
signer, err = pki.GetCA(cert.Signer)
if err != nil {
log.Fatalf("Cannot sign %v because cannot get CA %v: %v", cert.Name, cert.Signer, err)
}
}
if err := pki.Sign(signer, req); err != nil {
log.Fatalf("Cannot create bundle for %v: %v", cert.Name, err)
}
}
}
// get retrieves a bundle from the bolt database. If fullChain is true, the
// certificate will be the chain of trust from the primary tup to root CA.
func get(pki *easypki.EasyPKI, caName, bundleName string, fullChain bool) {
var bundle *certificate.Bundle
if caName == "" {
caName = bundleName
}
bundle, err := pki.GetBundle(caName, bundleName)
if err != nil {
log.Fatalf("Failed getting bundle %v within CA %v: %v", bundleName, caName, err)
}
leaf := bundle
chain := []*certificate.Bundle{bundle}
if fullChain {
for {
if leaf.Cert.Issuer.CommonName == leaf.Cert.Subject.CommonName {
break
}
ca, err := pki.GetCA(leaf.Cert.Issuer.CommonName)
if err != nil {
log.Fatalf("Failed getting signing CA %v: %v", leaf.Cert.Issuer.CommonName, err)
}
chain = append(chain, ca)
leaf = ca
}
}
key, err := os.Create(bundleName + ".key")
if err != nil {
log.Fatalf("Failed creating key output file: %v", err)
}
if err := pem.Encode(key, &pem.Block{
Bytes: x509.MarshalPKCS1PrivateKey(bundle.Key),
Type: "RSA PRIVATE KEY",
}); err != nil {
log.Fatalf("Failed ecoding private key: %v", err)
}
crtName := bundleName + ".crt"
if fullChain {
crtName = bundleName + "+chain.crt"
}
cert, err := os.Create(crtName)
if err != nil {
log.Fatalf("Failed creating chain output file: %v", err)
}
for _, c := range chain {
if err := pem.Encode(cert, &pem.Block{
Bytes: c.Cert.Raw,
Type: "CERTIFICATE",
}); err != nil {
log.Fatalf("Failed ecoding %v certificate: %v", c.Name, err)
}
}
}