Skip to content

Commit c83127e

Browse files
authored
Merge pull request #20 from EventStore/kunaldhingra/db-149-generate-fips-compliant-certificates-in-our-tools
Update default crypto to boringcrypto to generate FIPS compliant certificates
2 parents a0c75d5 + 51851f0 commit c83127e

14 files changed

+209
-25
lines changed

Diff for: .github/workflows/ci.yml

+12-3
Original file line numberDiff line numberDiff line change
@@ -21,25 +21,34 @@ jobs:
2121
name: Set up Go
2222
uses: actions/setup-go@v3
2323
with:
24-
go-version: 1.18
24+
go-version: 1.21
25+
env:
26+
GOEXPERIMENT: boringcrypto
27+
-
28+
name: Run Tests
29+
env:
30+
GOEXPERIMENT: boringcrypto
31+
run: go test ./...
2532
-
2633
name: Build and Publish
2734
uses: goreleaser/goreleaser-action@v3
2835
if: ${{ startsWith(github.ref, 'refs/tags/') }}
2936
with:
3037
version: latest
31-
args: release --rm-dist
38+
args: release --clean
3239
env:
3340
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
41+
GOEXPERIMENT: boringcrypto
3442
-
3543
name: Build and Publish (Dry Run)
3644
uses: goreleaser/goreleaser-action@v3
3745
if: ${{ !startsWith(github.ref, 'refs/tags/') }}
3846
with:
3947
version: latest
40-
args: release --skip-publish --rm-dist --snapshot
48+
args: release --skip-publish --clean --snapshot
4149
env:
4250
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51+
GOEXPERIMENT: boringcrypto
4352
-
4453
name: Docker meta
4554
id: meta

Diff for: .goreleaser.yml

+8-7
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,14 @@ archives:
2222
format_overrides:
2323
- goos: windows
2424
format: zip
25-
name_template: "{{.ProjectName}}_{{.Version}}_{{.Os}}-{{.Arch}}"
26-
replacements:
27-
darwin: Darwin
28-
linux: Linux
29-
windows: Windows
30-
386: i386
31-
amd64: x86_64
25+
name_template: >-
26+
{{- .ProjectName }}_
27+
{{- .Version }}_
28+
{{- title .Os }}_
29+
{{- if eq .Arch "amd64" }}x86_64
30+
{{- else if eq .Arch "386" }}i386
31+
{{- else }}{{ .Arch }}{{ end }}
32+
{{- if .Arm }}v{{ .Arm }}{{ end -}}
3233
changelog:
3334
sort: asc
3435
filters:

Diff for: Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.14-alpine AS build_base
1+
FROM golang:1.21-alpine AS build_base
22

33
RUN apk add --no-cache git
44

@@ -11,7 +11,7 @@ RUN go mod download
1111

1212
COPY . .
1313

14-
RUN go build -o ./out/es-gencert-cli .
14+
RUN GOEXPERIMENT=boringcrypto go build -o ./out/es-gencert-cli .
1515

1616
FROM alpine:3.9
1717
RUN apk add ca-certificates bash

Diff for: certificates/boring_darwin.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build darwin
2+
3+
package certificates
4+
5+
// Currently boringcryptography is only supported on Linux
6+
func isBoringEnabled() bool {
7+
return false
8+
}

Diff for: certificates/boring_linux.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build linux
2+
3+
package certificates
4+
5+
import (
6+
"crypto/boring"
7+
)
8+
9+
func isBoringEnabled() bool {
10+
return boring.Enabled()
11+
}

Diff for: certificates/boring_windows.go

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//go:build windows
2+
3+
package certificates
4+
5+
// Currently boringcryptography is only supported on Linux
6+
func isBoringEnabled() bool {
7+
return false
8+
}

