mirror of https://github.com/docker/docs.git
Big refactor to make signer use cryptoservices
- Add MemoryFileStore, a partial FileStore implementation that doesn't persist on disk. - Create a KeyStore interface that allows pluggable key store types. Use this interface in the cryptoservice implementation. - Add KeyMemoryStore, which uses MemoryFileStore to provide a KeyStore. - Add GetKey and DeleteKey functions to cryptoservice.CryptoService. - Refactor the hardware RSA signing service as a CryptoService. - Replace custom ed25519 code with cryptoservice.CryptoService. Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
parent
f5c1d8dbc9
commit
125d72fd77
|
@ -58,7 +58,7 @@
|
|||
},
|
||||
{
|
||||
"ImportPath": "github.com/endophage/gotuf",
|
||||
"Rev": "82786136d505f582d0f898a2e80c9f6b97b1402c"
|
||||
"Rev": "f81a3471fd94ba58e004ef9cd9bbbf81bfc565ed"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/go-sql-driver/mysql",
|
||||
|
|
|
@ -77,10 +77,13 @@ func NewPublicKey(algorithm KeyAlgorithm, public []byte) *PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
func PublicKeyFromPrivate(pk PrivateKey) *PublicKey {
|
||||
return &PublicKey{
|
||||
func PublicKeyFromPrivate(pk *PrivateKey) *PublicKey {
|
||||
pub := &PublicKey{
|
||||
pk.TUFKey,
|
||||
}
|
||||
pub.TUFKey.Value.Private = nil
|
||||
|
||||
return pub
|
||||
}
|
||||
|
||||
type PrivateKey struct {
|
||||
|
|
|
@ -29,10 +29,11 @@ func (k SigAlgorithm) String() string {
|
|||
const (
|
||||
defaultHashAlgorithm = "sha256"
|
||||
|
||||
EDDSASignature SigAlgorithm = "eddsa"
|
||||
RSAPSSSignature SigAlgorithm = "rsapss"
|
||||
ECDSASignature SigAlgorithm = "ecdsa"
|
||||
PyCryptoSignature SigAlgorithm = "pycrypto-pkcs#1 pss"
|
||||
EDDSASignature SigAlgorithm = "eddsa"
|
||||
RSAPSSSignature SigAlgorithm = "rsapss"
|
||||
RSAPKCS1v15Signature SigAlgorithm = "rsapkcs1v15"
|
||||
ECDSASignature SigAlgorithm = "ecdsa"
|
||||
PyCryptoSignature SigAlgorithm = "pycrypto-pkcs#1 pss"
|
||||
|
||||
ED25519Key KeyAlgorithm = "ed25519"
|
||||
RSAKey KeyAlgorithm = "rsa"
|
||||
|
|
|
@ -18,17 +18,17 @@ var (
|
|||
|
||||
type KeyDB struct {
|
||||
roles map[string]*data.Role
|
||||
keys map[string]*data.PublicKey
|
||||
keys map[string]data.Key
|
||||
}
|
||||
|
||||
func NewDB() *KeyDB {
|
||||
return &KeyDB{
|
||||
roles: make(map[string]*data.Role),
|
||||
keys: make(map[string]*data.PublicKey),
|
||||
keys: make(map[string]data.Key),
|
||||
}
|
||||
}
|
||||
|
||||
func (db *KeyDB) AddKey(k *data.PublicKey) {
|
||||
func (db *KeyDB) AddKey(k data.Key) {
|
||||
db.keys[k.ID()] = k
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ func (db *KeyDB) AddRole(r *data.Role) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (db *KeyDB) GetKey(id string) *data.PublicKey {
|
||||
func (db *KeyDB) GetKey(id string) data.Key {
|
||||
return db.keys[id]
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/endophage/gotuf/data"
|
||||
)
|
||||
|
||||
// Ed25519 implements a simple in memory keystore and trust service
|
||||
// Ed25519 implements a simple in memory cryptosystem for ED25519 keys
|
||||
type Ed25519 struct {
|
||||
keys map[string]*data.PrivateKey
|
||||
}
|
||||
|
@ -19,22 +19,21 @@ func NewEd25519() *Ed25519 {
|
|||
}
|
||||
}
|
||||
|
||||
// addKey allows you to add a private key to the trust service
|
||||
func (trust *Ed25519) addKey(k *data.PrivateKey) {
|
||||
trust.keys[k.ID()] = k
|
||||
// addKey allows you to add a private key
|
||||
func (e *Ed25519) addKey(k *data.PrivateKey) {
|
||||
e.keys[k.ID()] = k
|
||||
}
|
||||
|
||||
func (trust *Ed25519) RemoveKey(keyID string) {
|
||||
delete(trust.keys, keyID)
|
||||
func (e *Ed25519) RemoveKey(keyID string) error {
|
||||
delete(e.keys, keyID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (trust *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, error) {
|
||||
func (e *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, error) {
|
||||
signatures := make([]data.Signature, 0, len(keyIDs))
|
||||
for _, kID := range keyIDs {
|
||||
priv := [ed25519.PrivateKeySize]byte{}
|
||||
pub := [ed25519.PublicKeySize]byte{}
|
||||
copy(priv[:], trust.keys[kID].Private())
|
||||
copy(pub[:], trust.keys[kID].Public())
|
||||
copy(priv[:], e.keys[kID].Private())
|
||||
sig := ed25519.Sign(&priv, toSign)
|
||||
signatures = append(signatures, data.Signature{
|
||||
KeyID: kID,
|
||||
|
@ -46,7 +45,7 @@ func (trust *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, er
|
|||
|
||||
}
|
||||
|
||||
func (trust *Ed25519) Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) {
|
||||
func (e *Ed25519) Create(role string, algorithm data.KeyAlgorithm) (data.Key, error) {
|
||||
if algorithm != data.ED25519Key {
|
||||
return nil, errors.New("only ED25519 supported by this cryptoservice")
|
||||
}
|
||||
|
@ -57,16 +56,20 @@ func (trust *Ed25519) Create(role string, algorithm data.KeyAlgorithm) (*data.Pu
|
|||
}
|
||||
public := data.NewPublicKey(data.ED25519Key, pub[:])
|
||||
private := data.NewPrivateKey(data.ED25519Key, pub[:], priv[:])
|
||||
trust.addKey(private)
|
||||
e.addKey(private)
|
||||
return public, nil
|
||||
}
|
||||
|
||||
func (trust *Ed25519) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) {
|
||||
func (e *Ed25519) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) {
|
||||
k := make(map[string]*data.PublicKey)
|
||||
for _, kID := range keyIDs {
|
||||
if key, ok := trust.keys[kID]; ok {
|
||||
k[kID] = data.PublicKeyFromPrivate(*key)
|
||||
if key, ok := e.keys[kID]; ok {
|
||||
k[kID] = data.PublicKeyFromPrivate(key)
|
||||
}
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func (e *Ed25519) GetKey(keyID string) data.Key {
|
||||
return data.PublicKeyFromPrivate(e.keys[keyID])
|
||||
}
|
||||
|
|
|
@ -20,7 +20,13 @@ type KeyService interface {
|
|||
// the private key into the appropriate signing service.
|
||||
// The role isn't currently used for anything, but it's here to support
|
||||
// future features
|
||||
Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error)
|
||||
Create(role string, algorithm data.KeyAlgorithm) (data.Key, error)
|
||||
|
||||
// GetKey retrieves the public key if present, otherwise it returns nil
|
||||
GetKey(keyID string) data.Key
|
||||
|
||||
// RemoveKey deletes the specified key
|
||||
RemoveKey(keyID string) error
|
||||
}
|
||||
|
||||
// CryptoService defines a unified Signing and Key Service as this
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
|
||||
// Sign takes a data.Signed and a key, calculated and adds the signature
|
||||
// to the data.Signed
|
||||
func Sign(service CryptoService, s *data.Signed, keys ...*data.PublicKey) error {
|
||||
func Sign(service CryptoService, s *data.Signed, keys ...data.Key) error {
|
||||
logrus.Debugf("sign called with %d keys", len(keys))
|
||||
signatures := make([]data.Signature, 0, len(s.Signatures)+1)
|
||||
keyIDMemb := make(map[string]struct{})
|
||||
|
|
|
@ -27,13 +27,19 @@ func (mts *MockCryptoService) Sign(keyIDs []string, _ []byte) ([]data.Signature,
|
|||
return sigs, nil
|
||||
}
|
||||
|
||||
func (mts *MockCryptoService) Create(_ string, _ data.KeyAlgorithm) (*data.PublicKey, error) {
|
||||
func (mts *MockCryptoService) Create(_ string, _ data.KeyAlgorithm) (data.Key, error) {
|
||||
return &mts.testKey, nil
|
||||
}
|
||||
|
||||
func (mts *MockCryptoService) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) {
|
||||
keys := map[string]*data.PublicKey{"testID": &mts.testKey}
|
||||
return keys, nil
|
||||
func (mts *MockCryptoService) GetKey(keyID string) data.Key {
|
||||
if keyID == "testID" {
|
||||
return &mts.testKey
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mts *MockCryptoService) RemoveKey(keyID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ CryptoService = &MockCryptoService{}
|
||||
|
|
|
@ -19,10 +19,11 @@ import (
|
|||
// can be injected into a verificationService. For testing and configuration
|
||||
// purposes, it will not be used by default.
|
||||
var Verifiers = map[data.SigAlgorithm]Verifier{
|
||||
data.RSAPSSSignature: RSAPSSVerifier{},
|
||||
data.PyCryptoSignature: RSAPyCryptoVerifier{},
|
||||
data.ECDSASignature: ECDSAVerifier{},
|
||||
data.EDDSASignature: Ed25519Verifier{},
|
||||
data.RSAPSSSignature: RSAPSSVerifier{},
|
||||
data.RSAPKCS1v15Signature: RSAPKCS1v15Verifier{},
|
||||
data.PyCryptoSignature: RSAPyCryptoVerifier{},
|
||||
data.ECDSASignature: ECDSAVerifier{},
|
||||
data.EDDSASignature: Ed25519Verifier{},
|
||||
}
|
||||
|
||||
// RegisterVerifier provides a convenience function for init() functions
|
||||
|
@ -78,11 +79,7 @@ func verifyPSS(key interface{}, digest, sig []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// RSAPSSVerifier checks RSASSA-PSS signatures
|
||||
type RSAPSSVerifier struct{}
|
||||
|
||||
// Verify does the actual check.
|
||||
func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
||||
func getRSAPubKey(key data.Key) (crypto.PublicKey, error) {
|
||||
algorithm := key.Algorithm()
|
||||
var pubKey crypto.PublicKey
|
||||
|
||||
|
@ -91,12 +88,12 @@ func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
|||
pemCert, _ := pem.Decode([]byte(key.Public()))
|
||||
if pemCert == nil {
|
||||
logrus.Infof("failed to decode PEM-encoded x509 certificate")
|
||||
return ErrInvalid
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
cert, err := x509.ParseCertificate(pemCert.Bytes)
|
||||
if err != nil {
|
||||
logrus.Infof("failed to parse x509 certificate: %s\n", err)
|
||||
return ErrInvalid
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
pubKey = cert.PublicKey
|
||||
case data.RSAKey:
|
||||
|
@ -104,11 +101,24 @@ func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
|||
pubKey, err = x509.ParsePKIXPublicKey(key.Public())
|
||||
if err != nil {
|
||||
logrus.Infof("failed to parse public key: %s\n", err)
|
||||
return ErrInvalid
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
default:
|
||||
logrus.Infof("invalid key type for RSAPSS verifier: %s", algorithm)
|
||||
return ErrInvalid
|
||||
return nil, ErrInvalid
|
||||
}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// RSAPSSVerifier checks RSASSA-PSS signatures
|
||||
type RSAPSSVerifier struct{}
|
||||
|
||||
// Verify does the actual check.
|
||||
func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
||||
pubKey, err := getRSAPubKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
digest := sha256.Sum256(msg)
|
||||
|
@ -116,6 +126,29 @@ func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
|||
return verifyPSS(pubKey, digest[:], sig)
|
||||
}
|
||||
|
||||
// RSAPKCS1v15SVerifier checks RSA PKCS1v15 signatures
|
||||
type RSAPKCS1v15Verifier struct{}
|
||||
|
||||
func (v RSAPKCS1v15Verifier) Verify(key data.Key, sig []byte, msg []byte) error {
|
||||
pubKey, err := getRSAPubKey(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
digest := sha256.Sum256(msg)
|
||||
|
||||
rsaPub, ok := pubKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
logrus.Infof("value was not an RSA public key")
|
||||
return ErrInvalid
|
||||
}
|
||||
|
||||
if err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, digest[:], sig); err != nil {
|
||||
logrus.Errorf("Failed verification: %s", err.Error())
|
||||
return ErrInvalid
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RSAPSSVerifier checks RSASSA-PSS signatures
|
||||
type RSAPyCryptoVerifier struct{}
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -19,10 +19,10 @@ type VerifySuite struct{}
|
|||
var _ = Suite(&VerifySuite{})
|
||||
|
||||
func (VerifySuite) Test(c *C) {
|
||||
trust := NewEd25519()
|
||||
cryptoService := NewEd25519()
|
||||
type test struct {
|
||||
name string
|
||||
keys []*data.PublicKey
|
||||
keys []data.Key
|
||||
roles map[string]*data.Role
|
||||
s *data.Signed
|
||||
ver int
|
||||
|
@ -77,8 +77,8 @@ func (VerifySuite) Test(c *C) {
|
|||
{
|
||||
name: "more than enough signatures",
|
||||
mut: func(t *test) {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
Sign(trust, t.s, k)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
Sign(cryptoService, t.s, k)
|
||||
t.keys = append(t.keys, k)
|
||||
t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.ID())
|
||||
},
|
||||
|
@ -94,15 +94,15 @@ func (VerifySuite) Test(c *C) {
|
|||
{
|
||||
name: "unknown key",
|
||||
mut: func(t *test) {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
Sign(trust, t.s, k)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
Sign(cryptoService, t.s, k)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown key below threshold",
|
||||
mut: func(t *test) {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
Sign(trust, t.s, k)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
Sign(cryptoService, t.s, k)
|
||||
t.roles["root"].Threshold = 2
|
||||
},
|
||||
err: ErrRoleThreshold,
|
||||
|
@ -110,16 +110,16 @@ func (VerifySuite) Test(c *C) {
|
|||
{
|
||||
name: "unknown keys in db",
|
||||
mut: func(t *test) {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
Sign(trust, t.s, k)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
Sign(cryptoService, t.s, k)
|
||||
t.keys = append(t.keys, k)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "unknown keys in db below threshold",
|
||||
mut: func(t *test) {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
Sign(trust, t.s, k)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
Sign(cryptoService, t.s, k)
|
||||
t.keys = append(t.keys, k)
|
||||
t.roles["root"].Threshold = 2
|
||||
},
|
||||
|
@ -156,15 +156,15 @@ func (VerifySuite) Test(c *C) {
|
|||
t.typ = data.TUFTypes[t.role]
|
||||
}
|
||||
if t.keys == nil && t.s == nil {
|
||||
k, _ := trust.Create("root", data.ED25519Key)
|
||||
k, _ := cryptoService.Create("root", data.ED25519Key)
|
||||
meta := &signedMeta{Type: t.typ, Version: t.ver, Expires: t.exp.Format("2006-01-02 15:04:05 MST")}
|
||||
|
||||
b, err := cjson.Marshal(meta)
|
||||
c.Assert(err, IsNil)
|
||||
s := &data.Signed{Signed: b}
|
||||
Sign(trust, s, k)
|
||||
Sign(cryptoService, s, k)
|
||||
t.s = s
|
||||
t.keys = []*data.PublicKey{k}
|
||||
t.keys = []data.Key{k}
|
||||
}
|
||||
if t.roles == nil {
|
||||
t.roles = map[string]*data.Role{
|
||||
|
|
|
@ -579,7 +579,7 @@ func (tr *TufRepo) SignTimestamp(expires time.Time, cryptoService signed.CryptoS
|
|||
}
|
||||
|
||||
func (tr TufRepo) sign(signedData *data.Signed, role data.Role, cryptoService signed.CryptoService) (*data.Signed, error) {
|
||||
ks := make([]*data.PublicKey, 0, len(role.KeyIDs))
|
||||
ks := make([]data.Key, 0, len(role.KeyIDs))
|
||||
for _, kid := range role.KeyIDs {
|
||||
k := tr.keysDB.GetKey(kid)
|
||||
if k == nil {
|
||||
|
|
|
@ -14,9 +14,10 @@ import (
|
|||
"google.golang.org/grpc/credentials"
|
||||
|
||||
_ "github.com/docker/distribution/health"
|
||||
"github.com/docker/notary/cryptoservice"
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/api"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/docker/notary/trustmanager"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/miekg/pkcs11"
|
||||
|
||||
|
@ -68,7 +69,7 @@ func main() {
|
|||
}
|
||||
tlsConfig.Rand = rand.Reader
|
||||
|
||||
sigServices := make(signer.SigningServiceIndex)
|
||||
cryptoServices := make(signer.CryptoServiceIndex)
|
||||
|
||||
if pkcs11Lib != "" {
|
||||
if pin == "" {
|
||||
|
@ -79,14 +80,18 @@ func main() {
|
|||
|
||||
defer cleanup(ctx, session)
|
||||
|
||||
sigServices[data.RSAKey] = api.NewRSASigningService(ctx, session)
|
||||
cryptoServices[data.RSAKey] = api.NewRSAHardwareCryptoService(ctx, session)
|
||||
}
|
||||
|
||||
sigServices[data.ED25519Key] = api.EdDSASigningService{KeyDB: keys.NewKeyDB()}
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
|
||||
cryptoServices[data.ED25519Key] = cryptoService
|
||||
cryptoServices[data.ECDSAKey] = cryptoService
|
||||
|
||||
//RPC server setup
|
||||
kms := &api.KeyManagementServer{SigServices: sigServices}
|
||||
ss := &api.SignerServer{SigServices: sigServices}
|
||||
kms := &api.KeyManagementServer{CryptoServices: cryptoServices}
|
||||
ss := &api.SignerServer{CryptoServices: cryptoServices}
|
||||
|
||||
grpcServer := grpc.NewServer()
|
||||
pb.RegisterKeyManagementServer(grpcServer, kms)
|
||||
|
@ -105,7 +110,7 @@ func main() {
|
|||
//HTTP server setup
|
||||
server := http.Server{
|
||||
Addr: _Addr,
|
||||
Handler: api.Handlers(sigServices),
|
||||
Handler: api.Handlers(cryptoServices),
|
||||
TLSConfig: tlsConfig,
|
||||
}
|
||||
|
||||
|
|
|
@ -25,16 +25,16 @@ const (
|
|||
type CryptoService struct {
|
||||
gun string
|
||||
passphrase string
|
||||
keyStore *trustmanager.KeyFileStore
|
||||
keyStore trustmanager.KeyStore
|
||||
}
|
||||
|
||||
// NewCryptoService returns an instance of CryptoService
|
||||
func NewCryptoService(gun string, keyStore *trustmanager.KeyFileStore, passphrase string) *CryptoService {
|
||||
func NewCryptoService(gun string, keyStore trustmanager.KeyStore, passphrase string) *CryptoService {
|
||||
return &CryptoService{gun: gun, keyStore: keyStore, passphrase: passphrase}
|
||||
}
|
||||
|
||||
// Create is used to generate keys for targets, snapshots and timestamps
|
||||
func (ccs *CryptoService) Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) {
|
||||
func (ccs *CryptoService) Create(role string, algorithm data.KeyAlgorithm) (data.Key, error) {
|
||||
var privKey *data.PrivateKey
|
||||
var err error
|
||||
|
||||
|
@ -64,16 +64,27 @@ func (ccs *CryptoService) Create(role string, algorithm data.KeyAlgorithm) (*dat
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to add key to filestore: %v", err)
|
||||
}
|
||||
return data.PublicKeyFromPrivate(*privKey), nil
|
||||
return data.PublicKeyFromPrivate(privKey), nil
|
||||
}
|
||||
|
||||
// GetKey returns a key by ID
|
||||
func (ccs *CryptoService) GetKey(keyID string) data.Key {
|
||||
key, err := ccs.keyStore.GetKey(keyID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return data.PublicKeyFromPrivate(key)
|
||||
}
|
||||
|
||||
// RemoveKey deletes a key by ID
|
||||
func (ccs *CryptoService) RemoveKey(keyID string) error {
|
||||
return ccs.keyStore.Remove(keyID)
|
||||
}
|
||||
|
||||
// Sign returns the signatures for the payload with a set of keyIDs. It ignores
|
||||
// errors to sign and expects the called to validate if the number of returned
|
||||
// signatures is adequate.
|
||||
func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signature, error) {
|
||||
var sha256Sum [sha256.Size]byte
|
||||
sha256Computed := false
|
||||
|
||||
signatures := make([]data.Signature, 0, len(keyIDs))
|
||||
for _, keyid := range keyIDs {
|
||||
// ccs.gun will be empty if this is the root key
|
||||
|
@ -103,18 +114,10 @@ func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signatur
|
|||
|
||||
switch algorithm {
|
||||
case data.RSAKey:
|
||||
if !sha256Computed {
|
||||
sha256Sum = sha256.Sum256(payload)
|
||||
sha256Computed = true
|
||||
}
|
||||
sig, err = rsaSign(privKey, crypto.SHA256, sha256Sum[:])
|
||||
sig, err = rsaSign(privKey, payload)
|
||||
sigAlgorithm = data.RSAPSSSignature
|
||||
case data.ECDSAKey:
|
||||
if !sha256Computed {
|
||||
sha256Sum = sha256.Sum256(payload)
|
||||
sha256Computed = true
|
||||
}
|
||||
sig, err = ecdsaSign(privKey, sha256Sum[:])
|
||||
sig, err = ecdsaSign(privKey, payload)
|
||||
sigAlgorithm = data.ECDSASignature
|
||||
case data.ED25519Key:
|
||||
// ED25519 does not operate on a SHA256 hash
|
||||
|
@ -139,11 +142,13 @@ func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signatur
|
|||
return signatures, nil
|
||||
}
|
||||
|
||||
func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
|
||||
func rsaSign(privKey *data.PrivateKey, message []byte) ([]byte, error) {
|
||||
if privKey.Algorithm() != data.RSAKey {
|
||||
return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm())
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256(message)
|
||||
|
||||
// Create an rsa.PrivateKey out of the private key bytes
|
||||
rsaPrivKey, err := x509.ParsePKCS1PrivateKey(privKey.Private())
|
||||
if err != nil {
|
||||
|
@ -151,7 +156,7 @@ func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte,
|
|||
}
|
||||
|
||||
// Use the RSA key to RSASSA-PSS sign the data
|
||||
sig, err := rsa.SignPSS(rand.Reader, rsaPrivKey, hash, hashed[:], &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
|
||||
sig, err := rsa.SignPSS(rand.Reader, rsaPrivKey, crypto.SHA256, hashed[:], &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -159,11 +164,13 @@ func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte,
|
|||
return sig, nil
|
||||
}
|
||||
|
||||
func ecdsaSign(privKey *data.PrivateKey, hashed []byte) ([]byte, error) {
|
||||
func ecdsaSign(privKey *data.PrivateKey, message []byte) ([]byte, error) {
|
||||
if privKey.Algorithm() != data.ECDSAKey {
|
||||
return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm())
|
||||
}
|
||||
|
||||
hashed := sha256.Sum256(message)
|
||||
|
||||
// Create an ecdsa.PrivateKey out of the private key bytes
|
||||
ecdsaPrivKey, err := x509.ParseECPrivateKey(privKey.Private())
|
||||
if err != nil {
|
||||
|
|
|
@ -36,7 +36,7 @@ func (ucs *UnlockedCryptoService) ID() string {
|
|||
|
||||
// PublicKey Returns the public key associated with the private key
|
||||
func (ucs *UnlockedCryptoService) PublicKey() *data.PublicKey {
|
||||
return data.PublicKeyFromPrivate(*ucs.PrivKey)
|
||||
return data.PublicKeyFromPrivate(ucs.PrivKey)
|
||||
}
|
||||
|
||||
// GenerateCertificate generates an X509 Certificate from a template, given a GUN
|
||||
|
|
|
@ -30,7 +30,7 @@ func GetOrCreateTimestampKey(gun string, store storage.MetaStore, crypto signed.
|
|||
}
|
||||
err = store.SetTimestampKey(gun, key.Algorithm(), key.Public())
|
||||
if err == nil {
|
||||
return &key.TUFKey, nil
|
||||
return data.NewTUFKey(key.Algorithm(), key.Public(), key.Private()), nil
|
||||
}
|
||||
|
||||
if _, ok := err.(*storage.ErrTimestampKeyExists); ok {
|
||||
|
|
|
@ -7,33 +7,34 @@ import (
|
|||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/endophage/gotuf/signed"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
// Handlers sets up all the handers for the routes, injecting a specific SigningService object for them to use
|
||||
func Handlers(sigServices signer.SigningServiceIndex) *mux.Router {
|
||||
// Handlers sets up all the handers for the routes, injecting a specific CryptoService object for them to use
|
||||
func Handlers(cryptoServices signer.CryptoServiceIndex) *mux.Router {
|
||||
r := mux.NewRouter()
|
||||
|
||||
r.Methods("GET").Path("/{ID}").Handler(KeyInfo(sigServices))
|
||||
r.Methods("POST").Path("/new/{Algorithm}").Handler(CreateKey(sigServices))
|
||||
r.Methods("POST").Path("/delete").Handler(DeleteKey(sigServices))
|
||||
r.Methods("POST").Path("/sign").Handler(Sign(sigServices))
|
||||
r.Methods("GET").Path("/{ID}").Handler(KeyInfo(cryptoServices))
|
||||
r.Methods("POST").Path("/new/{Algorithm}").Handler(CreateKey(cryptoServices))
|
||||
r.Methods("POST").Path("/delete").Handler(DeleteKey(cryptoServices))
|
||||
r.Methods("POST").Path("/sign").Handler(Sign(cryptoServices))
|
||||
return r
|
||||
}
|
||||
|
||||
// getSigningService handles looking up the correct signing service, given the
|
||||
// getCryptoService handles looking up the correct signing service, given the
|
||||
// algorithm specified in the HTTP request. If the algorithm isn't specified
|
||||
// or isn't supported, an error is returned to the client and this function
|
||||
// returns a nil SigningService
|
||||
func getSigningService(w http.ResponseWriter, algorithm string, sigServices signer.SigningServiceIndex) signer.SigningService {
|
||||
// returns a nil CryptoService
|
||||
func getCryptoService(w http.ResponseWriter, algorithm string, cryptoServices signer.CryptoServiceIndex) signed.CryptoService {
|
||||
if algorithm == "" {
|
||||
http.Error(w, "algorithm not specified", http.StatusBadRequest)
|
||||
return nil
|
||||
}
|
||||
|
||||
service := sigServices[data.KeyAlgorithm(algorithm)]
|
||||
service := cryptoServices[data.KeyAlgorithm(algorithm)]
|
||||
|
||||
if service == nil {
|
||||
http.Error(w, "algorithm "+algorithm+" not supported", http.StatusBadRequest)
|
||||
|
@ -44,11 +45,11 @@ func getSigningService(w http.ResponseWriter, algorithm string, sigServices sign
|
|||
}
|
||||
|
||||
// KeyInfo returns a Handler that given a specific Key ID param, returns the public key bits of that key
|
||||
func KeyInfo(sigServices signer.SigningServiceIndex) http.Handler {
|
||||
func KeyInfo(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
|
||||
key, _, err := FindKeyByID(sigServices, &pb.KeyID{ID: vars["ID"]})
|
||||
tufKey, _, err := FindKeyByID(cryptoServices, &pb.KeyID{ID: vars["ID"]})
|
||||
if err != nil {
|
||||
switch err {
|
||||
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
|
||||
|
@ -63,34 +64,48 @@ func KeyInfo(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
return
|
||||
}
|
||||
}
|
||||
key := &pb.PublicKey{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
PublicKey: tufKey.Public(),
|
||||
}
|
||||
json.NewEncoder(w).Encode(key)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// CreateKey returns a handler that generates a new
|
||||
func CreateKey(sigServices signer.SigningServiceIndex) http.Handler {
|
||||
func CreateKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
sigService := getSigningService(w, vars["Algorithm"], sigServices)
|
||||
if sigService == nil {
|
||||
// Error handled inside getSigningService
|
||||
cryptoService := getCryptoService(w, vars["Algorithm"], cryptoServices)
|
||||
if cryptoService == nil {
|
||||
// Error handled inside getCryptoService
|
||||
return
|
||||
}
|
||||
|
||||
key, err := sigService.CreateKey()
|
||||
tufKey, err := cryptoService.Create("", data.KeyAlgorithm(vars["Algorithm"]))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
key := &pb.PublicKey{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
PublicKey: tufKey.Public(),
|
||||
}
|
||||
json.NewEncoder(w).Encode(key)
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteKey returns a handler that delete a specific KeyID
|
||||
func DeleteKey(sigServices signer.SigningServiceIndex) http.Handler {
|
||||
func DeleteKey(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var keyID *pb.KeyID
|
||||
err := json.NewDecoder(r.Body).Decode(&keyID)
|
||||
|
@ -102,7 +117,7 @@ func DeleteKey(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
return
|
||||
}
|
||||
|
||||
_, sigService, err := FindKeyByID(sigServices, keyID)
|
||||
_, cryptoService, err := FindKeyByID(cryptoServices, keyID)
|
||||
|
||||
if err != nil {
|
||||
switch err {
|
||||
|
@ -119,9 +134,7 @@ func DeleteKey(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
}
|
||||
}
|
||||
|
||||
_, err = sigService.DeleteKey(keyID)
|
||||
|
||||
if err != nil {
|
||||
if err = cryptoService.RemoveKey(keyID.ID); err != nil {
|
||||
switch err {
|
||||
// If we received an ErrInvalidKeyID, the key doesn't exist, return 404
|
||||
case keys.ErrInvalidKeyID:
|
||||
|
@ -141,7 +154,7 @@ func DeleteKey(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
}
|
||||
|
||||
// Sign returns a handler that is able to perform signatures on a given blob
|
||||
func Sign(sigServices signer.SigningServiceIndex) http.Handler {
|
||||
func Sign(cryptoServices signer.CryptoServiceIndex) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
var sigRequest *pb.SignatureRequest
|
||||
err := json.NewDecoder(r.Body).Decode(&sigRequest)
|
||||
|
@ -154,7 +167,7 @@ func Sign(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
return
|
||||
}
|
||||
|
||||
_, sigService, err := FindKeyByID(sigServices, sigRequest.KeyID)
|
||||
tufKey, cryptoService, err := FindKeyByID(cryptoServices, sigRequest.KeyID)
|
||||
if err == keys.ErrInvalidKeyID {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -166,23 +179,18 @@ func Sign(sigServices signer.SigningServiceIndex) http.Handler {
|
|||
return
|
||||
}
|
||||
|
||||
signer, err := sigService.Signer(sigRequest.KeyID)
|
||||
if err == keys.ErrInvalidKeyID {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
} else if err != nil {
|
||||
// We got an unexpected error
|
||||
signatures, err := cryptoService.Sign([]string{sigRequest.KeyID.ID}, sigRequest.Content)
|
||||
if err != nil || len(signatures) != 1 {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
signature, err := signer.Sign(sigRequest)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
signature := &pb.Signature{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
Content: signatures[0].Signature,
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(signature)
|
||||
|
|
|
@ -11,9 +11,10 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/notary/cryptoservice"
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/api"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/docker/notary/trustmanager"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/miekg/pkcs11"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -22,14 +23,12 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
server *httptest.Server
|
||||
reader io.Reader
|
||||
hsmSigService *api.RSASigningService
|
||||
softwareSigService *api.EdDSASigningService
|
||||
deleteKeyBaseURL string
|
||||
createKeyBaseURL string
|
||||
keyInfoBaseURL string
|
||||
signBaseURL string
|
||||
server *httptest.Server
|
||||
reader io.Reader
|
||||
deleteKeyBaseURL string
|
||||
createKeyBaseURL string
|
||||
keyInfoBaseURL string
|
||||
signBaseURL string
|
||||
)
|
||||
|
||||
func SetupHSMEnv(t *testing.T) (*pkcs11.Ctx, pkcs11.SessionHandle) {
|
||||
|
@ -65,8 +64,8 @@ func SetupHSMEnv(t *testing.T) (*pkcs11.Ctx, pkcs11.SessionHandle) {
|
|||
return p, session
|
||||
}
|
||||
|
||||
func setup(sigServices signer.SigningServiceIndex) {
|
||||
server = httptest.NewServer(api.Handlers(sigServices))
|
||||
func setup(cryptoServices signer.CryptoServiceIndex) {
|
||||
server = httptest.NewServer(api.Handlers(cryptoServices))
|
||||
deleteKeyBaseURL = fmt.Sprintf("%s/delete", server.URL)
|
||||
createKeyBaseURL = fmt.Sprintf("%s/new", server.URL)
|
||||
keyInfoBaseURL = fmt.Sprintf("%s", server.URL)
|
||||
|
@ -74,10 +73,9 @@ func setup(sigServices signer.SigningServiceIndex) {
|
|||
}
|
||||
|
||||
func TestDeleteKeyHandlerReturns404WithNonexistentKey(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
fakeID := "c62e6d68851cef1f7e55a9d56e3b0c05f3359f16838cad43600f0554e7d3b54d"
|
||||
|
||||
|
@ -95,14 +93,13 @@ func TestDeleteKeyHandlerReturns404WithNonexistentKey(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDeleteKeyHandler(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
key, _ := sigService.CreateKey()
|
||||
tufKey, _ := cryptoService.Create("", data.ED25519Key)
|
||||
|
||||
requestJson, _ := json.Marshal(key.KeyInfo.KeyID)
|
||||
requestJson, _ := json.Marshal(&pb.KeyID{ID: tufKey.ID()})
|
||||
reader = strings.NewReader(string(requestJson))
|
||||
|
||||
request, err := http.NewRequest("POST", deleteKeyBaseURL, reader)
|
||||
|
@ -115,14 +112,13 @@ func TestDeleteKeyHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestKeyInfoHandler(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
key, _ := sigService.CreateKey()
|
||||
tufKey, _ := cryptoService.Create("", data.ED25519Key)
|
||||
|
||||
keyInfoURL := fmt.Sprintf("%s/%s", keyInfoBaseURL, key.KeyInfo.KeyID.ID)
|
||||
keyInfoURL := fmt.Sprintf("%s/%s", keyInfoBaseURL, tufKey.ID())
|
||||
|
||||
request, err := http.NewRequest("GET", keyInfoURL, nil)
|
||||
assert.Nil(t, err)
|
||||
|
@ -137,15 +133,16 @@ func TestKeyInfoHandler(t *testing.T) {
|
|||
err = json.Unmarshal(jsonBlob, &pubKey)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, key.KeyInfo.KeyID.ID, pubKey.KeyInfo.KeyID.ID)
|
||||
assert.Equal(t, tufKey.ID(), pubKey.KeyInfo.KeyID.ID)
|
||||
assert.Equal(t, 200, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestKeyInfoHandlerReturns404WithNonexistentKey(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
fakeID := "c62e6d68851cef1f7e55a9d56e3b0c05f3359f16838cad43600f0554e7d3b54d"
|
||||
keyInfoURL := fmt.Sprintf("%s/%s", keyInfoBaseURL, fakeID)
|
||||
|
@ -166,10 +163,8 @@ func TestHSMCreateKeyHandler(t *testing.T) {
|
|||
defer ctx.CloseSession(session)
|
||||
defer ctx.Logout(session)
|
||||
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewRSASigningService(ctx, session)
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
cryptoService := api.NewRSAHardwareCryptoService(ctx, session)
|
||||
setup(signer.CryptoServiceIndex{data.RSAKey: cryptoService})
|
||||
|
||||
createKeyURL := fmt.Sprintf("%s/%s", createKeyBaseURL, data.RSAKey)
|
||||
|
||||
|
@ -190,10 +185,9 @@ func TestHSMCreateKeyHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSoftwareCreateKeyHandler(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
createKeyURL := fmt.Sprintf("%s/%s", createKeyBaseURL, data.ED25519Key)
|
||||
|
||||
|
@ -220,14 +214,12 @@ func TestHSMSignHandler(t *testing.T) {
|
|||
defer ctx.CloseSession(session)
|
||||
defer ctx.Logout(session)
|
||||
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewRSASigningService(ctx, session)
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
cryptoService := api.NewRSAHardwareCryptoService(ctx, session)
|
||||
setup(signer.CryptoServiceIndex{data.RSAKey: cryptoService})
|
||||
|
||||
key, _ := sigService.CreateKey()
|
||||
tufKey, _ := cryptoService.Create("", data.RSAKey)
|
||||
|
||||
sigRequest := &pb.SignatureRequest{KeyID: key.KeyInfo.KeyID, Content: make([]byte, 10)}
|
||||
sigRequest := &pb.SignatureRequest{KeyID: &pb.KeyID{ID: tufKey.ID()}, Content: make([]byte, 10)}
|
||||
requestJson, _ := json.Marshal(sigRequest)
|
||||
|
||||
reader = strings.NewReader(string(requestJson))
|
||||
|
@ -246,20 +238,19 @@ func TestHSMSignHandler(t *testing.T) {
|
|||
err = json.Unmarshal(jsonBlob, &sig)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, key.KeyInfo.KeyID.ID, sig.KeyInfo.KeyID.ID)
|
||||
assert.Equal(t, tufKey.ID, sig.KeyInfo.KeyID.ID)
|
||||
assert.Equal(t, 200, res.StatusCode)
|
||||
}
|
||||
|
||||
func TestSoftwareSignHandler(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
key, err := sigService.CreateKey()
|
||||
tufKey, err := cryptoService.Create("", data.ED25519Key)
|
||||
assert.Nil(t, err)
|
||||
|
||||
sigRequest := &pb.SignatureRequest{KeyID: key.KeyInfo.KeyID, Content: make([]byte, 10)}
|
||||
sigRequest := &pb.SignatureRequest{KeyID: &pb.KeyID{ID: tufKey.ID()}, Content: make([]byte, 10)}
|
||||
requestJson, _ := json.Marshal(sigRequest)
|
||||
|
||||
reader = strings.NewReader(string(requestJson))
|
||||
|
@ -280,14 +271,13 @@ func TestSoftwareSignHandler(t *testing.T) {
|
|||
err = json.Unmarshal(jsonBlob, &sig)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, key.KeyInfo.KeyID.ID, sig.KeyInfo.KeyID.ID)
|
||||
assert.Equal(t, tufKey.ID(), sig.KeyInfo.KeyID.ID)
|
||||
}
|
||||
|
||||
func TestSoftwareSignWithInvalidRequestHandler(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
requestJson := "{\"blob\":\"7d16f1d0b95310a7bc557747fc4f20fcd41c1c5095ae42f189df0717e7d7f4a0a2b55debce630f43c4ac099769c612965e3fda3cd4c0078ee6a460f14fa19307\"}"
|
||||
reader = strings.NewReader(requestJson)
|
||||
|
@ -309,14 +299,13 @@ func TestSoftwareSignWithInvalidRequestHandler(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSignHandlerReturns404WithNonexistentKey(t *testing.T) {
|
||||
// We associate both key types with this signing service to bypass the
|
||||
// ID -> keyType logic in the tests
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
setup(signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService})
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
setup(signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService})
|
||||
|
||||
fakeID := "c62e6d68851cef1f7e55a9d56e3b0c05f3359f16838cad43600f0554e7d3b54d"
|
||||
|
||||
sigService.CreateKey()
|
||||
cryptoService.Create("", data.ED25519Key)
|
||||
|
||||
sigRequest := &pb.SignatureRequest{KeyID: &pb.KeyID{ID: fakeID}, Content: make([]byte, 10)}
|
||||
requestJson, _ := json.Marshal(sigRequest)
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"github.com/agl/ed25519"
|
||||
"github.com/endophage/gotuf/data"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
// Ed25519Signer implements the Signer interface for Ed25519 keys
|
||||
type Ed25519Signer struct {
|
||||
privateKey data.Key
|
||||
}
|
||||
|
||||
// Sign returns a signature for a given blob
|
||||
func (s *Ed25519Signer) Sign(request *pb.SignatureRequest) (*pb.Signature, error) {
|
||||
priv := [ed25519.PrivateKeySize]byte{}
|
||||
copy(priv[:], s.privateKey.Private())
|
||||
sig := ed25519.Sign(&priv, request.Content)
|
||||
|
||||
return &pb.Signature{KeyInfo: &pb.KeyInfo{KeyID: &pb.KeyID{ID: s.privateKey.ID()}, Algorithm: &pb.Algorithm{Algorithm: data.ED25519Key.String()}}, Content: sig[:]}, nil
|
||||
}
|
||||
|
||||
// NewEd25519Signer returns a Ed25519Signer, given a private key
|
||||
func NewEd25519Signer(key data.Key) *Ed25519Signer {
|
||||
return &Ed25519Signer{privateKey: key}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package api_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/agl/ed25519"
|
||||
"github.com/docker/notary/signer/api"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
type zeroReader struct{}
|
||||
|
||||
func (zeroReader) Read(buf []byte) (int, error) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
return len(buf), nil
|
||||
}
|
||||
|
||||
func TestSign(t *testing.T) {
|
||||
var zero zeroReader
|
||||
public, private, _ := ed25519.GenerateKey(zero)
|
||||
|
||||
blob := []byte("test message")
|
||||
|
||||
directSig := ed25519.Sign(private, blob)
|
||||
directSigHex := hex.EncodeToString(directSig[:])
|
||||
|
||||
key := data.NewPrivateKey(data.ED25519Key, public[:], private[:])
|
||||
signer := api.NewEd25519Signer(key)
|
||||
|
||||
sigRequest := &pb.SignatureRequest{KeyID: &pb.KeyID{ID: key.ID()}, Content: blob}
|
||||
|
||||
sig, err := signer.Sign(sigRequest)
|
||||
assert.Nil(t, err)
|
||||
signatureHex := fmt.Sprintf("%x", sig.Content)
|
||||
|
||||
assert.Equal(t, directSigHex, signatureHex)
|
||||
assert.Equal(t, sig.KeyInfo.KeyID.ID, key.ID())
|
||||
}
|
||||
|
||||
func BenchmarkSign(b *testing.B) {
|
||||
blob := []byte("7d16f1d0b95310a7bc557747fc4f20fcd41c1c5095ae42f189df")
|
||||
|
||||
keyDB := keys.NewKeyDB()
|
||||
var sigService = api.NewEdDSASigningService(keyDB)
|
||||
|
||||
key, _ := sigService.CreateKey()
|
||||
privkey, _ := keyDB.GetKey(key.KeyInfo.KeyID)
|
||||
|
||||
signer := api.NewEd25519Signer(privkey)
|
||||
sigRequest := &pb.SignatureRequest{KeyID: key.KeyInfo.KeyID, Content: blob}
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
_, _ = signer.Sign(sigRequest)
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
|
||||
"github.com/agl/ed25519"
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
// EdDSASigningService is an implementation of SigningService
|
||||
type EdDSASigningService struct {
|
||||
KeyDB signer.KeyDatabase
|
||||
}
|
||||
|
||||
// CreateKey creates a key and returns its public components
|
||||
func (s EdDSASigningService) CreateKey() (*pb.PublicKey, error) {
|
||||
pub, priv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k := data.NewPrivateKey(data.ED25519Key, pub[:], priv[:])
|
||||
|
||||
err = s.KeyDB.AddKey(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pubKey := &pb.PublicKey{KeyInfo: &pb.KeyInfo{KeyID: &pb.KeyID{ID: k.ID()}, Algorithm: &pb.Algorithm{Algorithm: k.Algorithm().String()}}, PublicKey: pub[:]}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// DeleteKey removes a key from the key database
|
||||
func (s EdDSASigningService) DeleteKey(keyID *pb.KeyID) (*pb.Void, error) {
|
||||
return s.KeyDB.DeleteKey(keyID)
|
||||
}
|
||||
|
||||
// KeyInfo returns the public components of a particular key
|
||||
func (s EdDSASigningService) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
|
||||
return s.KeyDB.KeyInfo(keyID)
|
||||
}
|
||||
|
||||
// Signer returns a Signer for a specific KeyID
|
||||
func (s EdDSASigningService) Signer(keyID *pb.KeyID) (signer.Signer, error) {
|
||||
key, err := s.KeyDB.GetKey(keyID)
|
||||
if err != nil {
|
||||
return nil, keys.ErrInvalidKeyID
|
||||
}
|
||||
return &Ed25519Signer{privateKey: key}, nil
|
||||
}
|
||||
|
||||
// NewEdDSASigningService returns an instance of KeyDB
|
||||
func NewEdDSASigningService(keyDB signer.KeyDatabase) *EdDSASigningService {
|
||||
return &EdDSASigningService{
|
||||
KeyDB: keyDB,
|
||||
}
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
package api_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/docker/notary/signer/api"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
type FakeKeyDB struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *FakeKeyDB) CreateKey() (*pb.PublicKey, error) {
|
||||
args := m.Mock.Called()
|
||||
return args.Get(0).(*pb.PublicKey), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *FakeKeyDB) AddKey(key data.Key) error {
|
||||
args := m.Mock.Called()
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *FakeKeyDB) DeleteKey(keyID *pb.KeyID) (*pb.Void, error) {
|
||||
args := m.Mock.Called(keyID.ID)
|
||||
return nil, args.Error(0)
|
||||
}
|
||||
|
||||
func (m *FakeKeyDB) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
|
||||
args := m.Mock.Called(keyID.ID)
|
||||
return args.Get(0).(*pb.PublicKey), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *FakeKeyDB) GetKey(keyID *pb.KeyID) (data.Key, error) {
|
||||
args := m.Mock.Called(keyID.ID)
|
||||
return args.Get(0).(data.Key), args.Error(1)
|
||||
}
|
||||
|
||||
func TestDeleteKey(t *testing.T) {
|
||||
fakeKeyID := "830158bb5a4af00a3f689a8f29120f0fa7f8ae57cf00ce1fede8ae8652b5181a"
|
||||
|
||||
m := FakeKeyDB{}
|
||||
sigService := api.NewEdDSASigningService(&m)
|
||||
|
||||
m.On("DeleteKey", fakeKeyID).Return(nil).Once()
|
||||
_, err := sigService.DeleteKey(&pb.KeyID{ID: fakeKeyID})
|
||||
|
||||
m.Mock.AssertExpectations(t)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestKeyInfo(t *testing.T) {
|
||||
fakeKeyID := "830158bb5a4af00a3f689a8f29120f0fa7f8ae57cf00ce1fede8ae8652b5181a"
|
||||
|
||||
m := FakeKeyDB{}
|
||||
sigService := api.NewEdDSASigningService(&m)
|
||||
|
||||
m.On("KeyInfo", fakeKeyID).Return(&pb.PublicKey{}, nil).Once()
|
||||
_, err := sigService.KeyInfo(&pb.KeyID{ID: fakeKeyID})
|
||||
|
||||
m.Mock.AssertExpectations(t)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestCreateKey(t *testing.T) {
|
||||
m := FakeKeyDB{}
|
||||
sigService := api.NewEdDSASigningService(&m)
|
||||
|
||||
m.On("AddKey").Return(nil).Once()
|
||||
|
||||
_, err := sigService.CreateKey()
|
||||
|
||||
m.Mock.AssertExpectations(t)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestSigner(t *testing.T) {
|
||||
fakeKeyID := "830158bb5a4af00a3f689a8f29120f0fa7f8ae57cf00ce1fede8ae8652b5181a"
|
||||
m := FakeKeyDB{}
|
||||
sigService := api.NewEdDSASigningService(&m)
|
||||
|
||||
m.On("GetKey", fakeKeyID).Return(&data.PrivateKey{}, nil).Once()
|
||||
_, err := sigService.Signer(&pb.KeyID{ID: fakeKeyID})
|
||||
|
||||
m.Mock.AssertExpectations(t)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
func BenchmarkCreateKey(b *testing.B) {
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
for n := 0; n < b.N; n++ {
|
||||
_, _ = sigService.CreateKey()
|
||||
}
|
||||
}
|
|
@ -3,6 +3,8 @@ package api
|
|||
import (
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/endophage/gotuf/signed"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
@ -10,10 +12,12 @@ import (
|
|||
// FindKeyByID looks for the key with the given ID in each of the
|
||||
// signing services in sigServices. It returns the first matching key it finds,
|
||||
// or ErrInvalidKeyID if the key is not found in any of the signing services.
|
||||
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 {
|
||||
// It also returns the CryptoService associated with the key, so the caller
|
||||
// can perform operations with the key (such as signing).
|
||||
func FindKeyByID(cryptoServices signer.CryptoServiceIndex, keyID *pb.KeyID) (data.Key, signed.CryptoService, error) {
|
||||
for _, service := range cryptoServices {
|
||||
key := service.GetKey(keyID.ID)
|
||||
if key != nil {
|
||||
return key, service, nil
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,39 +17,47 @@ import (
|
|||
|
||||
//KeyManagementServer implements the KeyManagementServer grpc interface
|
||||
type KeyManagementServer struct {
|
||||
SigServices signer.SigningServiceIndex
|
||||
CryptoServices signer.CryptoServiceIndex
|
||||
}
|
||||
|
||||
//SignerServer implements the SignerServer grpc interface
|
||||
type SignerServer struct {
|
||||
SigServices signer.SigningServiceIndex
|
||||
CryptoServices signer.CryptoServiceIndex
|
||||
}
|
||||
|
||||
//CreateKey returns a PublicKey created using KeyManagementServer's SigningService
|
||||
func (s *KeyManagementServer) CreateKey(ctx context.Context, algorithm *pb.Algorithm) (*pb.PublicKey, error) {
|
||||
service := s.SigServices[data.KeyAlgorithm(algorithm.Algorithm)]
|
||||
keyAlgo := data.KeyAlgorithm(algorithm.Algorithm)
|
||||
|
||||
service := s.CryptoServices[keyAlgo]
|
||||
|
||||
if service == nil {
|
||||
return nil, fmt.Errorf("algorithm %s not supported for create key", algorithm.Algorithm)
|
||||
}
|
||||
|
||||
key, err := service.CreateKey()
|
||||
tufKey, err := service.Create("", keyAlgo)
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.Internal, "Key creation failed")
|
||||
}
|
||||
log.Println("[Notary-signer CreateKey] : Created KeyID ", key.KeyInfo.KeyID.ID)
|
||||
return key, nil
|
||||
log.Println("[Notary-signer CreateKey] : Created KeyID ", tufKey.ID())
|
||||
return &pb.PublicKey{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
PublicKey: tufKey.Public(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//DeleteKey deletes they key associated with a KeyID
|
||||
func (s *KeyManagementServer) DeleteKey(ctx context.Context, keyID *pb.KeyID) (*pb.Void, error) {
|
||||
_, service, err := FindKeyByID(s.SigServices, keyID)
|
||||
_, service, err := FindKeyByID(s.CryptoServices, keyID)
|
||||
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
|
||||
}
|
||||
|
||||
_, err = service.DeleteKey(keyID)
|
||||
err = service.RemoveKey(keyID.ID)
|
||||
log.Println("[Notary-signer DeleteKey] : Deleted KeyID ", keyID.ID)
|
||||
if err != nil {
|
||||
switch err {
|
||||
|
@ -65,39 +73,47 @@ func (s *KeyManagementServer) DeleteKey(ctx context.Context, keyID *pb.KeyID) (*
|
|||
|
||||
//GetKeyInfo returns they PublicKey associated with a KeyID
|
||||
func (s *KeyManagementServer) GetKeyInfo(ctx context.Context, keyID *pb.KeyID) (*pb.PublicKey, error) {
|
||||
_, service, err := FindKeyByID(s.SigServices, keyID)
|
||||
_, service, err := FindKeyByID(s.CryptoServices, keyID)
|
||||
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", keyID.ID)
|
||||
}
|
||||
|
||||
key, err := service.KeyInfo(keyID)
|
||||
if err != nil {
|
||||
tufKey := service.GetKey(keyID.ID)
|
||||
if tufKey == 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 &pb.PublicKey{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
PublicKey: tufKey.Public(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
//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) {
|
||||
_, service, err := FindKeyByID(s.SigServices, sr.KeyID)
|
||||
tufKey, service, err := FindKeyByID(s.CryptoServices, sr.KeyID)
|
||||
|
||||
if err != nil {
|
||||
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 ", sr.KeyID.ID)
|
||||
signer, err := service.Signer(sr.KeyID)
|
||||
if err == keys.ErrInvalidKeyID {
|
||||
return nil, grpc.Errorf(codes.NotFound, "Invalid keyID: key %s not found", sr.KeyID.ID)
|
||||
} else if err != nil {
|
||||
|
||||
signatures, err := service.Sign([]string{sr.KeyID.ID}, sr.Content)
|
||||
if err != nil || len(signatures) != 1 {
|
||||
return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", sr.KeyID.ID, sr.Content)
|
||||
}
|
||||
|
||||
signature, err := signer.Sign(sr)
|
||||
if err != nil {
|
||||
return nil, grpc.Errorf(codes.Internal, "Signing failed for keyID %s on hash %s", sr.KeyID.ID, sr.Content)
|
||||
signature := &pb.Signature{
|
||||
KeyInfo: &pb.KeyInfo{
|
||||
KeyID: &pb.KeyID{ID: tufKey.ID()},
|
||||
Algorithm: &pb.Algorithm{Algorithm: tufKey.Algorithm().String()},
|
||||
},
|
||||
Content: signatures[0].Signature,
|
||||
}
|
||||
|
||||
return signature, nil
|
||||
|
|
|
@ -6,9 +6,10 @@ import (
|
|||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/docker/notary/cryptoservice"
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/api"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/docker/notary/trustmanager"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -26,12 +27,13 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
sigService := api.NewEdDSASigningService(keys.NewKeyDB())
|
||||
sigServices := signer.SigningServiceIndex{data.ED25519Key: sigService, data.RSAKey: sigService}
|
||||
keyStore := trustmanager.NewKeyMemoryStore()
|
||||
cryptoService := cryptoservice.NewCryptoService("", keyStore, "")
|
||||
cryptoServices := signer.CryptoServiceIndex{data.ED25519Key: cryptoService, data.RSAKey: cryptoService, data.ECDSAKey: cryptoService}
|
||||
void = &pb.Void{}
|
||||
//server setup
|
||||
kms := &api.KeyManagementServer{SigServices: sigServices}
|
||||
ss := &api.SignerServer{SigServices: sigServices}
|
||||
kms := &api.KeyManagementServer{CryptoServices: cryptoServices}
|
||||
ss := &api.SignerServer{CryptoServices: cryptoServices}
|
||||
grpcServer = grpc.NewServer()
|
||||
pb.RegisterKeyManagementServer(grpcServer, kms)
|
||||
pb.RegisterSignerServer(grpcServer, ss)
|
||||
|
|
|
@ -10,23 +10,20 @@ import (
|
|||
"log"
|
||||
"math/big"
|
||||
|
||||
"github.com/docker/notary/signer"
|
||||
"github.com/docker/notary/signer/keys"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/miekg/pkcs11"
|
||||
|
||||
pb "github.com/docker/notary/proto"
|
||||
)
|
||||
|
||||
// RSASigningService is an implementation of SigningService
|
||||
type RSASigningService struct {
|
||||
// RSAHardwareCryptoService is an implementation of SigningService
|
||||
type RSAHardwareCryptoService struct {
|
||||
keys map[string]*keys.HSMRSAKey
|
||||
context *pkcs11.Ctx
|
||||
session pkcs11.SessionHandle
|
||||
}
|
||||
|
||||
// CreateKey creates a key and returns its public components
|
||||
func (s RSASigningService) CreateKey() (*pb.PublicKey, error) {
|
||||
|
||||
// Create creates a key and returns its public components
|
||||
func (s *RSAHardwareCryptoService) Create(role string, algo data.KeyAlgorithm) (data.Key, error) {
|
||||
// For now generate random labels for keys
|
||||
// (diogo): add link between keyID and label in database so we can support multiple keys
|
||||
randomLabel := make([]byte, 32)
|
||||
|
@ -101,100 +98,87 @@ func (s RSASigningService) CreateKey() (*pb.PublicKey, error) {
|
|||
|
||||
s.keys[keyID] = k
|
||||
|
||||
pubKey := &pb.PublicKey{KeyInfo: &pb.KeyInfo{KeyID: &pb.KeyID{ID: keyID}, Algorithm: &pb.Algorithm{Algorithm: k.Algorithm().String()}}, PublicKey: k.Public()}
|
||||
|
||||
return pubKey, nil
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// DeleteKey removes a key from the key database
|
||||
func (s RSASigningService) DeleteKey(keyID *pb.KeyID) (*pb.Void, error) {
|
||||
if _, ok := s.keys[keyID.ID]; !ok {
|
||||
return nil, keys.ErrInvalidKeyID
|
||||
// RemoveKey removes a key from the key database
|
||||
func (s *RSAHardwareCryptoService) RemoveKey(keyID string) error {
|
||||
if _, ok := s.keys[keyID]; !ok {
|
||||
return keys.ErrInvalidKeyID
|
||||
}
|
||||
|
||||
delete(s.keys, keyID.ID)
|
||||
return nil, nil
|
||||
delete(s.keys, keyID)
|
||||
return nil
|
||||
}
|
||||
|
||||
// KeyInfo returns the public components of a particular key
|
||||
func (s RSASigningService) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
|
||||
k, ok := s.keys[keyID.ID]
|
||||
if !ok {
|
||||
return nil, keys.ErrInvalidKeyID
|
||||
}
|
||||
|
||||
pubKey := &pb.PublicKey{KeyInfo: &pb.KeyInfo{KeyID: keyID, Algorithm: &pb.Algorithm{Algorithm: k.Algorithm().String()}}, PublicKey: k.Public()}
|
||||
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// Signer returns a Signer for a specific KeyID
|
||||
func (s RSASigningService) Signer(keyID *pb.KeyID) (signer.Signer, error) {
|
||||
key, ok := s.keys[keyID.ID]
|
||||
if !ok {
|
||||
return nil, keys.ErrInvalidKeyID
|
||||
}
|
||||
// TODO(diogo): Investigate if caching is worth it. Is this object expensive to create?
|
||||
return &RSASigner{privateKey: key, context: s.context, session: s.session}, nil
|
||||
}
|
||||
|
||||
// RSASigner implements the Signer interface for RSA keys
|
||||
type RSASigner struct {
|
||||
privateKey *keys.HSMRSAKey
|
||||
context *pkcs11.Ctx
|
||||
session pkcs11.SessionHandle
|
||||
// GetKey returns the public components of a particular key
|
||||
func (s *RSAHardwareCryptoService) GetKey(keyID string) data.Key {
|
||||
return s.keys[keyID]
|
||||
}
|
||||
|
||||
// Sign returns a signature for a given signature request
|
||||
func (s *RSASigner) Sign(request *pb.SignatureRequest) (*pb.Signature, error) {
|
||||
priv := s.privateKey.PKCS11ObjectHandle()
|
||||
var sig []byte
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
//TODO(mccauley): move this to RSA OAEP
|
||||
s.context.SignInit(s.session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_SHA256_RSA_PKCS, nil)}, priv)
|
||||
|
||||
sig, err = s.context.Sign(s.session, request.Content)
|
||||
if err != nil {
|
||||
log.Printf("Error while signing: %s", err)
|
||||
func (s *RSAHardwareCryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signature, error) {
|
||||
signatures := make([]data.Signature, 0, len(keyIDs))
|
||||
for _, keyid := range keyIDs {
|
||||
privateKey, present := s.keys[keyid]
|
||||
if !present {
|
||||
// We skip keys that aren't found
|
||||
continue
|
||||
}
|
||||
|
||||
// (diogo): XXX: Remove this before shipping
|
||||
digest := sha256.Sum256(request.Content)
|
||||
pub, err := x509.ParsePKIXPublicKey(s.privateKey.Public())
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse public key: %s\n", err)
|
||||
return nil, err
|
||||
priv := privateKey.PKCS11ObjectHandle()
|
||||
var sig []byte
|
||||
var err error
|
||||
for i := 0; i < 3; i++ {
|
||||
//TODO(mccauley): move this to RSA OAEP
|
||||
s.context.SignInit(s.session, []*pkcs11.Mechanism{pkcs11.NewMechanism(pkcs11.CKM_SHA256_RSA_PKCS, nil)}, priv)
|
||||
|
||||
sig, err = s.context.Sign(s.session, payload)
|
||||
if err != nil {
|
||||
log.Printf("Error while signing: %s", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// (diogo): XXX: Remove this before shipping
|
||||
digest := sha256.Sum256(payload)
|
||||
pub, err := x509.ParsePKIXPublicKey(privateKey.Public())
|
||||
if err != nil {
|
||||
log.Printf("Failed to parse public key: %s\n", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rsaPub, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
log.Printf("Value returned from ParsePKIXPublicKey was not an RSA public key")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, digest[:], sig)
|
||||
if err != nil {
|
||||
log.Printf("Failed verification. Retrying: %s", err)
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
rsaPub, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
log.Printf("Value returned from ParsePKIXPublicKey was not an RSA public key")
|
||||
return nil, err
|
||||
// (diogo): XXX: END Area of removal
|
||||
if sig == nil {
|
||||
return nil, errors.New("Failed to create signature")
|
||||
}
|
||||
|
||||
err = rsa.VerifyPKCS1v15(rsaPub, crypto.SHA256, digest[:], sig)
|
||||
if err != nil {
|
||||
log.Printf("Failed verification. Retrying: %s", err)
|
||||
continue
|
||||
}
|
||||
break
|
||||
signatures = append(signatures, data.Signature{
|
||||
KeyID: keyid,
|
||||
Method: data.RSAPKCS1v15Signature,
|
||||
Signature: sig[:],
|
||||
})
|
||||
}
|
||||
|
||||
// (diogo): XXX: END Area of removal
|
||||
if sig == nil {
|
||||
return nil, errors.New("Failed to create signature")
|
||||
}
|
||||
|
||||
returnSig := &pb.Signature{KeyInfo: &pb.KeyInfo{KeyID: &pb.KeyID{ID: s.privateKey.ID()}, Algorithm: &pb.Algorithm{Algorithm: s.privateKey.Algorithm().String()}}, Content: sig[:]}
|
||||
log.Printf("[Notary-signer Server] Signature request JSON: %s , response: %s", string(request.Content), returnSig)
|
||||
return returnSig, nil
|
||||
return signatures, nil
|
||||
}
|
||||
|
||||
// NewRSASigningService returns an instance of KeyDB
|
||||
func NewRSASigningService(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) *RSASigningService {
|
||||
return &RSASigningService{
|
||||
// NewRSAHardwareCryptoService returns an instance of RSAHardwareCryptoService
|
||||
func NewRSAHardwareCryptoService(ctx *pkcs11.Ctx, session pkcs11.SessionHandle) *RSAHardwareCryptoService {
|
||||
return &RSAHardwareCryptoService{
|
||||
keys: make(map[string]*keys.HSMRSAKey),
|
||||
context: ctx,
|
||||
session: session,
|
|
@ -1,62 +0,0 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
pb "github.com/docker/notary/proto"
|
||||
"github.com/endophage/gotuf/data"
|
||||
)
|
||||
|
||||
// KeyDB represents an in-memory key keystore
|
||||
type KeyDB struct {
|
||||
keys map[string]data.Key
|
||||
}
|
||||
|
||||
// CreateKey is needed to implement KeyManager. Returns an empty key.
|
||||
func (db *KeyDB) CreateKey() (*pb.PublicKey, error) {
|
||||
k := &pb.PublicKey{}
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// AddKey Adds a new key to the database
|
||||
func (db *KeyDB) AddKey(key data.Key) error {
|
||||
if _, ok := db.keys[key.ID()]; ok {
|
||||
return ErrExists
|
||||
}
|
||||
db.keys[key.ID()] = key
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetKey returns the private bits of a key
|
||||
func (db *KeyDB) GetKey(keyID *pb.KeyID) (data.Key, error) {
|
||||
if key, ok := db.keys[keyID.ID]; ok {
|
||||
return key, nil
|
||||
}
|
||||
return nil, ErrInvalidKeyID
|
||||
}
|
||||
|
||||
// DeleteKey deletes the keyID from the database
|
||||
func (db *KeyDB) DeleteKey(keyID *pb.KeyID) (*pb.Void, error) {
|
||||
_, err := db.GetKey(keyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
delete(db.keys, keyID.ID)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// KeyInfo returns the public bits of a key, given a specific keyID
|
||||
func (db *KeyDB) KeyInfo(keyID *pb.KeyID) (*pb.PublicKey, error) {
|
||||
key, err := db.GetKey(keyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.PublicKey{KeyInfo: &pb.KeyInfo{KeyID: keyID, Algorithm: &pb.Algorithm{Algorithm: key.Algorithm().String()}}, PublicKey: key.Public()}, nil
|
||||
}
|
||||
|
||||
// NewKeyDB returns an instance of KeyDB
|
||||
func NewKeyDB() *KeyDB {
|
||||
return &KeyDB{
|
||||
keys: make(map[string]data.Key),
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package signer
|
|||
import (
|
||||
pb "github.com/docker/notary/proto"
|
||||
"github.com/endophage/gotuf/data"
|
||||
"github.com/endophage/gotuf/signed"
|
||||
)
|
||||
|
||||
// SigningService is the interface to implement a key management and signing service
|
||||
|
@ -13,9 +14,9 @@ type SigningService interface {
|
|||
Signer(keyID *pb.KeyID) (Signer, error)
|
||||
}
|
||||
|
||||
// SigningServiceIndex represents a mapping between a service algorithm string
|
||||
// and a signing service
|
||||
type SigningServiceIndex map[data.KeyAlgorithm]SigningService
|
||||
// CryptoServiceIndex represents a mapping between a service algorithm string
|
||||
// and a CryptoService
|
||||
type CryptoServiceIndex map[data.KeyAlgorithm]signed.CryptoService
|
||||
|
||||
// KeyManager is the interface to implement key management (possibly a key database)
|
||||
type KeyManager interface {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package signer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
|
@ -62,8 +63,7 @@ func (trust *NotarySigner) Sign(keyIDs []string, toSign []byte) ([]data.Signatur
|
|||
}
|
||||
|
||||
// Create creates a remote key and returns the PublicKey associated with the remote private key
|
||||
// TODO(diogo): Ignoring algorithm for now until notary-signer supports it
|
||||
func (trust *NotarySigner) Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) {
|
||||
func (trust *NotarySigner) Create(role string, algorithm data.KeyAlgorithm) (data.Key, error) {
|
||||
publicKey, err := trust.kmClient.CreateKey(context.Background(), &pb.Algorithm{Algorithm: algorithm.String()})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -73,17 +73,14 @@ func (trust *NotarySigner) Create(role string, algorithm data.KeyAlgorithm) (*da
|
|||
return public, nil
|
||||
}
|
||||
|
||||
// PublicKeys returns the public key(s) associated with the passed in keyIDs
|
||||
func (trust *NotarySigner) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) {
|
||||
publicKeys := make(map[string]*data.PublicKey)
|
||||
for _, ID := range keyIDs {
|
||||
keyID := pb.KeyID{ID: ID}
|
||||
public, err := trust.kmClient.GetKeyInfo(context.Background(), &keyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
publicKeys[public.KeyInfo.KeyID.ID] =
|
||||
data.NewPublicKey(data.KeyAlgorithm(public.KeyInfo.Algorithm.Algorithm), public.PublicKey)
|
||||
}
|
||||
return publicKeys, nil
|
||||
// RemoveKey deletes a key
|
||||
func (trust *NotarySigner) RemoveKey(keyid string) error {
|
||||
//TODO(aaronl): Not implemented yet
|
||||
return errors.New("DeleteKey not implemented in NotarySigner")
|
||||
}
|
||||
|
||||
// GetKey retrieves a key
|
||||
func (trust *NotarySigner) GetKey(keyid string) data.Key {
|
||||
//TODO(aaronl): Not implemented yet
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -20,14 +21,21 @@ var (
|
|||
ErrPathOutsideStore = errors.New("path outside file store")
|
||||
)
|
||||
|
||||
// FileStore is the interface for all FileStores
|
||||
type FileStore interface {
|
||||
// LimitedFileStore implements the bare bones primitives (no symlinks or
|
||||
// hierarchy)
|
||||
type LimitedFileStore interface {
|
||||
Add(fileName string, data []byte) error
|
||||
Remove(fileName string) error
|
||||
RemoveDir(directoryName string) error
|
||||
Get(fileName string) ([]byte, error)
|
||||
GetPath(fileName string) (string, error)
|
||||
ListFiles(symlinks bool) []string
|
||||
}
|
||||
|
||||
// FileStore is the interface for full-featured FileStores
|
||||
type FileStore interface {
|
||||
LimitedFileStore
|
||||
|
||||
RemoveDir(directoryName string) error
|
||||
GetPath(fileName string) (string, error)
|
||||
ListDir(directoryName string, symlinks bool) []string
|
||||
Link(src, dst string) error
|
||||
BaseDir() string
|
||||
|
@ -41,7 +49,7 @@ type SimpleFileStore struct {
|
|||
}
|
||||
|
||||
// NewSimpleFileStore creates a directory with 755 permissions
|
||||
func NewSimpleFileStore(baseDir string, fileExt string) (FileStore, error) {
|
||||
func NewSimpleFileStore(baseDir string, fileExt string) (*SimpleFileStore, error) {
|
||||
baseDir = filepath.Clean(baseDir)
|
||||
|
||||
if err := CreateDirectory(baseDir); err != nil {
|
||||
|
@ -56,7 +64,7 @@ func NewSimpleFileStore(baseDir string, fileExt string) (FileStore, error) {
|
|||
}
|
||||
|
||||
// NewPrivateSimpleFileStore creates a directory with 700 permissions
|
||||
func NewPrivateSimpleFileStore(baseDir string, fileExt string) (FileStore, error) {
|
||||
func NewPrivateSimpleFileStore(baseDir string, fileExt string) (*SimpleFileStore, error) {
|
||||
if err := CreatePrivateDirectory(baseDir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -213,3 +221,68 @@ func createDirectory(dir string, perms os.FileMode) error {
|
|||
dir = dir + "/"
|
||||
return os.MkdirAll(dir, perms)
|
||||
}
|
||||
|
||||
// MemoryFileStore is an implementation of LimitedFileStore that keeps
|
||||
// the contents in memory.
|
||||
type MemoryFileStore struct {
|
||||
sync.Mutex
|
||||
|
||||
files map[string][]byte
|
||||
}
|
||||
|
||||
// NewMemoryFileStore creates a MemoryFileStore
|
||||
func NewMemoryFileStore() *MemoryFileStore {
|
||||
return &MemoryFileStore{
|
||||
files: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
// ErrMemFileNotFound is returned for a nonexistent "file" in the memory file
|
||||
// store
|
||||
var ErrMemFileNotFound = errors.New("key not found in memory file store")
|
||||
|
||||
// Add writes data to a file with a given name
|
||||
func (f *MemoryFileStore) Add(name string, data []byte) error {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
f.files[name] = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// Remove removes a file identified by name
|
||||
func (f *MemoryFileStore) Remove(name string) error {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
if _, present := f.files[name]; !present {
|
||||
return ErrMemFileNotFound
|
||||
}
|
||||
delete(f.files, name)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get returns the data given a file name
|
||||
func (f *MemoryFileStore) Get(name string) ([]byte, error) {
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
|
||||
fileData, present := f.files[name]
|
||||
if !present {
|
||||
return nil, ErrMemFileNotFound
|
||||
}
|
||||
|
||||
return fileData, nil
|
||||
}
|
||||
|
||||
// ListFiles lists all the files inside of a store
|
||||
func (f *MemoryFileStore) ListFiles(symlinks bool) []string {
|
||||
var list []string
|
||||
|
||||
for name := range f.files {
|
||||
list = append(list, name)
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
|
|
|
@ -11,9 +11,25 @@ const (
|
|||
keyExtension = "key"
|
||||
)
|
||||
|
||||
// KeyStore is a generic interface for private key storage
|
||||
type KeyStore interface {
|
||||
LimitedFileStore
|
||||
|
||||
AddKey(name string, privKey *data.PrivateKey) error
|
||||
GetKey(name string) (*data.PrivateKey, error)
|
||||
AddEncryptedKey(name string, privKey *data.PrivateKey, passphrase string) error
|
||||
GetDecryptedKey(name string, passphrase string) (*data.PrivateKey, error)
|
||||
ListKeys() []string
|
||||
}
|
||||
|
||||
// KeyFileStore persists and manages private keys on disk
|
||||
type KeyFileStore struct {
|
||||
FileStore
|
||||
SimpleFileStore
|
||||
}
|
||||
|
||||
// KeyMemoryStore manages private keys in memory
|
||||
type KeyMemoryStore struct {
|
||||
MemoryFileStore
|
||||
}
|
||||
|
||||
// NewKeyFileStore returns a new KeyFileStore creating a private directory to
|
||||
|
@ -24,11 +40,73 @@ func NewKeyFileStore(baseDir string) (*KeyFileStore, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &KeyFileStore{fileStore}, nil
|
||||
return &KeyFileStore{*fileStore}, nil
|
||||
}
|
||||
|
||||
// AddKey stores the contents of a PEM-encoded private key as a PEM block
|
||||
func (s *KeyFileStore) AddKey(name string, privKey *data.PrivateKey) error {
|
||||
return addKey(s, name, privKey)
|
||||
}
|
||||
|
||||
// GetKey returns the PrivateKey given a KeyID
|
||||
func (s *KeyFileStore) GetKey(name string) (*data.PrivateKey, error) {
|
||||
return getKey(s, name)
|
||||
}
|
||||
|
||||
// AddEncryptedKey stores the contents of a PEM-encoded private key as an encrypted PEM block
|
||||
func (s *KeyFileStore) AddEncryptedKey(name string, privKey *data.PrivateKey, passphrase string) error {
|
||||
return addEncryptedKey(s, name, privKey, passphrase)
|
||||
}
|
||||
|
||||
// GetDecryptedKey decrypts and returns the PEM Encoded private key given a flename
|
||||
// and a passphrase
|
||||
func (s *KeyFileStore) GetDecryptedKey(name string, passphrase string) (*data.PrivateKey, error) {
|
||||
return getDecryptedKey(s, name, passphrase)
|
||||
}
|
||||
|
||||
// ListKeys returns a list of unique PublicKeys present on the KeyFileStore.
|
||||
// There might be symlinks associating Certificate IDs to Public Keys, so this
|
||||
// method only returns the IDs that aren't symlinks
|
||||
func (s *KeyFileStore) ListKeys() []string {
|
||||
return listKeys(s)
|
||||
}
|
||||
|
||||
// NewKeyMemoryStore returns a new KeyMemoryStore which holds keys in memory
|
||||
func NewKeyMemoryStore() *KeyMemoryStore {
|
||||
memStore := NewMemoryFileStore()
|
||||
|
||||
return &KeyMemoryStore{*memStore}
|
||||
}
|
||||
|
||||
// AddKey stores the contents of a PEM-encoded private key as a PEM block
|
||||
func (s *KeyMemoryStore) AddKey(name string, privKey *data.PrivateKey) error {
|
||||
return addKey(s, name, privKey)
|
||||
}
|
||||
|
||||
// GetKey returns the PrivateKey given a KeyID
|
||||
func (s *KeyMemoryStore) GetKey(name string) (*data.PrivateKey, error) {
|
||||
return getKey(s, name)
|
||||
}
|
||||
|
||||
// AddEncryptedKey stores the contents of a PEM-encoded private key as an encrypted PEM block
|
||||
func (s *KeyMemoryStore) AddEncryptedKey(name string, privKey *data.PrivateKey, passphrase string) error {
|
||||
return addEncryptedKey(s, name, privKey, passphrase)
|
||||
}
|
||||
|
||||
// GetDecryptedKey decrypts and returns the PEM Encoded private key given a flename
|
||||
// and a passphrase
|
||||
func (s *KeyMemoryStore) GetDecryptedKey(name string, passphrase string) (*data.PrivateKey, error) {
|
||||
return getDecryptedKey(s, name, passphrase)
|
||||
}
|
||||
|
||||
// ListKeys returns a list of unique PublicKeys present on the KeyFileStore.
|
||||
// There might be symlinks associating Certificate IDs to Public Keys, so this
|
||||
// method only returns the IDs that aren't symlinks
|
||||
func (s *KeyMemoryStore) ListKeys() []string {
|
||||
return listKeys(s)
|
||||
}
|
||||
|
||||
func addKey(s LimitedFileStore, name string, privKey *data.PrivateKey) error {
|
||||
pemPrivKey, err := KeyToPEM(privKey)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -37,8 +115,7 @@ func (s *KeyFileStore) AddKey(name string, privKey *data.PrivateKey) error {
|
|||
return s.Add(name, pemPrivKey)
|
||||
}
|
||||
|
||||
// GetKey returns the PrivateKey given a KeyID
|
||||
func (s *KeyFileStore) GetKey(name string) (*data.PrivateKey, error) {
|
||||
func getKey(s LimitedFileStore, name string) (*data.PrivateKey, error) {
|
||||
keyBytes, err := s.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -53,8 +130,7 @@ func (s *KeyFileStore) GetKey(name string) (*data.PrivateKey, error) {
|
|||
return privKey, nil
|
||||
}
|
||||
|
||||
// AddEncryptedKey stores the contents of a PEM-encoded private key as an encrypted PEM block
|
||||
func (s *KeyFileStore) AddEncryptedKey(name string, privKey *data.PrivateKey, passphrase string) error {
|
||||
func addEncryptedKey(s LimitedFileStore, name string, privKey *data.PrivateKey, passphrase string) error {
|
||||
encryptedPrivKey, err := EncryptPrivateKey(privKey, passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -63,9 +139,7 @@ func (s *KeyFileStore) AddEncryptedKey(name string, privKey *data.PrivateKey, pa
|
|||
return s.Add(name, encryptedPrivKey)
|
||||
}
|
||||
|
||||
// GetDecryptedKey decrypts and returns the PEM Encoded private key given a flename
|
||||
// and a passphrase
|
||||
func (s *KeyFileStore) GetDecryptedKey(name string, passphrase string) (*data.PrivateKey, error) {
|
||||
func getDecryptedKey(s LimitedFileStore, name string, passphrase string) (*data.PrivateKey, error) {
|
||||
keyBytes, err := s.Get(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -80,10 +154,7 @@ func (s *KeyFileStore) GetDecryptedKey(name string, passphrase string) (*data.Pr
|
|||
return privKey, nil
|
||||
}
|
||||
|
||||
// ListKeys returns a list of unique PublicKeys present on the KeyFileStore.
|
||||
// There might be symlinks associating Certificate IDs to Public Keys, so this
|
||||
// method only returns the IDs that aren't symlinks
|
||||
func (s *KeyFileStore) ListKeys() []string {
|
||||
func listKeys(s LimitedFileStore) []string {
|
||||
var keyIDList []string
|
||||
for _, f := range s.ListFiles(false) {
|
||||
keyID := strings.TrimSpace(strings.TrimSuffix(filepath.Base(f), filepath.Ext(f)))
|
||||
|
|
Loading…
Reference in New Issue