The existing code was wrongly assuming that UserID packets must be immediately followed by a Signature packet. However, this is not true. See RFC4880 11.1: > Immediately following each User ID packet, there are zero or more > Signature packets. This change will ensure that Entities that are not immediately followed by a Signature packet are read without raising a StructuralError. Instead, UserID packets that are not immediately followed by a self signature will be ignored. Maximum backwards compatibility is retained because revoked UserIDs are not added to the Entity's identities. In a follow-up patch, we should probably add these UserIDs to the Entity's identities too, but not without making sure that the revocation is also available in the Entity's (or the Identity's) Revocations slice. This would require adding support for a new Signature Type, "Certification revocation signature", as defined in RFC 48880 5.2.1. Fixes golang/go#25850 Change-Id: Idde34b97429998f28e0c687171024e51ed959bf0 Reviewed-on: https://go-review.googlesource.com/118376 Reviewed-by: Filippo Valsorda <filippo@golang.org> Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
645 lines
18 KiB
Go
645 lines
18 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/rsa"
|
|
"io"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/openpgp/armor"
|
|
"golang.org/x/crypto/openpgp/errors"
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
)
|
|
|
|
// 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
|
|
Subkeys []Subkey
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// A KeyRing provides access to public and private keys.
|
|
type KeyRing interface {
|
|
// KeysById returns the set of keys that have the given key id.
|
|
KeysById(id uint64) []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.
|
|
KeysByIdUsage(id uint64, 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 {
|
|
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 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 := 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}, 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.PublicKey.PubKeyAlgo.CanSign() &&
|
|
!subkey.Sig.KeyExpired(now) {
|
|
candidateSubkey = i
|
|
break
|
|
}
|
|
}
|
|
|
|
if candidateSubkey != -1 {
|
|
subkey := e.Subkeys[candidateSubkey]
|
|
return 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 := e.primaryIdentity()
|
|
if !i.SelfSignature.FlagsValid || i.SelfSignature.FlagSign &&
|
|
!i.SelfSignature.KeyExpired(now) {
|
|
return Key{e, e.PrimaryKey, e.PrivateKey, i.SelfSignature}, true
|
|
}
|
|
|
|
return Key{}, false
|
|
}
|
|
|
|
// An EntityList contains one or more Entities.
|
|
type EntityList []*Entity
|
|
|
|
// KeysById returns the set of keys that have the given key id.
|
|
func (el EntityList) KeysById(id uint64) (keys []Key) {
|
|
for _, e := range el {
|
|
if e.PrimaryKey.KeyId == id {
|
|
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
|
|
}
|
|
}
|
|
keys = append(keys, Key{e, e.PrimaryKey, e.PrivateKey, selfSig})
|
|
}
|
|
|
|
for _, subKey := range e.Subkeys {
|
|
if subKey.PublicKey.KeyId == id {
|
|
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
|
|
}
|
|
}
|
|
}
|
|
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.
|
|
func (el EntityList) KeysByIdUsage(id uint64, requiredUsage byte) (keys []Key) {
|
|
for _, key := range el.KeysById(id) {
|
|
if len(key.Entity.Revocations) > 0 {
|
|
continue
|
|
}
|
|
|
|
if key.SelfSignature.RevocationReason != nil {
|
|
continue
|
|
}
|
|
|
|
if key.SelfSignature.FlagsValid && requiredUsage != 0 {
|
|
var usage byte
|
|
if key.SelfSignature.FlagCertify {
|
|
usage |= packet.KeyFlagCertify
|
|
}
|
|
if key.SelfSignature.FlagSign {
|
|
usage |= packet.KeyFlagSign
|
|
}
|
|
if key.SelfSignature.FlagEncryptCommunications {
|
|
usage |= packet.KeyFlagEncryptCommunications
|
|
}
|
|
if key.SelfSignature.FlagEncryptStorage {
|
|
usage |= 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.Sig.FlagsValid || subKey.Sig.FlagEncryptStorage || subKey.Sig.FlagEncryptCommunications) {
|
|
keys = append(keys, Key{e, subKey.PublicKey, subKey.PrivateKey, subKey.Sig})
|
|
}
|
|
}
|
|
}
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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")
|
|
}
|
|
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
|
|
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
|
|
|
|
for {
|
|
p, err = packets.Next()
|
|
if err == io.EOF {
|
|
break EachPacket
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sig, ok := p.(*packet.Signature)
|
|
if !ok {
|
|
packets.Unread(p)
|
|
continue EachPacket
|
|
}
|
|
|
|
if (sig.SigType == packet.SigTypePositiveCert || sig.SigType == packet.SigTypeGenericCert) && sig.IssuerKeyId != nil && *sig.IssuerKeyId == e.PrimaryKey.KeyId {
|
|
if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, e.PrimaryKey, sig); err != nil {
|
|
return nil, errors.StructuralError("user ID self-signature invalid: " + err.Error())
|
|
}
|
|
current.SelfSignature = sig
|
|
e.Identities[pkt.Id] = current
|
|
} else {
|
|
current.Signatures = append(current.Signatures, sig)
|
|
}
|
|
}
|
|
case *packet.Signature:
|
|
if pkt.SigType == packet.SigTypeKeyRevocation {
|
|
revocations = append(revocations, pkt)
|
|
} else if pkt.SigType == packet.SigTypeDirectSignature {
|
|
// TODO: RFC4880 5.2.1 permits signatures
|
|
// directly on keys (eg. to bind additional
|
|
// revocation keys).
|
|
} else if current == nil {
|
|
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 {
|
|
err = e.PrimaryKey.VerifyRevocationSignature(revocation)
|
|
if err == nil {
|
|
e.Revocations = append(e.Revocations, revocation)
|
|
} else {
|
|
// TODO: RFC 4880 5.2.3.15 defines revocation keys.
|
|
return nil, errors.StructuralError("revocation signature signed by alternate key")
|
|
}
|
|
}
|
|
|
|
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
|
|
p, err := packets.Next()
|
|
if err == io.EOF {
|
|
return io.ErrUnexpectedEOF
|
|
}
|
|
if err != nil {
|
|
return errors.StructuralError("subkey signature invalid: " + err.Error())
|
|
}
|
|
var ok bool
|
|
subKey.Sig, ok = p.(*packet.Signature)
|
|
if !ok {
|
|
return errors.StructuralError("subkey packet not followed by signature")
|
|
}
|
|
if subKey.Sig.SigType != packet.SigTypeSubkeyBinding && subKey.Sig.SigType != packet.SigTypeSubkeyRevocation {
|
|
return errors.StructuralError("subkey signature with wrong type")
|
|
}
|
|
err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
|
|
if err != nil {
|
|
return errors.StructuralError("subkey signature invalid: " + err.Error())
|
|
}
|
|
e.Subkeys = append(e.Subkeys, subKey)
|
|
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,
|
|
},
|
|
}
|
|
err = e.Identities[uid.Id].SelfSignature.SignUserId(uid.Id, e.PrimaryKey, e.PrivateKey, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 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
|
|
err = e.Subkeys[0].Sig.SignKey(e.Subkeys[0].PublicKey, e.PrivateKey, config)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
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.
|
|
// config is ignored
|
|
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
|
|
}
|
|
err = ident.SelfSignature.Serialize(w)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
for _, subkey := range e.Subkeys {
|
|
err = subkey.PrivateKey.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
|
|
}
|
|
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
|
|
}
|