github.com/bdehamer/docker@v1.5.0/graph/manifest.go (about)

     1  package graph
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  
    10  	log "github.com/Sirupsen/logrus"
    11  	"github.com/docker/docker/engine"
    12  	"github.com/docker/docker/pkg/tarsum"
    13  	"github.com/docker/docker/registry"
    14  	"github.com/docker/docker/runconfig"
    15  	"github.com/docker/libtrust"
    16  )
    17  
    18  func (s *TagStore) newManifest(localName, remoteName, tag string) ([]byte, error) {
    19  	manifest := &registry.ManifestData{
    20  		Name:          remoteName,
    21  		Tag:           tag,
    22  		SchemaVersion: 1,
    23  	}
    24  	localRepo, err := s.Get(localName)
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  	if localRepo == nil {
    29  		return nil, fmt.Errorf("Repo does not exist: %s", localName)
    30  	}
    31  
    32  	// Get the top-most layer id which the tag points to
    33  	layerId, exists := localRepo[tag]
    34  	if !exists {
    35  		return nil, fmt.Errorf("Tag does not exist for %s: %s", localName, tag)
    36  	}
    37  	layersSeen := make(map[string]bool)
    38  
    39  	layer, err := s.graph.Get(layerId)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	manifest.Architecture = layer.Architecture
    44  	manifest.FSLayers = make([]*registry.FSLayer, 0, 4)
    45  	manifest.History = make([]*registry.ManifestHistory, 0, 4)
    46  	var metadata runconfig.Config
    47  	if layer.Config != nil {
    48  		metadata = *layer.Config
    49  	}
    50  
    51  	for ; layer != nil; layer, err = layer.GetParent() {
    52  		if err != nil {
    53  			return nil, err
    54  		}
    55  
    56  		if layersSeen[layer.ID] {
    57  			break
    58  		}
    59  		if layer.Config != nil && metadata.Image != layer.ID {
    60  			err = runconfig.Merge(&metadata, layer.Config)
    61  			if err != nil {
    62  				return nil, err
    63  			}
    64  		}
    65  
    66  		checksum, err := layer.GetCheckSum(s.graph.ImageRoot(layer.ID))
    67  		if err != nil {
    68  			return nil, fmt.Errorf("Error getting image checksum: %s", err)
    69  		}
    70  		if tarsum.VersionLabelForChecksum(checksum) != tarsum.Version1.String() {
    71  			archive, err := layer.TarLayer()
    72  			if err != nil {
    73  				return nil, err
    74  			}
    75  
    76  			tarSum, err := tarsum.NewTarSum(archive, true, tarsum.Version1)
    77  			if err != nil {
    78  				return nil, err
    79  			}
    80  			if _, err := io.Copy(ioutil.Discard, tarSum); err != nil {
    81  				return nil, err
    82  			}
    83  
    84  			checksum = tarSum.Sum(nil)
    85  
    86  			// Save checksum value
    87  			if err := layer.SaveCheckSum(s.graph.ImageRoot(layer.ID), checksum); err != nil {
    88  				return nil, err
    89  			}
    90  		}
    91  
    92  		jsonData, err := layer.RawJson()
    93  		if err != nil {
    94  			return nil, fmt.Errorf("Cannot retrieve the path for {%s}: %s", layer.ID, err)
    95  		}
    96  
    97  		manifest.FSLayers = append(manifest.FSLayers, &registry.FSLayer{BlobSum: checksum})
    98  
    99  		layersSeen[layer.ID] = true
   100  
   101  		manifest.History = append(manifest.History, &registry.ManifestHistory{V1Compatibility: string(jsonData)})
   102  	}
   103  
   104  	manifestBytes, err := json.MarshalIndent(manifest, "", "   ")
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	return manifestBytes, nil
   110  }
   111  
   112  // loadManifest loads a manifest from a byte array and verifies its content.
   113  // The signature must be verified or an error is returned. If the manifest
   114  // contains no signatures by a trusted key for the name in the manifest, the
   115  // image is not considered verified. The parsed manifest object and a boolean
   116  // for whether the manifest is verified is returned.
   117  func (s *TagStore) loadManifest(eng *engine.Engine, manifestBytes []byte) (*registry.ManifestData, bool, error) {
   118  	sig, err := libtrust.ParsePrettySignature(manifestBytes, "signatures")
   119  	if err != nil {
   120  		return nil, false, fmt.Errorf("error parsing payload: %s", err)
   121  	}
   122  
   123  	keys, err := sig.Verify()
   124  	if err != nil {
   125  		return nil, false, fmt.Errorf("error verifying payload: %s", err)
   126  	}
   127  
   128  	payload, err := sig.Payload()
   129  	if err != nil {
   130  		return nil, false, fmt.Errorf("error retrieving payload: %s", err)
   131  	}
   132  
   133  	var manifest registry.ManifestData
   134  	if err := json.Unmarshal(payload, &manifest); err != nil {
   135  		return nil, false, fmt.Errorf("error unmarshalling manifest: %s", err)
   136  	}
   137  	if manifest.SchemaVersion != 1 {
   138  		return nil, false, fmt.Errorf("unsupported schema version: %d", manifest.SchemaVersion)
   139  	}
   140  
   141  	var verified bool
   142  	for _, key := range keys {
   143  		job := eng.Job("trust_key_check")
   144  		b, err := key.MarshalJSON()
   145  		if err != nil {
   146  			return nil, false, fmt.Errorf("error marshalling public key: %s", err)
   147  		}
   148  		namespace := manifest.Name
   149  		if namespace[0] != '/' {
   150  			namespace = "/" + namespace
   151  		}
   152  		stdoutBuffer := bytes.NewBuffer(nil)
   153  
   154  		job.Args = append(job.Args, namespace)
   155  		job.Setenv("PublicKey", string(b))
   156  		// Check key has read/write permission (0x03)
   157  		job.SetenvInt("Permission", 0x03)
   158  		job.Stdout.Add(stdoutBuffer)
   159  		if err = job.Run(); err != nil {
   160  			return nil, false, fmt.Errorf("error running key check: %s", err)
   161  		}
   162  		result := engine.Tail(stdoutBuffer, 1)
   163  		log.Debugf("Key check result: %q", result)
   164  		if result == "verified" {
   165  			verified = true
   166  		}
   167  	}
   168  
   169  	return &manifest, verified, nil
   170  }
   171  
   172  func checkValidManifest(manifest *registry.ManifestData) error {
   173  	if len(manifest.FSLayers) != len(manifest.History) {
   174  		return fmt.Errorf("length of history not equal to number of layers")
   175  	}
   176  
   177  	if len(manifest.FSLayers) == 0 {
   178  		return fmt.Errorf("no FSLayers in manifest")
   179  	}
   180  
   181  	return nil
   182  }