Don't hardcode RSA algorithm

When we need to find a key from its ID, search all available signing
services. There should only be a few, so this shouldn't have much
overhead. This avoids the need to maintain a persistent mapping between
key ID and the responsible signing service.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann 2015-07-14 10:49:43 -07:00
parent 321b155596
commit e7e9ef4a0d
7 changed files with 74 additions and 57 deletions

View File

@ -47,15 +47,7 @@ func KeyInfo(sigServices signer.SigningServiceIndex) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r) vars := mux.Vars(r)
// TODO(diogo): call resolve method from KeyID -> KeyInfo key, _, err := FindKeyByID(sigServices, &pb.KeyID{ID: vars["ID"]})
sigService := getSigningService(w, RSAAlgorithm, sigServices)
if sigService == nil {
// Error handled inside getSigningService
return
}
keyID := &pb.KeyID{ID: vars["ID"]}
key, err := sigService.KeyInfo(keyID)
if err != nil { if err != nil {
switch err { switch err {
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404 // If we received an ErrInvalidKeyID, the key doesn't exist, return 404
@ -109,11 +101,21 @@ func DeleteKey(sigServices signer.SigningServiceIndex) http.Handler {
return return
} }
// TODO(diogo): call resolve method from KeyID -> KeyInfo _, sigService, err := FindKeyByID(sigServices, keyID)
sigService := getSigningService(w, RSAAlgorithm, sigServices)
if sigService == nil { if err != nil {
// Error handled inside getSigningService switch err {
return // If we received an ErrInvalidKeyID, the key doesn't exist, return 404
case keys.ErrInvalidKeyID:
w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error()))
return
// If we received anything else, it is unexpected, and we return a 500
default:
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return
}
} }
_, err = sigService.DeleteKey(keyID) _, err = sigService.DeleteKey(keyID)
@ -151,15 +153,19 @@ func Sign(sigServices signer.SigningServiceIndex) http.Handler {
return return
} }
// TODO(diogo): call resolve method from KeyID -> KeyInfo _, sigService, err := FindKeyByID(sigServices, sigRequest.KeyID)
keyInfo := &pb.KeyInfo{KeyID: sigRequest.KeyID, Algorithm: &pb.Algorithm{Algorithm: RSAAlgorithm}} if err == keys.ErrInvalidKeyID {
sigService := getSigningService(w, keyInfo.Algorithm.Algorithm, sigServices) w.WriteHeader(http.StatusNotFound)
if sigService == nil { w.Write([]byte(err.Error()))
// Error handled inside getSigningService return
} else if err != nil {
// We got an unexpected error
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(err.Error()))
return return
} }
signer, err := sigService.Signer(keyInfo) signer, err := sigService.Signer(sigRequest.KeyID)
if err == keys.ErrInvalidKeyID { if err == keys.ErrInvalidKeyID {
w.WriteHeader(http.StatusNotFound) w.WriteHeader(http.StatusNotFound)
w.Write([]byte(err.Error())) w.Write([]byte(err.Error()))

View File

@ -52,9 +52,8 @@ func (s EdDSASigningService) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
} }
// Signer returns a Signer for a specific KeyID // Signer returns a Signer for a specific KeyID
func (s EdDSASigningService) Signer(keyInfo *pb.KeyInfo) (signer.Signer, error) { func (s EdDSASigningService) Signer(keyID *pb.KeyID) (signer.Signer, error) {
// TODO(diogo): add verification of keyInfo.Algorithm to be ECDSA key, err := s.KeyDB.GetKey(keyID)
key, err := s.KeyDB.GetKey(keyInfo.KeyID)
if err != nil { if err != nil {
return nil, keys.ErrInvalidKeyID return nil, keys.ErrInvalidKeyID
} }

View File

@ -84,7 +84,7 @@ func TestSigner(t *testing.T) {
sigService := api.NewEdDSASigningService(&m) sigService := api.NewEdDSASigningService(&m)
m.On("GetKey", fakeKeyID).Return(&keys.Key{}, nil).Once() m.On("GetKey", fakeKeyID).Return(&keys.Key{}, nil).Once()
_, err := sigService.Signer(&pb.KeyInfo{KeyID: &pb.KeyID{ID: fakeKeyID}}) _, err := sigService.Signer(&pb.KeyID{ID: fakeKeyID})
m.Mock.AssertExpectations(t) m.Mock.AssertExpectations(t)
assert.Nil(t, err) assert.Nil(t, err)

19
signer/api/find_key.go Normal file
View File

@ -0,0 +1,19 @@
package api
import (
"github.com/docker/notary/signer"
"github.com/docker/notary/signer/keys"
pb "github.com/docker/notary/proto"
)
func FindKeyByID(sigServices signer.SigningServiceIndex, keyID *pb.KeyID) (*pb.PublicKey, signer.SigningService, error) {
for _, service := range sigServices {
key, err := service.KeyInfo(keyID)
if err == nil {
return key, service, nil
}
}
return nil, nil, keys.ErrInvalidKeyID
}

View File

@ -42,22 +42,20 @@ func (s *KeyManagementServer) CreateKey(ctx context.Context, algorithm *pb.Algor
//DeleteKey deletes they key associated with a KeyID //DeleteKey deletes they key associated with a KeyID
func (s *KeyManagementServer) DeleteKey(ctx context.Context, keyID *pb.KeyID) (*pb.Void, error) { func (s *KeyManagementServer) DeleteKey(ctx context.Context, keyID *pb.KeyID) (*pb.Void, error) {
// TODO(diogo): call resolve method from KeyID -> KeyInfo _, service, err := FindKeyByID(s.SigServices, keyID)
keyInfo := &pb.KeyInfo{KeyID: keyID, Algorithm: &pb.Algorithm{Algorithm: RSAAlgorithm}}
service := s.SigServices[keyInfo.Algorithm.Algorithm]
if service == nil { if err != nil {
return nil, fmt.Errorf("algorithm %s not supported for delete key", keyInfo.Algorithm.Algorithm) return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
} }
_, err := service.DeleteKey(keyInfo.KeyID) _, err = service.DeleteKey(keyID)
log.Println("[Notary-signer DeleteKey] : Deleted KeyID ", keyInfo.KeyID.ID) log.Println("[Notary-signer DeleteKey] : Deleted KeyID ", keyID.ID)
if err != nil { if err != nil {
switch err { switch err {
case keys.ErrInvalidKeyID: case keys.ErrInvalidKeyID:
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyInfo.KeyID.ID) return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
default: default:
return nil, grpc.Errorf(codes.Internal, "Key deletion for keyID %s failed", keyInfo.KeyID.ID) return nil, grpc.Errorf(codes.Internal, "Key deletion for keyID %s failed", keyID.ID)
} }
} }
@ -66,43 +64,39 @@ func (s *KeyManagementServer) DeleteKey(ctx context.Context, keyID *pb.KeyID) (*
//GetKeyInfo returns they PublicKey associated with a KeyID //GetKeyInfo returns they PublicKey associated with a KeyID
func (s *KeyManagementServer) GetKeyInfo(ctx context.Context, keyID *pb.KeyID) (*pb.PublicKey, error) { func (s *KeyManagementServer) GetKeyInfo(ctx context.Context, keyID *pb.KeyID) (*pb.PublicKey, error) {
// TODO(diogo): call resolve method from KeyID -> KeyInfo _, service, err := FindKeyByID(s.SigServices, keyID)
keyInfo := &pb.KeyInfo{KeyID: keyID, Algorithm: &pb.Algorithm{Algorithm: RSAAlgorithm}}
service := s.SigServices[keyInfo.Algorithm.Algorithm]
if service == nil {
return nil, fmt.Errorf("algorithm %s not supported for get key info", keyInfo.Algorithm.Algorithm)
}
key, err := service.KeyInfo(keyInfo.KeyID)
if err != nil { if err != nil {
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyInfo.KeyID.ID) return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
} }
log.Println("[Notary-signer GetKeyInfo] : Returning PublicKey for KeyID ", keyInfo.KeyID.ID)
key, err := service.KeyInfo(keyID)
if err != nil {
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
}
log.Println("[Notary-signer GetKeyInfo] : Returning PublicKey for KeyID ", keyID.ID)
return key, nil return key, nil
} }
//Sign signs a message and returns the signature using a private key associate with the KeyID from the SignatureRequest //Sign signs a message and returns the signature using a private key associate with the KeyID from the SignatureRequest
func (s *SignerServer) Sign(ctx context.Context, sr *pb.SignatureRequest) (*pb.Signature, error) { func (s *SignerServer) Sign(ctx context.Context, sr *pb.SignatureRequest) (*pb.Signature, error) {
// TODO(diogo): call resolve method from KeyID -> KeyInfo _, service, err := FindKeyByID(s.SigServices, sr.KeyID)
keyInfo := &pb.KeyInfo{KeyID: sr.KeyID, Algorithm: &pb.Algorithm{Algorithm: RSAAlgorithm}}
service := s.SigServices[keyInfo.Algorithm.Algorithm]
if service == nil { if err != nil {
return nil, fmt.Errorf("algorithm %s not supported for sign", keyInfo.Algorithm.Algorithm) return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", sr.KeyID.ID)
} }
log.Println("[Notary-signer Sign] : Signing ", string(sr.Content), " with KeyID ", keyInfo.KeyID.ID) log.Println("[Notary-signer Sign] : Signing ", string(sr.Content), " with KeyID ", sr.KeyID.ID)
signer, err := service.Signer(keyInfo) signer, err := service.Signer(sr.KeyID)
if err == keys.ErrInvalidKeyID { if err == keys.ErrInvalidKeyID {
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key not found") return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", sr.KeyID.ID)
} else if err != nil { } else if err != nil {
return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", keyInfo.KeyID.ID, sr.Content) return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", sr.KeyID.ID, sr.Content)
} }
signature, err := signer.Sign(sr) signature, err := signer.Sign(sr)
if err != nil { if err != nil {
return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", keyInfo.KeyID.ID, sr.Content) return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", sr.KeyID.ID, sr.Content)
} }
return signature, nil return signature, nil

View File

@ -139,9 +139,8 @@ func (s RSASigningService) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
} }
// Signer returns a Signer for a specific KeyID // Signer returns a Signer for a specific KeyID
func (s RSASigningService) Signer(keyInfo *pb.KeyInfo) (signer.Signer, error) { func (s RSASigningService) Signer(keyID *pb.KeyID) (signer.Signer, error) {
// TODO(diogo): Add verification of keyInfo.Algorithm to be RSA. key, ok := s.keys[keyID.ID]
key, ok := s.keys[keyInfo.KeyID.ID]
if !ok { if !ok {
return nil, keys.ErrInvalidKeyID return nil, keys.ErrInvalidKeyID
} }

View File

@ -10,7 +10,7 @@ type SigningService interface {
KeyManager KeyManager
// Signer returns a Signer for a given keyID // Signer returns a Signer for a given keyID
Signer(keyID *pb.KeyInfo) (Signer, error) Signer(keyID *pb.KeyID) (Signer, error)
} }
// SigningServiceIndex represents a mapping between a service algorithm string // SigningServiceIndex represents a mapping between a service algorithm string