diff --git a/age/keysource.go b/age/keysource.go index 7ef038ddf..48dff56d1 100644 --- a/age/keysource.go +++ b/age/keysource.go @@ -1,11 +1,9 @@ package age import ( - "bufio" "bytes" "fmt" "io" - "io/ioutil" "os" "path/filepath" "strings" @@ -91,7 +89,7 @@ func (key *MasterKey) SetEncryptedDataKey(enc []byte) { // Decrypt decrypts the EncryptedKey field with the age identity and returns the result. func (key *MasterKey) Decrypt() ([]byte, error) { - ageKeyFile, ok := os.LookupEnv("SOPS_AGE_KEY_FILE") + ageKeyFilePath, ok := os.LookupEnv("SOPS_AGE_KEY_FILE") if !ok { userConfigDir, err := os.UserConfigDir() @@ -100,35 +98,36 @@ func (key *MasterKey) Decrypt() ([]byte, error) { return nil, fmt.Errorf("user config directory could not be determined: %v", err) } - ageKeyFile = filepath.Join(userConfigDir, "sops", "age", "keys.txt") + ageKeyFilePath = filepath.Join(userConfigDir, "sops", "age", "keys.txt") } - identities, err := parseIdentitiesFile(ageKeyFile) + ageKeyFile, err := os.Open(ageKeyFilePath) + + if err != nil { + return nil, fmt.Errorf("failed to open file: %v", err) + } + + defer ageKeyFile.Close() + + identities, err := age.ParseIdentities(ageKeyFile) if err != nil { return nil, err } - var buffer *bytes.Buffer + buffer := &bytes.Buffer{} + reader := bytes.NewReader([]byte(key.EncryptedKey)) + r, err := age.Decrypt(reader, identities...) - for _, identity := range identities { - buffer = &bytes.Buffer{} - reader := bytes.NewReader([]byte(key.EncryptedKey)) - - r, err := age.Decrypt(reader, identity) - - if err != nil { - continue - } - - if _, err := io.Copy(buffer, r); err != nil { - continue - } - - return buffer.Bytes(), nil + if err != nil { + return nil, fmt.Errorf("no age identity found in %q that could decrypt the data", ageKeyFilePath) } - return nil, fmt.Errorf("no age identity found in %q that could decrypt the data", ageKeyFile) + if _, err := io.Copy(buffer, r); err != nil { + return nil, fmt.Errorf("failed to copy decrypted data into bytes.Buffer") + } + + return buffer.Bytes(), nil } // NeedsRotation returns whether the data key needs to be rotated or not. @@ -194,57 +193,3 @@ func parseRecipient(recipient string) (*age.X25519Recipient, error) { return parsedRecipient, nil } - -// parseIdentitiesFile parses a file containing age private keys. Derived from -// https://github.com/FiloSottile/age/blob/189041b668629795593766bcb8d3f70ee248b842/cmd/age/parse.go -// but should be replaced with a library function if a future version of the age library exposes -// this functionality. -func parseIdentitiesFile(name string) ([]age.Identity, error) { - f, err := os.Open(name) - if err != nil { - return nil, fmt.Errorf("failed to open file: %v", err) - } - defer f.Close() - - contents, err := ioutil.ReadAll(io.LimitReader(f, privateKeySizeLimit)) - if err != nil { - return nil, fmt.Errorf("failed to read %q: %v", name, err) - } - if len(contents) == privateKeySizeLimit { - return nil, fmt.Errorf("failed to read %q: file too long", name) - } - - var ids []age.Identity - var ageParsingError error - scanner := bufio.NewScanner(bytes.NewReader(contents)) - for scanner.Scan() { - line := scanner.Text() - if strings.HasPrefix(line, "#") || line == "" { - continue - } - if strings.HasPrefix(line, "-----BEGIN") { - ageParsingError = fmt.Errorf("sops does not yet support SSH keys via age. SSH key found in file at %q", name) - continue - } - if ageParsingError != nil { - continue - } - i, err := age.ParseX25519Identity(line) - if err != nil { - ageParsingError = fmt.Errorf("malformed secret keys file %q: %v", name, err) - continue - } - ids = append(ids, i) - } - if err := scanner.Err(); err != nil { - return nil, fmt.Errorf("failed to read %q: %v", name, err) - } - if ageParsingError != nil { - return nil, ageParsingError - } - - if len(ids) == 0 { - return nil, fmt.Errorf("no secret keys found in %q", name) - } - return ids, nil -} diff --git a/go.mod b/go.mod index 63b375811..e7c39f9a6 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( cloud.google.com/go v0.43.0 - filippo.io/age v1.0.0-beta4 + filippo.io/age v1.0.0-beta5 github.com/Azure/azure-sdk-for-go v31.2.0+incompatible github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Azure/go-autorest/autorest v0.9.0 diff --git a/go.sum b/go.sum index 072d419ef..197274951 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ cloud.google.com/go v0.43.0 h1:banaiRPAM8kUVYneOSkhgcDsLzEvL25FinuiSZaH/2w= cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= contrib.go.opencensus.io/exporter/ocagent v0.4.12 h1:jGFvw3l57ViIVEPKKEUXPcLYIXJmQxLUh6ey1eJhwyc= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= -filippo.io/age v1.0.0-beta4 h1:czSjaSa0owsI5gw/cE9yI/mfTiuhgYjozHI96v0PVJo= -filippo.io/age v1.0.0-beta4/go.mod h1:TOa3exZvzRCLfjmbJGsqwSQ0HtWjJfTTCQnQsNCC4E0= +filippo.io/age v1.0.0-beta5 h1:H3R+VF81f69NdAQhBOSviEtgUd1cZRS1URhUlm2oXjw= +filippo.io/age v1.0.0-beta5/go.mod h1:TOa3exZvzRCLfjmbJGsqwSQ0HtWjJfTTCQnQsNCC4E0= github.com/Azure/azure-sdk-for-go v31.2.0+incompatible h1:kZFnTLmdQYNGfakatSivKHUfUnDZhqNdchHD4oIhp5k= github.com/Azure/azure-sdk-for-go v31.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= @@ -280,10 +280,6 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=