// verifyManifest ensures that the manifest content is valid from the // perspective of the registry. It ensures that the signature is valid for the // enclosed payload. As a policy, the registry only tries to store valid // content, leaving trust policies of that content up to consumers. func (ms *signedManifestHandler) verifyManifest(ctx context.Context, mnfst schema1.SignedManifest, skipDependencyVerification bool) error { var errs distribution.ErrManifestVerification if len(mnfst.Name) > reference.NameTotalLengthMax { errs = append(errs, distribution.ErrManifestNameInvalid{ Name: mnfst.Name, Reason: fmt.Errorf("manifest name must not be more than %v characters", reference.NameTotalLengthMax), }) } if !reference.NameRegexp.MatchString(mnfst.Name) { errs = append(errs, distribution.ErrManifestNameInvalid{ Name: mnfst.Name, Reason: fmt.Errorf("invalid manifest name format"), }) } if len(mnfst.History) != len(mnfst.FSLayers) { errs = append(errs, fmt.Errorf("mismatched history and fslayer cardinality %d != %d", len(mnfst.History), len(mnfst.FSLayers))) } if _, err := schema1.Verify(&mnfst); err != nil { switch err { case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey: errs = append(errs, distribution.ErrManifestUnverified{}) default: if err.Error() == "invalid signature" { // TODO(stevvooe): This should be exported by libtrust errs = append(errs, distribution.ErrManifestUnverified{}) } else { errs = append(errs, err) } } } if !skipDependencyVerification { for _, fsLayer := range mnfst.References() { _, err := ms.repository.Blobs(ctx).Stat(ctx, fsLayer.Digest) if err != nil { if err != distribution.ErrBlobUnknown { errs = append(errs, err) } // On error here, we always append unknown blob errors. errs = append(errs, distribution.ErrManifestBlobUnknown{Digest: fsLayer.Digest}) } } } if len(errs) != 0 { return errs } return nil }
// signedManifestFillImageMetadata fills a given image with metadata. It also corrects layer sizes with blob sizes. Newer // Docker client versions don't set layer sizes in the manifest at all. Origin master needs correct layer // sizes for proper image quota support. That's why we need to fill the metadata in the registry. func (r *repository) signedManifestFillImageMetadata(manifest *schema1.SignedManifest, image *imageapi.Image) error { signatures, err := manifest.Signatures() if err != nil { return err } for _, signDigest := range signatures { image.DockerImageSignatures = append(image.DockerImageSignatures, signDigest) } if err := imageapi.ImageWithMetadata(image); err != nil { return err } refs := manifest.References() blobSet := sets.NewString() image.DockerImageMetadata.Size = int64(0) blobs := r.Blobs(r.ctx) for i := range image.DockerImageLayers { layer := &image.DockerImageLayers[i] // DockerImageLayers represents manifest.Manifest.FSLayers in reversed order desc, err := blobs.Stat(r.ctx, refs[len(image.DockerImageLayers)-i-1].Digest) if err != nil { context.GetLogger(r.ctx).Errorf("failed to stat blobs %s of image %s", layer.Name, image.DockerImageReference) return err } if layer.MediaType == "" { if desc.MediaType != "" { layer.MediaType = desc.MediaType } else { layer.MediaType = schema1.MediaTypeManifestLayer } } layer.LayerSize = desc.Size // count empty layer just once (empty layer may actually have non-zero size) if !blobSet.Has(layer.Name) { image.DockerImageMetadata.Size += desc.Size blobSet.Insert(layer.Name) } } if len(image.DockerImageConfig) > 0 && !blobSet.Has(image.DockerImageMetadata.ID) { blobSet.Insert(image.DockerImageMetadata.ID) image.DockerImageMetadata.Size += int64(len(image.DockerImageConfig)) } return nil }