github.com/thieman/docker@v1.6.0/graph/manifest.go (about)

     1  package graph
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  
     8  	log "github.com/Sirupsen/logrus"
     9  	"github.com/docker/distribution/digest"
    10  	"github.com/docker/docker/engine"
    11  	"github.com/docker/docker/registry"
    12  	"github.com/docker/docker/utils"
    13  	"github.com/docker/libtrust"
    14  )
    15  
    16  // loadManifest loads a manifest from a byte array and verifies its content.
    17  // The signature must be verified or an error is returned. If the manifest
    18  // contains no signatures by a trusted key for the name in the manifest, the
    19  // image is not considered verified. The parsed manifest object and a boolean
    20  // for whether the manifest is verified is returned.
    21  func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte, dgst, ref string) (*registry.ManifestData, bool, error) {
    22  	sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures")
    23  	if err != nil {
    24  		return nil, false, fmt.Errorf("error parsing payload: %s", err)
    25  	}
    26  
    27  	keys, err := sig.Verify()
    28  	if err != nil {
    29  		return nil, false, fmt.Errorf("error verifying payload: %s", err)
    30  	}
    31  
    32  	payload, err := sig.Payload()
    33  	if err != nil {
    34  		return nil, false, fmt.Errorf("error retrieving payload: %s", err)
    35  	}
    36  
    37  	var manifestDigest digest.Digest
    38  
    39  	if dgst != "" {
    40  		manifestDigest, err = digest.ParseDigest(dgst)
    41  		if err != nil {
    42  			return nil, false, fmt.Errorf("invalid manifest digest from registry: %s", err)
    43  		}
    44  
    45  		dgstVerifier, err := digest.NewDigestVerifier(manifestDigest)
    46  		if err != nil {
    47  			return nil, false, fmt.Errorf("unable to verify manifest digest from registry: %s", err)
    48  		}
    49  
    50  		dgstVerifier.Write(payload)
    51  
    52  		if !dgstVerifier.Verified() {
    53  			computedDigest, _ := digest.FromBytes(payload)
    54  			return nil, false, fmt.Errorf("unable to verify manifest digest: registry has %q, computed %q", manifestDigest, computedDigest)
    55  		}
    56  	}
    57  
    58  	if utils.DigestReference(ref) && ref != manifestDigest.String() {
    59  		return nil, false, fmt.Errorf("mismatching image manifest digest: got %q, expected %q", manifestDigest, ref)
    60  	}
    61  
    62  	var manifest registry.ManifestData
    63  	if err := json.Unmarshal(payload, &manifest); err != nil {
    64  		return nil, false, fmt.Errorf("error unmarshalling manifest: %s", err)
    65  	}
    66  	if manifest.SchemaVersion != 1 {
    67  		return nil, false, fmt.Errorf("unsupported schema version: %d", manifest.SchemaVersion)
    68  	}
    69  
    70  	var verified bool
    71  	for _, key := range keys {
    72  		job := eng.Job("trust_key_check")
    73  		b, err := key.MarshalJSON()
    74  		if err != nil {
    75  			return nil, false, fmt.Errorf("error marshalling public key: %s", err)
    76  		}
    77  		namespace := manifest.Name
    78  		if namespace[0] != '/' {
    79  			namespace = "/" + namespace
    80  		}
    81  		stdoutBuffer := bytes.NewBuffer(nil)
    82  
    83  		job.Args = append(job.Args, namespace)
    84  		job.Setenv("PublicKey", string(b))
    85  		// Check key has read/write permission (0x03)
    86  		job.SetenvInt("Permission", 0x03)
    87  		job.Stdout.Add(stdoutBuffer)
    88  		if err = job.Run(); err != nil {
    89  			return nil, false, fmt.Errorf("error running key check: %s", err)
    90  		}
    91  		result := engine.Tail(stdoutBuffer, 1)
    92  		log.Debugf("Key check result: %q", result)
    93  		if result == "verified" {
    94  			verified = true
    95  		}
    96  	}
    97  
    98  	return &manifest, verified, nil
    99  }
   100  
   101  func checkValidManifest(manifest *registry.ManifestData) error {
   102  	if len(manifest.FSLayers) != len(manifest.History) {
   103  		return fmt.Errorf("length of history not equal to number of layers")
   104  	}
   105  
   106  	if len(manifest.FSLayers) == 0 {
   107  		return fmt.Errorf("no FSLayers in manifest")
   108  	}
   109  
   110  	return nil
   111  }