// CreateStatements creates and signs a statement from a stream of grants // and revocations in a JSON array. func CreateStatement(grants, revocations io.Reader, expiration time.Duration, key libtrust.PrivateKey, chain []*x509.Certificate) (*Statement, error) { var statement Statement err := json.NewDecoder(grants).Decode(&statement.jsonStatement.Grants) if err != nil { return nil, err } err = json.NewDecoder(revocations).Decode(&statement.jsonStatement.Revocations) if err != nil { return nil, err } statement.jsonStatement.Expiration = time.Now().UTC().Add(expiration) statement.jsonStatement.IssuedAt = time.Now().UTC() b, err := json.MarshalIndent(&statement.jsonStatement, "", " ") if err != nil { return nil, err } statement.signature, err = libtrust.NewJSONSignature(b) if err != nil { return nil, err } err = statement.signature.SignWithChain(key, chain) if err != nil { return nil, err } return &statement, nil }
func generateStatement(grants []*Grant, key libtrust.PrivateKey, chain []*x509.Certificate) (*Statement, error) { var statement Statement statement.Grants = make([]*jsonGrant, len(grants)) for i, grant := range grants { statement.Grants[i] = &jsonGrant{ Subject: grant.Subject, Permission: grant.Permission, Grantee: grant.Grantee, } } statement.IssuedAt = time.Now() statement.Expiration = time.Now().Add(testStatementExpiration) statement.Revocations = make([]*jsonRevocation, 0) marshalled, err := json.MarshalIndent(statement.jsonStatement, "", " ") if err != nil { return nil, err } sig, err := libtrust.NewJSONSignature(marshalled) if err != nil { return nil, err } err = sig.SignWithChain(key, chain) if err != nil { return nil, err } statement.signature = sig return &statement, nil }
// SignWithChain signs the manifest with the given private key and x509 chain. // The public key of the first element in the chain must be the public key // corresponding with the sign key. func SignWithChain(m *Manifest, key libtrust.PrivateKey, chain []*x509.Certificate) (*SignedManifest, error) { p, err := json.MarshalIndent(m, "", " ") if err != nil { return nil, err } js, err := libtrust.NewJSONSignature(p) if err != nil { return nil, err } if err := js.SignWithChain(key, chain); err != nil { return nil, err } pretty, err := js.PrettySignature("signatures") if err != nil { return nil, err } return &SignedManifest{ Manifest: *m, Raw: pretty, }, nil }
// Sign signs the manifest with the provided private key, returning a // SignedManifest. This typically won't be used within the registry, except // for testing. func Sign(m *Manifest, pk libtrust.PrivateKey) (*SignedManifest, error) { p, err := json.MarshalIndent(m, "", " ") if err != nil { return nil, err } js, err := libtrust.NewJSONSignature(p) if err != nil { return nil, err } if err := js.Sign(pk); err != nil { return nil, err } pretty, err := js.PrettySignature("signatures") if err != nil { return nil, err } return &SignedManifest{ Manifest: *m, Raw: pretty, }, nil }
// get retrieves the manifest, keyed by revision digest. func (rs *revisionStore) get(ctx context.Context, revision digest.Digest) (*manifest.SignedManifest, error) { // Ensure that this revision is available in this repository. _, err := rs.blobStore.Stat(ctx, revision) if err != nil { if err == distribution.ErrBlobUnknown { return nil, distribution.ErrManifestUnknownRevision{ Name: rs.repository.Name(), Revision: revision, } } return nil, err } // TODO(stevvooe): Need to check descriptor from above to ensure that the // mediatype is as we expect for the manifest store. content, err := rs.blobStore.Get(ctx, revision) if err != nil { if err == distribution.ErrBlobUnknown { return nil, distribution.ErrManifestUnknownRevision{ Name: rs.repository.Name(), Revision: revision, } } return nil, err } // Fetch the signatures for the manifest signatures, err := rs.repository.Signatures().Get(revision) if err != nil { return nil, err } jsig, err := libtrust.NewJSONSignature(content, signatures...) if err != nil { return nil, err } // Extract the pretty JWS raw, err := jsig.PrettySignature("signatures") if err != nil { return nil, err } var sm manifest.SignedManifest if err := json.Unmarshal(raw, &sm); err != nil { return nil, err } return &sm, nil }
func (s *TagStore) pushV2Repository(r *registry.Session, localRepo Repository, out io.Writer, repoInfo *registry.RepositoryInfo, tag string, sf *utils.StreamFormatter) error { endpoint, err := r.V2RegistryEndpoint(repoInfo.Index) if err != nil { if repoInfo.Index.Official { log.Debugf("Unable to push to V2 registry, falling back to v1: %s", err) return ErrV2RegistryUnavailable } return fmt.Errorf("error getting registry endpoint: %s", err) } tags, err := s.getImageTags(localRepo, tag) if err != nil { return err } if len(tags) == 0 { return fmt.Errorf("No tags to push for %s", repoInfo.LocalName) } auth, err := r.GetV2Authorization(endpoint, repoInfo.RemoteName, false) if err != nil { return fmt.Errorf("error getting authorization: %s", err) } for _, tag := range tags { log.Debugf("Pushing repository: %s:%s", repoInfo.CanonicalName, tag) layerId, exists := localRepo[tag] if !exists { return fmt.Errorf("tag does not exist: %s", tag) } layer, err := s.graph.Get(layerId) if err != nil { return err } m := ®istry.ManifestData{ SchemaVersion: 1, Name: repoInfo.RemoteName, Tag: tag, Architecture: layer.Architecture, } var metadata runconfig.Config if layer.Config != nil { metadata = *layer.Config } layersSeen := make(map[string]bool) layers := []*image.Image{layer} for ; layer != nil; layer, err = layer.GetParent() { if err != nil { return err } if layersSeen[layer.ID] { break } layers = append(layers, layer) layersSeen[layer.ID] = true } m.FSLayers = make([]*registry.FSLayer, len(layers)) m.History = make([]*registry.ManifestHistory, len(layers)) // Schema version 1 requires layer ordering from top to root for i, layer := range layers { log.Debugf("Pushing layer: %s", layer.ID) if layer.Config != nil && metadata.Image != layer.ID { err = runconfig.Merge(&metadata, layer.Config) if err != nil { return err } } jsonData, err := layer.RawJson() if err != nil { return fmt.Errorf("cannot retrieve the path for %s: %s", layer.ID, err) } checksum, err := layer.GetCheckSum(s.graph.ImageRoot(layer.ID)) if err != nil { return fmt.Errorf("error getting image checksum: %s", err) } var exists bool if len(checksum) > 0 { sumParts := strings.SplitN(checksum, ":", 2) if len(sumParts) < 2 { return fmt.Errorf("Invalid checksum: %s", checksum) } // Call mount blob exists, err = r.HeadV2ImageBlob(endpoint, repoInfo.RemoteName, sumParts[0], sumParts[1], auth) if err != nil { out.Write(sf.FormatProgress(stringid.TruncateID(layer.ID), "Image push failed", nil)) return err } } if !exists { if cs, err := s.pushV2Image(r, layer, endpoint, repoInfo.RemoteName, sf, out, auth); err != nil { return err } else if cs != checksum { // Cache new checksum if err := layer.SaveCheckSum(s.graph.ImageRoot(layer.ID), cs); err != nil { return err } checksum = cs } } else { out.Write(sf.FormatProgress(stringid.TruncateID(layer.ID), "Image already exists", nil)) } m.FSLayers[i] = ®istry.FSLayer{BlobSum: checksum} m.History[i] = ®istry.ManifestHistory{V1Compatibility: string(jsonData)} } if err := checkValidManifest(m); err != nil { return fmt.Errorf("invalid manifest: %s", err) } log.Debugf("Pushing %s:%s to v2 repository", repoInfo.LocalName, tag) mBytes, err := json.MarshalIndent(m, "", " ") if err != nil { return err } js, err := libtrust.NewJSONSignature(mBytes) if err != nil { return err } if err = js.Sign(s.trustKey); err != nil { return err } signedBody, err := js.PrettySignature("signatures") if err != nil { return err } 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, signedBody, mBytes, auth) if err != nil { return err } out.Write(sf.FormatStatus("", "Digest: %s", digest)) } return nil }