Merge pull request #805 from stevvooe/ng-manifest-bugs

NG: Various Manifest Oriented bugfixes
This commit is contained in:
Olivier Gambier 2014-12-01 18:45:12 -08:00
commit fc1db3ad10
3 changed files with 36 additions and 13 deletions

View file

@ -250,6 +250,10 @@ func TestManifestAPI(t *testing.T) {
t.Fatalf("should have received two invalid digest errors: %v", respErrs) t.Fatalf("should have received two invalid digest errors: %v", respErrs)
} }
// TODO(stevvooe): Add a test case where we take a mostly valid registry,
// tamper with the content and ensure that we get a unverified manifest
// error.
// Push 2 random layers // Push 2 random layers
expectedLayers := make(map[digest.Digest]io.ReadSeeker) expectedLayers := make(map[digest.Digest]io.ReadSeeker)
@ -277,7 +281,7 @@ func TestManifestAPI(t *testing.T) {
resp = putManifest(t, "putting signed manifest", manifestURL, signedManifest) resp = putManifest(t, "putting signed manifest", manifestURL, signedManifest)
checkResponse(t, "putting manifest", resp, http.StatusOK) checkResponse(t, "putting signed manifest", resp, http.StatusOK)
resp, err = http.Get(manifestURL) resp, err = http.Get(manifestURL)
if err != nil { if err != nil {
@ -299,10 +303,16 @@ func TestManifestAPI(t *testing.T) {
} }
func putManifest(t *testing.T, msg, url string, v interface{}) *http.Response { func putManifest(t *testing.T, msg, url string, v interface{}) *http.Response {
body, err := json.Marshal(v) var body []byte
if sm, ok := v.(*storage.SignedManifest); ok {
body = sm.Raw
} else {
var err error
body, err = json.MarshalIndent(v, "", " ")
if err != nil { if err != nil {
t.Fatalf("unexpected error marshaling %v: %v", v, err) t.Fatalf("unexpected error marshaling %v: %v", v, err)
} }
}
req, err := http.NewRequest("PUT", url, bytes.NewReader(body)) req, err := http.NewRequest("PUT", url, bytes.NewReader(body))
if err != nil { if err != nil {

View file

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/Sirupsen/logrus"
"github.com/docker/libtrust" "github.com/docker/libtrust"
"github.com/docker/docker-registry/digest" "github.com/docker/docker-registry/digest"
@ -78,7 +80,7 @@ type Manifest struct {
// SignedManifest. This typically won't be used within the registry, except // SignedManifest. This typically won't be used within the registry, except
// for testing. // for testing.
func (m *Manifest) Sign(pk libtrust.PrivateKey) (*SignedManifest, error) { func (m *Manifest) Sign(pk libtrust.PrivateKey) (*SignedManifest, error) {
p, err := json.Marshal(m) p, err := json.MarshalIndent(m, "", " ")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -107,7 +109,7 @@ func (m *Manifest) Sign(pk libtrust.PrivateKey) (*SignedManifest, error) {
// The public key of the first element in the chain must be the public key // The public key of the first element in the chain must be the public key
// corresponding with the sign key. // corresponding with the sign key.
func (m *Manifest) SignWithChain(key libtrust.PrivateKey, chain []*x509.Certificate) (*SignedManifest, error) { func (m *Manifest) SignWithChain(key libtrust.PrivateKey, chain []*x509.Certificate) (*SignedManifest, error) {
p, err := json.Marshal(m) p, err := json.MarshalIndent(m, "", " ")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -138,8 +140,9 @@ type SignedManifest struct {
Manifest Manifest
// Raw is the byte representation of the ImageManifest, used for signature // Raw is the byte representation of the ImageManifest, used for signature
// verification. The manifest byte representation cannot change or it will // verification. The value of Raw must be used directly during
// have to be re-signed. // serialization, or the signature check will fail. The manifest byte
// representation cannot change or it will have to be re-signed.
Raw []byte `json:"-"` Raw []byte `json:"-"`
} }
@ -148,6 +151,7 @@ type SignedManifest struct {
func (sm *SignedManifest) Verify() ([]libtrust.PublicKey, error) { func (sm *SignedManifest) Verify() ([]libtrust.PublicKey, error) {
js, err := libtrust.ParsePrettySignature(sm.Raw, "signatures") js, err := libtrust.ParsePrettySignature(sm.Raw, "signatures")
if err != nil { if err != nil {
logrus.WithField("err", err).Debugf("(*SignedManifest).Verify")
return nil, err return nil, err
} }
@ -174,13 +178,16 @@ func (sm *SignedManifest) UnmarshalJSON(b []byte) error {
} }
sm.Manifest = manifest sm.Manifest = manifest
sm.Raw = b sm.Raw = make([]byte, len(b), len(b))
copy(sm.Raw, b)
return nil return nil
} }
// MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner // MarshalJSON returns the contents of raw. If Raw is nil, marshals the inner
// contents. // contents. Applications requiring a marshaled signed manifest should simply
// use Raw directly, since the the content produced by json.Marshal will
// compacted and will fail signature checks.
func (sm *SignedManifest) MarshalJSON() ([]byte, error) { func (sm *SignedManifest) MarshalJSON() ([]byte, error) {
if len(sm.Raw) > 0 { if len(sm.Raw) > 0 {
return sm.Raw, nil return sm.Raw, nil

View file

@ -111,11 +111,13 @@ func (ms *manifestStore) verifyManifest(name, tag string, manifest *SignedManife
var errs ErrManifestVerification var errs ErrManifestVerification
if manifest.Name != name { if manifest.Name != name {
return fmt.Errorf("name does not match manifest name") // TODO(stevvooe): This needs to be an exported error
errs = append(errs, fmt.Errorf("name does not match manifest name"))
} }
if manifest.Tag != tag { if manifest.Tag != tag {
return fmt.Errorf("tag does not match manifest tag") // TODO(stevvooe): This needs to be an exported error.
errs = append(errs, fmt.Errorf("tag does not match manifest tag"))
} }
// TODO(stevvooe): These pubkeys need to be checked with either Verify or // TODO(stevvooe): These pubkeys need to be checked with either Verify or
@ -127,9 +129,13 @@ func (ms *manifestStore) verifyManifest(name, tag string, manifest *SignedManife
case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey: case libtrust.ErrMissingSignatureKey, libtrust.ErrInvalidJSONContent, libtrust.ErrMissingSignatureKey:
errs = append(errs, ErrManifestUnverified{}) errs = append(errs, ErrManifestUnverified{})
default: default:
if err.Error() == "invalid signature" { // TODO(stevvooe): This should be exported by libtrust
errs = append(errs, ErrManifestUnverified{})
} else {
errs = append(errs, err) errs = append(errs, err)
} }
} }
}
for _, fsLayer := range manifest.FSLayers { for _, fsLayer := range manifest.FSLayers {
exists, err := ms.layerService.Exists(name, fsLayer.BlobSum) exists, err := ms.layerService.Exists(name, fsLayer.BlobSum)