diff options
author | Tim Culverhouse <tim@timculverhouse.com> | 2022-04-25 08:30:44 -0500 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-04-27 09:46:25 +0200 |
commit | 57699b1fa6367a42d5877afcfdb1504e52835ed9 (patch) | |
tree | b5000bfad3d62f01127f5831d64d27aac07872e1 /lib/crypto/pgp/pgp.go | |
parent | d09636ee0b9957ed60fc01224ddfbb03c4f4b7fa (diff) | |
download | aerc-57699b1fa6367a42d5877afcfdb1504e52835ed9.tar.gz |
feat: add gpg integration
This commit adds gpg system integration. This is done through two new
packages: gpgbin, which handles the system calls and parsing; and gpg
which is mostly a copy of emersion/go-pgpmail with modifications to
interface with package gpgbin. gpg includes tests for many cases, and
by it's nature also tests package gpgbin. I separated these in case an
external dependency is ever used for the gpg sys-calls/parsing (IE we
mirror how go-pgpmail+openpgp currently are dependencies)
Two new config options are introduced:
* pgp-provider. If it is not explicitly set to "gpg", aerc will default to
it's internal pgp provider
* pgp-key-id: (Optionally) specify a key by short or long keyId
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'lib/crypto/pgp/pgp.go')
-rw-r--r-- | lib/crypto/pgp/pgp.go | 61 |
1 files changed, 40 insertions, 21 deletions
diff --git a/lib/crypto/pgp/pgp.go b/lib/crypto/pgp/pgp.go index 70a003a0..92a15ee6 100644 --- a/lib/crypto/pgp/pgp.go +++ b/lib/crypto/pgp/pgp.go @@ -79,6 +79,20 @@ func (m *Mail) getEntityByEmail(email string) (e *openpgp.Entity, err error) { return nil, fmt.Errorf("entity not found in keyring") } +func (m *Mail) getSignerEntityByKeyId(id string) (*openpgp.Entity, error) { + id = strings.ToUpper(id) + for _, key := range Keyring.DecryptionKeys() { + if key.Entity == nil { + continue + } + kId := key.Entity.PrimaryKey.KeyIdString() + if strings.Contains(kId, id) { + return key.Entity, nil + } + } + return nil, fmt.Errorf("entity not found in keyring") +} + func (m *Mail) getSignerEntityByEmail(email string) (e *openpgp.Entity, err error) { for _, key := range Keyring.DecryptionKeys() { if key.Entity == nil { @@ -157,12 +171,12 @@ func (m *Mail) ImportKeys(r io.Reader) error { return nil } -func (m *Mail) Encrypt(buf *bytes.Buffer, rcpts []string, signerEmail string, decryptKeys openpgp.PromptFunction, header *mail.Header) (io.WriteCloser, error) { +func (m *Mail) Encrypt(buf *bytes.Buffer, rcpts []string, signer string, decryptKeys openpgp.PromptFunction, header *mail.Header) (io.WriteCloser, error) { var err error var to []*openpgp.Entity - var signer *openpgp.Entity - if signerEmail != "" { - signer, err = m.getSigner(signerEmail, decryptKeys) + var signerEntity *openpgp.Entity + if signer != "" { + signerEntity, err = m.getSigner(signer, decryptKeys) if err != nil { return nil, err } @@ -177,45 +191,50 @@ func (m *Mail) Encrypt(buf *bytes.Buffer, rcpts []string, signerEmail string, de } cleartext, err := pgpmail.Encrypt(buf, header.Header.Header, - to, signer, nil) + to, signerEntity, nil) if err != nil { return nil, err } return cleartext, nil } -func (m *Mail) Sign(buf *bytes.Buffer, signerEmail string, decryptKeys openpgp.PromptFunction, header *mail.Header) (io.WriteCloser, error) { +func (m *Mail) Sign(buf *bytes.Buffer, signer string, decryptKeys openpgp.PromptFunction, header *mail.Header) (io.WriteCloser, error) { var err error - var signer *openpgp.Entity - if signerEmail != "" { - signer, err = m.getSigner(signerEmail, decryptKeys) + var signerEntity *openpgp.Entity + if signer != "" { + signerEntity, err = m.getSigner(signer, decryptKeys) if err != nil { return nil, err } } - cleartext, err := pgpmail.Sign(buf, header.Header.Header, signer, nil) + cleartext, err := pgpmail.Sign(buf, header.Header.Header, signerEntity, nil) if err != nil { return nil, err } return cleartext, nil } -func (m *Mail) getSigner(signerEmail string, decryptKeys openpgp.PromptFunction) (signer *openpgp.Entity, err error) { - if err != nil { - return nil, err - } - signer, err = m.getSignerEntityByEmail(signerEmail) - if err != nil { - return nil, err +func (m *Mail) getSigner(signer string, decryptKeys openpgp.PromptFunction) (signerEntity *openpgp.Entity, err error) { + switch strings.Contains(signer, "@") { + case true: + signerEntity, err = m.getSignerEntityByEmail(signer) + if err != nil { + return nil, err + } + case false: + signerEntity, err = m.getSignerEntityByKeyId(signer) + if err != nil { + return nil, err + } } - key, ok := signer.SigningKey(time.Now()) + key, ok := signerEntity.SigningKey(time.Now()) if !ok { - return nil, fmt.Errorf("no signing key found for %s", signerEmail) + return nil, fmt.Errorf("no signing key found for %s", signer) } if !key.PrivateKey.Encrypted { - return signer, nil + return signerEntity, nil } _, err = decryptKeys([]openpgp.Key{key}, false) @@ -223,7 +242,7 @@ func (m *Mail) getSigner(signerEmail string, decryptKeys openpgp.PromptFunction) return nil, err } - return signer, nil + return signerEntity, nil } func handleSignatureError(e string) models.SignatureValidity { |