92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
|
package protonmail
|
||
|
|
||
|
import (
|
||
|
"time"
|
||
|
|
||
|
"golang.org/x/crypto/openpgp"
|
||
|
)
|
||
|
|
||
|
// primaryIdentity returns the Identity marked as primary or the first identity
|
||
|
// if none are so marked.
|
||
|
func primaryIdentity(e *openpgp.Entity) *openpgp.Identity {
|
||
|
var firstIdentity *openpgp.Identity
|
||
|
for _, ident := range e.Identities {
|
||
|
if firstIdentity == nil {
|
||
|
firstIdentity = ident
|
||
|
}
|
||
|
if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
|
||
|
return ident
|
||
|
}
|
||
|
}
|
||
|
return firstIdentity
|
||
|
}
|
||
|
|
||
|
// encryptionKey returns the best candidate Key for encrypting a message to the
|
||
|
// given Entity.
|
||
|
func encryptionKey(e *openpgp.Entity, now time.Time) (openpgp.Key, bool) {
|
||
|
candidateSubkey := -1
|
||
|
|
||
|
// Iterate the keys to find the newest key
|
||
|
var maxTime time.Time
|
||
|
for i, subkey := range e.Subkeys {
|
||
|
if subkey.Sig.FlagsValid &&
|
||
|
subkey.Sig.FlagEncryptCommunications &&
|
||
|
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
|
||
|
!subkey.Sig.KeyExpired(now) &&
|
||
|
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
|
||
|
candidateSubkey = i
|
||
|
maxTime = subkey.Sig.CreationTime
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if candidateSubkey != -1 {
|
||
|
subkey := e.Subkeys[candidateSubkey]
|
||
|
return openpgp.Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
|
||
|
}
|
||
|
|
||
|
// If we don't have any candidate subkeys for encryption and
|
||
|
// the primary key doesn't have any usage metadata then we
|
||
|
// assume that the primary key is ok. Or, if the primary key is
|
||
|
// marked as ok to encrypt to, then we can obviously use it.
|
||
|
i := primaryIdentity(e)
|
||
|
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications &&
|
||
|
e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
|
||
|
!i.SelfSignature.KeyExpired(now) {
|
||
|
return openpgp.Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
|
||
|
}
|
||
|
|
||
|
// This Entity appears to be signing only.
|
||
|
return openpgp.Key{}, false
|
||
|
}
|
||
|
|
||
|
// signingKey return the best candidate Key for signing a message with this
|
||
|
// Entity.
|
||
|
func signingKey(e *openpgp.Entity, now time.Time) (openpgp.Key, bool) {
|
||
|
candidateSubkey := -1
|
||
|
|
||
|
for i, subkey := range e.Subkeys {
|
||
|
if subkey.Sig.FlagsValid &&
|
||
|
subkey.Sig.FlagSign &&
|
||
|
subkey.PublicKey.PubKeyAlgo.CanSign() &&
|
||
|
!subkey.Sig.KeyExpired(now) {
|
||
|
candidateSubkey = i
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if candidateSubkey != -1 {
|
||
|
subkey := e.Subkeys[candidateSubkey]
|
||
|
return openpgp.Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig}, true
|
||
|
}
|
||
|
|
||
|
// If we have no candidate subkey then we assume that it's ok to sign
|
||
|
// with the primary key.
|
||
|
i := primaryIdentity(e)
|
||
|
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign &&
|
||
|
!i.SelfSignature.KeyExpired(now) {
|
||
|
return openpgp.Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
|
||
|
}
|
||
|
|
||
|
return openpgp.Key{}, false
|
||
|
}
|