Skip to content

Commit

Permalink
add internal/fips package for FIPS 140 support
Browse files Browse the repository at this point in the history
This commit adds a `internal/fips` package.
Now, the KES server / CLI can be built using
the Go BoringCrypto FIPS 140 module. This module
is only available on linux/amd64.

In FIPS mode, a KES server will only used NIST/FIPS
approved primitives and reject any ciphertexts (including
valid ones) generated e.g. using ChaCha20-Poly1305.

Signed-off-by: Andreas Auernhammer <aead@mail.de>
  • Loading branch information
Andreas Auernhammer authored and harshavardhana committed Apr 27, 2021
1 parent 92fa79d commit 9153644
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 17 deletions.
4 changes: 2 additions & 2 deletions cmd/kes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
"strings"

"github.com/minio/kes"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/term"
)

// Use e.g.: go build -ldflags "-X main.version=v1.0.0"
Expand Down Expand Up @@ -122,7 +122,7 @@ func newClient(insecureSkipVerify bool) *kes.Client {
})
}

func isTerm(f *os.File) bool { return terminal.IsTerminal(int(f.Fd())) }
func isTerm(f *os.File) bool { return term.IsTerminal(int(f.Fd())) }

// cancelOnSignal returns a new Context that gets canceled when
// one of the signals is received. It is allowed to call the
Expand Down
26 changes: 21 additions & 5 deletions cmd/kes/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package main
import (
"context"
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/x509"
"crypto/x509/pkix"
Expand All @@ -31,6 +33,7 @@ import (

"github.com/fatih/color"
"github.com/minio/kes"
"github.com/minio/kes/internal/fips"
"github.com/minio/kes/internal/secret"
"golang.org/x/crypto/ssh/terminal"
)
Expand Down Expand Up @@ -154,9 +157,22 @@ func newIdentityCmd(args []string) {
commonName = cli.Arg(0)
}

public, private, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
stdlog.Fatalf("Error: failed to generate private key: %v", err)
var (
publicKey crypto.PublicKey
privateKey crypto.PrivateKey
)
if fips.Enabled {
private, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
stdlog.Fatalf("Error: failed to generate private key: %v", err)
}
publicKey, privateKey = private.Public(), private
} else {
public, private, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
stdlog.Fatalf("Error: failed to generate private key: %v", err)
}
publicKey, privateKey = public, private
}

serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
Expand Down Expand Up @@ -196,11 +212,11 @@ func newIdentityCmd(args []string) {
BasicConstraintsValid: true,
}

derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, public, private)
derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey, privateKey)
if err != nil {
stdlog.Fatalf("Error: failed to create certificate: %v", err)
}
privBytes, err := x509.MarshalPKCS8PrivateKey(private)
privBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
stdlog.Fatalf("Error: failed to create private key: %v", err)
}
Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ require (
github.com/prometheus/common v0.13.0
github.com/secure-io/sio-go v0.3.0
golang.org/x/crypto v0.0.0-20200709230013-948cd5f35899
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72
google.golang.org/api v0.31.0
google.golang.org/genproto v0.0.0-20200901141002-b3bf27a9dbd1
google.golang.org/grpc v1.31.1
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,10 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a h1:i47hUS795cOydZI4AwJQCKXOr4BvxzvikwDoDtHhP2Y=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72 h1:VqE9gduFZ4dbR7XoL77lHFp0/DyDUBKSXK7CMFkVcV0=
golang.org/x/term v0.0.0-20210406210042-72f3dc4e9b72/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
13 changes: 13 additions & 0 deletions internal/fips/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright 2021 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.

package fips

// Enabled indicates whether cryptographic primitives,
// like AES or SHA-256, are implemented using a FIPS 140
// certified module.
//
// If FIPS-140 is enabled no non-NIST/FIPS approved
// primitives must be used.
const Enabled = enabled
9 changes: 9 additions & 0 deletions internal/fips/fips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.

// +build fips,linux,amd64

package fips

const enabled = 0 == 0
9 changes: 9 additions & 0 deletions internal/fips/nofips.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021 - MinIO, Inc. All rights reserved.
// Use of this source code is governed by the AGPLv3
// license that can be found in the LICENSE file.

// +build !fips

package fips

const enabled = 0 == 1
11 changes: 6 additions & 5 deletions internal/secret/secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"strings"

"github.com/minio/kes"
"github.com/minio/kes/internal/fips"
"github.com/secure-io/sio-go/sioutil"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/chacha20poly1305"
Expand Down Expand Up @@ -67,7 +68,7 @@ func (s Secret) Wrap(plaintext, associatedData []byte) ([]byte, error) {
}

var algorithm string
if sioutil.NativeAES() {
if fips.Enabled || sioutil.NativeAES() {
algorithm = "AES-256-GCM-HMAC-SHA-256"
} else {
algorithm = "ChaCha20Poly1305"
Expand Down Expand Up @@ -148,8 +149,8 @@ func (s Secret) Unwrap(ciphertext []byte, associatedData []byte) ([]byte, error)
}

var aead cipher.AEAD
switch sealedSecret.Algorithm {
case "AES-256-GCM-HMAC-SHA-256":
switch {
case sealedSecret.Algorithm == "AES-256-GCM-HMAC-SHA-256":
mac := hmac.New(sha256.New, s[:])
mac.Write(sealedSecret.IV)
sealingKey := mac.Sum(nil)
Expand All @@ -162,7 +163,7 @@ func (s Secret) Unwrap(ciphertext []byte, associatedData []byte) ([]byte, error)
if err != nil {
return nil, err
}
case "ChaCha20Poly1305":
case !fips.Enabled && sealedSecret.Algorithm == "ChaCha20Poly1305":
sealingKey, err := chacha20.HChaCha20(s[:], sealedSecret.IV)
if err != nil {
return nil, err
Expand All @@ -172,7 +173,7 @@ func (s Secret) Unwrap(ciphertext []byte, associatedData []byte) ([]byte, error)
return nil, err
}
default:
return nil, kes.NewError(http.StatusBadRequest, "invalid algorithm: "+sealedSecret.Algorithm)
return nil, kes.NewError(http.StatusUnprocessableEntity, "unsupported cryptographic algorithm")
}

if n := len(sealedSecret.Nonce); n != aead.NonceSize() {
Expand Down
4 changes: 2 additions & 2 deletions internal/xterm/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"sync"

"github.com/fatih/color"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/term"
)

// HCell represents a single header cell of a table.
Expand Down Expand Up @@ -119,7 +119,7 @@ func (t *Table) Draw() {
t.lock.Lock()
defer t.lock.Unlock()

width, height, _ := terminal.GetSize(int(os.Stdout.Fd()))
width, height, _ := term.GetSize(int(os.Stdout.Fd()))

fmt.Print("\033[3J\033[0;0H", "\r") // ASCII sequence to clean scroll + move to position (0,0)
fmt.Printf("\033[%dM", height+1) // ASCII sequence to delete height+1 rows
Expand Down

0 comments on commit 9153644

Please sign in to comment.