mirror of https://github.com/docker/docs.git
Adding EncryptedFileStore and changing interfaces
Signed-off-by: Diogo Monica <diogo@docker.com>
This commit is contained in:
parent
fd8471038c
commit
d5cdeb93bb
|
@ -113,7 +113,7 @@ func keysRemove(cmd *cobra.Command, args []string) {
|
|||
}
|
||||
|
||||
// Remove all the keys under the Global Unique Name
|
||||
err = privKeyStore.RemoveAll(gunOrID)
|
||||
err = privKeyStore.RemoveDir(gunOrID)
|
||||
if err != nil {
|
||||
fatalf("failed to remove all Private keys under Global Unique Name: %s", gunOrID)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ const tufDir string = configPath + "tuf/"
|
|||
|
||||
var caStore trustmanager.X509Store
|
||||
var certificateStore trustmanager.X509Store
|
||||
var privKeyStore *trustmanager.KeyFileStore
|
||||
var privKeyStore trustmanager.EncryptedFileStore
|
||||
|
||||
var rawOutput bool
|
||||
|
||||
|
|
|
@ -15,14 +15,20 @@ type FileStore interface {
|
|||
Add(fileName string, data []byte) error
|
||||
Remove(fileName string) error
|
||||
RemoveDir(directoryName string) error
|
||||
GetData(fileName string) ([]byte, error)
|
||||
Get(fileName string) ([]byte, error)
|
||||
GetPath(fileName string) string
|
||||
ListAll() []string
|
||||
ListDir(directoryName string) []string
|
||||
}
|
||||
|
||||
// fileStore implements FileStore
|
||||
type fileStore struct {
|
||||
type EncryptedFileStore interface {
|
||||
FileStore
|
||||
AddEncrypted(fileName string, keyBytes []byte, passphrase string) error
|
||||
GetDecrypted(fileName string, passphrase string) ([]byte, error)
|
||||
}
|
||||
|
||||
// SimpleFileStore implements FileStore
|
||||
type SimpleFileStore struct {
|
||||
baseDir string
|
||||
fileExt string
|
||||
perms os.FileMode
|
||||
|
@ -34,7 +40,7 @@ func NewFileStore(baseDir string, fileExt string) (FileStore, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &fileStore{
|
||||
return &SimpleFileStore{
|
||||
baseDir: baseDir,
|
||||
fileExt: fileExt,
|
||||
perms: visible,
|
||||
|
@ -47,7 +53,7 @@ func NewPrivateFileStore(baseDir string, fileExt string) (FileStore, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &fileStore{
|
||||
return &SimpleFileStore{
|
||||
baseDir: baseDir,
|
||||
fileExt: fileExt,
|
||||
perms: private,
|
||||
|
@ -55,21 +61,21 @@ func NewPrivateFileStore(baseDir string, fileExt string) (FileStore, error) {
|
|||
}
|
||||
|
||||
// Add writes data to a file with a given name
|
||||
func (f *fileStore) Add(name string, data []byte) error {
|
||||
func (f *SimpleFileStore) Add(name string, data []byte) error {
|
||||
filePath := f.genFilePath(name)
|
||||
createDirectory(filepath.Dir(filePath), f.perms)
|
||||
return ioutil.WriteFile(filePath, data, f.perms)
|
||||
}
|
||||
|
||||
// Remove removes a file identified by name
|
||||
func (f *fileStore) Remove(name string) error {
|
||||
func (f *SimpleFileStore) Remove(name string) error {
|
||||
// Attempt to remove
|
||||
filePath := f.genFilePath(name)
|
||||
return os.Remove(filePath)
|
||||
}
|
||||
|
||||
// RemoveDir removes the directory identified by name
|
||||
func (f *fileStore) RemoveDir(name string) error {
|
||||
func (f *SimpleFileStore) RemoveDir(name string) error {
|
||||
dirPath := filepath.Join(f.baseDir, name)
|
||||
|
||||
// Check to see if directory exists
|
||||
|
@ -86,8 +92,8 @@ func (f *fileStore) RemoveDir(name string) error {
|
|||
return os.RemoveAll(dirPath)
|
||||
}
|
||||
|
||||
// GetData returns the data given a file name
|
||||
func (f *fileStore) GetData(name string) ([]byte, error) {
|
||||
// Get returns the data given a file name
|
||||
func (f *SimpleFileStore) Get(name string) ([]byte, error) {
|
||||
filePath := f.genFilePath(name)
|
||||
data, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
|
@ -98,23 +104,23 @@ func (f *fileStore) GetData(name string) ([]byte, error) {
|
|||
}
|
||||
|
||||
// GetPath returns the full final path of a file with a given name
|
||||
func (f *fileStore) GetPath(name string) string {
|
||||
func (f *SimpleFileStore) GetPath(name string) string {
|
||||
return f.genFilePath(name)
|
||||
}
|
||||
|
||||
// List lists all the files inside of a store
|
||||
func (f *fileStore) ListAll() []string {
|
||||
func (f *SimpleFileStore) ListAll() []string {
|
||||
return f.list(f.baseDir)
|
||||
}
|
||||
|
||||
// List lists all the files inside of a directory identified by a name
|
||||
func (f *fileStore) ListDir(name string) []string {
|
||||
func (f *SimpleFileStore) ListDir(name string) []string {
|
||||
fullPath := filepath.Join(f.baseDir, name)
|
||||
return f.list(fullPath)
|
||||
}
|
||||
|
||||
// list lists all the files in a directory given a full path
|
||||
func (f *fileStore) list(path string) []string {
|
||||
func (f *SimpleFileStore) list(path string) []string {
|
||||
files := make([]string, 0, 0)
|
||||
filepath.Walk(path, func(fp string, fi os.FileInfo, err error) error {
|
||||
// If there are errors, ignore this particular file
|
||||
|
@ -137,7 +143,7 @@ func (f *fileStore) list(path string) []string {
|
|||
}
|
||||
|
||||
// genFilePath returns the full path with extension given a file name
|
||||
func (f *fileStore) genFilePath(name string) string {
|
||||
func (f *SimpleFileStore) genFilePath(name string) string {
|
||||
fileName := fmt.Sprintf("%s.%s", name, f.fileExt)
|
||||
return filepath.Join(f.baseDir, fileName)
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ func TestAddFile(t *testing.T) {
|
|||
// Since we're generating this manually we need to add the extension '.'
|
||||
expectedFilePath := filepath.Join(tempBaseDir, testName+"."+testExt)
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -69,8 +69,8 @@ func TestRemoveFile(t *testing.T) {
|
|||
t.Fatalf("failed to generate random file: %v", err)
|
||||
}
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -108,8 +108,8 @@ func TestRemoveDir(t *testing.T) {
|
|||
t.Fatalf("failed to generate random file: %v", err)
|
||||
}
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -151,8 +151,8 @@ func TestListAll(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -188,8 +188,8 @@ func TestListDir(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -213,8 +213,8 @@ func TestGetPath(t *testing.T) {
|
|||
testExt := "crt"
|
||||
perms := os.FileMode(0755)
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: "",
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
|
@ -249,13 +249,13 @@ func TestGetData(t *testing.T) {
|
|||
t.Fatalf("failed to generate random file: %v", err)
|
||||
}
|
||||
|
||||
// Create our FileStore
|
||||
store := &fileStore{
|
||||
// Create our SimpleFileStore
|
||||
store := &SimpleFileStore{
|
||||
baseDir: tempBaseDir,
|
||||
fileExt: testExt,
|
||||
perms: perms,
|
||||
}
|
||||
testData, err := store.GetData(testName)
|
||||
testData, err := store.Get(testName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get data from: %s", testName)
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package trustmanager
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
import "errors"
|
||||
|
||||
const (
|
||||
keyExtension = "key"
|
||||
|
@ -12,88 +8,49 @@ const (
|
|||
|
||||
// KeyFileStore persists and manages private keys on disk
|
||||
type KeyFileStore struct {
|
||||
fingerprintMap map[string]string
|
||||
fileStore FileStore
|
||||
FileStore
|
||||
}
|
||||
|
||||
// NewKeyFileStore returns a new KeyFileStore.
|
||||
func NewKeyFileStore(directory string) (*KeyFileStore, error) {
|
||||
fileStore, err := NewPrivateFileStore(directory, keyExtension)
|
||||
// NewKeyFileStore returns a new KeyFileStore creating a private directory to
|
||||
// hold the keys.
|
||||
func NewKeyFileStore(baseDir string) (EncryptedFileStore, error) {
|
||||
fileStore, err := NewFileStore(baseDir, keyExtension)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &KeyFileStore{
|
||||
fingerprintMap: make(map[string]string),
|
||||
fileStore: fileStore,
|
||||
}, nil
|
||||
return &KeyFileStore{fileStore}, nil
|
||||
}
|
||||
|
||||
// Add stores both the PrivateKey bytes in a file
|
||||
func (s *KeyFileStore) Add(fileName string, privKey crypto.PrivateKey) error {
|
||||
if privKey == nil {
|
||||
return errors.New("adding nil key to keyFileStore")
|
||||
}
|
||||
// AddEncrypted stores the contents of a PEM-encoded private key as an encrypted PEM block
|
||||
func (s *KeyFileStore) AddEncrypted(fileName string, pemKey []byte, passphrase string) error {
|
||||
|
||||
pemKey, err := KeyToPEM(privKey)
|
||||
privKey, err := ParsePEMPrivateKey(pemKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.fileStore.Add(fileName, pemKey)
|
||||
}
|
||||
|
||||
// Get returns a PrivateKey given a filename
|
||||
func (s *KeyFileStore) Get(fileName string) (crypto.PrivateKey, error) {
|
||||
keyBytes, err := s.fileStore.GetData(fileName)
|
||||
if err != nil {
|
||||
return nil, errors.New("Could not retrieve private key material")
|
||||
}
|
||||
|
||||
return ParseRawPrivateKey(keyBytes)
|
||||
}
|
||||
|
||||
// AddEncrypted stores the contents of the private key as an encrypted PEM block
|
||||
func (s *KeyFileStore) AddEncrypted(fileName string, privKey crypto.PrivateKey, passphrase string) error {
|
||||
if privKey == nil {
|
||||
return errors.New("adding nil key to keyFileStore")
|
||||
}
|
||||
|
||||
encryptedKey, err := KeyToEncryptedPEM(privKey, passphrase)
|
||||
encryptedKey, err := EncryptPrivateKey(privKey, passphrase)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(encryptedKey))
|
||||
return s.fileStore.Add(fileName, encryptedKey)
|
||||
return s.Add(fileName, encryptedKey)
|
||||
}
|
||||
|
||||
// GetDecrypted decrypts and returns the private key
|
||||
func (s *KeyFileStore) GetDecrypted(fileName string, passphrase string) (crypto.PrivateKey, error) {
|
||||
keyBytes, err := s.fileStore.GetData(fileName)
|
||||
// GetDecrypted decrypts and returns the PEM Encoded private key given a flename
|
||||
// and a passphrase
|
||||
func (s *KeyFileStore) GetDecrypted(fileName string, passphrase string) ([]byte, error) {
|
||||
keyBytes, err := s.Get(fileName)
|
||||
if err != nil {
|
||||
return nil, errors.New("could not retrieve private key material")
|
||||
}
|
||||
|
||||
return ParseRawEncryptedPrivateKey(keyBytes, passphrase)
|
||||
// Gets an unencrypted PrivateKey.
|
||||
privKey, err := ParsePEMEncryptedPrivateKey(keyBytes, passphrase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remove removes a key from a store
|
||||
func (s *KeyFileStore) Remove(fileName string) error {
|
||||
return s.fileStore.Remove(fileName)
|
||||
}
|
||||
|
||||
// RemoveAll removes all the keys under a directory
|
||||
func (s *KeyFileStore) RemoveAll(directoryName string) error {
|
||||
return s.fileStore.RemoveDir(directoryName)
|
||||
}
|
||||
|
||||
// List returns a list of all the keys the store is currently managing
|
||||
func (s *KeyFileStore) ListAll() []string {
|
||||
return s.fileStore.ListAll()
|
||||
}
|
||||
|
||||
// List returns a list of all the keys the store is currently managing
|
||||
func (s *KeyFileStore) ListDir(directoryName string) []string {
|
||||
return s.fileStore.ListDir(directoryName)
|
||||
return KeyToPEM(privKey)
|
||||
}
|
||||
|
|
|
@ -35,8 +35,14 @@ func TestAddKey(t *testing.T) {
|
|||
t.Fatalf("could not generate private key: %v", err)
|
||||
}
|
||||
|
||||
// Get the PEM for the key
|
||||
pemKey, err := KeyToPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to convert private key to PEM: %v", err)
|
||||
}
|
||||
|
||||
// Call the Add function
|
||||
err = store.Add(testName, key)
|
||||
err = store.Add(testName, pemKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add file to store: %v", err)
|
||||
}
|
||||
|
@ -106,16 +112,11 @@ EMl3eFOJXjIch/wIesRSN+2dGOsl7neercjMh1i9RvpCwHDx/E0=
|
|||
}
|
||||
|
||||
// Call the Get function
|
||||
privKey, err := store.Get(testName)
|
||||
pemKey, err := store.Get(testName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get file from store: %v", err)
|
||||
}
|
||||
|
||||
pemKey, err := KeyToPEM(privKey)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to convert key to PEM: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(testData, pemKey) {
|
||||
t.Fatalf("unexpected content in the file: %s", filePath)
|
||||
}
|
||||
|
@ -146,8 +147,14 @@ func TestAddEncryptedAndGetDecrypted(t *testing.T) {
|
|||
t.Fatalf("could not generate private key: %v", err)
|
||||
}
|
||||
|
||||
// Get PEM encodedd key
|
||||
pemKey, err := KeyToPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not encode key to PEM: %v", err)
|
||||
}
|
||||
|
||||
// Call the Add function
|
||||
err = store.AddEncrypted(testName, key, "diogomonica")
|
||||
err = store.AddEncrypted(testName, pemKey, "diogomonica")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add file to store: %v", err)
|
||||
}
|
||||
|
@ -157,17 +164,7 @@ func TestAddEncryptedAndGetDecrypted(t *testing.T) {
|
|||
t.Fatalf("could not decrypt private key: %v", err)
|
||||
}
|
||||
|
||||
pemKey, err := KeyToPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("could not convert private key to PEM: %v", err)
|
||||
}
|
||||
|
||||
decryptedPemKey, err := KeyToPEM(pemPrivKey)
|
||||
if err != nil {
|
||||
t.Fatalf("could not convert private key to PEM: %v", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(string(pemKey), string(decryptedPemKey)) {
|
||||
if !strings.Contains(string(pemKey), string(pemPrivKey)) {
|
||||
t.Fatalf("expected private key content in the file: %s", expectedFilePath)
|
||||
}
|
||||
}
|
||||
|
@ -197,8 +194,13 @@ func TestGetDecryptedWithTamperedCipherText(t *testing.T) {
|
|||
t.Fatalf("could not generate private key: %v", err)
|
||||
}
|
||||
|
||||
// Get PEM encodedd key
|
||||
pemKey, err := KeyToPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not encode key to PEM: %v", err)
|
||||
}
|
||||
// Call the Add function
|
||||
err = store.AddEncrypted(testName, key, "diogomonica")
|
||||
err = store.AddEncrypted(testName, pemKey, "diogomonica")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add file to store: %v", err)
|
||||
}
|
||||
|
@ -240,8 +242,13 @@ func TestGetDecryptedWithInvalidPassphrase(t *testing.T) {
|
|||
t.Fatalf("could not generate private key: %v", err)
|
||||
}
|
||||
|
||||
// Get PEM encodedd key
|
||||
pemKey, err := KeyToPEM(key)
|
||||
if err != nil {
|
||||
t.Fatalf("Could not encode key to PEM: %v", err)
|
||||
}
|
||||
// Call the Add function
|
||||
err = store.AddEncrypted(testName, key, "diogomonica")
|
||||
err = store.AddEncrypted(testName, pemKey, "diogomonica")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to add file to stoAFre: %v", err)
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ func (s X509FileStore) addNamedCert(cert *x509.Certificate) error {
|
|||
}
|
||||
|
||||
// Convert certificate to PEM
|
||||
certBytes := ToPEM(cert)
|
||||
certBytes := CertToPEM(cert)
|
||||
// Compute FileName
|
||||
fileName := fileName(cert)
|
||||
|
||||
|
|
|
@ -49,14 +49,14 @@ func GetCertFromURL(urlStr string) (*x509.Certificate, error) {
|
|||
return cert, nil
|
||||
}
|
||||
|
||||
// ToPEM is an utility function returns a PEM encoded x509 Certificate
|
||||
func ToPEM(cert *x509.Certificate) []byte {
|
||||
// CertToPEM is an utility function returns a PEM encoded x509 Certificate
|
||||
func CertToPEM(cert *x509.Certificate) []byte {
|
||||
pemCert := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
||||
|
||||
return pemCert
|
||||
}
|
||||
|
||||
// KeyToPEM is an utility function returns a PEM encoded Key
|
||||
// KeyToPEM returns a PEM encoded key from a crypto.PrivateKey
|
||||
func KeyToPEM(key crypto.PrivateKey) ([]byte, error) {
|
||||
rsaKey, ok := key.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
|
@ -67,8 +67,9 @@ func KeyToPEM(key crypto.PrivateKey) ([]byte, error) {
|
|||
return pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes}), nil
|
||||
}
|
||||
|
||||
// KeyToEncryptedPEM is an utility function returns a PEM encoded Key
|
||||
func KeyToEncryptedPEM(key crypto.PrivateKey, passphrase string) ([]byte, error) {
|
||||
// EncryptPrivateKey returns an encrypted PEM encoded key given a Private key
|
||||
// and a passphrase
|
||||
func EncryptPrivateKey(key crypto.PrivateKey, passphrase string) ([]byte, error) {
|
||||
rsaKey, ok := key.(*rsa.PrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("only RSA keys are currently supported")
|
||||
|
@ -76,7 +77,6 @@ func KeyToEncryptedPEM(key crypto.PrivateKey, passphrase string) ([]byte, error)
|
|||
|
||||
keyBytes := x509.MarshalPKCS1PrivateKey(rsaKey)
|
||||
|
||||
//TODO(diogo): if we do keystretching, where do we keep the salt + params?
|
||||
password := []byte(passphrase)
|
||||
cipherType := x509.PEMCipherAES256
|
||||
blockType := "RSA PRIVATE KEY"
|
||||
|
@ -168,16 +168,16 @@ func LoadKeyFromFile(filename string) (crypto.PrivateKey, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
key, err := ParseRawPrivateKey(pemBytes)
|
||||
key, err := ParsePEMPrivateKey(pemBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// ParseRawPrivateKey returns a private key from a PEM encoded private key. It
|
||||
// ParsePEMPrivateKey returns a private key from a PEM encoded private key. It
|
||||
// only supports RSA (PKCS#1).
|
||||
func ParseRawPrivateKey(pemBytes []byte) (crypto.PrivateKey, error) {
|
||||
func ParsePEMPrivateKey(pemBytes []byte) (crypto.PrivateKey, error) {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
return nil, errors.New("no valid key found")
|
||||
|
@ -191,9 +191,9 @@ func ParseRawPrivateKey(pemBytes []byte) (crypto.PrivateKey, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// ParseRawEncryptedPrivateKey returns a private key from a PEM encrypted private key. It
|
||||
// ParsePEMEncryptedPrivateKey returns a private key from a PEM encrypted private key. It
|
||||
// only supports RSA (PKCS#1).
|
||||
func ParseRawEncryptedPrivateKey(pemBytes []byte, passphrase string) (crypto.PrivateKey, error) {
|
||||
func ParsePEMEncryptedPrivateKey(pemBytes []byte, passphrase string) (crypto.PrivateKey, error) {
|
||||
block, _ := pem.Decode(pemBytes)
|
||||
if block == nil {
|
||||
return nil, errors.New("no valid private key found")
|
||||
|
|
Loading…
Reference in New Issue