From c1a49be639e6e0e297e39b4001672eb08f4c8b92 Mon Sep 17 00:00:00 2001 From: Andreas Auernhammer Date: Wed, 24 Feb 2021 18:00:15 +0100 Subject: [PATCH] use crypto/sha256 for FIPS 140-2 compliance (#11623) This commit replaces the usage of github.com/minio/sha256-simd with crypto/sha256 of the standard library in all non-performance critical paths. This is necessary for FIPS 140-2 compliance which requires that all crypto. primitives are implemented by a FIPS-validated module. Go can use the Google FIPS module. The boringcrypto branch of the Go standard library uses the BoringSSL FIPS module to implement crypto. primitives like AES or SHA256. We only keep github.com/minio/sha256-simd when computing the content-SHA256 of an object. Therefore, this commit relies on a build tag `fips`. When MinIO is compiled without the `fips` flag it will use github.com/minio/sha256-simd. When MinIO is compiled with the fips flag (go build --tags "fips") then MinIO uses crypto/sha256 to compute the content-SHA256. --- cmd/bitrot.go | 2 +- cmd/bucket-targets.go | 2 +- cmd/crypto/key.go | 2 +- cmd/crypto/kms.go | 2 +- cmd/encryption-v1.go | 2 +- cmd/erasure-metadata.go | 2 +- cmd/format-erasure.go | 2 +- cmd/gateway/azure/gateway-azure.go | 2 +- cmd/hasher.go | 3 +-- cmd/signature-v4-utils.go | 7 +++---- cmd/signature-v4.go | 2 +- cmd/streaming-signature-v4.go | 2 +- cmd/update.go | 1 - pkg/event/target/kafka_scram_client.go | 7 +++---- pkg/hash/reader.go | 3 +-- pkg/hash/sha256_fips.go | 28 ++++++++++++++++++++++++++ pkg/hash/sha256_nofips.go | 27 +++++++++++++++++++++++++ pkg/madmin/api.go | 4 +++- pkg/madmin/utils.go | 9 --------- 19 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 pkg/hash/sha256_fips.go create mode 100644 pkg/hash/sha256_nofips.go diff --git a/cmd/bitrot.go b/cmd/bitrot.go index 24f7ecd39..ec478727e 100644 --- a/cmd/bitrot.go +++ b/cmd/bitrot.go @@ -17,13 +17,13 @@ package cmd import ( + "crypto/sha256" "errors" "hash" "io" "github.com/minio/highwayhash" "github.com/minio/minio/cmd/logger" - sha256 "github.com/minio/sha256-simd" "golang.org/x/crypto/blake2b" ) diff --git a/cmd/bucket-targets.go b/cmd/bucket-targets.go index d46abe35e..49c4cf2c8 100644 --- a/cmd/bucket-targets.go +++ b/cmd/bucket-targets.go @@ -18,6 +18,7 @@ package cmd import ( "context" + "crypto/sha256" "encoding/hex" "encoding/json" "net/http" @@ -32,7 +33,6 @@ import ( "github.com/minio/minio/cmd/crypto" "github.com/minio/minio/pkg/bucket/versioning" "github.com/minio/minio/pkg/madmin" - sha256 "github.com/minio/sha256-simd" ) const ( diff --git a/cmd/crypto/key.go b/cmd/crypto/key.go index 561d749ea..b4f9fafc5 100644 --- a/cmd/crypto/key.go +++ b/cmd/crypto/key.go @@ -19,13 +19,13 @@ import ( "context" "crypto/hmac" "crypto/rand" + "crypto/sha256" "encoding/binary" "errors" "io" "path" "github.com/minio/minio/cmd/logger" - sha256 "github.com/minio/sha256-simd" "github.com/minio/sio" ) diff --git a/cmd/crypto/kms.go b/cmd/crypto/kms.go index 444492070..ebd952b53 100644 --- a/cmd/crypto/kms.go +++ b/cmd/crypto/kms.go @@ -19,13 +19,13 @@ import ( "context" "crypto/hmac" "crypto/rand" + "crypto/sha256" "errors" "fmt" "io" "sort" "github.com/minio/minio/cmd/logger" - sha256 "github.com/minio/sha256-simd" "github.com/minio/sio" ) diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index 6de14b42e..d15c42f47 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -20,6 +20,7 @@ import ( "bufio" "crypto/hmac" "crypto/rand" + "crypto/sha256" "crypto/subtle" "encoding/binary" "encoding/hex" @@ -33,7 +34,6 @@ import ( "github.com/minio/minio/cmd/crypto" xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/cmd/logger" - sha256 "github.com/minio/sha256-simd" "github.com/minio/sio" ) diff --git a/cmd/erasure-metadata.go b/cmd/erasure-metadata.go index a65c6f7d4..43324dbc0 100644 --- a/cmd/erasure-metadata.go +++ b/cmd/erasure-metadata.go @@ -18,6 +18,7 @@ package cmd import ( "context" + "crypto/sha256" "encoding/hex" "fmt" "net/http" @@ -28,7 +29,6 @@ import ( "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/bucket/replication" "github.com/minio/minio/pkg/sync/errgroup" - "github.com/minio/sha256-simd" ) const erasureAlgorithm = "rs-vandermonde" diff --git a/cmd/format-erasure.go b/cmd/format-erasure.go index 8e28739f7..6220d8802 100644 --- a/cmd/format-erasure.go +++ b/cmd/format-erasure.go @@ -18,6 +18,7 @@ package cmd import ( "context" + "crypto/sha256" "encoding/hex" "encoding/json" "errors" @@ -33,7 +34,6 @@ import ( "github.com/minio/minio/pkg/color" xioutil "github.com/minio/minio/pkg/ioutil" "github.com/minio/minio/pkg/sync/errgroup" - sha256 "github.com/minio/sha256-simd" ) const ( diff --git a/cmd/gateway/azure/gateway-azure.go b/cmd/gateway/azure/gateway-azure.go index 016ccbfa7..a18c4606e 100644 --- a/cmd/gateway/azure/gateway-azure.go +++ b/cmd/gateway/azure/gateway-azure.go @@ -20,6 +20,7 @@ import ( "bytes" "context" "crypto/rand" + "crypto/sha256" "encoding/base64" "encoding/hex" "encoding/json" @@ -46,7 +47,6 @@ import ( "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/bucket/policy" "github.com/minio/minio/pkg/bucket/policy/condition" - sha256 "github.com/minio/sha256-simd" minio "github.com/minio/minio/cmd" ) diff --git a/cmd/hasher.go b/cmd/hasher.go index bac821eab..d9d1371e5 100644 --- a/cmd/hasher.go +++ b/cmd/hasher.go @@ -18,9 +18,8 @@ package cmd import ( "crypto/md5" + "crypto/sha256" "encoding/hex" - - "github.com/minio/sha256-simd" ) // getSHA256Hash returns SHA-256 hash in hex encoding of given data. diff --git a/cmd/signature-v4-utils.go b/cmd/signature-v4-utils.go index 8f70a55ec..90f53f955 100644 --- a/cmd/signature-v4-utils.go +++ b/cmd/signature-v4-utils.go @@ -19,6 +19,7 @@ package cmd import ( "bytes" "crypto/hmac" + "crypto/sha256" "encoding/hex" "io" "io/ioutil" @@ -29,7 +30,6 @@ import ( xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/cmd/logger" "github.com/minio/minio/pkg/auth" - "github.com/minio/sha256-simd" ) // http Header "x-amz-content-sha256" == "UNSIGNED-PAYLOAD" indicates that the @@ -65,10 +65,9 @@ func getContentSha256Cksum(r *http.Request, stype serviceType) string { if err != nil { logger.CriticalIf(GlobalContext, err) } - sum256 := sha256.New() - sum256.Write(payload) + sum256 := sha256.Sum256(payload) r.Body = ioutil.NopCloser(bytes.NewReader(payload)) - return hex.EncodeToString(sum256.Sum(nil)) + return hex.EncodeToString(sum256[:]) } var ( diff --git a/cmd/signature-v4.go b/cmd/signature-v4.go index 5bcd31656..757a22092 100644 --- a/cmd/signature-v4.go +++ b/cmd/signature-v4.go @@ -26,6 +26,7 @@ package cmd import ( "bytes" + "crypto/sha256" "crypto/subtle" "encoding/hex" "net/http" @@ -38,7 +39,6 @@ import ( "github.com/minio/minio-go/v7/pkg/s3utils" "github.com/minio/minio-go/v7/pkg/set" xhttp "github.com/minio/minio/cmd/http" - sha256 "github.com/minio/sha256-simd" ) // AWS Signature Version '4' constants. diff --git a/cmd/streaming-signature-v4.go b/cmd/streaming-signature-v4.go index 0de211593..4cef296cf 100644 --- a/cmd/streaming-signature-v4.go +++ b/cmd/streaming-signature-v4.go @@ -21,6 +21,7 @@ package cmd import ( "bufio" "bytes" + "crypto/sha256" "encoding/hex" "errors" "hash" @@ -31,7 +32,6 @@ import ( humanize "github.com/dustin/go-humanize" xhttp "github.com/minio/minio/cmd/http" "github.com/minio/minio/pkg/auth" - sha256 "github.com/minio/sha256-simd" ) // Streaming AWS Signature Version '4' constants. diff --git a/cmd/update.go b/cmd/update.go index cb256df74..fd79ce094 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -39,7 +39,6 @@ import ( "github.com/minio/minio/pkg/env" xnet "github.com/minio/minio/pkg/net" "github.com/minio/selfupdate" - _ "github.com/minio/sha256-simd" // Needed for sha256 hash verifier. ) const ( diff --git a/pkg/event/target/kafka_scram_client.go b/pkg/event/target/kafka_scram_client.go index efecec893..3cd951209 100644 --- a/pkg/event/target/kafka_scram_client.go +++ b/pkg/event/target/kafka_scram_client.go @@ -17,20 +17,19 @@ package target import ( + "crypto/sha256" "crypto/sha512" - "hash" - "github.com/minio/sha256-simd" "github.com/xdg/scram" ) // KafkaSHA256 is a function that returns a crypto/sha256 hasher and should be used // to create Client objects configured for SHA-256 hashing. -var KafkaSHA256 scram.HashGeneratorFcn = func() hash.Hash { return sha256.New() } +var KafkaSHA256 scram.HashGeneratorFcn = sha256.New // KafkaSHA512 is a function that returns a crypto/sha512 hasher and should be used // to create Client objects configured for SHA-512 hashing. -var KafkaSHA512 scram.HashGeneratorFcn = func() hash.Hash { return sha512.New() } +var KafkaSHA512 scram.HashGeneratorFcn = sha512.New // XDGSCRAMClient implements the client-side of an authentication // conversation with a server. A new conversation must be created for diff --git a/pkg/hash/reader.go b/pkg/hash/reader.go index ab9d84fdd..a86368eec 100644 --- a/pkg/hash/reader.go +++ b/pkg/hash/reader.go @@ -25,7 +25,6 @@ import ( "io" "github.com/minio/minio/pkg/etag" - sha256 "github.com/minio/sha256-simd" ) // A Reader wraps an io.Reader and computes the MD5 checksum @@ -115,7 +114,7 @@ func NewReader(src io.Reader, size int64, md5Hex, sha256Hex string, actualSize i src = io.LimitReader(src, size) } if len(SHA256) != 0 { - hash = sha256.New() + hash = newSHA256() } return &Reader{ src: etag.NewReader(src, etag.ETag(MD5)), diff --git a/pkg/hash/sha256_fips.go b/pkg/hash/sha256_fips.go new file mode 100644 index 000000000..056d68b5b --- /dev/null +++ b/pkg/hash/sha256_fips.go @@ -0,0 +1,28 @@ +// MinIO Cloud Storage, (C) 2021 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build fips + +package hash + +import ( + "crypto/sha256" + "hash" +) + +// newSHA256 returns a new hash.Hash computing the SHA256 checksum. +// The SHA256 implementation is FIPS 140-2 compliant when the +// boringcrypto branch of Go is used. +// Ref: https://github.com/golang/go/tree/dev.boringcrypto +func newSHA256() hash.Hash { return sha256.New() } diff --git a/pkg/hash/sha256_nofips.go b/pkg/hash/sha256_nofips.go new file mode 100644 index 000000000..f75a7dc27 --- /dev/null +++ b/pkg/hash/sha256_nofips.go @@ -0,0 +1,27 @@ +// MinIO Cloud Storage, (C) 2021 MinIO, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !fips + +package hash + +import ( + "hash" + + sha256 "github.com/minio/sha256-simd" +) + +// newSHA256 returns a new hash.Hash computing the SHA256 checksum. +// The SHA256 implementation is not FIPS 140-2 compliant. +func newSHA256() hash.Hash { return sha256.New() } diff --git a/pkg/madmin/api.go b/pkg/madmin/api.go index d1e2a6121..d34a43579 100644 --- a/pkg/madmin/api.go +++ b/pkg/madmin/api.go @@ -19,6 +19,7 @@ package madmin import ( "bytes" "context" + "crypto/sha256" "encoding/hex" "errors" "fmt" @@ -476,7 +477,8 @@ func (adm AdminClient) newRequest(ctx context.Context, method string, reqData re if length := len(reqData.content); length > 0 { req.ContentLength = int64(length) } - req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum256(reqData.content))) + sum := sha256.Sum256(reqData.content) + req.Header.Set("X-Amz-Content-Sha256", hex.EncodeToString(sum[:])) req.Body = ioutil.NopCloser(bytes.NewReader(reqData.content)) req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, location) diff --git a/pkg/madmin/utils.go b/pkg/madmin/utils.go index 3dc4fa983..4f992e2b2 100644 --- a/pkg/madmin/utils.go +++ b/pkg/madmin/utils.go @@ -25,8 +25,6 @@ import ( "net/url" "strings" - sha256 "github.com/minio/sha256-simd" - "github.com/minio/minio-go/v7/pkg/s3utils" ) @@ -37,13 +35,6 @@ const ( adminAPIPrefix = "/" + AdminAPIVersion ) -// sum256 calculate sha256 sum for an input byte array. -func sum256(data []byte) []byte { - hash := sha256.New() - hash.Write(data) - return hash.Sum(nil) -} - // jsonDecoder decode json to go type. func jsonDecoder(body io.Reader, v interface{}) error { d := json.NewDecoder(body)