-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathbash.go
251 lines (207 loc) · 6.17 KB
/
bash.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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//go:build bashpki
// A reference implementation for those who want to customize their PKI.
// This is turned off in vanilla Fioctl builds, and can be enabled in a fork.
package x509
import (
"os"
"os/exec"
"github.com/foundriesio/fioctl/subcommands"
)
type KeyStorage interface {
configure()
}
func (s *fileStorage) configure() {}
func (s *hsmStorage) configure() {
os.Setenv("HSM_MODULE", s.Module)
os.Setenv("HSM_PIN", s.Pin)
os.Setenv("HSM_TOKEN_LABEL", s.TokenLabel)
}
func run(script string, arg ...string) string {
factoryCaKeyStorage.configure()
arg = append([]string{"-s"}, arg...)
cmd := exec.Command("/bin/sh", arg...)
cmd.Stderr = os.Stderr
in, err := cmd.StdinPipe()
subcommands.DieNotNil(err, "Failed to start the shell")
go func() {
defer in.Close()
_, err := in.Write([]byte(script))
subcommands.DieNotNil(err, "Failed to pass the script to the shell")
}()
out, err := cmd.Output()
subcommands.DieNotNil(err, "Failed to execute the shell script")
return string(out)
}
func CreateFactoryCa(ou string) string {
const script = `#!/bin/sh -e
## This script creates the offline private key, factory_ca.key, and x509 certficate, factory_ca.pem,
## owned by the customer that provides a chain of trust for all other certficates used by this factory.
if [ $# -ne 1 ] ; then
echo "ERROR: $0 <ou>"
exit 1
fi
ou=$1
cat >ca.cnf <<EOF
[req]
prompt = no
distinguished_name = dn
x509_extensions = ext
[dn]
CN = Factory-CA
OU = ${ou}
[ext]
basicConstraints=CA:TRUE
keyUsage = keyCertSign, cRLSign
extendedKeyUsage = critical, clientAuth, serverAuth
EOF
if [ -n "$HSM_MODULE" ] ; then
lbl=${HSM_TOKEN_LABEL-device-gateway-root}
pkcs11-tool --module $HSM_MODULE \
--keypairgen --key-type EC:prime256v1 \
--token-label $lbl \
--id 01 \
--label root-ca \
--pin $HSM_PIN
key="pkcs11:token=${lbl};object=root-ca;type=private;pin-value=$HSM_PIN"
extra="-engine pkcs11 -keyform engine"
else
openssl ecparam -genkey -name prime256v1 | openssl ec -out factory_ca.key
key=factory_ca.key
chmod 400 $key
fi
openssl req $extra -new -x509 -days 7300 -config ca.cnf -key "$key" -out factory_ca.pem -sha256
chmod 400 factory_ca.pem
rm ca.cnf
`
run(script, ou)
return readFile(FactoryCaCertFile)
}
func CreateDeviceCa(cn, ou string) string {
return CreateDeviceCaExt(cn, ou, DeviceCaKeyFile, DeviceCaCertFile)
}
func CreateDeviceCaExt(cn, ou, keyFile, certFile string) string {
const script = `#!/bin/sh -e
## This is an optional script a customer can use to create a certificate
## capable of signing a certicate signing request from an LMP device.
## The certicate created here will be trusted by the Foundries device gateway.
## This is useful for creating CA owned by the customer for use in a manufacturing facility.
if [ $# -ne 3 ] ; then
echo "ERROR: $0 <key-create> <cn> <ou>"
exit 1
fi
key=$1
cn=$2
ou=$3
cat >ca.cnf <<EOF
[req]
prompt = no
distinguished_name = dn
x509_extensions = ext
[dn]
CN = ${cn}
OU = ${ou}
[ext]
keyUsage=critical, keyCertSign
basicConstraints=critical, CA:TRUE, pathlen:0
EOF
openssl ecparam -genkey -name prime256v1 | openssl ec -out $key
openssl req -new -config ca.cnf -key $key
chmod 400 $key
rm ca.cnf`
csrPem := run(script, keyFile, cn, ou)
crtPem := signCaCsr("device-ca-*", csrPem)
writeFile(certFile, crtPem)
return crtPem
}
func SignTlsCsr(csrPem string) string {
crtPem := signTlsCsr("tls-*", csrPem)
writeFile(TlsCertFile, crtPem)
return crtPem
}
func SignEstCsr(csrPem string) string {
return signTlsCsr("est-*", csrPem)
}
func SignCaCsr(csrPem string) string {
crtPem := signCaCsr("online-ca-*", csrPem)
writeFile(OnlineCaCertFile, crtPem)
return crtPem
}
func SignEl2GoCsr(csrPem string) string {
return signCaCsr("el2g-*", csrPem)
}
func CreateCrl(serials map[string]int) string {
if true {
panic("This function is not implemented in Bash implementation")
}
return "Neverland"
}
func signTlsCsr(tmpFileMask, csrPem string) string {
const script = `#!/bin/sh -e
## This script signs the "tls-csr" returned when creating Factory certificates.
## This certificate are signed so that the devices trust the TLS connection with the Foundries device gateway.
if [ $# -ne 2 ] ; then
echo "ERROR: $0 <tls csr> <tls crt>"
exit 1
fi
csr=$1
crt=$2
dns=$(openssl req -text -noout -verify -in $csr | grep DNS:)
echo "signing with dns name: $dns" 1>&2
cat >server.ext <<EOF
keyUsage=critical, digitalSignature
extendedKeyUsage=critical, serverAuth
subjectAltName=$dns
EOF
if [ -n "$HSM_MODULE" ] ; then
lbl=${HSM_TOKEN_LABEL-device-gateway-root}
key="pkcs11:token=${lbl};object=root-ca;type=private;pin-value=$HSM_PIN"
extra="-CAkeyform engine -engine pkcs11"
else
key=factory_ca.key
fi
openssl x509 -req -days 3650 $extra -in $csr -CAcreateserial \
-extfile server.ext -CAkey "$key" -CA factory_ca.pem -sha256 -out $crt
rm server.ext factory_ca.srl || true`
return signCsr(script, tmpFileMask, csrPem)
}
func signCaCsr(tmpFileMask, csrPem string) string {
const script = `#!/bin/sh -e
## This script signs "device ca" signing requests.
## The request may come from either the Factory (so that lmp-device-register will work)
## or locally with "create_device_ca" for manufacturing style device creation.
if [ $# -ne 2 ] ; then
echo "ERROR: $0 <ca csr> <ca crt>"
exit 1
fi
csr=$1
crt=$2
cat >ca.ext <<EOF
keyUsage=critical, keyCertSign
basicConstraints=critical, CA:TRUE, pathlen:0
EOF
if [ -n "$HSM_MODULE" ] ; then
lbl=${HSM_TOKEN_LABEL-device-gateway-root}
key="pkcs11:token=${lbl};object=root-ca;type=private;pin-value=$HSM_PIN"
extra="-CAkeyform engine -engine pkcs11"
else
key=factory_ca.key
fi
openssl x509 -req -days 3650 $extra -in $csr -CAcreateserial \
-extfile ca.ext -CAkey "$key" -CA factory_ca.pem -sha256 -out $crt
rm ca.ext`
return signCsr(script, tmpFileMask, csrPem)
}
func signCsr(script, tmpFileMask, csrPem string) string {
csrFile, err := os.CreateTemp("", tmpFileMask+".csr")
subcommands.DieNotNil(err)
defer os.Remove(csrFile.Name())
defer csrFile.Close()
_, err = csrFile.Write([]byte(csrPem))
subcommands.DieNotNil(err)
crtFile, err := os.CreateTemp("", tmpFileMask+".crt")
subcommands.DieNotNil(err)
defer os.Remove(crtFile.Name())
defer crtFile.Close()
run(script, csrFile.Name(), crtFile.Name())
return readFile(crtFile.Name())
}