2018-11-05 23:01:53 +01:00
|
|
|
package crypto
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"crypto/ecdsa"
|
|
|
|
|
"crypto/rsa"
|
2019-05-14 08:07:49 +00:00
|
|
|
"encoding/hex"
|
2018-11-05 23:01:53 +01:00
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"io"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"golang.org/x/crypto/openpgp"
|
|
|
|
|
"golang.org/x/crypto/openpgp/armor"
|
|
|
|
|
"golang.org/x/crypto/openpgp/packet"
|
2019-05-10 12:53:48 +02:00
|
|
|
xrsa "golang.org/x/crypto/rsa"
|
2018-11-05 23:01:53 +01:00
|
|
|
|
2019-05-13 14:07:18 +02:00
|
|
|
armorUtils "github.com/ProtonMail/gopenpgp/armor"
|
2018-11-05 23:01:53 +01:00
|
|
|
)
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// KeyRing contains multiple private and public keys.
|
|
|
|
|
type KeyRing struct {
|
|
|
|
|
// PGP entities in this keyring.
|
|
|
|
|
entities openpgp.EntityList
|
|
|
|
|
|
|
|
|
|
// FirstKeyID as obtained from API to match salt
|
|
|
|
|
FirstKeyID string
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
// A keypair contains a private key and a public key.
|
2019-05-15 13:40:19 +02:00
|
|
|
type pgpKeyObject struct {
|
2019-06-03 17:00:01 +02:00
|
|
|
ID string
|
|
|
|
|
Version int
|
|
|
|
|
Flags int
|
|
|
|
|
PrivateKey string
|
|
|
|
|
Primary int
|
|
|
|
|
Token *string `json:",omitempty"`
|
|
|
|
|
Signature *string `json:",omitempty"`
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:33:01 +00:00
|
|
|
// PrivateKeyReader
|
2019-05-15 13:40:19 +02:00
|
|
|
func (ko *pgpKeyObject) PrivateKeyReader() io.Reader {
|
2018-11-05 23:01:53 +01:00
|
|
|
return strings.NewReader(ko.PrivateKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Identity contains the name and the email of a key holder.
|
|
|
|
|
type Identity struct {
|
|
|
|
|
Name string
|
|
|
|
|
Email string
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-15 14:36:04 +02:00
|
|
|
// GetEntities returns openpgp entities contained in this KeyRing.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) GetEntities() openpgp.EntityList {
|
|
|
|
|
return keyRing.entities
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-15 14:36:04 +02:00
|
|
|
// GetSigningEntity returns first private unlocked signing entity from keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) GetSigningEntity() (*openpgp.Entity, error) {
|
2018-11-21 21:11:30 +01:00
|
|
|
var signEntity *openpgp.Entity
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, e := range keyRing.entities {
|
2018-11-21 21:11:30 +01:00
|
|
|
// Entity.PrivateKey must be a signing key
|
|
|
|
|
if e.PrivateKey != nil {
|
2019-06-03 17:00:01 +02:00
|
|
|
if !e.PrivateKey.Encrypted {
|
|
|
|
|
signEntity = e
|
|
|
|
|
break
|
2018-11-21 21:11:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 14:42:38 +00:00
|
|
|
if signEntity == nil {
|
2019-05-14 18:05:01 +02:00
|
|
|
err := errors.New("gopenpgp: cannot sign message, unable to unlock signer key")
|
2019-05-14 14:42:38 +00:00
|
|
|
return signEntity, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return signEntity, nil
|
2018-11-21 21:11:30 +01:00
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// Unlock tries to unlock as many keys as possible with the following password. Note
|
2018-11-05 23:01:53 +01:00
|
|
|
// that keyrings can contain keys locked with different passwords, and thus
|
|
|
|
|
// err == nil does not mean that all keys have been successfully decrypted.
|
|
|
|
|
// If err != nil, the password is wrong for every key, and err is the last error
|
|
|
|
|
// encountered.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) Unlock(passphrase []byte) error {
|
2018-11-05 23:01:53 +01:00
|
|
|
// Build a list of keys to decrypt
|
|
|
|
|
var keys []*packet.PrivateKey
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, e := range keyRing.entities {
|
2018-11-05 23:01:53 +01:00
|
|
|
// Entity.PrivateKey must be a signing key
|
|
|
|
|
if e.PrivateKey != nil {
|
|
|
|
|
keys = append(keys, e.PrivateKey)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Entity.Subkeys can be used for encryption
|
|
|
|
|
for _, subKey := range e.Subkeys {
|
2019-05-14 14:42:38 +00:00
|
|
|
if subKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage ||
|
|
|
|
|
subKey.Sig.FlagEncryptCommunications) {
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
keys = append(keys, subKey.PrivateKey)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(keys) == 0 {
|
2019-05-13 14:07:18 +02:00
|
|
|
return errors.New("gopenpgp: cannot unlock key ring, no private key available")
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
var n int
|
|
|
|
|
for _, key := range keys {
|
|
|
|
|
if !key.Encrypted {
|
|
|
|
|
continue // Key already decrypted
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = key.Decrypt(passphrase); err == nil {
|
|
|
|
|
n++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
// UnlockWithPassphrase is a wrapper for Unlock that uses strings
|
|
|
|
|
func (keyRing *KeyRing) UnlockWithPassphrase(passphrase string) error {
|
|
|
|
|
return keyRing.Unlock([]byte(passphrase))
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WriteArmoredPublicKey outputs armored public keys from the keyring to w.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) {
|
2018-11-05 23:01:53 +01:00
|
|
|
aw, err := armor.Encode(w, openpgp.PublicKeyType, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, e := range keyRing.entities {
|
2018-11-05 23:01:53 +01:00
|
|
|
if err = e.Serialize(aw); err != nil {
|
|
|
|
|
aw.Close()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = aw.Close()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 08:07:49 +00:00
|
|
|
// GetArmoredPublicKey returns the armored public keys from this keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) GetArmoredPublicKey() (s string, err error) {
|
2018-11-05 23:01:53 +01:00
|
|
|
b := &bytes.Buffer{}
|
2019-06-03 17:00:01 +02:00
|
|
|
if err = keyRing.WriteArmoredPublicKey(b); err != nil {
|
2018-11-05 23:01:53 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s = b.String()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-14 08:07:49 +00:00
|
|
|
// WritePublicKey outputs unarmored public keys from the keyring to w.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) WritePublicKey(w io.Writer) (err error) {
|
|
|
|
|
for _, e := range keyRing.entities {
|
2019-05-14 08:07:49 +00:00
|
|
|
if err = e.Serialize(w); err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetPublicKey returns the unarmored public keys from this keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) GetPublicKey() (b []byte, err error) {
|
2019-05-14 08:07:49 +00:00
|
|
|
var outBuf bytes.Buffer
|
2019-06-03 17:00:01 +02:00
|
|
|
if err = keyRing.WritePublicKey(&outBuf); err != nil {
|
2019-05-14 08:07:49 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
b = outBuf.Bytes()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-15 14:36:04 +02:00
|
|
|
// GetFingerprint gets the fingerprint from the keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) GetFingerprint() (string, error) {
|
|
|
|
|
for _, entity := range keyRing.entities {
|
2019-05-14 08:07:49 +00:00
|
|
|
fp := entity.PrimaryKey.Fingerprint
|
|
|
|
|
return hex.EncodeToString(fp[:]), nil
|
|
|
|
|
}
|
|
|
|
|
return "", errors.New("can't find public key")
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-15 14:36:04 +02:00
|
|
|
// CheckPassphrase checks if private key passphrase is correct for every sub key.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) CheckPassphrase(passphrase string) bool {
|
2019-05-14 08:07:49 +00:00
|
|
|
var keys []*packet.PrivateKey
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, entity := range keyRing.entities {
|
2019-05-14 08:07:49 +00:00
|
|
|
keys = append(keys, entity.PrivateKey)
|
|
|
|
|
}
|
|
|
|
|
var decryptError error
|
|
|
|
|
var n int
|
|
|
|
|
for _, key := range keys {
|
|
|
|
|
if !key.Encrypted {
|
|
|
|
|
continue // Key already decrypted
|
|
|
|
|
}
|
|
|
|
|
if decryptError = key.Decrypt([]byte(passphrase)); decryptError == nil {
|
|
|
|
|
n++
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-14 14:42:38 +00:00
|
|
|
|
|
|
|
|
return n != 0
|
2019-05-14 08:07:49 +00:00
|
|
|
}
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
// readFrom reads unarmored and armored keys from r and adds them to the keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) readFrom(r io.Reader, armored bool) error {
|
2018-11-05 23:01:53 +01:00
|
|
|
var err error
|
|
|
|
|
var entities openpgp.EntityList
|
|
|
|
|
if armored {
|
|
|
|
|
entities, err = openpgp.ReadArmoredKeyRing(r)
|
|
|
|
|
} else {
|
|
|
|
|
entities, err = openpgp.ReadKeyRing(r)
|
|
|
|
|
}
|
|
|
|
|
for _, entity := range entities {
|
|
|
|
|
if entity.PrivateKey != nil {
|
|
|
|
|
switch entity.PrivateKey.PrivateKey.(type) {
|
|
|
|
|
// TODO: type mismatch after crypto lib update, fix this:
|
|
|
|
|
case *rsa.PrivateKey:
|
2019-05-14 14:42:38 +00:00
|
|
|
entity.PrimaryKey = packet.NewRSAPublicKey(
|
|
|
|
|
time.Now(),
|
|
|
|
|
entity.PrivateKey.PrivateKey.(*rsa.PrivateKey).Public().(*xrsa.PublicKey))
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
case *ecdsa.PrivateKey:
|
2019-05-14 14:42:38 +00:00
|
|
|
entity.PrimaryKey = packet.NewECDSAPublicKey(
|
|
|
|
|
time.Now(),
|
|
|
|
|
entity.PrivateKey.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey))
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, subkey := range entity.Subkeys {
|
|
|
|
|
if subkey.PrivateKey != nil {
|
|
|
|
|
switch subkey.PrivateKey.PrivateKey.(type) {
|
|
|
|
|
case *rsa.PrivateKey:
|
2019-05-14 14:42:38 +00:00
|
|
|
subkey.PublicKey = packet.NewRSAPublicKey(
|
|
|
|
|
time.Now(),
|
|
|
|
|
subkey.PrivateKey.PrivateKey.(*rsa.PrivateKey).Public().(*xrsa.PublicKey))
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
case *ecdsa.PrivateKey:
|
2019-05-14 14:42:38 +00:00
|
|
|
subkey.PublicKey = packet.NewECDSAPublicKey(
|
|
|
|
|
time.Now(),
|
|
|
|
|
subkey.PrivateKey.PrivateKey.(*ecdsa.PrivateKey).Public().(*ecdsa.PublicKey))
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(entities) == 0 {
|
2019-05-15 13:40:19 +02:00
|
|
|
return errors.New("gopenpgp: key ring doesn't contain any key")
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
keyRing.entities = append(keyRing.entities, entities...)
|
2018-11-05 23:01:53 +01:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// BuildKeyRing reads keyring from binary data
|
2019-06-03 17:00:01 +02:00
|
|
|
func (pgp *GopenPGP) BuildKeyRing(binKeys []byte) (keyRing *KeyRing, err error) {
|
|
|
|
|
keyRing = &KeyRing{}
|
2018-11-09 02:03:19 +01:00
|
|
|
entriesReader := bytes.NewReader(binKeys)
|
2019-06-03 17:00:01 +02:00
|
|
|
err = keyRing.readFrom(entriesReader, false)
|
2018-11-09 02:03:19 +01:00
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// BuildKeyRingNoError does not return error on fail
|
2019-06-03 17:00:01 +02:00
|
|
|
func (pgp *GopenPGP) BuildKeyRingNoError(binKeys []byte) (keyRing *KeyRing) {
|
|
|
|
|
keyRing, _ = pgp.BuildKeyRing(binKeys)
|
2018-11-09 02:03:19 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// BuildKeyRingArmored reads armored string and returns keyring
|
2019-06-03 17:00:01 +02:00
|
|
|
func (pgp *GopenPGP) BuildKeyRingArmored(key string) (keyRing *KeyRing, err error) {
|
2018-11-09 02:03:19 +01:00
|
|
|
keyRaw, err := armorUtils.Unarmor(key)
|
2019-05-13 12:42:29 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2018-11-09 02:03:19 +01:00
|
|
|
keyReader := bytes.NewReader(keyRaw)
|
|
|
|
|
keyEntries, err := openpgp.ReadKeyRing(keyReader)
|
|
|
|
|
return &KeyRing{entities: keyEntries}, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-29 17:45:13 +02:00
|
|
|
// UnmarshalJSON reads multiple keys from a json array and fills the keyring
|
|
|
|
|
func (keyRing *KeyRing) UnmarshalJSON(jsonData []byte) (err error) {
|
2019-06-03 17:00:01 +02:00
|
|
|
keyObjs, err := unmarshalJSON(jsonData)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-05 23:01:53 +01:00
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
return keyRing.newKeyRingFromPGPKeyObject(keyObjs)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UnlockJSONKeyRing reads keys from a JSON array, creates a newKeyRing,
|
|
|
|
|
// then tries to unlock them with the provided keyRing using the token in the structure.
|
|
|
|
|
// If the token is not available it will fall back to just reading the keys, and leave them locked.
|
|
|
|
|
func (keyRing *KeyRing) UnlockJSONKeyRing(jsonData []byte) (newKeyRing *KeyRing, err error) {
|
|
|
|
|
keyObjs, err := unmarshalJSON(jsonData)
|
2019-08-29 17:45:13 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
newKeyRing = &KeyRing{}
|
|
|
|
|
err = newKeyRing.newKeyRingFromPGPKeyObject(keyObjs)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, ko := range keyObjs {
|
|
|
|
|
if ko.Token == nil || ko.Signature == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
message, err := NewPGPMessageFromArmored(*ko.Token)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
signature, err := NewPGPSignatureFromArmored(*ko.Signature)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-02 07:36:02 -07:00
|
|
|
token, err := keyRing.Decrypt(message, nil, 0)
|
2019-06-03 17:00:01 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-02 07:36:02 -07:00
|
|
|
err = keyRing.VerifyDetached(token, signature, 0)
|
2019-06-03 17:00:01 +02:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = newKeyRing.Unlock(token.GetBinary())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.New("gopenpgp: wrong token")
|
|
|
|
|
}
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-03 17:00:01 +02:00
|
|
|
return newKeyRing, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newKeyRingFromPGPKeyObject fills a KeyRing given an array of pgpKeyObject
|
|
|
|
|
func (keyRing *KeyRing) newKeyRingFromPGPKeyObject(keyObjs []pgpKeyObject) error {
|
|
|
|
|
keyRing.entities = nil
|
2019-03-07 15:15:35 +01:00
|
|
|
for i, ko := range keyObjs {
|
|
|
|
|
if i == 0 {
|
2019-06-03 17:00:01 +02:00
|
|
|
keyRing.FirstKeyID = ko.ID
|
2019-03-07 15:15:35 +01:00
|
|
|
}
|
2019-06-03 17:00:01 +02:00
|
|
|
err := keyRing.readFrom(ko.PrivateKeyReader(), true)
|
2019-05-14 14:42:38 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
2019-05-14 14:42:38 +00:00
|
|
|
return nil
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-08-29 17:45:13 +02:00
|
|
|
// unmarshalJSON decodes key json from the API
|
2019-06-03 17:00:01 +02:00
|
|
|
func unmarshalJSON(jsonData []byte) ([]pgpKeyObject, error) {
|
|
|
|
|
keyObjs := []pgpKeyObject{}
|
|
|
|
|
if err := json.Unmarshal(jsonData, &keyObjs); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return keyObjs, nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-05 23:01:53 +01:00
|
|
|
// Identities returns the list of identities associated with this key ring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) Identities() []*Identity {
|
2018-11-05 23:01:53 +01:00
|
|
|
var identities []*Identity
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, e := range keyRing.entities {
|
2018-11-05 23:01:53 +01:00
|
|
|
for _, id := range e.Identities {
|
|
|
|
|
identities = append(identities, &Identity{
|
|
|
|
|
Name: id.UserId.Name,
|
|
|
|
|
Email: id.UserId.Email,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return identities
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-15 14:36:04 +02:00
|
|
|
// KeyIds returns array of IDs of keys in this KeyRing.
|
2019-06-03 17:00:01 +02:00
|
|
|
func (keyRing *KeyRing) KeyIds() []uint64 {
|
2018-11-05 23:01:53 +01:00
|
|
|
var res []uint64
|
2019-06-03 17:00:01 +02:00
|
|
|
for _, e := range keyRing.entities {
|
2018-11-05 23:01:53 +01:00
|
|
|
res = append(res, e.PrimaryKey.KeyId)
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// ReadArmoredKeyRing reads an armored data into keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func ReadArmoredKeyRing(r io.Reader) (keyRing *KeyRing, err error) {
|
|
|
|
|
keyRing = &KeyRing{}
|
|
|
|
|
err = keyRing.readFrom(r, true)
|
2018-11-05 23:01:53 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// ReadKeyRing reads an binary data into keyring.
|
2019-06-03 17:00:01 +02:00
|
|
|
func ReadKeyRing(r io.Reader) (keyRing *KeyRing, err error) {
|
|
|
|
|
keyRing = &KeyRing{}
|
|
|
|
|
err = keyRing.readFrom(r, false)
|
2018-11-05 23:01:53 +01:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-07 15:15:35 +01:00
|
|
|
// FilterExpiredKeys takes a given KeyRing list and it returns only those
|
|
|
|
|
// KeyRings which contain at least, one unexpired Key. It returns only unexpired
|
2019-05-15 14:36:04 +02:00
|
|
|
// parts of these KeyRings.
|
2018-11-05 23:01:53 +01:00
|
|
|
func FilterExpiredKeys(contactKeys []*KeyRing) (filteredKeys []*KeyRing, err error) {
|
|
|
|
|
now := time.Now()
|
|
|
|
|
hasExpiredEntity := false
|
2019-05-14 14:42:38 +00:00
|
|
|
filteredKeys = make([]*KeyRing, 0)
|
2018-11-05 23:01:53 +01:00
|
|
|
|
|
|
|
|
for _, contactKeyRing := range contactKeys {
|
|
|
|
|
keyRingHasUnexpiredEntity := false
|
|
|
|
|
keyRingHasTotallyExpiredEntity := false
|
|
|
|
|
for _, entity := range contactKeyRing.GetEntities() {
|
|
|
|
|
hasExpired := false
|
|
|
|
|
hasUnexpired := false
|
|
|
|
|
for _, subkey := range entity.Subkeys {
|
2019-04-27 07:22:10 +02:00
|
|
|
if subkey.PublicKey.KeyExpired(subkey.Sig, now) {
|
2018-11-05 23:01:53 +01:00
|
|
|
hasExpired = true
|
|
|
|
|
} else {
|
|
|
|
|
hasUnexpired = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if hasExpired && !hasUnexpired {
|
|
|
|
|
keyRingHasTotallyExpiredEntity = true
|
|
|
|
|
} else if hasUnexpired {
|
|
|
|
|
keyRingHasUnexpiredEntity = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if keyRingHasUnexpiredEntity {
|
|
|
|
|
filteredKeys = append(filteredKeys, contactKeyRing)
|
|
|
|
|
} else if keyRingHasTotallyExpiredEntity {
|
|
|
|
|
hasExpiredEntity = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(filteredKeys) == 0 && hasExpiredEntity {
|
2019-06-03 17:00:01 +02:00
|
|
|
return filteredKeys, errors.New("gopenpgp: all contacts keys are expired")
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-14 14:42:38 +00:00
|
|
|
return filteredKeys, nil
|
2018-11-05 23:01:53 +01:00
|
|
|
}
|
2019-08-29 17:45:13 +02:00
|
|
|
|
|
|
|
|
// FirstKey returns a KeyRing with only the first key of the original one
|
|
|
|
|
func (keyRing *KeyRing) FirstKey() *KeyRing {
|
2019-08-30 12:22:50 +02:00
|
|
|
if len(keyRing.entities) == 0 {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2019-08-29 17:45:13 +02:00
|
|
|
newKeyRing := &KeyRing{}
|
|
|
|
|
newKeyRing.FirstKeyID = keyRing.FirstKeyID
|
|
|
|
|
newKeyRing.entities = keyRing.entities[:1]
|
|
|
|
|
|
2019-08-30 12:22:50 +02:00
|
|
|
return newKeyRing
|
2019-08-29 17:45:13 +02:00
|
|
|
}
|