diff options
Diffstat (limited to 'vendor/github.com/keybase/go-crypto/openpgp/keys.go')
-rw-r--r-- | vendor/github.com/keybase/go-crypto/openpgp/keys.go | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/vendor/github.com/keybase/go-crypto/openpgp/keys.go b/vendor/github.com/keybase/go-crypto/openpgp/keys.go new file mode 100644 index 0000000000..e1a458879c --- /dev/null +++ b/vendor/github.com/keybase/go-crypto/openpgp/keys.go @@ -0,0 +1,902 @@ +// 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 +} |