Refactor api (#6)
* Refactor library, remove duplicates * Rebuild structure to use Messages and Signature models * Use PGPSplitMessage * Remove signature model * Various fixes * Add helpers with tests * Fixes, add some docs, add tests * Add attachment helpers * Add helpers Symmetric encryption * Edit docs + examples * Rename kr to keyRing * Various fixes for documentation * Edit JSON handling functions, add decrypt keyring via token * Add proposal changes doc * Fix CI * Drop *Message functions, join CleartextMessage and BinaryMessage * Change canonicalization and trimming only to text signatures * Add cleartextsignature, detach signature from message model, move helpers * Documentation, remove optional parameters * Move verification to separate model * Don't return message in VerifyDetached * Update table of contents in readme * Appease golint * Run go fmt * Rename Encrypt/DecryptMessageWithPassword to ..WithToken These functions shouldn't be used with user-provided passwords, as they don't do any key-stretching. * Change key generation usernames
This commit is contained in:
parent
82d49bf235
commit
e65ed17b41
34 changed files with 2573 additions and 1478 deletions
|
|
@ -8,31 +8,35 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"golang.org/x/crypto/openpgp/armor"
|
||||
pgperrors "golang.org/x/crypto/openpgp/errors"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
xrsa "golang.org/x/crypto/rsa"
|
||||
|
||||
armorUtils "github.com/ProtonMail/gopenpgp/armor"
|
||||
"github.com/ProtonMail/gopenpgp/constants"
|
||||
"github.com/ProtonMail/gopenpgp/models"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// A keypair contains a private key and a public key.
|
||||
type pgpKeyObject struct {
|
||||
ID string
|
||||
Version int
|
||||
Flags int
|
||||
Fingerprint string
|
||||
PublicKey string `json:",omitempty"`
|
||||
PrivateKey string
|
||||
Primary int
|
||||
ID string
|
||||
Version int
|
||||
Flags int
|
||||
PrivateKey string
|
||||
Primary int
|
||||
Token *string `json:",omitempty"`
|
||||
Signature *string `json:",omitempty"`
|
||||
}
|
||||
|
||||
// PrivateKeyReader
|
||||
|
|
@ -46,87 +50,22 @@ type Identity struct {
|
|||
Email string
|
||||
}
|
||||
|
||||
// Signature is be used to check a signature. Because the signature is checked
|
||||
// when the reader is consumed, Signature must only be used after EOF has been
|
||||
// seen. A signature is only valid if s.Err() returns nil, otherwise the
|
||||
// sender's identity cannot be trusted.
|
||||
type Signature struct {
|
||||
md *openpgp.MessageDetails
|
||||
}
|
||||
|
||||
// SignedString wraps string with a Signature
|
||||
type SignedString struct {
|
||||
String string
|
||||
Signed *Signature
|
||||
}
|
||||
|
||||
var errKeyringNotUnlocked = errors.New("gopenpgp: cannot sign message, key ring is not unlocked")
|
||||
|
||||
// Err returns a non-nil error if the signature is invalid.
|
||||
func (s *Signature) Err() error {
|
||||
return s.md.SignatureError
|
||||
}
|
||||
|
||||
// KeyRing returns the key ring that was used to produce the signature, if
|
||||
// available.
|
||||
func (s *Signature) KeyRing() *KeyRing {
|
||||
if s.md.SignedBy == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &KeyRing{
|
||||
entities: openpgp.EntityList{s.md.SignedBy.Entity},
|
||||
}
|
||||
}
|
||||
|
||||
// IsBy returns true if the signature has been created by kr's owner.
|
||||
func (s *Signature) IsBy(kr *KeyRing) bool {
|
||||
// Use fingerprint if possible
|
||||
if s.md.SignedBy != nil {
|
||||
for _, e := range kr.entities {
|
||||
if e.PrimaryKey.Fingerprint == s.md.SignedBy.PublicKey.Fingerprint {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
for _, e := range kr.entities {
|
||||
if e.PrimaryKey.KeyId == s.md.SignedByKeyId {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetEntities returns openpgp entities contained in this KeyRing.
|
||||
func (kr *KeyRing) GetEntities() openpgp.EntityList {
|
||||
return kr.entities
|
||||
func (keyRing *KeyRing) GetEntities() openpgp.EntityList {
|
||||
return keyRing.entities
|
||||
}
|
||||
|
||||
// GetSigningEntity returns first private unlocked signing entity from keyring.
|
||||
func (kr *KeyRing) GetSigningEntity(passphrase string) (*openpgp.Entity, error) {
|
||||
func (keyRing *KeyRing) GetSigningEntity() (*openpgp.Entity, error) {
|
||||
var signEntity *openpgp.Entity
|
||||
|
||||
for _, e := range kr.entities {
|
||||
for _, e := range keyRing.entities {
|
||||
// Entity.PrivateKey must be a signing key
|
||||
if e.PrivateKey != nil {
|
||||
if e.PrivateKey.Encrypted {
|
||||
if err := e.PrivateKey.Decrypt([]byte(passphrase)); err != nil {
|
||||
continue
|
||||
}
|
||||
if !e.PrivateKey.Encrypted {
|
||||
signEntity = e
|
||||
break
|
||||
}
|
||||
signEntity = e
|
||||
break
|
||||
}
|
||||
}
|
||||
if signEntity == nil {
|
||||
|
|
@ -137,184 +76,15 @@ func (kr *KeyRing) GetSigningEntity(passphrase string) (*openpgp.Entity, error)
|
|||
return signEntity, nil
|
||||
}
|
||||
|
||||
// Encrypt encrypts data to this keyring's owner. If sign is not nil, it also
|
||||
// signs data with it. The keyring sign must be unlocked to be able to sign data,
|
||||
// if not an error will be returned.
|
||||
func (kr *KeyRing) Encrypt(w io.Writer, sign *KeyRing, filename string, canonicalizeText bool) (io.WriteCloser, error) {
|
||||
// The API returns keys sorted by descending priority
|
||||
// Only encrypt to the first one
|
||||
var encryptEntities []*openpgp.Entity
|
||||
for _, e := range kr.entities {
|
||||
encryptEntities = append(encryptEntities, e)
|
||||
break
|
||||
}
|
||||
|
||||
var signEntity *openpgp.Entity
|
||||
if sign != nil {
|
||||
// To sign a message, the private key must be decrypted
|
||||
for _, e := range sign.entities {
|
||||
// Entity.PrivateKey must be a signing key
|
||||
if e.PrivateKey != nil && !e.PrivateKey.Encrypted {
|
||||
signEntity = e
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if signEntity == nil {
|
||||
return nil, errKeyringNotUnlocked
|
||||
}
|
||||
}
|
||||
|
||||
return EncryptCore(
|
||||
w,
|
||||
encryptEntities,
|
||||
signEntity,
|
||||
filename,
|
||||
canonicalizeText,
|
||||
func() time.Time { return GetGopenPGP().GetTime() })
|
||||
}
|
||||
|
||||
// EncryptCore is lower-level encryption method used by KeyRing.Encrypt.
|
||||
func EncryptCore(w io.Writer, encryptEntities []*openpgp.Entity, signEntity *openpgp.Entity, filename string,
|
||||
canonicalizeText bool, timeGenerator func() time.Time) (io.WriteCloser, error) {
|
||||
|
||||
config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: timeGenerator}
|
||||
|
||||
hints := &openpgp.FileHints{
|
||||
IsBinary: !canonicalizeText,
|
||||
FileName: filename,
|
||||
}
|
||||
if canonicalizeText {
|
||||
return openpgp.EncryptText(w, encryptEntities, signEntity, hints, config)
|
||||
}
|
||||
return openpgp.Encrypt(w, encryptEntities, signEntity, hints, config)
|
||||
}
|
||||
|
||||
// An io.WriteCloser that both encrypts and armors data.
|
||||
type armorEncryptWriter struct {
|
||||
aw io.WriteCloser // Armored writer
|
||||
ew io.WriteCloser // Encrypted writer
|
||||
}
|
||||
|
||||
// Write encrypted data
|
||||
func (w *armorEncryptWriter) Write(b []byte) (n int, err error) {
|
||||
return w.ew.Write(b)
|
||||
}
|
||||
|
||||
// Close armor and encryption io.WriteClose
|
||||
func (w *armorEncryptWriter) Close() (err error) {
|
||||
if err = w.ew.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
err = w.aw.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// EncryptArmored encrypts and armors data to the keyring's owner.
|
||||
// Wrapper of Encrypt.
|
||||
func (kr *KeyRing) EncryptArmored(w io.Writer, sign *KeyRing) (wc io.WriteCloser, err error) {
|
||||
aw, err := armorUtils.ArmorWithTypeBuffered(w, constants.PGPMessageHeader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ew, err := kr.Encrypt(aw, sign, "", false)
|
||||
if err != nil {
|
||||
aw.Close()
|
||||
return
|
||||
}
|
||||
|
||||
wc = &armorEncryptWriter{aw: aw, ew: ew}
|
||||
return
|
||||
}
|
||||
|
||||
// EncryptMessage encrypts and armors a string to the keyring's owner.
|
||||
// Wrapper of Encrypt.
|
||||
func (kr *KeyRing) EncryptMessage(s string, sign *KeyRing) (encrypted string, err error) {
|
||||
var b bytes.Buffer
|
||||
w, err := kr.EncryptArmored(&b, sign)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = w.Write([]byte(s)); err != nil {
|
||||
return
|
||||
}
|
||||
if err = w.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
encrypted = b.String()
|
||||
return
|
||||
}
|
||||
|
||||
// EncryptSymmetric data using generated symmetric key encrypted with this KeyRing.
|
||||
// Wrapper of Encrypt.
|
||||
func (kr *KeyRing) EncryptSymmetric(textToEncrypt string, canonicalizeText bool) (outSplit *models.EncryptedSplit,
|
||||
err error) {
|
||||
|
||||
var encryptedWriter io.WriteCloser
|
||||
buffer := &bytes.Buffer{}
|
||||
|
||||
if encryptedWriter, err = kr.Encrypt(buffer, kr, "msg.txt", canonicalizeText); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = io.Copy(encryptedWriter, bytes.NewBufferString(textToEncrypt)); err != nil {
|
||||
return
|
||||
}
|
||||
encryptedWriter.Close()
|
||||
|
||||
if outSplit, err = SeparateKeyAndData(kr, buffer, len(textToEncrypt), -1); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DecryptMessage decrypts an armored string sent to the keypair's owner.
|
||||
// If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors),
|
||||
// contents are still provided if library clients wish to process this message further.
|
||||
func (kr *KeyRing) DecryptMessage(encrypted string) (SignedString, error) {
|
||||
r, signed, err := kr.DecryptArmored(strings.NewReader(encrypted))
|
||||
if err != nil && err != pgperrors.ErrSignatureExpired {
|
||||
return SignedString{String: encrypted, Signed: nil}, err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(r)
|
||||
if err != nil && err != pgperrors.ErrSignatureExpired {
|
||||
return SignedString{String: encrypted, Signed: nil}, err
|
||||
}
|
||||
|
||||
s := string(b)
|
||||
return SignedString{String: s, Signed: signed}, nil
|
||||
}
|
||||
|
||||
// DecryptMessageIfNeeded data if has armored PGP message format, if not return original data.
|
||||
// If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors),
|
||||
// contents are still provided if library clients wish to process this message further.
|
||||
func (kr *KeyRing) DecryptMessageIfNeeded(data string) (decrypted string, err error) {
|
||||
if re := regexp.MustCompile("^-----BEGIN " + constants.PGPMessageHeader + "-----(?s:.+)-----END " +
|
||||
constants.PGPMessageHeader + "-----"); re.MatchString(data) {
|
||||
|
||||
var signed SignedString
|
||||
signed, err = kr.DecryptMessage(data)
|
||||
decrypted = signed.String
|
||||
} else {
|
||||
decrypted = data
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Unlock tries to unlock as many keys as possible with the following password. Note
|
||||
// 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.
|
||||
func (kr *KeyRing) Unlock(passphrase []byte) error {
|
||||
func (keyRing *KeyRing) Unlock(passphrase []byte) error {
|
||||
// Build a list of keys to decrypt
|
||||
var keys []*packet.PrivateKey
|
||||
for _, e := range kr.entities {
|
||||
for _, e := range keyRing.entities {
|
||||
// Entity.PrivateKey must be a signing key
|
||||
if e.PrivateKey != nil {
|
||||
keys = append(keys, e.PrivateKey)
|
||||
|
|
@ -352,48 +122,19 @@ func (kr *KeyRing) Unlock(passphrase []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Decrypt decrypts a message sent to the keypair's owner. If the message is not
|
||||
// signed, signed will be nil.
|
||||
// If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors),
|
||||
// contents are still provided if library clients wish to process this message further.
|
||||
func (kr *KeyRing) Decrypt(r io.Reader) (decrypted io.Reader, signed *Signature, err error) {
|
||||
md, err := openpgp.ReadMessage(r, kr.entities, nil, nil)
|
||||
if err != nil && err != pgperrors.ErrSignatureExpired {
|
||||
return
|
||||
}
|
||||
|
||||
decrypted = md.UnverifiedBody
|
||||
if md.IsSigned {
|
||||
signed = &Signature{md}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DecryptArmored decrypts an armored message sent to the keypair's owner.
|
||||
// If error is errors.ErrSignatureExpired (from golang.org/x/crypto/openpgp/errors),
|
||||
// contents are still provided if library clients wish to process this message further.
|
||||
func (kr *KeyRing) DecryptArmored(r io.Reader) (decrypted io.Reader, signed *Signature, err error) {
|
||||
block, err := armor.Decode(r)
|
||||
if err != nil && err != pgperrors.ErrSignatureExpired {
|
||||
return
|
||||
}
|
||||
|
||||
if block.Type != constants.PGPMessageHeader {
|
||||
err = errors.New("gopenpgp: not an armored PGP message")
|
||||
return
|
||||
}
|
||||
|
||||
return kr.Decrypt(block.Body)
|
||||
// UnlockWithPassphrase is a wrapper for Unlock that uses strings
|
||||
func (keyRing *KeyRing) UnlockWithPassphrase(passphrase string) error {
|
||||
return keyRing.Unlock([]byte(passphrase))
|
||||
}
|
||||
|
||||
// WriteArmoredPublicKey outputs armored public keys from the keyring to w.
|
||||
func (kr *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) {
|
||||
func (keyRing *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) {
|
||||
aw, err := armor.Encode(w, openpgp.PublicKeyType, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, e := range kr.entities {
|
||||
for _, e := range keyRing.entities {
|
||||
if err = e.Serialize(aw); err != nil {
|
||||
aw.Close()
|
||||
return
|
||||
|
|
@ -405,9 +146,9 @@ func (kr *KeyRing) WriteArmoredPublicKey(w io.Writer) (err error) {
|
|||
}
|
||||
|
||||
// GetArmoredPublicKey returns the armored public keys from this keyring.
|
||||
func (kr *KeyRing) GetArmoredPublicKey() (s string, err error) {
|
||||
func (keyRing *KeyRing) GetArmoredPublicKey() (s string, err error) {
|
||||
b := &bytes.Buffer{}
|
||||
if err = kr.WriteArmoredPublicKey(b); err != nil {
|
||||
if err = keyRing.WriteArmoredPublicKey(b); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -416,8 +157,8 @@ func (kr *KeyRing) GetArmoredPublicKey() (s string, err error) {
|
|||
}
|
||||
|
||||
// WritePublicKey outputs unarmored public keys from the keyring to w.
|
||||
func (kr *KeyRing) WritePublicKey(w io.Writer) (err error) {
|
||||
for _, e := range kr.entities {
|
||||
func (keyRing *KeyRing) WritePublicKey(w io.Writer) (err error) {
|
||||
for _, e := range keyRing.entities {
|
||||
if err = e.Serialize(w); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
@ -427,9 +168,9 @@ func (kr *KeyRing) WritePublicKey(w io.Writer) (err error) {
|
|||
}
|
||||
|
||||
// GetPublicKey returns the unarmored public keys from this keyring.
|
||||
func (kr *KeyRing) GetPublicKey() (b []byte, err error) {
|
||||
func (keyRing *KeyRing) GetPublicKey() (b []byte, err error) {
|
||||
var outBuf bytes.Buffer
|
||||
if err = kr.WritePublicKey(&outBuf); err != nil {
|
||||
if err = keyRing.WritePublicKey(&outBuf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -438,8 +179,8 @@ func (kr *KeyRing) GetPublicKey() (b []byte, err error) {
|
|||
}
|
||||
|
||||
// GetFingerprint gets the fingerprint from the keyring.
|
||||
func (kr *KeyRing) GetFingerprint() (string, error) {
|
||||
for _, entity := range kr.entities {
|
||||
func (keyRing *KeyRing) GetFingerprint() (string, error) {
|
||||
for _, entity := range keyRing.entities {
|
||||
fp := entity.PrimaryKey.Fingerprint
|
||||
return hex.EncodeToString(fp[:]), nil
|
||||
}
|
||||
|
|
@ -447,10 +188,10 @@ func (kr *KeyRing) GetFingerprint() (string, error) {
|
|||
}
|
||||
|
||||
// CheckPassphrase checks if private key passphrase is correct for every sub key.
|
||||
func (kr *KeyRing) CheckPassphrase(passphrase string) bool {
|
||||
func (keyRing *KeyRing) CheckPassphrase(passphrase string) bool {
|
||||
var keys []*packet.PrivateKey
|
||||
|
||||
for _, entity := range kr.entities {
|
||||
for _, entity := range keyRing.entities {
|
||||
keys = append(keys, entity.PrivateKey)
|
||||
}
|
||||
var decryptError error
|
||||
|
|
@ -468,7 +209,7 @@ func (kr *KeyRing) CheckPassphrase(passphrase string) bool {
|
|||
}
|
||||
|
||||
// readFrom reads unarmored and armored keys from r and adds them to the keyring.
|
||||
func (kr *KeyRing) readFrom(r io.Reader, armored bool) error {
|
||||
func (keyRing *KeyRing) readFrom(r io.Reader, armored bool) error {
|
||||
var err error
|
||||
var entities openpgp.EntityList
|
||||
if armored {
|
||||
|
|
@ -515,27 +256,27 @@ func (kr *KeyRing) readFrom(r io.Reader, armored bool) error {
|
|||
return errors.New("gopenpgp: key ring doesn't contain any key")
|
||||
}
|
||||
|
||||
kr.entities = append(kr.entities, entities...)
|
||||
keyRing.entities = append(keyRing.entities, entities...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildKeyRing reads keyring from binary data
|
||||
func (pgp *GopenPGP) BuildKeyRing(binKeys []byte) (kr *KeyRing, err error) {
|
||||
kr = &KeyRing{}
|
||||
func (pgp *GopenPGP) BuildKeyRing(binKeys []byte) (keyRing *KeyRing, err error) {
|
||||
keyRing = &KeyRing{}
|
||||
entriesReader := bytes.NewReader(binKeys)
|
||||
err = kr.readFrom(entriesReader, false)
|
||||
err = keyRing.readFrom(entriesReader, false)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// BuildKeyRingNoError does not return error on fail
|
||||
func (pgp *GopenPGP) BuildKeyRingNoError(binKeys []byte) (kr *KeyRing) {
|
||||
kr, _ = pgp.BuildKeyRing(binKeys)
|
||||
func (pgp *GopenPGP) BuildKeyRingNoError(binKeys []byte) (keyRing *KeyRing) {
|
||||
keyRing, _ = pgp.BuildKeyRing(binKeys)
|
||||
return
|
||||
}
|
||||
|
||||
// BuildKeyRingArmored reads armored string and returns keyring
|
||||
func (pgp *GopenPGP) BuildKeyRingArmored(key string) (kr *KeyRing, err error) {
|
||||
func (pgp *GopenPGP) BuildKeyRingArmored(key string) (keyRing *KeyRing, err error) {
|
||||
keyRaw, err := armorUtils.Unarmor(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -545,36 +286,98 @@ func (pgp *GopenPGP) BuildKeyRingArmored(key string) (kr *KeyRing, err error) {
|
|||
return &KeyRing{entities: keyEntries}, err
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements encoding/json.Unmarshaler.
|
||||
func (kr *KeyRing) UnmarshalJSON(b []byte) (err error) {
|
||||
kr.entities = nil
|
||||
|
||||
keyObjs := []pgpKeyObject{}
|
||||
if err = json.Unmarshal(b, &keyObjs); err != nil {
|
||||
return
|
||||
// ReadFromJSON reads multiple keys from a json array and fills the keyring
|
||||
func (keyRing *KeyRing) ReadFromJSON(jsonData []byte) (err error) {
|
||||
keyObjs, err := unmarshalJSON(jsonData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(keyObjs) == 0 {
|
||||
return
|
||||
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)
|
||||
newKeyRing = &KeyRing{}
|
||||
err = newKeyRing.newKeyRingFromPGPKeyObject(keyObjs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
token, _, err := keyRing.Decrypt(message, nil, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ver, err := keyRing.VerifyDetached(token, signature, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !ver.IsValid() {
|
||||
return nil, errors.New("gopenpgp: unable to verify token")
|
||||
}
|
||||
|
||||
err = newKeyRing.Unlock(token.GetBinary())
|
||||
if err != nil {
|
||||
return nil, errors.New("gopenpgp: wrong token")
|
||||
}
|
||||
}
|
||||
|
||||
return newKeyRing, nil
|
||||
}
|
||||
|
||||
// newKeyRingFromPGPKeyObject fills a KeyRing given an array of pgpKeyObject
|
||||
func (keyRing *KeyRing) newKeyRingFromPGPKeyObject(keyObjs []pgpKeyObject) error {
|
||||
keyRing.entities = nil
|
||||
for i, ko := range keyObjs {
|
||||
if i == 0 {
|
||||
kr.FirstKeyID = ko.ID
|
||||
keyRing.FirstKeyID = ko.ID
|
||||
}
|
||||
err = kr.readFrom(ko.PrivateKeyReader(), true)
|
||||
err := keyRing.readFrom(ko.PrivateKeyReader(), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshalJSON implements encoding/json.Unmarshaler.
|
||||
func unmarshalJSON(jsonData []byte) ([]pgpKeyObject, error) {
|
||||
keyObjs := []pgpKeyObject{}
|
||||
if err := json.Unmarshal(jsonData, &keyObjs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(keyObjs) == 0 {
|
||||
return nil, errors.New("gopenpgp: no key found")
|
||||
}
|
||||
|
||||
return keyObjs, nil
|
||||
}
|
||||
|
||||
// Identities returns the list of identities associated with this key ring.
|
||||
func (kr *KeyRing) Identities() []*Identity {
|
||||
func (keyRing *KeyRing) Identities() []*Identity {
|
||||
var identities []*Identity
|
||||
for _, e := range kr.entities {
|
||||
for _, e := range keyRing.entities {
|
||||
for _, id := range e.Identities {
|
||||
identities = append(identities, &Identity{
|
||||
Name: id.UserId.Name,
|
||||
|
|
@ -586,25 +389,25 @@ func (kr *KeyRing) Identities() []*Identity {
|
|||
}
|
||||
|
||||
// KeyIds returns array of IDs of keys in this KeyRing.
|
||||
func (kr *KeyRing) KeyIds() []uint64 {
|
||||
func (keyRing *KeyRing) KeyIds() []uint64 {
|
||||
var res []uint64
|
||||
for _, e := range kr.entities {
|
||||
for _, e := range keyRing.entities {
|
||||
res = append(res, e.PrimaryKey.KeyId)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// ReadArmoredKeyRing reads an armored data into keyring.
|
||||
func ReadArmoredKeyRing(r io.Reader) (kr *KeyRing, err error) {
|
||||
kr = &KeyRing{}
|
||||
err = kr.readFrom(r, true)
|
||||
func ReadArmoredKeyRing(r io.Reader) (keyRing *KeyRing, err error) {
|
||||
keyRing = &KeyRing{}
|
||||
err = keyRing.readFrom(r, true)
|
||||
return
|
||||
}
|
||||
|
||||
// ReadKeyRing reads an binary data into keyring.
|
||||
func ReadKeyRing(r io.Reader) (kr *KeyRing, err error) {
|
||||
kr = &KeyRing{}
|
||||
err = kr.readFrom(r, false)
|
||||
func ReadKeyRing(r io.Reader) (keyRing *KeyRing, err error) {
|
||||
keyRing = &KeyRing{}
|
||||
err = keyRing.readFrom(r, false)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -643,7 +446,7 @@ func FilterExpiredKeys(contactKeys []*KeyRing) (filteredKeys []*KeyRing, err err
|
|||
}
|
||||
|
||||
if len(filteredKeys) == 0 && hasExpiredEntity {
|
||||
return filteredKeys, errors.New("all contacts keys are expired")
|
||||
return filteredKeys, errors.New("gopenpgp: all contacts keys are expired")
|
||||
}
|
||||
|
||||
return filteredKeys, nil
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue