From 9865ca948572c60476b8d92c0708ca7975160422 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone <562321+ret2libc@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:22:44 +0100 Subject: [PATCH] Added support for sha384/sha512 hash algorithms in hashedrekords (#1959) * Added support for sha384/sha512 hash algorithms in hashedrekords Includes changes provided by @bobcallaway Signed-off-by: Riccardo Schirone * Added e2e test for hashedrekord type Make sure Rekor accepts SHA256 digest but not SHA1 Signed-off-by: Riccardo Schirone * hashedrekord: add a SHA1 backstop test for CreateFromArtifactProperties Signed-off-by: William Woodruff --------- Signed-off-by: Riccardo Schirone Signed-off-by: William Woodruff Co-authored-by: William Woodruff --- .../models/hashedrekord_v001_schema.go | 12 +- pkg/generated/restapi/embedded_spec.go | 18 +- pkg/types/hashedrekord/v0.0.1/e2e_test.go | 94 +++++++++++ pkg/types/hashedrekord/v0.0.1/entry.go | 30 +++- pkg/types/hashedrekord/v0.0.1/entry_test.go | 157 ++++++++++++++++-- .../v0.0.1/hashedrekord_v0_0_1_schema.json | 4 +- pkg/util/sha.go | 38 +++++ pkg/util/sha_test.go | 67 ++++++++ 8 files changed, 389 insertions(+), 31 deletions(-) create mode 100644 pkg/types/hashedrekord/v0.0.1/e2e_test.go diff --git a/pkg/generated/models/hashedrekord_v001_schema.go b/pkg/generated/models/hashedrekord_v001_schema.go index f8bf233ed..3b906ae29 100644 --- a/pkg/generated/models/hashedrekord_v001_schema.go +++ b/pkg/generated/models/hashedrekord_v001_schema.go @@ -277,10 +277,10 @@ type HashedrekordV001SchemaDataHash struct { // The hashing function used to compute the hash value // Required: true - // Enum: [sha256] + // Enum: [sha256 sha384 sha512] Algorithm *string `json:"algorithm"` - // The hash value for the content + // The hash value for the content, as represented by a lower case hexadecimal string // Required: true Value *string `json:"value"` } @@ -307,7 +307,7 @@ var hashedrekordV001SchemaDataHashTypeAlgorithmPropEnum []interface{} func init() { var res []string - if err := json.Unmarshal([]byte(`["sha256"]`), &res); err != nil { + if err := json.Unmarshal([]byte(`["sha256","sha384","sha512"]`), &res); err != nil { panic(err) } for _, v := range res { @@ -319,6 +319,12 @@ const ( // HashedrekordV001SchemaDataHashAlgorithmSha256 captures enum value "sha256" HashedrekordV001SchemaDataHashAlgorithmSha256 string = "sha256" + + // HashedrekordV001SchemaDataHashAlgorithmSha384 captures enum value "sha384" + HashedrekordV001SchemaDataHashAlgorithmSha384 string = "sha384" + + // HashedrekordV001SchemaDataHashAlgorithmSha512 captures enum value "sha512" + HashedrekordV001SchemaDataHashAlgorithmSha512 string = "sha512" ) // prop value enum diff --git a/pkg/generated/restapi/embedded_spec.go b/pkg/generated/restapi/embedded_spec.go index 3e353768c..234f9122c 100644 --- a/pkg/generated/restapi/embedded_spec.go +++ b/pkg/generated/restapi/embedded_spec.go @@ -1659,11 +1659,13 @@ func init() { "description": "The hashing function used to compute the hash value", "type": "string", "enum": [ - "sha256" + "sha256", + "sha384", + "sha512" ] }, "value": { - "description": "The hash value for the content", + "description": "The hash value for the content, as represented by a lower case hexadecimal string", "type": "string" } } @@ -1682,11 +1684,13 @@ func init() { "description": "The hashing function used to compute the hash value", "type": "string", "enum": [ - "sha256" + "sha256", + "sha384", + "sha512" ] }, "value": { - "description": "The hash value for the content", + "description": "The hash value for the content, as represented by a lower case hexadecimal string", "type": "string" } } @@ -3261,11 +3265,13 @@ func init() { "description": "The hashing function used to compute the hash value", "type": "string", "enum": [ - "sha256" + "sha256", + "sha384", + "sha512" ] }, "value": { - "description": "The hash value for the content", + "description": "The hash value for the content, as represented by a lower case hexadecimal string", "type": "string" } } diff --git a/pkg/types/hashedrekord/v0.0.1/e2e_test.go b/pkg/types/hashedrekord/v0.0.1/e2e_test.go new file mode 100644 index 000000000..04fd77876 --- /dev/null +++ b/pkg/types/hashedrekord/v0.0.1/e2e_test.go @@ -0,0 +1,94 @@ +// +// Copyright 2024 The Sigstore Authors. +// +// 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. + +//go:build e2e + +package hashedrekord + +import ( + "bytes" + "context" + "crypto" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "os" + "testing" + "time" + + "github.com/sigstore/rekor/pkg/client" + "github.com/sigstore/rekor/pkg/generated/client/entries" + "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/sigstore/pkg/cryptoutils" + "github.com/sigstore/sigstore/pkg/signature" +) + +func rekorServer() string { + if s := os.Getenv("REKOR_SERVER"); s != "" { + return s + } + return "http://localhost:3000" +} + +// TestSHA256HashedRekordEntry tests sending a valid HashedRekord proposed entry. +func TestSHA256HashedRekordEntry(t *testing.T) { + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("error generating key: %v", err) + } + pubBytes, err := cryptoutils.MarshalPublicKeyToPEM(privKey.Public()) + if err != nil { + t.Fatalf("error marshaling public key: %v", err) + } + + data := []byte("data") + signer, err := signature.LoadSigner(privKey, crypto.SHA256) + if err != nil { + t.Fatalf("error loading verifier: %v", err) + } + signature, err := signer.SignMessage(bytes.NewReader(data)) + if err != nil { + t.Fatalf("error signing message: %v", err) + } + + ap := types.ArtifactProperties{ + ArtifactBytes: []byte("data"), + ArtifactHash: "sha256:3a6eb0790f39ac87c94f3856b2dd2c5d110e6811602261a9a923d3bb23adc8b7", + PublicKeyBytes: [][]byte{pubBytes}, + PKIFormat: "x509", + SignatureBytes: signature, + } + + ei := NewEntry() + + entry, err := ei.CreateFromArtifactProperties(context.Background(), ap) + if err != nil { + t.Fatalf("error creating entry: %v", err) + } + + rc, err := client.GetRekorClient(rekorServer()) + if err != nil { + t.Errorf("error getting client: %v", err) + } + + params := &entries.CreateLogEntryParams{} + params.SetProposedEntry(entry) + params.SetContext(context.Background()) + params.SetTimeout(5 * time.Second) + + if _, err = rc.Entries.CreateLogEntry(params); err != nil { + t.Fatalf("expected no errors when submitting hashedrekord entry with sha256 to rekor %s", err) + } +} diff --git a/pkg/types/hashedrekord/v0.0.1/entry.go b/pkg/types/hashedrekord/v0.0.1/entry.go index 5f0cb138a..4fa6ebac0 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry.go +++ b/pkg/types/hashedrekord/v0.0.1/entry.go @@ -18,6 +18,7 @@ package hashedrekord import ( "bytes" "context" + "crypto" "crypto/ed25519" "crypto/sha256" "encoding/hex" @@ -38,6 +39,7 @@ import ( "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" hashedrekord "github.com/sigstore/rekor/pkg/types/hashedrekord" + "github.com/sigstore/rekor/pkg/util" "github.com/sigstore/sigstore/pkg/signature/options" ) @@ -178,17 +180,38 @@ func (v *V001Entry) validate() (pki.Signature, pki.PublicKey, error) { return nil, nil, types.ValidationError(errors.New("invalid value for hash")) } + var alg crypto.Hash + switch swag.StringValue(hash.Algorithm) { + case models.HashedrekordV001SchemaDataHashAlgorithmSha384: + alg = crypto.SHA384 + case models.HashedrekordV001SchemaDataHashAlgorithmSha512: + alg = crypto.SHA512 + default: + alg = crypto.SHA256 + } + decoded, err := hex.DecodeString(*hash.Value) if err != nil { return nil, nil, err } - if err := sigObj.Verify(nil, keyObj, options.WithDigest(decoded)); err != nil { + if err := sigObj.Verify(nil, keyObj, options.WithDigest(decoded), options.WithCryptoSignerOpts(alg)); err != nil { return nil, nil, types.ValidationError(fmt.Errorf("verifying signature: %w", err)) } return sigObj, keyObj, nil } +func getDataHashAlgorithm(hashAlgorithm crypto.Hash) string { + switch hashAlgorithm { + case crypto.SHA384: + return models.HashedrekordV001SchemaDataHashAlgorithmSha384 + case crypto.SHA512: + return models.HashedrekordV001SchemaDataHashAlgorithmSha512 + default: + return models.HashedrekordV001SchemaDataHashAlgorithmSha256 + } +} + func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.ArtifactProperties) (models.ProposedEntry, error) { returnVal := models.Hashedrekord{} re := V001Entry{} @@ -230,10 +253,11 @@ func (v V001Entry) CreateFromArtifactProperties(_ context.Context, props types.A return nil, errors.New("only one public key must be provided") } + hashAlgorithm, hashValue := util.UnprefixSHA(props.ArtifactHash) re.HashedRekordObj.Signature.PublicKey.Content = strfmt.Base64(publicKeyBytes[0]) re.HashedRekordObj.Data.Hash = &models.HashedrekordV001SchemaDataHash{ - Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), - Value: swag.String(props.ArtifactHash), + Algorithm: swag.String(getDataHashAlgorithm(hashAlgorithm)), + Value: swag.String(hashValue), } if _, _, err := re.validate(); err != nil { diff --git a/pkg/types/hashedrekord/v0.0.1/entry_test.go b/pkg/types/hashedrekord/v0.0.1/entry_test.go index 343712dc8..2330adeb3 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry_test.go +++ b/pkg/types/hashedrekord/v0.0.1/entry_test.go @@ -24,6 +24,7 @@ import ( "crypto/elliptic" "crypto/rand" "crypto/sha256" + "crypto/sha512" "crypto/x509" "crypto/x509/pkix" "encoding/hex" @@ -38,6 +39,7 @@ import ( "github.com/sigstore/rekor/pkg/generated/models" x509r "github.com/sigstore/rekor/pkg/pki/x509" "github.com/sigstore/rekor/pkg/types" + "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/signature" "go.uber.org/goleak" ) @@ -53,10 +55,46 @@ func TestNewEntryReturnType(t *testing.T) { } } +func TestRejectsSHA1(t *testing.T) { + privKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("error generating key: %v", err) + } + pubBytes, err := cryptoutils.MarshalPublicKeyToPEM(privKey.Public()) + if err != nil { + t.Fatalf("error marshaling public key: %v", err) + } + + data := []byte("data") + signer, err := signature.LoadSigner(privKey, crypto.SHA256) + if err != nil { + t.Fatalf("error loading verifier: %v", err) + } + signature, err := signer.SignMessage(bytes.NewReader(data)) + if err != nil { + t.Fatalf("error signing message: %v", err) + } + + ap := types.ArtifactProperties{ + ArtifactBytes: data, + ArtifactHash: "sha1:a17c9aaa61e80a1bf71d0d850af4e5baa9800bbd", + PublicKeyBytes: [][]byte{pubBytes}, + PKIFormat: "x509", + SignatureBytes: signature, + } + + ei := NewEntry() + _, err = ei.CreateFromArtifactProperties(context.Background(), ap) + if err == nil { + t.Fatalf("expected error creating entry") + } +} + func TestCrossFieldValidation(t *testing.T) { type TestCase struct { caseDesc string entry V001Entry + expectedHashValue string expectUnmarshalSuccess bool expectCanonicalizeSuccess bool expectedVerifierSuccess bool @@ -90,11 +128,19 @@ func TestCrossFieldValidation(t *testing.T) { }) dataBytes := []byte("sign me!") - h := sha256.Sum256(dataBytes) - dataSHA := hex.EncodeToString(h[:]) - - signer, _ := signature.LoadSigner(key, crypto.SHA256) - sigBytes, _ := signer.SignMessage(bytes.NewReader(dataBytes)) + sha256Sum := sha256.Sum256(dataBytes) + sha384Sum := sha512.Sum384(dataBytes) + sha512Sum := sha512.Sum512(dataBytes) + dataSHA256 := hex.EncodeToString(sha256Sum[:]) + dataSHA384 := hex.EncodeToString(sha384Sum[:]) + dataSHA512 := hex.EncodeToString(sha512Sum[:]) + + sha256Signer, _ := signature.LoadSigner(key, crypto.SHA256) + sha256SigBytes, _ := sha256Signer.SignMessage(bytes.NewReader(dataBytes)) + sha384Signer, _ := signature.LoadSigner(key, crypto.SHA384) + sha384SigBytes, _ := sha384Signer.SignMessage(bytes.NewReader(dataBytes)) + sha512Signer, _ := signature.LoadSigner(key, crypto.SHA512) + sha512SigBytes, _ := sha512Signer.SignMessage(bytes.NewReader(dataBytes)) incorrectLengthHash := sha256.Sum224(dataBytes) incorrectLengthSHA := hex.EncodeToString(incorrectLengthHash[:]) @@ -124,10 +170,11 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, }, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectedVerifierSuccess: false, }, @@ -136,11 +183,12 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{}, }, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectedVerifierSuccess: false, }, @@ -149,13 +197,14 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: invalidKeyBytes, }, }, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, // successful even if unmarshalling fails, because the ed25519 key is valid expectedVerifierSuccess: true, @@ -165,13 +214,14 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: keyBytes, }, }, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectedVerifierSuccess: true, }, @@ -180,7 +230,7 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: keyBytes, }, @@ -188,27 +238,75 @@ func TestCrossFieldValidation(t *testing.T) { Data: &models.HashedrekordV001SchemaData{}, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectedVerifierSuccess: true, }, { - caseDesc: "signature with hash", + caseDesc: "signature with sha256 hash", entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: keyBytes, }, }, Data: &models.HashedrekordV001SchemaData{ Hash: &models.HashedrekordV001SchemaDataHash{ - Value: swag.String(dataSHA), + Value: swag.String(dataSHA256), Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), }, }, }, }, + expectedHashValue: "sha256:" + dataSHA256, + expectUnmarshalSuccess: true, + expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, + }, + { + caseDesc: "signature with sha384 hash", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Signature: &models.HashedrekordV001SchemaSignature{ + Content: sha384SigBytes, + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: keyBytes, + }, + }, + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Value: swag.String(dataSHA384), + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha384), + }, + }, + }, + }, + expectedHashValue: "sha384:" + dataSHA384, + expectUnmarshalSuccess: true, + expectCanonicalizeSuccess: true, + expectedVerifierSuccess: true, + }, + { + caseDesc: "signature with sha512 hash", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Signature: &models.HashedrekordV001SchemaSignature{ + Content: sha512SigBytes, + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: keyBytes, + }, + }, + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Value: swag.String(dataSHA512), + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha512), + }, + }, + }, + }, + expectedHashValue: "sha512:" + dataSHA512, expectUnmarshalSuccess: true, expectCanonicalizeSuccess: true, expectedVerifierSuccess: true, @@ -218,7 +316,7 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: keyBytes, }, @@ -231,6 +329,7 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectCanonicalizeSuccess: false, expectedVerifierSuccess: true, @@ -240,7 +339,7 @@ func TestCrossFieldValidation(t *testing.T) { entry: V001Entry{ HashedRekordObj: models.HashedrekordV001Schema{ Signature: &models.HashedrekordV001SchemaSignature{ - Content: sigBytes, + Content: sha256SigBytes, PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ Content: keyBytes, }, @@ -253,6 +352,30 @@ func TestCrossFieldValidation(t *testing.T) { }, }, }, + expectedHashValue: "sha256:" + dataSHA256, + expectUnmarshalSuccess: false, + expectCanonicalizeSuccess: false, + expectedVerifierSuccess: true, + }, + { + caseDesc: "signature with mismatched hash & invalid signature", + entry: V001Entry{ + HashedRekordObj: models.HashedrekordV001Schema{ + Signature: &models.HashedrekordV001SchemaSignature{ + Content: sha512SigBytes, + PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{ + Content: keyBytes, + }, + }, + Data: &models.HashedrekordV001SchemaData{ + Hash: &models.HashedrekordV001SchemaDataHash{ + Value: swag.String(dataSHA256), + Algorithm: swag.String(models.HashedrekordV001SchemaDataHashAlgorithmSha256), + }, + }, + }, + }, + expectedHashValue: "sha256:" + dataSHA256, expectUnmarshalSuccess: false, expectCanonicalizeSuccess: false, expectedVerifierSuccess: true, @@ -293,7 +416,7 @@ func TestCrossFieldValidation(t *testing.T) { hash, err := v.ArtifactHash() if err != nil { t.Errorf("unexpected failure with ArtifactHash: %v", err) - } else if hash != "sha256:"+dataSHA { + } else if hash != tc.expectedHashValue { t.Errorf("unexpected match with ArtifactHash: %s", hash) } } @@ -323,7 +446,7 @@ func TestCrossFieldValidation(t *testing.T) { hash, err := ei.ArtifactHash() if err != nil { t.Errorf("unexpected failure with ArtifactHash: %v", err) - } else if hash != "sha256:"+dataSHA { + } else if hash != tc.expectedHashValue { t.Errorf("unexpected match with ArtifactHash: %s", hash) } } diff --git a/pkg/types/hashedrekord/v0.0.1/hashedrekord_v0_0_1_schema.json b/pkg/types/hashedrekord/v0.0.1/hashedrekord_v0_0_1_schema.json index 8752ae60f..576071ed8 100644 --- a/pkg/types/hashedrekord/v0.0.1/hashedrekord_v0_0_1_schema.json +++ b/pkg/types/hashedrekord/v0.0.1/hashedrekord_v0_0_1_schema.json @@ -38,10 +38,10 @@ "algorithm": { "description": "The hashing function used to compute the hash value", "type": "string", - "enum": [ "sha256" ] + "enum": [ "sha256", "sha384", "sha512" ] }, "value": { - "description": "The hash value for the content", + "description": "The hash value for the content, as represented by a lower case hexadecimal string", "type": "string" } }, diff --git a/pkg/util/sha.go b/pkg/util/sha.go index 8509a5585..07b8fb1b5 100644 --- a/pkg/util/sha.go +++ b/pkg/util/sha.go @@ -15,6 +15,7 @@ package util import ( + "crypto" "fmt" "strings" ) @@ -33,9 +34,46 @@ func PrefixSHA(sha string) string { prefix = "sha1:" case 64: prefix = "sha256:" + case 96: + prefix = "sha384:" case 128: prefix = "sha512:" } return fmt.Sprintf("%v%v", prefix, sha) } + +func UnprefixSHA(sha string) (crypto.Hash, string) { + components := strings.Split(sha, ":") + + if len(components) == 2 { + prefix := components[0] + sha = components[1] + + switch prefix { + case "sha1": + return crypto.SHA1, sha + case "sha256": + return crypto.SHA256, sha + case "sha384": + return crypto.SHA384, sha + case "sha512": + return crypto.SHA512, sha + default: + return crypto.Hash(0), "" + } + } + + switch len(sha) { + case 40: + return crypto.SHA1, sha + case 64: + return crypto.SHA256, sha + case 96: + return crypto.SHA384, sha + case 128: + return crypto.SHA512, sha + } + + return crypto.Hash(0), "" +} diff --git a/pkg/util/sha_test.go b/pkg/util/sha_test.go index 2b2e518b0..29c4b7322 100644 --- a/pkg/util/sha_test.go +++ b/pkg/util/sha_test.go @@ -15,6 +15,7 @@ package util import ( + "crypto" "testing" ) @@ -43,6 +44,10 @@ func TestPrefixSHA(t *testing.T) { input: "cfd356237e261871e8f92ae6710a75a65a925ae121d94d28533f008bd3e00b5472d261b5d0e1ab4082e3078dd1ad2af57876ed3c1c797c4097dbed870f458408", want: "sha512:cfd356237e261871e8f92ae6710a75a65a925ae121d94d28533f008bd3e00b5472d261b5d0e1ab4082e3078dd1ad2af57876ed3c1c797c4097dbed870f458408", }, + { + input: "78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + want: "sha384:78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + }, } for _, tr := range testCases { @@ -52,3 +57,65 @@ func TestPrefixSHA(t *testing.T) { } } } + +func TestUnprefixSHA(t *testing.T) { + type prefixedSHA struct { + crypto.Hash + string + } + var testCases = []struct { + input string + want prefixedSHA + }{ + { + input: "87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7", + want: prefixedSHA{ + crypto.SHA256, + "87428fc522803d31065e7bce3cf03fe475096631e5e07bbd7a0fde60c4cf25c7", + }, + }, + { + input: "sha512:162b0b32f02482d5aca0a7c93dd03ceac3acd7e410a5f18f3fb990fc958ae0df6f32233b91831eaf99ca581a8c4ddf9c8ba315ac482db6d4ea01cc7884a635be", + want: prefixedSHA{ + crypto.SHA512, + "162b0b32f02482d5aca0a7c93dd03ceac3acd7e410a5f18f3fb990fc958ae0df6f32233b91831eaf99ca581a8c4ddf9c8ba315ac482db6d4ea01cc7884a635be", + }, + }, + { + input: "09b80428c53912d4174162fd5b7c7d485bdcc3ab", + want: prefixedSHA{ + crypto.SHA1, + "09b80428c53912d4174162fd5b7c7d485bdcc3ab", + }, + }, + { + input: "cfd356237e261871e8f92ae6710a75a65a925ae121d94d28533f008bd3e00b5472d261b5d0e1ab4082e3078dd1ad2af57876ed3c1c797c4097dbed870f458408", + want: prefixedSHA{ + crypto.SHA512, + "cfd356237e261871e8f92ae6710a75a65a925ae121d94d28533f008bd3e00b5472d261b5d0e1ab4082e3078dd1ad2af57876ed3c1c797c4097dbed870f458408", + }, + }, + { + input: "78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + want: prefixedSHA{ + crypto.SHA384, + "78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + }, + }, + { + input: "sha384:78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + want: prefixedSHA{ + crypto.SHA384, + "78674b244bc9cba8ecb6dcb660b059728236e36b2f30fbcd6e17b1b64255f3ac596fbe5c84d1cc9d2a0979513260de09", + }, + }, + } + + for _, tr := range testCases { + algo, value := UnprefixSHA(tr.input) + got := prefixedSHA{algo, value} + if got != tr.want { + t.Errorf("Got '%v' expected '%v' (input %s)", got, tr.want, tr.input) + } + } +}