mirror of
https://github.com/octoleo/restic.git
synced 2024-11-19 19:45:18 +00:00
6e1a3987b7
This commit adds a command called `self-update` which downloads the latest released version of restic from GitHub and replacing the current binary with it. It does not rely on any external program (so it'll work everywhere), but still verifies the GPG signature using the embedded GPG public key. By default, the `self-update` command is hidden behind the `selfupdate` built tag, which is only set when restic is built using `build.go`. The reason for this is that downstream distributions will then not include the command by default, so users are encouraged to use the platform-specific distribution mechanism.
653 lines
18 KiB
Go
653 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, but
|
|
// excluding signatures from other entities, to the given Writer.
|
|
// Identities and subkeys are re-signed in case they changed since NewEntry.
|
|
// 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
|
|
}
|
|
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
|
|
}
|
|
err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, config)
|
|
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, including
|
|
// signatures from other entities. 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
|
|
}
|