Diff for: certificates/common_test.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build linux
2+
3+
package certificates
4+
5+
import (
6+
"crypto/boring"
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestBoringCryptoAvailable(t *testing.T) {
13+
assert.True(t, boring.Enabled())
14+
}

Diff for: certificates/create_ca.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"errors"
1111
"flag"
1212
"fmt"
13-
"io/ioutil"
1413
"os"
1514
"path"
1615
"strings"
@@ -93,7 +92,11 @@ func (c *CreateCA) Run(args []string) int {
9392
if err != nil {
9493
c.Ui.Error(err.Error())
9594
} else {
96-
c.Ui.Output(fmt.Sprintf("A CA certificate & key file have been generated in the '%s' directory", outputDir))
95+
if isBoringEnabled() {
96+
c.Ui.Output(fmt.Sprintf("A CA certificate & key file have been generated in the '%s' directory (FIPS mode enabled).", outputDir))
97+
} else {
98+
c.Ui.Output(fmt.Sprintf("A CA certificate & key file have been generated in the '%s' directory.", outputDir))
99+
}
97100
}
98101
return 0
99102
}
@@ -146,7 +149,7 @@ func generateCACertificate(years int, days int, outputDir string, caCert *x509.C
146149
}
147150

148151
privateKeyPem := new(bytes.Buffer)
149-
pem.Encode(privateKeyPem, &pem.Block{
152+
err = pem.Encode(privateKeyPem, &pem.Block{
150153
Type: "RSA PRIVATE KEY",
151154
Bytes: x509.MarshalPKCS1PrivateKey(privateKey),
152155
})
@@ -179,13 +182,13 @@ func generateCACertificate(years int, days int, outputDir string, caCert *x509.C
179182
}
180183

181184
certFile := "ca.crt"
182-
err = ioutil.WriteFile(path.Join(outputDir, certFile), certPem.Bytes(), 0444)
185+
err = os.WriteFile(path.Join(outputDir, certFile), certPem.Bytes(), 0444)
183186
if err != nil {
184187
return fmt.Errorf("error writing CA certificate to %s: %s", certFile, err.Error())
185188
}
186189

187190
keyFile := "ca.key"
188-
err = ioutil.WriteFile(path.Join(outputDir, keyFile), privateKeyPem.Bytes(), 0400)
191+
err = os.WriteFile(path.Join(outputDir, keyFile), privateKeyPem.Bytes(), 0400)
189192
if err != nil {
190193
return fmt.Errorf("error writing CA's private key to %s: %s", keyFile, err.Error())
191194
}

Diff for: certificates/create_ca_test.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package certificates
2+
3+
import (
4+
"crypto/rsa"
5+
"crypto/x509"
6+
"os"
7+
"path"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestGenerateCACertificate(t *testing.T) {
14+
15+
t.Run("nominal-case", func(t *testing.T) {
16+
years := 1
17+
days := 0
18+
outputDir := "./ca"
19+
var caCert *x509.Certificate
20+
var caKey *rsa.PrivateKey
21+
22+
// Clean up from previous runs
23+
os.RemoveAll(outputDir)
24+
25+
certificateError := generateCACertificate(years, days, outputDir, caCert, caKey)
26+
27+
certFilePath := path.Join(outputDir, "ca.crt")
28+
keyFilePath := path.Join(outputDir, "ca.key")
29+
30+
_, certPathError := os.Stat(certFilePath)
31+
_, keyPathError := os.Stat(keyFilePath)
32+
33+
assert.NoError(t, certificateError)
34+
assert.False(t, os.IsNotExist(certPathError))
35+
assert.False(t, os.IsNotExist(keyPathError))
36+
37+
// Clean up
38+
os.RemoveAll(outputDir)
39+
40+
})
41+
42+
}

Diff for: certificates/create_certs.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"fmt"
66
"github.com/mitchellh/cli"
77
"gopkg.in/yaml.v3"
8-
"io/ioutil"
8+
"os"
99
"reflect"
1010
"strings"
1111
)
@@ -33,7 +33,7 @@ func (c *CreateCertificates) Run(args []string) int {
3333
if err := flags.Parse(args); err != nil {
3434
return 1
3535
}
36-
configData, err := ioutil.ReadFile(arguments.ConfigPath)
36+
configData, err := os.ReadFile(arguments.ConfigPath)
3737
if err != nil {
3838
c.Ui.Error(err.Error())
3939
return 1

Diff for: certificates/create_node.go

+10-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"errors"
1111
"flag"
1212
"fmt"
13-
"io/ioutil"
1413
"net"
1514
"os"
1615
"path"
@@ -37,7 +36,7 @@ type CreateNodeArguments struct {
3736
}
3837

3938
func readCertificateFromFile(path string) (*x509.Certificate, error) {
40-
pemBytes, err := ioutil.ReadFile(path)
39+
pemBytes, err := os.ReadFile(path)
4140
if err != nil {
4241
return nil, fmt.Errorf("error reading file: %s", err.Error())
4342
}
@@ -55,7 +54,7 @@ func readCertificateFromFile(path string) (*x509.Certificate, error) {
5554
}
5655

5756
func readRSAKeyFromFile(path string) (*rsa.PrivateKey, error) {
58-
keyBytes, err := ioutil.ReadFile(path)
57+
keyBytes, err := os.ReadFile(path)
5958
if err != nil {
6059
return nil, fmt.Errorf("error reading file: %s", err.Error())
6160
}
@@ -198,7 +197,12 @@ func (c *CreateNode) Run(args []string) int {
198197
return 1
199198
}
200199

201-
c.Ui.Output(fmt.Sprintf("A node certificate & key file have been generated in the '%s' directory.", outputDir))
200+
if isBoringEnabled() {
201+
c.Ui.Output(fmt.Sprintf("A node certificate & key file have been generated in the '%s' directory (FIPS mode enabled).", outputDir))
202+
} else {
203+
c.Ui.Output(fmt.Sprintf("A node certificate & key file have been generated in the '%s' directory.", outputDir))
204+
}
205+
202206
return 0
203207
}
204208

@@ -267,13 +271,13 @@ func generateNodeCertificate(caCert *x509.Certificate, caPrivateKey *rsa.Private
267271
}
268272

269273
certFile := fmt.Sprintf("%s.crt", outputBaseFileName)
270-
err = ioutil.WriteFile(path.Join(outputDir, certFile), certPem.Bytes(), 0444)
274+
err = os.WriteFile(path.Join(outputDir, certFile), certPem.Bytes(), 0444)
271275
if err != nil {
272276
return fmt.Errorf("error writing certificate to %s: %s", certFile, err.Error())
273277
}
274278

275279
keyFile := fmt.Sprintf("%s.key", outputBaseFileName)
276-
err = ioutil.WriteFile(path.Join(outputDir, keyFile), privateKeyPem.Bytes(), 0400)
280+
err = os.WriteFile(path.Join(outputDir, keyFile), privateKeyPem.Bytes(), 0400)
277281
if err != nil {
278282
return fmt.Errorf("error writing private key to %s: %s", keyFile, err.Error())
279283
}

Diff for: certificates/create_node_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package certificates
2+
3+
import (
4+
"crypto/rsa"
5+
"crypto/x509"
6+
"os"
7+
"path"
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestGenerateNodeCertificate(t *testing.T) {
14+
15+
t.Run("nominal-case", func(t *testing.T) {
16+
17+
years := 1
18+
days := 0
19+
outputDirCA := "./ca"
20+
outputDirNode := "./node"
21+
var caCert *x509.Certificate
22+
var caKey *rsa.PrivateKey
23+
var nodeCertFileName = "node"
24+
var ipAddresses = "127.0.0.1"
25+
var dnsNames = []string{"localhost"}
26+
var commonName = "EventStoreDB"
27+
28+
// Clean up from previous runs
29+
os.RemoveAll(outputDirCA)
30+
os.RemoveAll(outputDirNode)
31+
32+
certificateError := generateCACertificate(years, days, outputDirCA, caCert, caKey)
33+
34+
certFilePath := path.Join(outputDirCA, "ca.crt")
35+
keyFilePath := path.Join(outputDirCA, "ca.key")
36+
37+
_, certPathError := os.Stat(certFilePath)
38+
_, keyPathError := os.Stat(keyFilePath)
39+
40+
assert.NoError(t, certificateError)
41+
assert.False(t, os.IsNotExist(certPathError))
42+
assert.False(t, os.IsNotExist(keyPathError))
43+
44+
caCertificate, err := readCertificateFromFile(certFilePath)
45+
assert.NoError(t, err)
46+
caPrivateKey, err := readRSAKeyFromFile(keyFilePath)
47+
assert.NoError(t, err)
48+
49+
ips, err := parseIPAddresses(ipAddresses)
50+
assert.NoError(t, err)
51+
52+
certificateError = generateNodeCertificate(caCertificate, caPrivateKey, ips, dnsNames, years, days, outputDirNode, nodeCertFileName, commonName)
53+
54+
nodeCertPath := path.Join(outputDirNode, "node.crt")
55+
nodeKeyPath := path.Join(outputDirNode, "node.key")
56+
57+
_, nodeCertPathError := os.Stat(nodeCertPath)
58+
_, nodeKeyPathError := os.Stat(nodeKeyPath)
59+
60+
assert.NoError(t, certificateError)
61+
assert.False(t, os.IsNotExist(nodeCertPathError))
62+
assert.False(t, os.IsNotExist(nodeKeyPathError))
63+
64+
// Clean up
65+
os.RemoveAll(outputDirCA)
66+
os.RemoveAll(outputDirNode)
67+
68+
})
69+
}

Diff for: go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ go 1.14
55
require (
66
github.com/hashicorp/go-multierror v1.0.0
77
github.com/mitchellh/cli v1.1.1
8+
github.com/stretchr/testify v1.8.4 // indirect
89
gopkg.in/yaml.v3 v3.0.1 // indirect
910
)

Diff for: go.sum

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26
22
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
33
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
44
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
5+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
7+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
58
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
69
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
710
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -14,10 +17,21 @@ github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI
1417
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
1518
github.com/mitchellh/cli v1.1.1 h1:J64v/xD7Clql+JVKSvkYojLOXu1ibnY9ZjGLwSt/89w=
1619
github.com/mitchellh/cli v1.1.1/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
20+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
21+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1722
github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w=
1823
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
24+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
25+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
26+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
27+
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
28+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
29+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
30+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
31+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
1932
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc h1:MeuS1UDyZyFH++6vVy44PuufTeFF0d0nfI6XB87YGSk=
2033
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
2134
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
35+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
2236
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2337
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

0 commit comments

Comments
 (0)