internal/plugin,cmd/age: implement preliminary plugin client support

This commit is contained in:
Filippo Valsorda
2021-01-04 01:08:42 +01:00
parent cff70cffe2
commit f6a5b94705
4 changed files with 326 additions and 4 deletions

View File

@@ -249,7 +249,7 @@ func main() {
}
encryptPass(pass, in, out, armorFlag)
default:
encryptKeys(recipientFlags, recipientsFileFlags, identityFlags, in, out, armorFlag)
encryptNotPass(recipientFlags, recipientsFileFlags, identityFlags, in, out, armorFlag)
}
}
@@ -279,7 +279,7 @@ func passphrasePromptForEncryption() (string, error) {
return p, nil
}
func encryptKeys(keys, files, identities []string, in io.Reader, out io.Writer, armor bool) {
func encryptNotPass(keys, files, identities []string, in io.Reader, out io.Writer, armor bool) {
var recipients []age.Recipient
for _, arg := range keys {
r, err := parseRecipient(arg)

View File

@@ -99,7 +99,7 @@ func (i *EncryptedIdentity) decrypt() error {
if err != nil {
return fmt.Errorf("failed to decrypt identity file: %v", err)
}
i.identities, err = age.ParseIdentities(d)
i.identities, err = parseIdentities(d)
return err
}

View File

@@ -15,6 +15,7 @@ import (
"filippo.io/age"
"filippo.io/age/agessh"
"filippo.io/age/armor"
"filippo.io/age/internal/plugin"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/ssh"
)
@@ -32,6 +33,8 @@ func (gitHubRecipientError) Error() string {
func parseRecipient(arg string) (age.Recipient, error) {
switch {
case strings.HasPrefix(arg, "age1") && strings.Count(arg, "1") > 1:
return plugin.NewRecipient(arg)
case strings.HasPrefix(arg, "age1"):
return age.ParseX25519Recipient(arg)
case strings.HasPrefix(arg, "ssh-"):
@@ -187,7 +190,7 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) {
// An unencrypted age identity file.
default:
ids, err := age.ParseIdentities(b)
ids, err := parseIdentities(b)
if err != nil {
return nil, fmt.Errorf("failed to read %q: %v", name, err)
}
@@ -195,6 +198,45 @@ func parseIdentitiesFile(name string) ([]age.Identity, error) {
}
}
func parseIdentity(s string) (age.Identity, error) {
switch {
case strings.HasPrefix(s, "AGE-PLUGIN-"):
return plugin.NewIdentity(s)
case strings.HasPrefix(s, "AGE-SECRET-KEY-1"):
return age.ParseX25519Identity(s)
}
return nil, fmt.Errorf("unknown identity type")
}
// parseIdentities is like age.ParseIdentities, but supports plugin identities.
func parseIdentities(f io.Reader) ([]age.Identity, error) {
const privateKeySizeLimit = 1 << 24 // 16 MiB
var ids []age.Identity
scanner := bufio.NewScanner(io.LimitReader(f, privateKeySizeLimit))
var n int
for scanner.Scan() {
n++
line := scanner.Text()
if strings.HasPrefix(line, "#") || line == "" {
continue
}
i, err := parseIdentity(line)
if err != nil {
return nil, fmt.Errorf("error at line %d: %v", n, err)
}
ids = append(ids, i)
}
if err := scanner.Err(); err != nil {
return nil, fmt.Errorf("failed to read secret keys file: %v", err)
}
if len(ids) == 0 {
return nil, fmt.Errorf("no secret keys found")
}
return ids, nil
}
func parseSSHIdentity(name string, pemBytes []byte) ([]age.Identity, error) {
id, err := agessh.ParseIdentity(pemBytes)
if sshErr, ok := err.(*ssh.PassphraseMissingError); ok {