diff --git a/cmd/tuf-notary/sign.go b/cmd/tuf-notary/sign.go new file mode 100644 index 0000000..d872f1c --- /dev/null +++ b/cmd/tuf-notary/sign.go @@ -0,0 +1,84 @@ +package main + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "strconv" + + docopt "github.com/docopt/docopt-go" + tufnotary "github.com/notaryproject/tuf/tuf-notary" + godigest "github.com/opencontainers/go-digest" + artifactspec "github.com/oras-project/artifacts-spec/specs-go/v1" +) + +func init() { + register("sign", cmdSign, ` +usage: tuf-notary sign [--repo=] + +Sign digest and upload the signature alongside it to rolename repo on +the registry. This will add a tuf targets metadata file to the repository. + +Options: + --repo Set the tuf repository name. By default this will be 'tuf-repo' + `) +} + +func cmdSign(args []string, opts docopt.Opts) error { + repository := "tuf-repo" + if r := opts["--repo"]; r != nil { + repository = r.(string) + } + + registry := args[0] + signer := args[1] + digest := args[2] + length, err := strconv.ParseInt(args[3], 10, 64) + if err != nil { + return err + } + mediatype := args[4] + + //TODO verify these + err = tufnotary.DownloadTUFMetadata(registry, repository, "root") + if err != nil { + return err + } + err = tufnotary.DownloadTUFMetadata(registry, repository, "targets") + if err != nil { + return err + } + + //TODO add new delegation in the repo for this signature, add this there + // blocking on the delegations pr in go-tuf + + descriptor := artifactspec.Descriptor{ + MediaType: mediatype, + Digest: godigest.FromString(digest), + Size: length, + } + bytes, _ := json.Marshal(&descriptor) + fmt.Println(json.RawMessage(bytes)) + err = tufnotary.Sign(repository, signer, digest, length, json.RawMessage(bytes)) + + if err != nil { + return err + } + + //TODO: once the signature is added to the correct delegated metadata, + //upload the correct thing here + + //upload targets with a reference to root metadata + filename := fmt.Sprintf("%s/staged/%s.json", repository, "targets") + contents, err := ioutil.ReadFile(filename) + if err != nil { + return fmt.Errorf("failed to read %s: %w", filename, err) + } + targets_desc, err := tufnotary.UploadTUFMetadata(registry, repository, "targets", contents, "root") + if err != nil { + return err + } + fmt.Println("uploaded targets " + targets_desc.Digest.String()) + + return err +} diff --git a/go.mod b/go.mod index 14d0f54..2ea5fca 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/opencontainers/image-spec v1.0.1 github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 github.com/stretchr/testify v1.7.0 - github.com/theupdateframework/go-tuf v0.0.0-20211018203538-5908a16987fa + github.com/theupdateframework/go-tuf v0.0.0-20220126190704-b1554f825046 oras.land/oras-go v0.5.0 ) @@ -46,12 +46,14 @@ require ( github.com/moby/term v0.0.0-20200312100748-672ec06f55cd // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.7.1 // indirect github.com/prometheus/client_model v0.2.0 // indirect github.com/prometheus/common v0.10.0 // indirect github.com/prometheus/procfs v0.6.0 // indirect + github.com/secure-systems-lab/go-securesystemslib v0.3.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/cobra v1.2.1 // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -59,11 +61,11 @@ require ( github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 // indirect github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 // indirect github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f // indirect - golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect + golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect - golang.org/x/text v0.3.5 // indirect + golang.org/x/text v0.3.6 // indirect google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect google.golang.org/grpc v1.38.0 // indirect google.golang.org/protobuf v1.26.0 // indirect diff --git a/go.sum b/go.sum index b852afe..9b08984 100644 --- a/go.sum +++ b/go.sum @@ -138,6 +138,7 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -583,6 +584,8 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 h1:2YMUDyDH0glYA4gNG/zEg9HNVzgGX8kr/NBLR9AQkLQ= +github.com/oras-project/artifacts-spec v1.0.0-draft.1.1/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= @@ -642,6 +645,8 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/secure-systems-lab/go-securesystemslib v0.3.0 h1:PH0mUKuUSXVEVDbrKMgGPcrqrnKA8gJii614+EKKi7g= +github.com/secure-systems-lab/go-securesystemslib v0.3.0/go.mod h1:o8hhjkbNl2gOamKUA/eNW3xUrntHT9L4W89W1nfj43U= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= @@ -700,6 +705,8 @@ github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q91 github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug= github.com/theupdateframework/go-tuf v0.0.0-20211018203538-5908a16987fa h1:MMp8facAo/gVHqBZ9J73Kkv18W3gdJGvmAYZNaD1rnU= github.com/theupdateframework/go-tuf v0.0.0-20211018203538-5908a16987fa/go.mod h1:pQW1KcCMYPCuZ4pvCkYQhoE2k9SzTuh31AWhf1j/7HM= +github.com/theupdateframework/go-tuf v0.0.0-20220126190704-b1554f825046 h1:+h1qapiqyJN+rb+dxgdtAsDrwBRr2qHk3nF3ITqxzew= +github.com/theupdateframework/go-tuf v0.0.0-20220126190704-b1554f825046/go.mod h1:I0Gs4Tev4hYQ5wiNqN8VJ7qS0gw7KOZNQuckC624RmE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= @@ -774,6 +781,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= +golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -859,6 +868,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -961,12 +972,14 @@ golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -975,6 +988,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/registry-access.go b/registry-access.go index 82bee66..bb9f10b 100644 --- a/registry-access.go +++ b/registry-access.go @@ -47,3 +47,21 @@ func UploadTUFMetadata(registry string, repository string, name string, contents return desc, nil } + +func DownloadTUFMetadata(registry string, repository string, name string) error { + ref := registry + "/" + repository + ":" + name + + mediaType := "application/vnd.cncf.notary.tuf+json" + ctx := context.Background() + + reg, err := content.NewRegistry(content.RegistryOptions{PlainHTTP: true}) + if err != nil { + return err + } + + fileStore := content.NewFile("") + defer fileStore.Close() + allowedMediaTypes := []string{mediaType} + _, err = oras.Copy(ctx, reg, ref, fileStore, "", oras.WithAllowedMediaTypes(allowedMediaTypes)) + return err +} diff --git a/tuf-repository.go b/tuf-repository.go index 4243fc6..27b10d4 100644 --- a/tuf-repository.go +++ b/tuf-repository.go @@ -1,6 +1,12 @@ package tufnotary import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "github.com/theupdateframework/go-tuf" util "github.com/theupdateframework/go-tuf/util" ) @@ -58,3 +64,47 @@ func Init(repository string) error { err = repo.Timestamp() return err } + +func Sign(tufRepository string, signer string, digest string, length int64, descriptor json.RawMessage) error { + + workingDir, err := os.Getwd() + if err != nil { + return err + } + + dir := filepath.Join(workingDir, tufRepository) + + var p util.PassphraseFunc + // TODO passphase func (same as in delegations) + + repo, err := tuf.NewRepo(tuf.FileSystemStore(dir, p)) + if err != nil { + return err + } + + digestParts := strings.Split(digest, ":") + + path := fmt.Sprintf("%s/%s", signer, digest) + err = repo.AddTargetsWithDigest(digestParts[1], digestParts[0], length, path, descriptor) + if err != nil { + return err + } + + err = repo.Sign("targets") + if err != nil { + return err + } + + err = repo.Snapshot() + if err != nil { + return err + } + + err = repo.Timestamp() + if err != nil { + return err + } + + err = repo.Commit() + return err +}