// Put stores the content p in the blob store, calculating the digest. If the // content is already present, only the digest will be returned. This should // only be used for small objects, such as manifests. This implemented as a convenience for other Put implementations func (bs *blobStore) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) { dgst, err := digest.FromBytes(p) if err != nil { context.GetLogger(ctx).Errorf("blobStore: error digesting content: %v, %s", err, string(p)) return distribution.Descriptor{}, err } desc, err := bs.statter.Stat(ctx, dgst) if err == nil { // content already present return desc, nil } else if err != distribution.ErrBlobUnknown { context.GetLogger(ctx).Errorf("blobStore: error stating content (%v): %#v", dgst, err) // real error, return it return distribution.Descriptor{}, err } bp, err := bs.path(dgst) if err != nil { return distribution.Descriptor{}, err } // TODO(stevvooe): Write out mediatype here, as well. return distribution.Descriptor{ Size: int64(len(p)), // NOTE(stevvooe): The central blob store firewalls media types from // other users. The caller should look this up and override the value // for the specific repository. MediaType: "application/octet-stream", Digest: dgst, }, bs.driver.PutContent(ctx, bp, p) }
// Finally Push the (signed) manifest of the blobs we've just pushed func (r *Session) PutV2ImageManifest(ep *Endpoint, imageName, tagName string, signedManifest, rawManifest []byte, auth *RequestAuthorization) (digest.Digest, error) { routeURL, err := getV2Builder(ep).BuildManifestURL(imageName, tagName) if err != nil { return "", err } method := "PUT" log.Debugf("[registry] Calling %q %s", method, routeURL) req, err := r.reqFactory.NewRequest(method, routeURL, bytes.NewReader(signedManifest)) if err != nil { return "", err } if err := auth.Authorize(req); err != nil { return "", err } res, _, err := r.doRequest(req) if err != nil { return "", err } defer res.Body.Close() // All 2xx and 3xx responses can be accepted for a put. if res.StatusCode >= 400 { if res.StatusCode == 401 { return "", errLoginRequired } errBody, err := ioutil.ReadAll(res.Body) if err != nil { return "", err } log.Debugf("Unexpected response from server: %q %#v", errBody, res.Header) return "", utils.NewHTTPRequestError(fmt.Sprintf("Server error: %d trying to push %s:%s manifest", res.StatusCode, imageName, tagName), res) } hdrDigest, err := digest.ParseDigest(res.Header.Get(DockerDigestHeader)) if err != nil { return "", fmt.Errorf("invalid manifest digest from registry: %s", err) } dgstVerifier, err := digest.NewDigestVerifier(hdrDigest) if err != nil { return "", fmt.Errorf("invalid manifest digest from registry: %s", err) } dgstVerifier.Write(rawManifest) if !dgstVerifier.Verified() { computedDigest, _ := digest.FromBytes(rawManifest) return "", fmt.Errorf("unable to verify manifest digest: registry has %q, computed %q", hdrDigest, computedDigest) } return hdrDigest, nil }
func digestFromManifest(m *manifest.SignedManifest, localName string) (digest.Digest, int, error) { payload, err := m.Payload() if err != nil { // If this failed, the signatures section was corrupted // or missing. Treat the entire manifest as the payload. payload = m.Raw } manifestDigest, err := digest.FromBytes(payload) if err != nil { logrus.Infof("Could not compute manifest digest for %s:%s : %v", localName, m.Tag, err) } return manifestDigest, len(payload), nil }
func manifestDigest(sm *manifest.SignedManifest) (digest.Digest, error) { payload, err := sm.Payload() if err != nil { return "", err } dgst, err := digest.FromBytes(payload) if err != nil { return "", err } return dgst, nil }
func (p *v2Puller) tryNextID(imgs []contentAddressableDescriptor, i int, idMap map[string]struct{}) error { nextID, _ := digest.FromBytes([]byte(imgs[i].id)) imgs[i].id = nextID.Hex() if _, exists := idMap[imgs[i].id]; !exists { p.graph.imageMutex.Lock(imgs[i].id) defer p.graph.imageMutex.Unlock(imgs[i].id) } if p.graph.Exists(imgs[i].id) { if err := p.validateImageInGraph(imgs[i].id, imgs, i); err != nil { return fmt.Errorf("not using existing strongID permutation %s: %v", imgs[i].id, err) } } return nil }
func (lbs *linkedBlobStore) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) { dgst, err := digest.FromBytes(p) if err != nil { return distribution.Descriptor{}, err } // Place the data in the blob store first. desc, err := lbs.blobStore.Put(ctx, mediaType, p) if err != nil { context.GetLogger(ctx).Errorf("error putting into main store: %v", err) return distribution.Descriptor{}, err } if err := lbs.blobAccessController.SetDescriptor(ctx, dgst, desc); err != nil { return distribution.Descriptor{}, err } // TODO(stevvooe): Write out mediatype if incoming differs from what is // returned by Put above. Note that we should allow updates for a given // repository. return desc, lbs.linkBlob(ctx, desc) }
// digestManifest takes a digest of the given manifest. This belongs somewhere // better but we'll wait for a refactoring cycle to find that real somewhere. func digestManifest(ctx context.Context, sm *manifest.SignedManifest) (digest.Digest, error) { p, err := sm.Payload() if err != nil { if !strings.Contains(err.Error(), "missing signature key") { ctxu.GetLogger(ctx).Errorf("error getting manifest payload: %v", err) return "", err } // NOTE(stevvooe): There are no signatures but we still have a // payload. The request will fail later but this is not the // responsibility of this part of the code. p = sm.Raw } dgst, err := digest.FromBytes(p) if err != nil { ctxu.GetLogger(ctx).Errorf("error digesting manifest: %v", err) return "", err } return dgst, err }
func (b *bridge) createManifestEvent(action string, repo string, sm *manifest.SignedManifest) (*Event, error) { event := b.createEvent(action) event.Target.MediaType = manifest.ManifestMediaType event.Target.Repository = repo p, err := sm.Payload() if err != nil { return nil, err } event.Target.Length = int64(len(p)) event.Target.Size = int64(len(p)) event.Target.Digest, err = digest.FromBytes(p) if err != nil { return nil, err } event.Target.URL, err = b.ub.BuildManifestURL(sm.Name, event.Target.Digest.String()) if err != nil { return nil, err } return event, nil }
// loadManifest loads a manifest from a byte array and verifies its content. // The signature must be verified or an error is returned. If the manifest // 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, 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) } keys, err := sig.Verify() if err != nil { return nil, false, fmt.Errorf("error verifying payload: %s", err) } payload, err := sig.Payload() if err != nil { 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) } if manifest.SchemaVersion != 1 { return nil, false, fmt.Errorf("unsupported schema version: %d", manifest.SchemaVersion) } var verified bool for _, key := range keys { job := eng.Job("trust_key_check") b, err := key.MarshalJSON() if err != nil { return nil, false, fmt.Errorf("error marshalling public key: %s", err) } namespace := manifest.Name if namespace[0] != '/' { namespace = "/" + namespace } stdoutBuffer := bytes.NewBuffer(nil) job.Args = append(job.Args, namespace) job.Setenv("PublicKey", string(b)) // Check key has read/write permission (0x03) job.SetenvInt("Permission", 0x03) job.Stdout.Add(stdoutBuffer) if err = job.Run(); err != nil { return nil, false, fmt.Errorf("error running key check: %s", err) } result := engine.Tail(stdoutBuffer, 1) log.Debugf("Key check result: %q", result) if result == "verified" { verified = true } } return &manifest, verified, nil }