mirror of
https://github.com/clearlinux/docker.git
synced 2026-09-04 20:51:44 +00:00
Add verification of image manifest digests
Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
This commit is contained in:
+28
-1
@@ -6,8 +6,10 @@ import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/docker/engine"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/utils"
|
||||
"github.com/docker/libtrust"
|
||||
)
|
||||
|
||||
@@ -16,7 +18,7 @@ import (
|
||||
// contains no signatures by a trusted key for the name in the manifest, the
|
||||
// image is not considered verified. The parsed manifest object and a boolean
|
||||
// for whether the manifest is verified is returned.
|
||||
func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte) (*registry.ManifestData, bool, error) {
|
||||
func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte, dgst, ref string) (*registry.ManifestData, bool, error) {
|
||||
sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures")
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("error parsing payload: %s", err)
|
||||
@@ -32,6 +34,31 @@ func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte) (*regi
|
||||
return nil, false, fmt.Errorf("error retrieving payload: %s", err)
|
||||
}
|
||||
|
||||
var manifestDigest digest.Digest
|
||||
|
||||
if dgst != "" {
|
||||
manifestDigest, err = digest.ParseDigest(dgst)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("invalid manifest digest from registry: %s", err)
|
||||
}
|
||||
|
||||
dgstVerifier, err := digest.NewDigestVerifier(manifestDigest)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("unable to verify manifest digest from registry: %s", err)
|
||||
}
|
||||
|
||||
dgstVerifier.Write(payload)
|
||||
|
||||
if !dgstVerifier.Verified() {
|
||||
computedDigest, _ := digest.FromBytes(payload)
|
||||
return nil, false, fmt.Errorf("unable to verify manifest digest: registry has %q, computed %q", manifestDigest, computedDigest)
|
||||
}
|
||||
}
|
||||
|
||||
if utils.DigestReference(ref) && ref != manifestDigest.String() {
|
||||
return nil, false, fmt.Errorf("mismatching image manifest digest: got %q, expected %q", manifestDigest, ref)
|
||||
}
|
||||
|
||||
var manifest registry.ManifestData
|
||||
if err := json.Unmarshal(payload, &manifest); err != nil {
|
||||
return nil, false, fmt.Errorf("error unmarshalling manifest: %s", err)
|
||||
|
||||
+5
-2
@@ -430,12 +430,15 @@ func (s *TagStore) pullV2Repository(eng *engine.Engine, r *registry.Session, out
|
||||
|
||||
func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Writer, endpoint *registry.Endpoint, repoInfo *registry.RepositoryInfo, tag string, sf *utils.StreamFormatter, parallel bool, auth *registry.RequestAuthorization) (bool, error) {
|
||||
log.Debugf("Pulling tag from V2 registry: %q", tag)
|
||||
|
||||
manifestBytes, manifestDigest, err := r.GetV2ImageManifest(endpoint, repoInfo.RemoteName, tag, auth)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
manifest, verified, err := s.loadManifest(eng, manifestBytes)
|
||||
// loadManifest ensures that the manifest payload has the expected digest
|
||||
// if the tag is a digest reference.
|
||||
manifest, verified, err := s.loadManifest(eng, manifestBytes, manifestDigest, tag)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error verifying manifest: %s", err)
|
||||
}
|
||||
@@ -605,7 +608,7 @@ func (s *TagStore) pullV2Tag(eng *engine.Engine, r *registry.Session, out io.Wri
|
||||
out.Write(sf.FormatStatus(utils.ImageReference(repoInfo.CanonicalName, tag), "The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security."))
|
||||
}
|
||||
|
||||
if len(manifestDigest) > 0 {
|
||||
if manifestDigest != "" {
|
||||
out.Write(sf.FormatStatus("", "Digest: %s", manifestDigest))
|
||||
}
|
||||
|
||||
|
||||
+2
-5
@@ -1,7 +1,6 @@
|
||||
package graph
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -432,14 +431,12 @@ func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, o
|
||||
log.Infof("Signed manifest for %s:%s using daemon's key: %s", repoInfo.LocalName, tag, s.trustKey.KeyID())
|
||||
|
||||
// push the manifest
|
||||
digest, err := r.PutV2ImageManifest(endpoint, repoInfo.RemoteName, tag, bytes.NewReader(signedBody), auth)
|
||||
digest, err := r.PutV2ImageManifest(endpoint, repoInfo.RemoteName, tag, signedBody, mBytes, auth)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(digest) > 0 {
|
||||
out.Write(sf.FormatStatus("", "Digest: %s", digest))
|
||||
}
|
||||
out.Write(sf.FormatStatus("", "Digest: %s", digest))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user