-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* notary library prototype * update with latest artifact spec * update with latest link API * proper variable naming for plain http access * refactor code to use latest spec * safe read blob * update registry to the latest spec * update reference API * update dependency * update artifact type * rename notary to notation * update to latest referrer API Signed-off-by: Shiwei Zhang <shizh@microsoft.com>
- Loading branch information
Showing
23 changed files
with
1,181 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package main | ||
|
||
import ( | ||
"net/http" | ||
) | ||
|
||
type transportWithBasicAuth struct { | ||
base http.RoundTripper | ||
hostname string | ||
username string | ||
password string | ||
} | ||
|
||
// TransportWithBasicAuth returns the specified transport with basic auth | ||
func TransportWithBasicAuth(tr http.RoundTripper, hostname, username, password string) http.RoundTripper { | ||
return &transportWithBasicAuth{ | ||
base: tr, | ||
hostname: hostname, | ||
username: username, | ||
password: password, | ||
} | ||
} | ||
|
||
func (tr *transportWithBasicAuth) RoundTrip(req *http.Request) (*http.Response, error) { | ||
if req.Host == tr.hostname { | ||
req.SetBasicAuth(tr.username, tr.password) | ||
} | ||
return tr.base.RoundTrip(req) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"crypto/x509" | ||
"fmt" | ||
"log" | ||
"net/http" | ||
"os" | ||
|
||
"github.com/notaryproject/notation-go-lib" | ||
"github.com/notaryproject/notation-go-lib/registry" | ||
x509n "github.com/notaryproject/notation-go-lib/signature/x509" | ||
"github.com/notaryproject/notation-go-lib/simple" | ||
) | ||
|
||
func main() { | ||
if len(os.Args) < 4 { | ||
fmt.Println("usage:", os.Args[0], "<key>", "<cert>", "<manifest>", "<references...>") | ||
} | ||
|
||
fmt.Println(">>> Initialize signing service") | ||
signing, err := getSigningService(os.Args[1], os.Args[2]) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Println(">>> Initialize registry service") | ||
ctx := context.Background() | ||
client := getSignatureRegistry( | ||
os.Getenv("notation_registry"), | ||
os.Getenv("notation_username"), | ||
os.Getenv("notation_password"), | ||
).Repository(ctx, os.Getenv("notation_repository")) | ||
|
||
fmt.Println(">>> Initialize manifest") | ||
references := os.Args[4:] | ||
manifestPath := os.Args[3] | ||
manifestDescriptor, err := registry.DescriptorFromFile(manifestPath) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
manifestDescriptor.MediaType = "application/vnd.docker.distribution.manifest.v2+json" | ||
fmt.Println(manifestDescriptor) | ||
|
||
fmt.Println(">>> Sign manifest") | ||
sig, err := signing.Sign(ctx, manifestDescriptor, references...) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
|
||
fmt.Println(">>> Verify signature") | ||
references, err = signing.Verify(ctx, manifestDescriptor, sig) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(references) | ||
|
||
fmt.Println(">>> Put signature") | ||
signatureDescriptor, err := client.Put(ctx, sig) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(signatureDescriptor.Digest) | ||
|
||
fmt.Println(">>> Link signature") | ||
artifactDescriptor, err := client.Link(ctx, manifestDescriptor, signatureDescriptor) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
fmt.Println(artifactDescriptor.Digest) | ||
|
||
fmt.Println(">>> Lookup signatures") | ||
signatureDigests, err := client.Lookup(ctx, manifestDescriptor.Digest) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
for _, signatureDigest := range signatureDigests { | ||
fmt.Println("-", signatureDigest) | ||
} | ||
|
||
for _, signatureDigest := range signatureDigests { | ||
fmt.Println(">>> Get signature:", signatureDigest) | ||
sig, err := client.Get(ctx, signatureDigest) | ||
if err != nil { | ||
log.Println(err) | ||
continue | ||
} | ||
|
||
fmt.Println(">>> Verify signature:", signatureDigest) | ||
references, err = signing.Verify(ctx, manifestDescriptor, sig) | ||
if err != nil { | ||
log.Println(err) | ||
continue | ||
} | ||
fmt.Println(references) | ||
} | ||
} | ||
|
||
func getSigningService(keyPath, certPath string) (notation.SigningService, error) { | ||
key, err := x509n.ReadPrivateKeyFile(keyPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
certs, err := x509n.ReadCertificateFile(certPath) | ||
if err != nil { | ||
return nil, err | ||
} | ||
rootCerts := x509.NewCertPool() | ||
for _, cert := range certs { | ||
rootCerts.AddCert(cert) | ||
} | ||
return simple.NewSigningService(key, certs, certs, rootCerts) | ||
} | ||
|
||
func getSignatureRegistry(name, username, password string) notation.SignatureRegistry { | ||
plainHTTP := username == "" // for http access | ||
tr := http.DefaultTransport | ||
if !plainHTTP { | ||
tr = TransportWithBasicAuth(tr, name, username, password) | ||
} | ||
return registry.NewClient(tr, name, plainHTTP) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module github.com/notaryproject/notation-go-lib | ||
|
||
go 1.17 | ||
|
||
require ( | ||
github.com/docker/go v1.5.1-1 | ||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 | ||
github.com/opencontainers/go-digest v1.0.0 | ||
github.com/opencontainers/image-spec v1.0.1 | ||
github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
github.com/docker/go v1.5.1-1 h1:hr4w35acWBPhGBXlzPoHpmZ/ygPjnmFVxGxxGnMyP7k= | ||
github.com/docker/go v1.5.1-1/go.mod h1:CADgU4DSXK5QUlFslkQu2yW2TKzFZcXq/leZfM0UH5Q= | ||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4= | ||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= | ||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | ||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | ||
github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= | ||
github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= | ||
github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d h1:fnJDGYyP6INkpdty1iJzXS3jI6n9RaLK0JN+glIPmsE= | ||
github.com/oras-project/artifacts-spec v0.0.0-20210827194259-6e52c5a2ed3d/go.mod h1:Xch2aLzSwtkhbFFN6LUzTfLtukYvMMdXJ4oZ8O7BOdc= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package notation | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/opencontainers/go-digest" | ||
oci "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
// SignatureRegistry provides signature repositories | ||
type SignatureRegistry interface { | ||
Repository(ctx context.Context, name string) SignatureRepository | ||
} | ||
|
||
// SignatureRepository provides a storage for signatures | ||
type SignatureRepository interface { | ||
// Lookup finds all signatures for the specified manifest | ||
Lookup(ctx context.Context, manifestDigest digest.Digest) ([]digest.Digest, error) | ||
|
||
// Get downloads the signature by the specified digest | ||
Get(ctx context.Context, signatureDigest digest.Digest) ([]byte, error) | ||
|
||
// Put uploads the signature to the registry | ||
Put(ctx context.Context, signature []byte) (oci.Descriptor, error) | ||
|
||
// Link creates an signature artifact linking the manifest and the signature | ||
Link(ctx context.Context, manifest, signature oci.Descriptor) (oci.Descriptor, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package registry | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/opencontainers/go-digest" | ||
oci "github.com/opencontainers/image-spec/specs-go/v1" | ||
) | ||
|
||
// DescriptorFromBytes computes the basic descriptor from the given bytes | ||
func DescriptorFromBytes(data []byte) oci.Descriptor { | ||
return oci.Descriptor{ | ||
Digest: digest.FromBytes(data), | ||
Size: int64(len(data)), | ||
} | ||
} | ||
|
||
// DescriptorFromFile computes the basic descriptor from the file | ||
func DescriptorFromFile(path string) (oci.Descriptor, error) { | ||
file, err := os.Open(path) | ||
if err != nil { | ||
return oci.Descriptor{}, err | ||
} | ||
defer file.Close() | ||
|
||
stat, err := file.Stat() | ||
if err != nil { | ||
return oci.Descriptor{}, err | ||
} | ||
|
||
digest, err := digest.FromReader(file) | ||
if err != nil { | ||
return oci.Descriptor{}, err | ||
} | ||
|
||
return oci.Descriptor{ | ||
Digest: digest, | ||
Size: stat.Size(), | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package registry | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
|
||
"github.com/opencontainers/go-digest" | ||
) | ||
|
||
const maxReadLimit = 4 * 1024 * 1024 | ||
|
||
func readAllVerified(r io.Reader, expected digest.Digest) ([]byte, error) { | ||
digester := expected.Algorithm().Digester() | ||
content, err := io.ReadAll(io.TeeReader( | ||
io.LimitReader(r, maxReadLimit), | ||
digester.Hash(), | ||
)) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(content) == maxReadLimit { | ||
return nil, fmt.Errorf("reached max read limit %d", maxReadLimit) | ||
} | ||
if actual := digester.Digest(); actual != expected { | ||
return nil, fmt.Errorf("mismatch digest: expect %v: got %v", expected, actual) | ||
} | ||
return content, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package registry | ||
|
||
const ( | ||
// ArtifactTypeNotation specifies the artifact type for a notation object. | ||
ArtifactTypeNotation = "application/vnd.cncf.notary.v2" | ||
) | ||
|
||
const ( | ||
// MediaTypeNotarySignature specifies the media type for the notary signature. | ||
MediaTypeNotarySignature = "application/vnd.cncf.notary.signature.v2+jwt" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package registry | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net/http" | ||
|
||
"github.com/notaryproject/notation-go-lib" | ||
) | ||
|
||
type registry struct { | ||
tr http.RoundTripper | ||
base string | ||
} | ||
|
||
// NewClient creates a client to the remote registry | ||
// for accessing the signatures. | ||
func NewClient(tr http.RoundTripper, name string, plainHTTP bool) notation.SignatureRegistry { | ||
scheme := "https" | ||
if plainHTTP { | ||
scheme = "http" | ||
} | ||
return ®istry{ | ||
tr: tr, | ||
base: fmt.Sprintf("%s://%s", scheme, name), | ||
} | ||
} | ||
|
||
func (r *registry) Repository(ctx context.Context, name string) notation.SignatureRepository { | ||
return &repository{ | ||
tr: r.tr, | ||
base: r.base, | ||
name: name, | ||
} | ||
} |
Oops, something went wrong.