0
Fork 0
mirror of https://codeberg.org/forgejo/forgejo.git synced 2024-12-29 02:44:08 -05:00
forgejo/vendor/github.com/keybase/go-crypto/openpgp/keys.go
Antoine GIRARD 274149dd14 Switch to keybase go-crypto (for some elliptic curve key) + test (#1925)
* Switch to keybase go-crypto (for some elliptic curve key) + test

* Use assert.NoError 

and add a little more context to failing test description

* Use assert.(No)Error everywhere 🌈

and assert.Error in place of .Nil/.NotNil
2017-06-14 08:43:43 +08:00

902 lines
28 KiB
Go

// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package openpgp
import (
"crypto/hmac"
"encoding/binary"
"io"
"time"
"github.com/keybase/go-crypto/openpgp/armor"
"github.com/keybase/go-crypto/openpgp/errors"
"github.com/keybase/go-crypto/openpgp/packet"
"github.com/keybase/go-crypto/rsa"
)
// PublicKeyType is the armor type for a PGP public key.
var PublicKeyType = "PGP PUBLIC KEY BLOCK"
// PrivateKeyType is the armor type for a PGP private key.
var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
// An Entity represents the components of an OpenPGP key: a primary public key
// (which must be a signing key), one or more identities claimed by that key,
// and zero or more subkeys, which may be encryption keys.
type Entity struct {
PrimaryKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Identities map[string]*Identity // indexed by Identity.Name
Revocations []*packet.Signature
// Revocations that are signed by designated revokers. Reading keys
// will not verify these revocations, because it won't have access to
// issuers' public keys, API consumers should do this instead (or
// not, and just assume that the key is probably revoked).
UnverifiedRevocations []*packet.Signature
Subkeys []Subkey
BadSubkeys []BadSubkey
}
// An Identity represents an identity claimed by an Entity and zero or more
// assertions by other entities about that claim.
type Identity struct {
Name string // by convention, has the form "Full Name (comment) <email@example.com>"
UserId *packet.UserId
SelfSignature *packet.Signature
Signatures []*packet.Signature
Revocation *packet.Signature
}
// A Subkey is an additional public key in an Entity. Subkeys can be used for
// encryption.
type Subkey struct {
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
Sig *packet.Signature
Revocation *packet.Signature
}
// BadSubkey is one that failed reconstruction, but we'll keep it around for
// informational purposes.
type BadSubkey struct {
Subkey
Err error
}
// A Key identifies a specific public key in an Entity. This is either the
// Entity's primary key or a subkey.
type Key struct {
Entity *Entity
PublicKey *packet.PublicKey
PrivateKey *packet.PrivateKey
SelfSignature *packet.Signature
KeyFlags packet.KeyFlagBits
}
// A KeyRing provides access to public and private keys.
type KeyRing interface {
// KeysById returns the set of keys that have the given key id.
// fp can be optionally supplied, which is the full key fingerprint.
// If it's provided, then it must match. This comes up in the case
// of GPG subpacket 33.
KeysById(id uint64, fp []byte) []Key
// KeysByIdAndUsage returns the set of keys with the given id
// that also meet the key usage given by requiredUsage.
// The requiredUsage is expressed as the bitwise-OR of
// packet.KeyFlag* values.
// fp can be optionally supplied, which is the full key fingerprint.
// If it's provided, then it must match. This comes up in the case
// of GPG subpacket 33.
KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) []Key
// DecryptionKeys returns all private keys that are valid for
// decryption.
DecryptionKeys() []Key
}
// primaryIdentity returns the Identity marked as primary or the first identity
// if none are so marked.
func (e *Entity) primaryIdentity() *Identity {
var firstIdentity *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 (e *Entity) encryptionKey(now time.Time) (Key, bool) {
candidateSubkey := -1
// Iterate the keys to find the newest key
var maxTime time.Time
for i, subkey := range e.Subkeys {
// NOTE(maxtaco)
// If there is a Flags subpacket, then we have to follow it, and only
// use keys that are marked for Encryption of Communication. If there
// isn't a Flags subpacket, and this is an Encrypt-Only key (right now only ElGamal
// suffices), then we implicitly use it. The check for primary below is a little
// more open-ended, but for now, let's be strict and potentially open up
// if we see bugs in the wild.
//
// One more note: old DSA/ElGamal keys tend not to have the Flags subpacket,
// so this sort of thing is pretty important for encrypting to older keys.
//
if ((subkey.Sig.FlagsValid && subkey.Sig.FlagEncryptCommunications) ||
(!subkey.Sig.FlagsValid && subkey.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal)) &&
subkey.PublicKey.PubKeyAlgo.CanEncrypt() &&
!subkey.Sig.KeyExpired(now) &&
subkey.Revocation == nil &&
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) {
candidateSubkey = i
maxTime = subkey.Sig.CreationTime
}
}
if candidateSubkey != -1 {
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, 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.
//
// NOTE(maxtaco) - see note above, how this policy is a little too open-ended
// for my liking, but leave it for now.
i := e.primaryIdentity()
if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagEncryptCommunications) &&
e.PrimaryKey.PubKeyAlgo.CanEncrypt() &&
!i.SelfSignature.KeyExpired(now) {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true
}
// This Entity appears to be signing only.
return Key{}, false
}
// signingKey return the best candidate Key for signing a message with this
// Entity.
func (e *Entity) signingKey(now time.Time) (Key, bool) {
candidateSubkey := -1
for i, subkey := range e.Subkeys {
if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) &&
subkey.PrivateKey.PrivateKey != nil &&
subkey.PublicKey.PubKeyAlgo.CanSign() &&
subkey.Revocation == nil &&
!subkey.Sig.KeyExpired(now) {
candidateSubkey = i
break
}
}
if candidateSubkey != -1 {
subkey := e.Subkeys[candidateSubkey]
return Key{e, subkey.PublicKey, subkey.PrivateKey, subkey.Sig, subkey.Sig.GetKeyFlags()}, true
}
// If we have no candidate subkey then we assume that it's ok to sign
// with the primary key.
i := e.primaryIdentity()
if (!i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign) &&
e.PrimaryKey.PubKeyAlgo.CanSign() &&
!i.SelfSignature.KeyExpired(now) &&
e.PrivateKey.PrivateKey != nil {
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature, i.SelfSignature.GetKeyFlags()}, true
}
return Key{}, false
}
// An EntityList contains one or more Entities.
type EntityList []*Entity
func keyMatchesIdAndFingerprint(key *packet.PublicKey, id uint64, fp []byte) bool {
if key.KeyId != id {
return false
}
if fp == nil {
return true
}
return hmac.Equal(fp, key.Fingerprint[:])
}
// KeysById returns the set of keys that have the given key id.
// fp can be optionally supplied, which is the full key fingerprint.
// If it's provided, then it must match. This comes up in the case
// of GPG subpacket 33.
func (el EntityList) KeysById(id uint64, fp []byte) (keys []Key) {
for _, e := range el {
if keyMatchesIdAndFingerprint(e.PrimaryKey, id, fp) {
var selfSig *packet.Signature
for _, ident := range e.Identities {
if selfSig == nil {
selfSig = ident.SelfSignature
} else if ident.SelfSignature.IsPrimaryId != nil && *ident.SelfSignature.IsPrimaryId {
selfSig = ident.SelfSignature
break
}
}
var keyFlags packet.KeyFlagBits
for _, ident := range e.Identities {
keyFlags.Merge(ident.SelfSignature.GetKeyFlags())
}
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig, keyFlags})
}
for _, subKey := range e.Subkeys {
if keyMatchesIdAndFingerprint(subKey.PublicKey, id, fp) {
// If there's both a a revocation and a sig, then take the
// revocation. Otherwise, we can proceed with the sig.
sig := subKey.Revocation
if sig == nil {
sig = subKey.Sig
}
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, sig, sig.GetKeyFlags()})
}
}
}
return
}
// KeysByIdAndUsage returns the set of keys with the given id that also meet
// the key usage given by requiredUsage. The requiredUsage is expressed as
// the bitwise-OR of packet.KeyFlag* values.
// fp can be optionally supplied, which is the full key fingerprint.
// If it's provided, then it must match. This comes up in the case
// of GPG subpacket 33.
func (el EntityList) KeysByIdUsage(id uint64, fp []byte, requiredUsage byte) (keys []Key) {
for _, key := range el.KeysById(id, fp) {
if len(key.Entity.Revocations) > 0 {
continue
}
if key.SelfSignature.RevocationReason != nil {
continue
}
if requiredUsage != 0 {
var usage byte
switch {
case key.KeyFlags.Valid:
usage = key.KeyFlags.BitField
case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoElGamal:
// We also need to handle the case where, although the sig's
// flags aren't valid, the key can is implicitly usable for
// encryption by virtue of being ElGamal. See also the comment
// in encryptionKey() above.
usage |= packet.KeyFlagEncryptCommunications
usage |= packet.KeyFlagEncryptStorage
case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoDSA ||
key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoECDSA ||
key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoEdDSA:
usage |= packet.KeyFlagSign
// For a primary RSA key without any key flags, be as permissiable
// as possible.
case key.PublicKey.PubKeyAlgo == packet.PubKeyAlgoRSA &&
keyMatchesIdAndFingerprint(key.Entity.PrimaryKey, id, fp):
usage = (packet.KeyFlagCertify | packet.KeyFlagSign |
packet.KeyFlagEncryptCommunications | packet.KeyFlagEncryptStorage)
}
if usage&requiredUsage != requiredUsage {
continue
}
}
keys = append(keys, key)
}
return
}
// DecryptionKeys returns all private keys that are valid for decryption.
func (el EntityList) DecryptionKeys() (keys []Key) {
for _, e := range el {
for _, subKey := range e.Subkeys {
if subKey.PrivateKey != nil && subKey.PrivateKey.PrivateKey != nil && (!subKey.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig, subKey.Sig.GetKeyFlags()})
}
}
}
return
}
// ReadArmoredKeyRing reads one or more public/private keys from an armor keyring file.
func ReadArmoredKeyRing(r io.Reader) (EntityList, error) {
block, err := armor.Decode(r)
if err == io.EOF {
return nil, errors.InvalidArgumentError("no armored data found")
}
if err != nil {
return nil, err
}
if block.Type != PublicKeyType && block.Type != PrivateKeyType {
return nil, errors.InvalidArgumentError("expected public or private key block, got: " + block.Type)
}
return ReadKeyRing(block.Body)
}
// ReadKeyRing reads one or more public/private keys. Unsupported keys are
// ignored as long as at least a single valid key is found.
func ReadKeyRing(r io.Reader) (el EntityList, err error) {
packets := packet.NewReader(r)
var lastUnsupportedError error
for {
var e *Entity
e, err = ReadEntity(packets)
if err != nil {
// TODO: warn about skipped unsupported/unreadable keys
if _, ok := err.(errors.UnsupportedError); ok {
lastUnsupportedError = err
err = readToNextPublicKey(packets)
} else if _, ok := err.(errors.StructuralError); ok {
// Skip unreadable, badly-formatted keys
lastUnsupportedError = err
err = readToNextPublicKey(packets)
}
if err == io.EOF {
err = nil
break
}
if err != nil {
el = nil
break
}
} else {
el = append(el, e)
}
}
if len(el) == 0 && err == nil {
err = lastUnsupportedError
}
return
}
// readToNextPublicKey reads packets until the start of the entity and leaves
// the first packet of the new entity in the Reader.
func readToNextPublicKey(packets *packet.Reader) (err error) {
var p packet.Packet
for {
p, err = packets.Next()
if err == io.EOF {
return
} else if err != nil {
if _, ok := err.(errors.UnsupportedError); ok {
err = nil
continue
}
return
}
if pk, ok := p.(*packet.PublicKey); ok && !pk.IsSubkey {
packets.Unread(p)
return
}
}
panic("unreachable")
}
// ReadEntity reads an entity (public key, identities, subkeys etc) from the
// given Reader.
func ReadEntity(packets *packet.Reader) (*Entity, error) {
e := new(Entity)
e.Identities = make(map[string]*Identity)
p, err := packets.Next()
if err != nil {
return nil, err
}
var ok bool
if e.PrimaryKey, ok = p.(*packet.PublicKey); !ok {
if e.PrivateKey, ok = p.(*packet.PrivateKey); !ok {
packets.Unread(p)
return nil, errors.StructuralError("first packet was not a public/private key")
} else {
e.PrimaryKey = &e.PrivateKey.PublicKey
}
}
if !e.PrimaryKey.PubKeyAlgo.CanSign() {
return nil, errors.StructuralError("primary key cannot be used for signatures")
}
var current *Identity
var revocations []*packet.Signature
designatedRevokers := make(map[uint64]bool)
EachPacket:
for {
p, err := packets.Next()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}
switch pkt := p.(type) {
case *packet.UserId:
// Make a new Identity object, that we might wind up throwing away.
// We'll only add it if we get a valid self-signature over this
// userID.
current = new(Identity)
current.Name = pkt.Id
current.UserId = pkt
case *packet.Signature:
if pkt.SigType == packet.SigTypeKeyRevocation {
// These revocations won't revoke UIDs (see
// SigTypeIdentityRevocation). Handle these first,
// because key might have revocation coming from
// another key (designated revoke).
revocations = append(revocations, pkt)
continue
}
// These are signatures by other people on this key. Let's just ignore them
// from the beginning, since they shouldn't affect our key decoding one way
// or the other.
if pkt.IssuerKeyId != nil && *pkt.IssuerKeyId != e.PrimaryKey.KeyId {
continue
}
// If this is a signature made by the keyholder, and the signature has stubbed out
// critical packets, then *now* we need to bail out.
if e := pkt.StubbedOutCriticalError; e != nil {
return nil, e
}
// Next handle the case of a self-signature. According to RFC8440,
// Section 5.2.3.3, if there are several self-signatures,
// we should take the newer one. If they were both created
// at the same time, but one of them has keyflags specified and the
// other doesn't, keep the one with the keyflags. We have actually
// seen this in the wild (see the 'Yield' test in read_test.go).
// If there is a tie, and both have the same value for FlagsValid,
// then "last writer wins."
//
// HOWEVER! We have seen yet more keys in the wild (see the 'Spiros'
// test in read_test.go), in which the later self-signature is a bunch
// of junk, and doesn't even specify key flags. Does it really make
// sense to overwrite reasonable key flags with the empty set? I'm not
// sure what that would be trying to achieve, and plus GPG seems to be
// ok with this situation, and ignores the later (empty) keyflag set.
// So further tighten our overwrite rules, and only allow the later
// signature to overwrite the earlier signature if so doing won't
// trash the key flags.
if current != nil &&
(current.SelfSignature == nil ||
(!pkt.CreationTime.Before(current.SelfSignature.CreationTime) &&
(pkt.FlagsValid || !current.SelfSignature.FlagsValid))) &&
(pkt.SigType == packet.SigTypePositiveCert || pkt.SigType == packet.SigTypeGenericCert) &&
pkt.IssuerKeyId != nil &&
*pkt.IssuerKeyId == e.PrimaryKey.KeyId {
if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil {
current.SelfSignature = pkt
// NOTE(maxtaco) 2016.01.11
// Only register an identity once we've gotten a valid self-signature.
// It's possible therefore for us to throw away `current` in the case
// no valid self-signatures were found. That's OK as long as there are
// other identies that make sense.
//
// NOTE! We might later see a revocation for this very same UID, and it
// won't be undone. We've preserved this feature from the original
// Google OpenPGP we forked from.
e.Identities[current.Name] = current
} else {
// We really should warn that there was a failure here. Not raise an error
// since this really shouldn't be a fail-stop error.
}
} else if current != nil && pkt.SigType == packet.SigTypeIdentityRevocation {
if err = e.PrimaryKey.VerifyUserIdSignature(current.Name, e.PrimaryKey, pkt); err == nil {
// Note: we are not removing the identity from
// e.Identities. Caller can always filter by Revocation
// field to ignore revoked identities.
current.Revocation = pkt
}
} else if pkt.SigType == packet.SigTypeDirectSignature {
if err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, pkt); err == nil {
if desig := pkt.DesignatedRevoker; desig != nil {
// If it's a designated revoker signature, take last 8 octects
// of fingerprint as Key ID and save it to designatedRevokers
// map. We consult this map later to see if a foreign
// revocation should be added to UnverifiedRevocations.
keyID := binary.BigEndian.Uint64(desig.Fingerprint[len(desig.Fingerprint)-8:])
designatedRevokers[keyID] = true
}
}
} else if current == nil {
// NOTE(maxtaco)
//
// See https://github.com/keybase/client/issues/2666
//
// There might have been a user attribute picture before this signature,
// in which case this is still a valid PGP key. In the future we might
// not ignore user attributes (like picture). But either way, it doesn't
// make sense to bail out here. Keep looking for other valid signatures.
//
// Used to be:
// return nil, errors.StructuralError("signature packet found before user id packet")
} else {
current.Signatures = append(current.Signatures, pkt)
}
case *packet.PrivateKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, &pkt.PublicKey, pkt)
if err != nil {
return nil, err
}
case *packet.PublicKey:
if pkt.IsSubkey == false {
packets.Unread(p)
break EachPacket
}
err = addSubkey(e, packets, pkt, nil)
if err != nil {
return nil, err
}
default:
// we ignore unknown packets
}
}
if len(e.Identities) == 0 {
return nil, errors.StructuralError("entity without any identities")
}
for _, revocation := range revocations {
if revocation.IssuerKeyId == nil || *revocation.IssuerKeyId == e.PrimaryKey.KeyId {
// Key revokes itself, something that we can verify.
err = e.PrimaryKey.VerifyRevocationSignature(e.PrimaryKey, revocation)
if err == nil {
e.Revocations = append(e.Revocations, revocation)
} else {
return nil, errors.StructuralError("revocation signature signed by alternate key")
}
} else if revocation.IssuerKeyId != nil {
if _, ok := designatedRevokers[*revocation.IssuerKeyId]; ok {
// Revocation is done by certified designated revoker,
// but we can't verify the revocation.
e.UnverifiedRevocations = append(e.UnverifiedRevocations, revocation)
}
}
}
return e, nil
}
func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
var subKey Subkey
subKey.PublicKey = pub
subKey.PrivateKey = priv
var lastErr error
for {
p, err := packets.Next()
if err == io.EOF {
break
}
if err != nil {
return errors.StructuralError("subkey signature invalid: " + err.Error())
}
sig, ok := p.(*packet.Signature)
if !ok {
// Hit a non-signature packet, so assume we're up to the next key
packets.Unread(p)
break
}
if st := sig.SigType; st != packet.SigTypeSubkeyBinding && st != packet.SigTypeSubkeyRevocation {
// Note(maxtaco):
// We used to error out here, but instead, let's fast-forward past
// packets that are in the wrong place (like misplaced 0x13 signatures)
// until we get to one that works. For a test case,
// see TestWithBadSubkeySignaturePackets.
continue
}
err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig)
if err != nil {
// Non valid signature, so again, no need to abandon all hope, just continue;
// make a note of the error we hit.
lastErr = errors.StructuralError("subkey signature invalid: " + err.Error())
continue
}
switch sig.SigType {
case packet.SigTypeSubkeyBinding:
// Does the "new" sig set expiration to later date than
// "previous" sig?
if subKey.Sig == nil || subKey.Sig.ExpiresBeforeOther(sig) {
subKey.Sig = sig
}
case packet.SigTypeSubkeyRevocation:
// First writer wins
if subKey.Revocation == nil {
subKey.Revocation = sig
}
}
}
if subKey.Sig != nil {
e.Subkeys = append(e.Subkeys, subKey)
} else {
if lastErr == nil {
lastErr = errors.StructuralError("Subkey wasn't signed; expected a 'binding' signature")
}
e.BadSubkeys = append(e.BadSubkeys, BadSubkey{Subkey: subKey, Err: lastErr})
}
return nil
}
const defaultRSAKeyBits = 2048
// NewEntity returns an Entity that contains a fresh RSA/RSA keypair with a
// single identity composed of the given full name, comment and email, any of
// which may be empty but must not contain any of "()<>\x00".
// If config is nil, sensible defaults will be used.
func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
currentTime := config.Now()
bits := defaultRSAKeyBits
if config != nil && config.RSABits != 0 {
bits = config.RSABits
}
uid := packet.NewUserId(name, comment, email)
if uid == nil {
return nil, errors.InvalidArgumentError("user id field contained invalid characters")
}
signingPriv, err := rsa.GenerateKey(config.Random(), bits)
if err != nil {
return nil, err
}
encryptingPriv, err := rsa.GenerateKey(config.Random(), bits)
if err != nil {
return nil, err
}
e := &Entity{
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
Identities: make(map[string]*Identity),
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
Name: uid.Name,
UserId: uid,
SelfSignature: &packet.Signature{
CreationTime: currentTime,
SigType: packet.SigTypePositiveCert,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),
IsPrimaryId: &isPrimaryId,
FlagsValid: true,
FlagSign: true,
FlagCertify: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
e.Subkeys = make([]Subkey, 1)
e.Subkeys[0] = Subkey{
PublicKey: packet.NewRSAPublicKey(currentTime, &encryptingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, encryptingPriv),
Sig: &packet.Signature{
CreationTime: currentTime,
SigType: packet.SigTypeSubkeyBinding,
PubKeyAlgo: packet.PubKeyAlgoRSA,
Hash: config.Hash(),
FlagsValid: true,
FlagEncryptStorage: true,
FlagEncryptCommunications: true,
IssuerKeyId: &e.PrimaryKey.KeyId,
},
}
e.Subkeys[0].PublicKey.IsSubkey = true
e.Subkeys[0].PrivateKey.IsSubkey = true
return e, nil
}
// SerializePrivate serializes an Entity, including private key material, to
// the given Writer. For now, it must only be used on an Entity returned from
// NewEntity.
// If config is nil, sensible defaults will be used.
func (e *Entity) SerializePrivate(w io.Writer, config *packet.Config) (err error) {
err = e.PrivateKey.Serialize(w)
if err != nil {
return
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return
}
if e.PrivateKey.PrivateKey != nil {
err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, config)
if err != nil {
return
}
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return
}
}
for _, subkey := range e.Subkeys {
err = subkey.PrivateKey.Serialize(w)
if err != nil {
return
}
// Workaround shortcoming of SignKey(), which doesn't work to reverse-sign
// sub-signing keys. So if requested, just reuse the signatures already
// available to us (if we read this key from a keyring).
if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() {
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
if err != nil {
return
}
}
if subkey.Revocation != nil {
err = subkey.Revocation.Serialize(w)
if err != nil {
return
}
}
err = subkey.Sig.Serialize(w)
if err != nil {
return
}
}
return nil
}
// Serialize writes the public part of the given Entity to w. (No private
// key material will be output).
func (e *Entity) Serialize(w io.Writer) error {
err := e.PrimaryKey.Serialize(w)
if err != nil {
return err
}
for _, ident := range e.Identities {
err = ident.UserId.Serialize(w)
if err != nil {
return err
}
err = ident.SelfSignature.Serialize(w)
if err != nil {
return err
}
for _, sig := range ident.Signatures {
err = sig.Serialize(w)
if err != nil {
return err
}
}
}
for _, subkey := range e.Subkeys {
err = subkey.PublicKey.Serialize(w)
if err != nil {
return err
}
if subkey.Revocation != nil {
err = subkey.Revocation.Serialize(w)
if err != nil {
return err
}
}
err = subkey.Sig.Serialize(w)
if err != nil {
return err
}
}
return nil
}
// SignIdentity adds a signature to e, from signer, attesting that identity is
// associated with e. The provided identity must already be an element of
// e.Identities and the private key of signer must have been decrypted if
// necessary.
// If config is nil, sensible defaults will be used.
func (e *Entity) SignIdentity(identity string, signer *Entity, config *packet.Config) error {
if signer.PrivateKey == nil {
return errors.InvalidArgumentError("signing Entity must have a private key")
}
if signer.PrivateKey.Encrypted {
return errors.InvalidArgumentError("signing Entity's private key must be decrypted")
}
ident, ok := e.Identities[identity]
if !ok {
return errors.InvalidArgumentError("given identity string not found in Entity")
}
sig := &packet.Signature{
SigType: packet.SigTypeGenericCert,
PubKeyAlgo: signer.PrivateKey.PubKeyAlgo,
Hash: config.Hash(),
CreationTime: config.Now(),
IssuerKeyId: &signer.PrivateKey.KeyId,
}
if err := sig.SignUserId(identity, e.PrimaryKey, signer.PrivateKey, config); err != nil {
return err
}
ident.Signatures = append(ident.Signatures, sig)
return nil
}
// CopySubkeyRevocations copies subkey revocations from the src Entity over
// to the receiver entity. We need this because `gpg --export-secret-key` does
// not appear to output subkey revocations. In this case we need to manually
// merge with the output of `gpg --export`.
func (e *Entity) CopySubkeyRevocations(src *Entity) {
m := make(map[[20]byte]*packet.Signature)
for _, subkey := range src.Subkeys {
if subkey.Revocation != nil {
m[subkey.PublicKey.Fingerprint] = subkey.Revocation
}
}
for i, subkey := range e.Subkeys {
if r := m[subkey.PublicKey.Fingerprint]; r != nil {
e.Subkeys[i].Revocation = r
}
}
}
// CheckDesignatedRevokers will try to confirm any of designated
// revocation of entity. For this function to work, revocation
// issuer's key should be found in keyring. First successfully
// verified designated revocation is returned along with the key that
// verified it.
func FindVerifiedDesignatedRevoke(keyring KeyRing, entity *Entity) (*packet.Signature, *Key) {
for _, sig := range entity.UnverifiedRevocations {
if sig.IssuerKeyId == nil {
continue
}
issuerKeyId := *sig.IssuerKeyId
issuerFingerprint := sig.IssuerFingerprint
keys := keyring.KeysByIdUsage(issuerKeyId, issuerFingerprint, packet.KeyFlagSign)
if len(keys) == 0 {
continue
}
for _, key := range keys {
err := key.PublicKey.VerifyRevocationSignature(entity.PrimaryKey, sig)
if err == nil {
return sig, &key
}
}
}
return nil, nil
}