@@ -5,14 +5,11 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
)
|
)
|
||||||
|
|
||||||
func HexHashBytes(input []byte) string {
|
func SHA256Hex(input []byte) string {
|
||||||
s256 := sha256.New()
|
return hex.EncodeToString(SHA256(input))
|
||||||
s256.Write(input)
|
|
||||||
hashSum := s256.Sum(nil)
|
|
||||||
return hex.EncodeToString(hashSum)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func S256(data []byte) []byte {
|
func SHA256(data []byte) []byte {
|
||||||
h := sha256.Sum256(data)
|
h := sha256.Sum256(data)
|
||||||
return h[:]
|
return h[:]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
package util
|
|
||||||
|
|
||||||
func StringInSlice(str string, list []string) bool {
|
|
||||||
for _, v := range list {
|
|
||||||
if v == str {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@ package attest_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
@@ -63,9 +64,9 @@ func ExampleVerify_remote() {
|
|||||||
panic(err) // failed policy or attestation signature verification
|
panic(err) // failed policy or attestation signature verification
|
||||||
}
|
}
|
||||||
if policy {
|
if policy {
|
||||||
print("policy passed: %v\n", policy)
|
fmt.Printf("policy passed: %v\n", policy)
|
||||||
return // passed policy
|
return // passed policy
|
||||||
}
|
}
|
||||||
// no policy found for image
|
// no policy found for image
|
||||||
print("no policy for image")
|
fmt.Printf("no policy for image")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package attestation
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"maps"
|
||||||
|
|
||||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/partial"
|
"github.com/google/go-containerregistry/pkg/v1/partial"
|
||||||
@@ -64,10 +65,7 @@ func GetAttestationsFromImage(image v1.Image) ([]AttestationLayer, error) {
|
|||||||
return nil, fmt.Errorf("failed to get descriptor for layer: %w", err)
|
return nil, fmt.Errorf("failed to get descriptor for layer: %w", err)
|
||||||
}
|
}
|
||||||
// copy original annotations
|
// copy original annotations
|
||||||
ann := make(map[string]string)
|
ann := maps.Clone(layerDesc.Annotations)
|
||||||
for k, v := range layerDesc.Annotations {
|
|
||||||
ann[k] = v
|
|
||||||
}
|
|
||||||
// only decode intoto statements
|
// only decode intoto statements
|
||||||
var stmt = new(intoto.Statement)
|
var stmt = new(intoto.Statement)
|
||||||
if mt == types.MediaType(intoto.PayloadType) {
|
if mt == types.MediaType(intoto.PayloadType) {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ func SignDSSE(ctx context.Context, payload []byte, payloadType string, signer ds
|
|||||||
encPayload := dsse.PAE(payloadType, payload)
|
encPayload := dsse.PAE(payloadType, payload)
|
||||||
|
|
||||||
// statement message digest
|
// statement message digest
|
||||||
hash := util.S256(encPayload)
|
hash := util.SHA256(encPayload)
|
||||||
|
|
||||||
// sign message digest
|
// sign message digest
|
||||||
sig, err := signer.Sign(ctx, hash)
|
sig, err := signer.Sign(ctx, hash)
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func verifySignature(ctx context.Context, sig Signature, payload []byte, keys Ke
|
|||||||
return fmt.Errorf("error failed to decode signature: %w", err)
|
return fmt.Errorf("error failed to decode signature: %w", err)
|
||||||
}
|
}
|
||||||
// verify payload ecdsa signature
|
// verify payload ecdsa signature
|
||||||
ok = ecdsa.VerifyASN1(publicKey, util.S256(payload), signature)
|
ok = ecdsa.VerifyASN1(publicKey, util.SHA256(payload), signature)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("payload signature is not valid")
|
return fmt.Errorf("payload signature is not valid")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ func TestGetTufMetadataMirror(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
tufMetadata, err := m.getTufMetadataMirror(server.URL + "/metadata")
|
tufMetadata, err := m.getTufMetadataMirror(server.URL + "/metadata")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// check that all roles are not empty
|
// check that all roles are not empty
|
||||||
assert.Greater(t, len(tufMetadata.Root), 0)
|
assert.Greater(t, len(tufMetadata.Root), 0)
|
||||||
@@ -39,15 +39,15 @@ func TestGetMetadataManifest(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
img, err := m.GetMetadataManifest(server.URL + "/metadata")
|
img, err := m.GetMetadataManifest(server.URL + "/metadata")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, img)
|
assert.NotNil(t, img)
|
||||||
|
|
||||||
image := *img
|
image := *img
|
||||||
mf, err := image.RawManifest()
|
mf, err := image.RawManifest()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
type Annotations struct {
|
type Annotations struct {
|
||||||
Annotations map[string]string `json:"annotations"`
|
Annotations map[string]string `json:"annotations"`
|
||||||
@@ -57,7 +57,7 @@ func TestGetMetadataManifest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
l := &Layers{}
|
l := &Layers{}
|
||||||
err = json.Unmarshal(mf, l)
|
err = json.Unmarshal(mf, l)
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// check that layers are annotated and use consistent snapshot naming
|
// check that layers are annotated and use consistent snapshot naming
|
||||||
for _, layer := range l.Layers {
|
for _, layer := range l.Layers {
|
||||||
@@ -69,7 +69,7 @@ func TestGetMetadataManifest(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, err := strconv.Atoi(parts[0])
|
_, err := strconv.Atoi(parts[0])
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +79,10 @@ func TestGetDelegatedMetadataMirrors(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
delegations, err := m.GetDelegatedMetadataMirrors()
|
delegations, err := m.GetDelegatedMetadataMirrors()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
assert.NotNil(t, delegations)
|
assert.NotNil(t, delegations)
|
||||||
assert.Greater(t, len(delegations), 0)
|
assert.Greater(t, len(delegations), 0)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func (m *TufMirror) GetTufTargetMirrors() ([]*MirrorImage, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("missing sha256 hash for target %s", t.Path)
|
return nil, fmt.Errorf("missing sha256 hash for target %s", t.Path)
|
||||||
}
|
}
|
||||||
name := strings.Join([]string{hash.String(), t.Path}, ".")
|
name := hash.String() + "." + t.Path
|
||||||
ann := map[string]string{tufFileAnnotation: name}
|
ann := map[string]string{tufFileAnnotation: name}
|
||||||
layer := mutate.Addendum{Layer: static.NewLayer(data, tufTargetMediaType), Annotations: ann}
|
layer := mutate.Addendum{Layer: static.NewLayer(data, tufTargetMediaType), Annotations: ann}
|
||||||
img, err = mutate.Append(img, layer)
|
img, err = mutate.Append(img, layer)
|
||||||
@@ -86,7 +86,7 @@ func (m *TufMirror) GetDelegatedTargetMirrors() ([]*MirrorIndex, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("failed to find target subdirectory [%s] in path: %s", subdir, target.Path)
|
return nil, fmt.Errorf("failed to find target subdirectory [%s] in path: %s", subdir, target.Path)
|
||||||
}
|
}
|
||||||
name := strings.Join([]string{hash.String(), filename}, ".")
|
name := hash.String() + "." + filename
|
||||||
ann := map[string]string{tufFileAnnotation: name}
|
ann := map[string]string{tufFileAnnotation: name}
|
||||||
layer := mutate.Addendum{Layer: static.NewLayer(data, tufTargetMediaType), Annotations: ann}
|
layer := mutate.Addendum{Layer: static.NewLayer(data, tufTargetMediaType), Annotations: ann}
|
||||||
img, err = mutate.Append(img, layer)
|
img, err = mutate.Append(img, layer)
|
||||||
|
|||||||
@@ -27,22 +27,22 @@ func TestGetTufTargetsMirror(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
targets, err := m.GetTufTargetMirrors()
|
targets, err := m.GetTufTargetMirrors()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Greater(t, len(targets), 0)
|
assert.Greater(t, len(targets), 0)
|
||||||
|
|
||||||
// check for image layer annotations
|
// check for image layer annotations
|
||||||
for _, target := range targets {
|
for _, target := range targets {
|
||||||
img := *target.Image
|
img := *target.Image
|
||||||
mf, err := img.RawManifest()
|
mf, err := img.RawManifest()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// unmarshal manifest with annotations
|
// unmarshal manifest with annotations
|
||||||
l := &Layers{}
|
l := &Layers{}
|
||||||
err = json.Unmarshal(mf, l)
|
err = json.Unmarshal(mf, l)
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// check that layers are annotated
|
// check that layers are annotated
|
||||||
for _, layer := range l.Layers {
|
for _, layer := range l.Layers {
|
||||||
@@ -61,10 +61,10 @@ func TestTargetDelegationMetadata(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
tm, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
tm, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
targets, err := tm.TufClient.LoadDelegatedTargets("test-role", "targets")
|
targets, err := tm.TufClient.LoadDelegatedTargets("test-role", "targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Greater(t, len(targets.Signed.Targets), 0)
|
assert.Greater(t, len(targets.Signed.Targets), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,22 +74,22 @@ func TestGetDelegatedTargetMirrors(t *testing.T) {
|
|||||||
|
|
||||||
path := test.CreateTempDir(t, "", "tuf_temp")
|
path := test.CreateTempDir(t, "", "tuf_temp")
|
||||||
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
m, err := NewTufMirror(embed.DevRoot, path, server.URL+"/metadata", server.URL+"/targets")
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
mirrors, err := m.GetDelegatedTargetMirrors()
|
mirrors, err := m.GetDelegatedTargetMirrors()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Greater(t, len(mirrors), 0)
|
assert.Greater(t, len(mirrors), 0)
|
||||||
|
|
||||||
// check for index image annotations
|
// check for index image annotations
|
||||||
for _, mirror := range mirrors {
|
for _, mirror := range mirrors {
|
||||||
idx := *mirror.Index
|
idx := *mirror.Index
|
||||||
mf, err := idx.RawManifest()
|
mf, err := idx.RawManifest()
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// unmarshal manifest with annotations
|
// unmarshal manifest with annotations
|
||||||
l := &Layers{}
|
l := &Layers{}
|
||||||
err = json.Unmarshal(mf, l)
|
err = json.Unmarshal(mf, l)
|
||||||
assert.Nil(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// check that layers are annotated
|
// check that layers are annotated
|
||||||
for _, layer := range l.Layers {
|
for _, layer := range l.Layers {
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/distribution/reference"
|
"github.com/distribution/reference"
|
||||||
"github.com/docker/attest/internal/util"
|
|
||||||
"github.com/docker/attest/pkg/oci"
|
"github.com/docker/attest/pkg/oci"
|
||||||
"github.com/docker/attest/pkg/tuf"
|
"github.com/docker/attest/pkg/tuf"
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ func findPolicyMatch(named reference.Named, mappings *PolicyMappings) (*PolicyMa
|
|||||||
}
|
}
|
||||||
// now search mirrors
|
// now search mirrors
|
||||||
for _, mirror := range mappings.Mirrors {
|
for _, mirror := range mappings.Mirrors {
|
||||||
if util.StringInSlice(reference.Domain(named), mirror.Mirror.Domains) &&
|
if slices.Contains(mirror.Mirror.Domains, reference.Domain(named)) &&
|
||||||
strings.HasPrefix(reference.Path(named), mirror.Mirror.Prefix) {
|
strings.HasPrefix(reference.Path(named), mirror.Mirror.Prefix) {
|
||||||
for _, mapping := range mappings.Policies {
|
for _, mapping := range mappings.Policies {
|
||||||
if mapping.Name == mirror.Name {
|
if mapping.Name == mirror.Name {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (s *ECDSA256_SignerVerifier) Verify(ctx context.Context, data []byte, sig [
|
|||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("public key is not ecdsa")
|
return fmt.Errorf("public key is not ecdsa")
|
||||||
}
|
}
|
||||||
ok = ecdsa.VerifyASN1(pub, util.S256(data), sig)
|
ok = ecdsa.VerifyASN1(pub, util.SHA256(data), sig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("payload signature is not valid")
|
return fmt.Errorf("payload signature is not valid")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ func KeyID(pubKey crypto.PublicKey) (string, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error marshalling public key: %w", err)
|
return "", fmt.Errorf("error marshalling public key: %w", err)
|
||||||
}
|
}
|
||||||
return util.HexHashBytes(pub), nil
|
return util.SHA256Hex(pub), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@@ -214,7 +213,7 @@ func (tl *RekorTL) VerifyEntryPayload(entryBytes, payload, publicKey []byte) err
|
|||||||
}
|
}
|
||||||
|
|
||||||
// compare payload hashes
|
// compare payload hashes
|
||||||
payloadHash := hex.EncodeToString(util.S256(payload))
|
payloadHash := util.SHA256Hex(payload)
|
||||||
if rekord.Hash != payloadHash {
|
if rekord.Hash != payloadHash {
|
||||||
return fmt.Errorf("error payload and tl entry hash mismatch")
|
return fmt.Errorf("error payload and tl entry hash mismatch")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func TestCreateX509Cert(t *testing.T) {
|
|||||||
func TestUploadAndVerifyLogEntry(t *testing.T) {
|
func TestUploadAndVerifyLogEntry(t *testing.T) {
|
||||||
// message digest
|
// message digest
|
||||||
payload := []byte("test")
|
payload := []byte("test")
|
||||||
hash := util.S256(payload)
|
hash := util.SHA256(payload)
|
||||||
|
|
||||||
// generate ephemeral keys to sign message digest
|
// generate ephemeral keys to sign message digest
|
||||||
signer, err := signerverifier.GenKeyPair()
|
signer, err := signerverifier.GenKeyPair()
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func TestFindFileInManifest(t *testing.T) {
|
|||||||
// make test image manifest
|
// make test image manifest
|
||||||
file := "test.json"
|
file := "test.json"
|
||||||
data := []byte("test")
|
data := []byte("test")
|
||||||
hash := v1.Hash{Algorithm: "sha256", Hex: util.HexHashBytes(data)}
|
hash := v1.Hash{Algorithm: "sha256", Hex: util.SHA256Hex(data)}
|
||||||
img := empty.Image
|
img := empty.Image
|
||||||
img = mutate.MediaType(img, types.OCIManifestSchema1)
|
img = mutate.MediaType(img, types.OCIManifestSchema1)
|
||||||
img = mutate.ConfigMediaType(img, types.OCIConfigJSON)
|
img = mutate.ConfigMediaType(img, types.OCIConfigJSON)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func NewTufClient(initialRoot []byte, tufPath, metadataSource, targetsSource str
|
|||||||
tufSource = OciSource
|
tufSource = OciSource
|
||||||
}
|
}
|
||||||
|
|
||||||
tufRootDigest := util.HexHashBytes(initialRoot)
|
tufRootDigest := util.SHA256Hex(initialRoot)
|
||||||
|
|
||||||
// create a directory for each initial root.json
|
// create a directory for each initial root.json
|
||||||
metadataPath := filepath.Join(tufPath, tufRootDigest)
|
metadataPath := filepath.Join(tufPath, tufRootDigest)
|
||||||
|
|||||||
Reference in New Issue
Block a user