Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
934 lines
29 KiB
934 lines
29 KiB
// 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, non-revoked key that can |
|
// encrypt. |
|
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 |
|
|
|
// Iterate the keys to find the newest, non-revoked key that can |
|
// sign. |
|
var maxTime time.Time |
|
for i, subkey := range e.Subkeys { |
|
if (!subkey.Sig.FlagsValid || subkey.Sig.FlagSign) && |
|
subkey.PrivateKey.PrivateKey != nil && |
|
subkey.PublicKey.PubKeyAlgo.CanSign() && |
|
!subkey.Sig.KeyExpired(now) && |
|
subkey.Revocation == nil && |
|
(maxTime.IsZero() || subkey.Sig.CreationTime.After(maxTime)) { |
|
candidateSubkey = i |
|
maxTime = subkey.Sig.CreationTime |
|
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 identities 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 { |
|
if err := subKey.PublicKey.ErrorIfDeprecated(); err != nil { |
|
// Key passed signature check but is deprecated. |
|
subKey.Sig = nil |
|
lastErr = err |
|
} |
|
} |
|
|
|
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.Id, |
|
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, |
|
}, |
|
} |
|
|
|
// If the user passes in a DefaultHash via packet.Config, set the |
|
// PreferredHash for the SelfSignature. |
|
if config != nil && config.DefaultHash != 0 { |
|
e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)} |
|
} |
|
|
|
// Likewise for DefaultCipher. |
|
if config != nil && config.DefaultCipher != 0 { |
|
e.Identities[uid.Id].SelfSignature.PreferredSymmetric = []uint8{uint8(config.DefaultCipher)} |
|
} |
|
|
|
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 |
|
} |
|
if e.PrivateKey.PrivateKey != nil && !config.ReuseSignatures() { |
|
// If not reusing existing signatures, sign subkey using private key |
|
// (subkey binding), but also sign primary key using subkey (primary |
|
// key binding) if subkey is used for signing. |
|
if subkey.Sig.FlagSign { |
|
err = subkey.Sig.CrossSignKey(e.PrimaryKey, subkey.PrivateKey, config) |
|
if err != nil { |
|
return err |
|
} |
|
} |
|
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 |
|
}
|
|
|