Skip to content

Commit

Permalink
add support for sha384 and sha512 to hashedrekord type
Browse files Browse the repository at this point in the history
Signed-off-by: Bob Callaway <[email protected]>
  • Loading branch information
bobcallaway committed Jan 17, 2024
1 parent ca115c9 commit b209631
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 29 deletions.
12 changes: 9 additions & 3 deletions pkg/generated/models/hashedrekord_v001_schema.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 12 additions & 6 deletions pkg/generated/restapi/embedded_spec.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 12 additions & 1 deletion pkg/types/hashedrekord/v0.0.1/entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package hashedrekord
import (
"bytes"
"context"
"crypto"
"crypto/ed25519"
"crypto/sha256"
"encoding/hex"
Expand Down Expand Up @@ -178,11 +179,21 @@ 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))
}

Expand Down
121 changes: 104 additions & 17 deletions pkg/types/hashedrekord/v0.0.1/entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"crypto/x509"
"crypto/x509/pkix"
"encoding/hex"
Expand Down Expand Up @@ -57,6 +58,7 @@ func TestCrossFieldValidation(t *testing.T) {
type TestCase struct {
caseDesc string
entry V001Entry
expectedHashValue string
expectUnmarshalSuccess bool
expectCanonicalizeSuccess bool
expectedVerifierSuccess bool
Expand Down Expand Up @@ -90,11 +92,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[:])
Expand Down Expand Up @@ -124,10 +134,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,
},
Expand All @@ -136,11 +147,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,
},
Expand All @@ -149,13 +161,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,
Expand All @@ -165,13 +178,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,
},
Expand All @@ -180,35 +194,83 @@ func TestCrossFieldValidation(t *testing.T) {
entry: V001Entry{
HashedRekordObj: models.HashedrekordV001Schema{
Signature: &models.HashedrekordV001SchemaSignature{
Content: sigBytes,
Content: sha256SigBytes,
PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{
Content: keyBytes,
},
},
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,
Expand All @@ -218,7 +280,7 @@ func TestCrossFieldValidation(t *testing.T) {
entry: V001Entry{
HashedRekordObj: models.HashedrekordV001Schema{
Signature: &models.HashedrekordV001SchemaSignature{
Content: sigBytes,
Content: sha256SigBytes,
PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{
Content: keyBytes,
},
Expand All @@ -231,6 +293,7 @@ func TestCrossFieldValidation(t *testing.T) {
},
},
},
expectedHashValue: "sha256:" + dataSHA256,
expectUnmarshalSuccess: false,
expectCanonicalizeSuccess: false,
expectedVerifierSuccess: true,
Expand All @@ -240,7 +303,7 @@ func TestCrossFieldValidation(t *testing.T) {
entry: V001Entry{
HashedRekordObj: models.HashedrekordV001Schema{
Signature: &models.HashedrekordV001SchemaSignature{
Content: sigBytes,
Content: sha256SigBytes,
PublicKey: &models.HashedrekordV001SchemaSignaturePublicKey{
Content: keyBytes,
},
Expand All @@ -253,6 +316,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,
Expand Down Expand Up @@ -293,7 +380,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)
}
}
Expand Down Expand Up @@ -323,7 +410,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)
}
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/types/hashedrekord/v0.0.1/hashedrekord_v0_0_1_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
},
Expand Down

0 comments on commit b209631

Please sign in to comment.