mirror of https://github.com/docker/docs.git
cryptoservices can abstract multiple keystores
Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)
This commit is contained in:
parent
e5c388d470
commit
f791c01974
|
|
@ -17,13 +17,13 @@ const (
|
|||
// CryptoService implements Sign and Create, holding a specific GUN and keystore to
|
||||
// operate on
|
||||
type CryptoService struct {
|
||||
gun string
|
||||
keyStore trustmanager.KeyStore
|
||||
gun string
|
||||
keyStores []trustmanager.KeyStore
|
||||
}
|
||||
|
||||
// NewCryptoService returns an instance of CryptoService
|
||||
func NewCryptoService(gun string, keyStore trustmanager.KeyStore) *CryptoService {
|
||||
return &CryptoService{gun: gun, keyStore: keyStore}
|
||||
func NewCryptoService(gun string, keyStores ...trustmanager.KeyStore) *CryptoService {
|
||||
return &CryptoService{gun: gun, keyStores: keyStores}
|
||||
}
|
||||
|
||||
// Create is used to generate keys for targets, snapshots and timestamps
|
||||
|
|
@ -53,30 +53,53 @@ func (ccs *CryptoService) Create(role, algorithm string) (data.PublicKey, error)
|
|||
logrus.Debugf("generated new %s key for role: %s and keyID: %s", algorithm, role, privKey.ID())
|
||||
|
||||
// Store the private key into our keystore with the name being: /GUN/ID.key with an alias of role
|
||||
err = ccs.keyStore.AddKey(filepath.Join(ccs.gun, privKey.ID()), role, privKey)
|
||||
for _, ks := range ccs.keyStores {
|
||||
err = ks.AddKey(filepath.Join(ccs.gun, privKey.ID()), role, privKey)
|
||||
if err == nil {
|
||||
return data.PublicKeyFromPrivate(privKey), nil
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add key to filestore: %v", err)
|
||||
}
|
||||
return data.PublicKeyFromPrivate(privKey), nil
|
||||
return nil, fmt.Errorf("keystores would not accept new private keys for unknown reasons")
|
||||
|
||||
}
|
||||
|
||||
// GetPrivateKey returns a private key by ID
|
||||
func (ccs *CryptoService) GetPrivateKey(keyID string) (data.PrivateKey, string, error) {
|
||||
return ccs.keyStore.GetKey(keyID)
|
||||
func (ccs *CryptoService) GetPrivateKey(keyID string) (k data.PrivateKey, id string, err error) {
|
||||
for _, ks := range ccs.keyStores {
|
||||
k, id, err = ks.GetKey(keyID)
|
||||
if k == nil || err != nil {
|
||||
continue
|
||||
}
|
||||
return
|
||||
}
|
||||
return // returns whatever the final values were
|
||||
}
|
||||
|
||||
// GetKey returns a key by ID
|
||||
func (ccs *CryptoService) GetKey(keyID string) data.PublicKey {
|
||||
key, _, err := ccs.keyStore.GetKey(keyID)
|
||||
if err != nil {
|
||||
return nil
|
||||
for _, ks := range ccs.keyStores {
|
||||
k, _, err := ks.GetKey(keyID)
|
||||
if k == nil || err != nil {
|
||||
continue
|
||||
}
|
||||
return data.PublicKeyFromPrivate(k)
|
||||
|
||||
}
|
||||
return data.PublicKeyFromPrivate(key)
|
||||
return nil // returns whatever the final values were
|
||||
}
|
||||
|
||||
// RemoveKey deletes a key by ID
|
||||
func (ccs *CryptoService) RemoveKey(keyID string) error {
|
||||
return ccs.keyStore.RemoveKey(keyID)
|
||||
func (ccs *CryptoService) RemoveKey(keyID string) (err error) {
|
||||
for _, ks := range ccs.keyStores {
|
||||
e := ks.RemoveKey(keyID)
|
||||
if e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
return // returns last error if any
|
||||
}
|
||||
|
||||
// Sign returns the signatures for the payload with a set of keyIDs. It ignores
|
||||
|
|
@ -90,10 +113,10 @@ func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signatur
|
|||
// Try to get the key first without a GUN (in which case it's a root
|
||||
// key). If that fails, try to get the key with the GUN (non-root
|
||||
// key). If that fails, then we don't have the key.
|
||||
privKey, _, err := ccs.keyStore.GetKey(keyName)
|
||||
privKey, _, err := ccs.GetPrivateKey(keyName)
|
||||
if err != nil {
|
||||
keyName = filepath.Join(ccs.gun, keyid)
|
||||
privKey, _, err = ccs.keyStore.GetKey(keyName)
|
||||
privKey, _, err = ccs.GetPrivateKey(keyName)
|
||||
if err != nil {
|
||||
logrus.Debugf("error attempting to retrieve key ID: %s, %v", keyid, err)
|
||||
return nil, err
|
||||
|
|
@ -128,3 +151,16 @@ func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signatur
|
|||
|
||||
return signatures, nil
|
||||
}
|
||||
|
||||
// ListKeys returns a list of key IDs valid for the given role
|
||||
func (ccs *CryptoService) ListKeys(role string) []string {
|
||||
var res []string
|
||||
for _, ks := range ccs.keyStores {
|
||||
for k, r := range ks.ListKeys() {
|
||||
if r == role {
|
||||
res = append(res, k)
|
||||
}
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,11 @@ type RSAHardwareCryptoService struct {
|
|||
session pkcs11.SessionHandle
|
||||
}
|
||||
|
||||
// ListKeys not implemented yet
|
||||
func (s *RSAHardwareCryptoService) ListKeys(role string) []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// Create creates a key and returns its public components
|
||||
func (s *RSAHardwareCryptoService) Create(role, algo string) (data.PublicKey, error) {
|
||||
// For now generate random labels for keys
|
||||
|
|
|
|||
|
|
@ -100,6 +100,11 @@ func (trust *NotarySigner) GetPrivateKey(keyid string) (data.PrivateKey, string,
|
|||
return nil, "", errors.New("Private key access not permitted.")
|
||||
}
|
||||
|
||||
// ListKeys not supported for NotarySigner
|
||||
func (trust *NotarySigner) ListKeys(role string) []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
// CheckHealth checks the health of one of the clients, since both clients run
|
||||
// from the same GRPC server.
|
||||
func (trust *NotarySigner) CheckHealth(timeout time.Duration) error {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ func (e *Ed25519) RemoveKey(keyID string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ListKeys returns the list of keys IDs for the role
|
||||
func (e *Ed25519) ListKeys(role string) []string {
|
||||
keyIDs := make([]string, 0, len(e.keys))
|
||||
for id := range e.keys {
|
||||
keyIDs = append(keyIDs, id)
|
||||
}
|
||||
return keyIDs
|
||||
}
|
||||
|
||||
// Sign generates an Ed25519 signature over the data
|
||||
func (e *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, error) {
|
||||
signatures := make([]data.Signature, 0, len(keyIDs))
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ type KeyService interface {
|
|||
|
||||
// RemoveKey deletes the specified key
|
||||
RemoveKey(keyID string) error
|
||||
|
||||
// ListKeys returns a map of IDs to role
|
||||
ListKeys(role string) []string
|
||||
}
|
||||
|
||||
// CryptoService defines a unified Signing and Key Service as this
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ func (mts *FailingCryptoService) Create(_, _ string) (data.PublicKey, error) {
|
|||
return mts.testKey, nil
|
||||
}
|
||||
|
||||
func (mts *FailingCryptoService) ListKeys(role string) []string {
|
||||
return []string{mts.testKey.ID()}
|
||||
}
|
||||
|
||||
func (mts *FailingCryptoService) GetKey(keyID string) data.PublicKey {
|
||||
if keyID == "testID" {
|
||||
return mts.testKey
|
||||
|
|
@ -72,6 +76,10 @@ func (mts *MockCryptoService) GetKey(keyID string) data.PublicKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (mts *MockCryptoService) ListKeys(role string) []string {
|
||||
return []string{mts.testKey.ID()}
|
||||
}
|
||||
|
||||
func (mts *MockCryptoService) GetPrivateKey(keyID string) (data.PrivateKey, string, error) {
|
||||
return nil, "", errors.New("Not implemented")
|
||||
}
|
||||
|
|
@ -103,6 +111,10 @@ func (mts *StrictMockCryptoService) GetKey(keyID string) data.PublicKey {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (mts *StrictMockCryptoService) ListKeys(role string) []string {
|
||||
return []string{mts.testKey.ID()}
|
||||
}
|
||||
|
||||
// Test signing and ensure the expected signature is added
|
||||
func TestBasicSign(t *testing.T) {
|
||||
testKey, _ := pem.Decode([]byte(testKeyPEM1))
|
||||
|
|
|
|||
Loading…
Reference in New Issue