This commit is contained in:
Adrian Utrilla 2017-09-12 09:59:23 -07:00
Родитель d1637e0da7
Коммит 93570b20d7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: D9B452CB733E4A16
23 изменённых файлов: 107 добавлений и 62 удалений

Просмотреть файл

@ -28,7 +28,7 @@ test:
$(GO) test -coverprofile=coverage_tmp.txt -covermode=atomic $(PROJECT) && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/aes -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/cmd/sops -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/yaml -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/config -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/stores/yaml -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
$(GO) test $(PROJECT)/stores/json -coverprofile=coverage_tmp.txt -covermode=atomic && cat coverage_tmp.txt >> coverage.txt
gpg --import pgp/sops_functional_tests_key.asc 2>&1 1>/dev/null || exit 0

Просмотреть файл

@ -1,5 +1,7 @@
// Package codes the exit statuses returned by the sops binary
package codes
// Exit statuses returned by the binary
const (
CouldNotReadInputFile int = 2
CouldNotWriteOutputFile int = 3

Просмотреть файл

@ -12,16 +12,23 @@ import (
"gopkg.in/urfave/cli.v1"
)
// DecryptTreeOpts are the options needed to decrypt a tree
type DecryptTreeOpts struct {
Tree *sops.Tree
Stash map[string][]interface{}
// Tree is the tree to be decrypted
Tree *sops.Tree
// Stash is a map to save information between encryption-decryption round-trips, such as IVs
Stash map[string][]interface{}
// KeyServices are the key services to be used for decryption of the data key
KeyServices []keyservice.KeyServiceClient
IgnoreMac bool
Cipher sops.DataKeyCipher
// IgnoreMac is whether or not to ignore the Message Authentication Code included in the SOPS tree
IgnoreMac bool
// Cipher is the cryptographic cipher to use to decrypt the values inside the tree
Cipher sops.DataKeyCipher
}
func DecryptTree(opts DecryptTreeOpts) ([]byte, error) {
dataKey, err := opts.Tree.Metadata.GetDataKeyWithKeyServices(opts.KeyServices)
// DecryptTree decrypts the tree passed in through the DecryptTreeOpts and additionally returns the decrypted data key
func DecryptTree(opts DecryptTreeOpts) (dataKey []byte, err error) {
dataKey, err = opts.Tree.Metadata.GetDataKeyWithKeyServices(opts.KeyServices)
if err != nil {
return nil, cli.NewExitError(err.Error(), codes.CouldNotRetrieveKey)
}
@ -42,13 +49,19 @@ func DecryptTree(opts DecryptTreeOpts) ([]byte, error) {
return dataKey, nil
}
// EncryptTreeOpts are the options needed to encrypt a tree
type EncryptTreeOpts struct {
Tree *sops.Tree
Stash map[string][]interface{}
Cipher sops.DataKeyCipher
// Tree is the tree to be encrypted
Tree *sops.Tree
// Stash is a map to save information between encryption-decryption round-trips, such as IVs
Stash map[string][]interface{}
// Cipher is the cryptographic cipher to use to encrypt the values inside the tree
Cipher sops.DataKeyCipher
// DataKey is the key the cipher should use to encrypt the values inside the tree
DataKey []byte
}
// EncryptTree encrypts the tree passed in through the EncryptTreeOpts
func EncryptTree(opts EncryptTreeOpts) error {
mac, err := opts.Tree.Encrypt(opts.DataKey, opts.Cipher, opts.Stash)
if err != nil {
@ -63,6 +76,7 @@ func EncryptTree(opts EncryptTreeOpts) error {
return nil
}
// LoadEncryptedFile loads an encrypted SOPS file, returning a SOPS tree
func LoadEncryptedFile(inputStore sops.Store, inputPath string) (*sops.Tree, error) {
fileBytes, err := ioutil.ReadFile(inputPath)
if err != nil {

Просмотреть файл

@ -20,7 +20,7 @@ type decryptOpts struct {
KeyServices []keyservice.KeyServiceClient
}
func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) {
func decrypt(opts decryptOpts) (decryptedFile []byte, err error) {
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)
if err != nil {
return nil, err
@ -38,7 +38,7 @@ func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) {
}
if len(opts.Extract) > 0 {
return Extract(tree, opts.Extract, opts.OutputStore)
return extract(tree, opts.Extract, opts.OutputStore)
}
decryptedFile, err = opts.OutputStore.Marshal(tree.Branch)
if err != nil {
@ -47,7 +47,7 @@ func Decrypt(opts decryptOpts) (decryptedFile []byte, err error) {
return decryptedFile, err
}
func Extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (output []byte, err error) {
func extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (output []byte, err error) {
v, err := tree.Branch.Truncate(path)
if err != nil {
return nil, fmt.Errorf("error truncating tree: %s", err)
@ -59,11 +59,10 @@ func Extract(tree *sops.Tree, path []interface{}, outputStore sops.Store) (outpu
return nil, cli.NewExitError(fmt.Sprintf("Error dumping file: %s", err), codes.ErrorDumpingTree)
}
return decrypted, err
} else {
bytes, err := outputStore.MarshalValue(v)
if err != nil {
return nil, cli.NewExitError(fmt.Sprintf("Error dumping tree: %s", err), codes.ErrorDumpingTree)
}
return bytes, nil
}
bytes, err := outputStore.MarshalValue(v)
if err != nil {
return nil, cli.NewExitError(fmt.Sprintf("Error dumping tree: %s", err), codes.ErrorDumpingTree)
}
return bytes, nil
}

Просмотреть файл

@ -76,7 +76,7 @@ type runEditorUntilOkOpts struct {
Tree *sops.Tree
}
func EditExample(opts editExampleOpts) ([]byte, error) {
func editExample(opts editExampleOpts) ([]byte, error) {
// Load the example file
var fileBytes []byte
if _, ok := opts.InputStore.(*json.BinaryStore); ok {
@ -109,10 +109,10 @@ func EditExample(opts editExampleOpts) ([]byte, error) {
}
stash := make(map[string][]interface{})
return edit(opts.editOpts, &tree, dataKey, stash)
return editTree(opts.editOpts, &tree, dataKey, stash)
}
func Edit(opts editOpts) ([]byte, error) {
func edit(opts editOpts) ([]byte, error) {
// Load the file
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)
if err != nil {
@ -127,10 +127,10 @@ func Edit(opts editOpts) ([]byte, error) {
return nil, err
}
return edit(opts, tree, dataKey, stash)
return editTree(opts, tree, dataKey, stash)
}
func edit(opts editOpts, tree *sops.Tree, dataKey []byte, stash map[string][]interface{}) ([]byte, error) {
func editTree(opts editOpts, tree *sops.Tree, dataKey []byte, stash map[string][]interface{}) ([]byte, error) {
// Create temporary file for editing
tmpdir, err := ioutil.TempDir("", "")
if err != nil {

Просмотреть файл

@ -23,7 +23,7 @@ type encryptOpts struct {
GroupQuorum int
}
func Encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
func encrypt(opts encryptOpts) (encryptedFile []byte, err error) {
// Load the file
fileBytes, err := ioutil.ReadFile(opts.InputPath)
if err != nil {

Просмотреть файл

@ -30,7 +30,7 @@ import (
"go.mozilla.org/sops/pgp"
"go.mozilla.org/sops/stores/json"
yamlstores "go.mozilla.org/sops/stores/yaml"
"go.mozilla.org/sops/yaml"
"go.mozilla.org/sops/config"
"gopkg.in/urfave/cli.v1"
)
@ -306,7 +306,7 @@ func main() {
if err != nil {
return err
}
output, err = Encrypt(encryptOpts{
output, err = encrypt(encryptOpts{
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
@ -326,7 +326,7 @@ func main() {
if err != nil {
return cli.NewExitError(fmt.Errorf("error parsing --extract path: %s", err), codes.InvalidTreePathFormat)
}
output, err = Decrypt(decryptOpts{
output, err = decrypt(decryptOpts{
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
@ -356,7 +356,7 @@ func main() {
for _, k := range pgp.MasterKeysFromFingerprintString(c.String("add-pgp")) {
rmMasterKeys = append(rmMasterKeys, k)
}
output, err = Rotate(rotateOpts{
output, err = rotate(rotateOpts{
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
@ -376,7 +376,7 @@ func main() {
if err != nil {
return err
}
output, err = Set(setOpts{
output, err = set(setOpts{
OutputStore: outputStore,
InputStore: inputStore,
InputPath: fileName,
@ -405,14 +405,14 @@ func main() {
ShowMasterKeys: c.Bool("show-master-keys"),
}
if fileExists {
output, err = Edit(opts)
output, err = edit(opts)
} else {
// File doesn't exist, edit the example file instead
keyGroups, err := keyGroups(c, fileName)
if err != nil {
return err
}
output, err = EditExample(editExampleOpts{
output, err = editExample(editExampleOpts{
editOpts: opts,
UnencryptedSuffix: c.String("unencrypted-suffix"),
KeyGroups: keyGroups,
@ -557,7 +557,7 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
return nil, cli.NewExitError(fmt.Sprintf("Error loading config file: %s", err), codes.ErrorReadingConfig)
}
}
groups, err := yaml.KeyGroupsForFile(file, confBytes, kmsEncryptionContext)
groups, err := config.KeyGroupsForFile(file, confBytes, kmsEncryptionContext)
if err != nil {
return nil, err
}

Просмотреть файл

@ -22,7 +22,7 @@ type rotateOpts struct {
KeyServices []keyservice.KeyServiceClient
}
func Rotate(opts rotateOpts) ([]byte, error) {
func rotate(opts rotateOpts) ([]byte, error) {
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)
if err != nil {
return nil, err

Просмотреть файл

@ -21,7 +21,7 @@ type setOpts struct {
KeyServices []keyservice.KeyServiceClient
}
func Set(opts setOpts) ([]byte, error) {
func set(opts setOpts) ([]byte, error) {
// Load the file
// TODO: Issue #173: if the file does not exist, create it with the contents passed in as opts.Value
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)

Просмотреть файл

@ -8,6 +8,7 @@ import (
"go.mozilla.org/sops/keyservice"
)
// AddOpts are the options for adding a key group to a SOPS file
type AddOpts struct {
InputPath string
InputStore sops.Store
@ -18,6 +19,7 @@ type AddOpts struct {
KeyServices []keyservice.KeyServiceClient
}
// Add adds a key group to a SOPS file
func Add(opts AddOpts) error {
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)
if err != nil {
@ -37,7 +39,7 @@ func Add(opts AddOpts) error {
if err != nil {
return err
}
var outputFile *os.File = os.Stdout
var outputFile = os.Stdout
if opts.InPlace {
var err error
outputFile, err = os.Create(opts.InputPath)

Просмотреть файл

@ -8,6 +8,7 @@ import (
"go.mozilla.org/sops/keyservice"
)
// DeleteOpts are the options for deleting a key group from a SOPS file
type DeleteOpts struct {
InputPath string
InputStore sops.Store
@ -25,6 +26,7 @@ func min(a, b int) int {
return a
}
// Delete deletes a key group from a SOPS file
func Delete(opts DeleteOpts) error {
tree, err := common.LoadEncryptedFile(opts.InputStore, opts.InputPath)
if err != nil {
@ -47,7 +49,7 @@ func Delete(opts DeleteOpts) error {
if err != nil {
return err
}
var outputFile *os.File = os.Stdout
var outputFile = os.Stdout
if opts.InPlace {
var err error
outputFile, err = os.Create(opts.InputPath)

Просмотреть файл

@ -12,11 +12,13 @@ import (
"google.golang.org/grpc"
)
// Opts are the options the key service server can take
type Opts struct {
Network string
Address string
}
// Run runs a SOPS key service server
func Run(opts Opts) error {
lis, err := net.Listen(opts.Network, opts.Address)
if err != nil {

Просмотреть файл

@ -1,4 +1,4 @@
package yaml //import "go.mozilla.org/sops/yaml"
package config //import "go.mozilla.org/sops/config"
import (
"fmt"
@ -71,6 +71,8 @@ func (f *configFile) load(bytes []byte) error {
return nil
}
// KeyGroupsForFile returns the key groups that should be use for a given file, based on the file's path and the
// configuration
func KeyGroupsForFile(filepath string, confBytes []byte, kmsEncryptionContext map[string]*string) ([]sops.KeyGroup, error) {
var err error
if confBytes == nil {

Просмотреть файл

@ -1,4 +1,4 @@
package yaml
package config
import (
"os"

Просмотреть файл

Просмотреть файл

@ -6,19 +6,25 @@ import (
"google.golang.org/grpc"
)
// LocalClient is a key service client that performs all operations locally
type LocalClient struct {
Server Server
}
// NewLocalClient creates a new local client
func NewLocalClient() LocalClient {
return LocalClient{Server{}}
}
// Decrypt processes a decrypt request locally
// See keyservice/server.go for more details
func (c LocalClient) Decrypt(ctx context.Context,
req *DecryptRequest, opts ...grpc.CallOption) (*DecryptResponse, error) {
return c.Server.Decrypt(ctx, req)
}
// Encrypt processes an encrypt request locally
// See keyservice/server.go for more details
func (c LocalClient) Encrypt(ctx context.Context,
req *EncryptRequest, opts ...grpc.CallOption) (*EncryptResponse, error) {
return c.Server.Encrypt(ctx, req)

Просмотреть файл

@ -8,6 +8,7 @@ import (
"go.mozilla.org/sops/pgp"
)
// KeyFromMasterKey converts a SOPS internal MasterKey to an RPC Key that can be serialized with Protocol Buffers
func KeyFromMasterKey(mk keys.MasterKey) Key {
switch mk := mk.(type) {
case *pgp.MasterKey:

Просмотреть файл

@ -6,8 +6,10 @@ import (
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
// Server is a key service server that uses SOPS MasterKeys to fulfill requests
type Server struct{}
func (ks *Server) encryptWithPgp(key *PgpKey, plaintext []byte) ([]byte, error) {
@ -58,6 +60,8 @@ func (ks *Server) decryptWithKms(key *KmsKey, ciphertext []byte) ([]byte, error)
return []byte(plaintext), err
}
// Encrypt takes an encrypt request and encrypts the provided plaintext with the provided key, returning the encrypted
// result
func (ks Server) Encrypt(ctx context.Context,
req *EncryptRequest) (*EncryptResponse, error) {
key := *req.Key
@ -79,12 +83,14 @@ func (ks Server) Encrypt(ctx context.Context,
Ciphertext: ciphertext,
}, nil
case nil:
return nil, grpc.Errorf(codes.NotFound, "Must provide a key")
return nil, status.Errorf(codes.NotFound, "Must provide a key")
default:
return nil, grpc.Errorf(codes.NotFound, "Unknown key type")
return nil, status.Errorf(codes.NotFound, "Unknown key type")
}
}
// Decrypt takes a decrypt request and decrypts the provided ciphertext with the provided key, returning the decrypted
// result
func (ks Server) Decrypt(ctx context.Context,
req *DecryptRequest) (*DecryptResponse, error) {
key := *req.Key

Просмотреть файл

@ -33,10 +33,12 @@ type MasterKey struct {
EncryptionContext map[string]*string
}
// EncryptedDataKey returns the encrypted data key this master key holds
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
// SetEncryptedDataKey sets the encrypted data key for this master key
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}

Просмотреть файл

@ -28,10 +28,12 @@ type MasterKey struct {
CreationDate time.Time
}
// EncryptedDataKey returns the encrypted data key this master key holds
func (key *MasterKey) EncryptedDataKey() []byte {
return []byte(key.EncryptedKey)
}
// SetEncryptedDataKey sets the encrypted data key for this master key
func (key *MasterKey) SetEncryptedDataKey(enc []byte) {
key.EncryptedKey = string(enc)
}
@ -77,7 +79,7 @@ func (key *MasterKey) encryptWithCryptoOpenPGP(dataKey []byte) error {
fingerprints := key.fingerprintMap(ring)
entity, ok := fingerprints[key.Fingerprint]
if !ok {
return fmt.Errorf("Key with fingerprint %s is not available in keyring.", key.Fingerprint)
return fmt.Errorf("key with fingerprint %s is not available in keyring", key.Fingerprint)
}
encbuf := new(bytes.Buffer)
armorbuf, err := armor.Encode(encbuf, "PGP MESSAGE", nil)

36
sops.go
Просмотреть файл

@ -1,5 +1,5 @@
/*
Package Sops manages JSON, YAML and BINARY documents to be encrypted or decrypted.
Package sops manages JSON, YAML and BINARY documents to be encrypted or decrypted.
This package should not be used directly. Instead, Sops users should install the
command line client via `go get -u go.mozilla.org/sops/cmd/sops`, or use the
@ -112,9 +112,9 @@ type Tree struct {
}
// Truncate truncates the tree to the path specified
func (tree TreeBranch) Truncate(path []interface{}) (interface{}, error) {
func (branch TreeBranch) Truncate(path []interface{}) (interface{}, error) {
log.Printf("Truncating tree to %s", path)
var current interface{} = tree
var current interface{} = branch
for _, component := range path {
switch component := component.(type) {
case string:
@ -142,7 +142,7 @@ func (tree TreeBranch) Truncate(path []interface{}) (interface{}, error) {
return current, nil
}
func (tree TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (interface{}, error) {
func (branch TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (interface{}, error) {
switch in := in.(type) {
case string:
return onLeaves(in, path)
@ -155,20 +155,20 @@ func (tree TreeBranch) walkValue(in interface{}, path []string, onLeaves func(in
case float64:
return onLeaves(in, path)
case TreeBranch:
return tree.walkBranch(in, path, onLeaves)
return branch.walkBranch(in, path, onLeaves)
case []interface{}:
return tree.walkSlice(in, path, onLeaves)
return branch.walkSlice(in, path, onLeaves)
default:
return nil, fmt.Errorf("Cannot walk value, unknown type: %T", in)
}
}
func (tree TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) ([]interface{}, error) {
func (branch TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) ([]interface{}, error) {
for i, v := range in {
if _, ok := v.(Comment); ok {
continue
}
newV, err := tree.walkValue(v, path, onLeaves)
newV, err := branch.walkValue(v, path, onLeaves)
if err != nil {
return nil, err
}
@ -177,7 +177,7 @@ func (tree TreeBranch) walkSlice(in []interface{}, path []string, onLeaves func(
return in, nil
}
func (tree TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (TreeBranch, error) {
func (branch TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in interface{}, path []string) (interface{}, error)) (TreeBranch, error) {
for i, item := range in {
if _, ok := item.Key.(Comment); ok {
continue
@ -187,7 +187,7 @@ func (tree TreeBranch) walkBranch(in TreeBranch, path []string, onLeaves func(in
return nil, fmt.Errorf("Tree contains a non-string key (type %T): %s. Only string keys are"+
"supported", item.Key, item.Key)
}
newV, err := tree.walkValue(item.Value, append(path, key), onLeaves)
newV, err := branch.walkValue(item.Value, append(path, key), onLeaves)
if err != nil {
return nil, err
}
@ -282,7 +282,7 @@ func (tree Tree) GenerateDataKey() ([]byte, []error) {
return newKey, tree.Metadata.UpdateMasterKeys(newKey)
}
// GenerateDataKey generates a new random data key and encrypts it with all MasterKeys.
// GenerateDataKeyWithKeyServices generates a new random data key and encrypts it with all MasterKeys.
func (tree *Tree) GenerateDataKeyWithKeyServices(svcs []keyservice.KeyServiceClient) ([]byte, []error) {
newKey := make([]byte, 32)
_, err := rand.Read(newKey)
@ -306,6 +306,7 @@ type Metadata struct {
DataKey []byte
}
// KeyGroup is a slice of SOPS MasterKeys that all encrypt the same part of the data key
type KeyGroup []keys.MasterKey
// Store provides a way to load and save the sops tree along with metadata
@ -326,10 +327,11 @@ func (m *Metadata) MasterKeyCount() int {
return count
}
// UpdateMasterKeysWithKeyServices encrypts the data key with all master keys using the provided key services
func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyservice.KeyServiceClient) (errs []error) {
if len(svcs) == 0 {
return []error{
fmt.Errorf("No key services provided, cansnot update master keys."),
fmt.Errorf("no key services provided, cannot update master keys"),
}
}
var parts [][]byte
@ -345,11 +347,11 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser
log.Printf("Multiple KeyGroups found, proceeding with Shamir with quorum %d", m.ShamirQuorum)
parts, err = shamir.Split(dataKey, len(m.KeyGroups), m.ShamirQuorum)
if err != nil {
errs = append(errs, fmt.Errorf("Could not split data key into parts for Shamir: %s", err))
errs = append(errs, fmt.Errorf("could not split data key into parts for Shamir: %s", err))
return
}
if len(parts) != len(m.KeyGroups) {
errs = append(errs, fmt.Errorf("Not enough parts obtained from Shamir. Need %d, got %d", len(m.KeyGroups), len(parts)))
errs = append(errs, fmt.Errorf("not enough parts obtained from Shamir: need %d, got %d", len(m.KeyGroups), len(parts)))
return
}
}
@ -365,7 +367,7 @@ func (m *Metadata) UpdateMasterKeysWithKeyServices(dataKey []byte, svcs []keyser
Plaintext: part,
})
if err != nil {
keyErrs = append(keyErrs, fmt.Errorf("Failed to encrypt new data key with master key %q: %v\n", key.ToString(), err))
keyErrs = append(keyErrs, fmt.Errorf("failed to encrypt new data key with master key %q: %v", key.ToString(), err))
continue
}
key.SetEncryptedDataKey(rsp.Ciphertext)
@ -423,12 +425,12 @@ func (m Metadata) GetDataKeyWithKeyServices(svcs []keyservice.KeyServiceClient)
var dataKey []byte
if len(m.KeyGroups) > 1 {
if len(parts) < m.ShamirQuorum {
return nil, fmt.Errorf("Not enough parts to recover data key with Shamir. Need %d, have %d.", m.ShamirQuorum, len(parts))
return nil, fmt.Errorf("not enough parts to recover data key with Shamir: need %d, have %d", m.ShamirQuorum, len(parts))
}
var err error
dataKey, err = shamir.Combine(parts)
if err != nil {
return nil, fmt.Errorf("Could not get data key from shamir parts: %s", err)
return nil, fmt.Errorf("could not get data key from shamir parts: %s", err)
}
} else {
if len(parts) != 1 {

Просмотреть файл

@ -10,12 +10,13 @@ import (
"go.mozilla.org/sops/pgp"
)
// SopsFile is a struct used by the stores as a helper unmarshal the SOPS metadata
type SopsFile struct {
Data interface{} `yaml:"data" json:"data"`
Metadata Metadata `yaml:"sops" json:"sops"`
}
// metadata is stored in SOPS encrypted files, and it contains the information necessary to decrypt the file.
// Metadata is stored in SOPS encrypted files, and it contains the information necessary to decrypt the file.
// This struct is just used for serialization, and SOPS uses another struct internally, sops.Metadata. It exists
// in order to allow the binary format to stay backwards compatible over time, but at the same time allow the internal
// representation SOPS uses to change over time.
@ -49,6 +50,7 @@ type kmskey struct {
EncryptedDataKey string `yaml:"enc" json:"enc"`
}
// MetadataFromInternal converts an internal SOPS metadata representation to a representation appropriate for storage
func MetadataFromInternal(sopsMetadata sops.Metadata) Metadata {
var m Metadata
m.LastModified = sopsMetadata.LastModified.Format(time.RFC3339)
@ -101,6 +103,7 @@ func kmsKeysFromGroup(group sops.KeyGroup) (keys []kmskey) {
return
}
// ToInternal converts a storage-appropriate Metadata struct to a SOPS internal representation
func (m *Metadata) ToInternal() (sops.Metadata, error) {
lastModified, err := time.Parse(time.RFC3339, m.LastModified)
if err != nil {

Просмотреть файл

@ -134,14 +134,14 @@ func (store Store) MarshalWithMetadata(tree sops.TreeBranch, metadata sops.Metad
return out, nil
}
// MarshalInterface takes any value and marshals it into a yaml document
// MarshalValue takes any value and marshals it into a yaml document
func (store Store) MarshalValue(v interface{}) ([]byte, error) {
v = store.treeValueToYamlValue(v)
return (&yaml.YAMLMarshaler{Indent: 4}).Marshal(v)
}
// UnmarshalMetadata takes a yaml document as a string and extracts sops' metadata from it
func (s *Store) UnmarshalMetadata(in []byte) (sops.Metadata, error) {
func (store *Store) UnmarshalMetadata(in []byte) (sops.Metadata, error) {
file := stores.SopsFile{}
err := yaml.Unmarshal(in, &file)
if err != nil {