mirror of
https://github.com/Luzifer/cloudkeys-go.git
synced 2024-11-14 17:02:43 +00:00
Knut Ahlers
a1df72edc5
commitf0db1ff1f8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:19:56 2017 +0100 Mark option as deprecated Signed-off-by: Knut Ahlers <knut@ahlers.me> commit9891df2a16
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:11:56 2017 +0100 Fix: Typo Signed-off-by: Knut Ahlers <knut@ahlers.me> commit836006de64
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 12:04:20 2017 +0100 Add new dependencies Signed-off-by: Knut Ahlers <knut@ahlers.me> commitd64fee60c8
Author: Knut Ahlers <knut@ahlers.me> Date: Sun Dec 24 11:55:52 2017 +0100 Replace insecure password hashing Prior this commit passwords were hashed with a static salt and using the SHA1 hashing function. This could lead to passwords being attackable in case someone gets access to the raw data stored inside the database. This commit introduces password hashing using bcrypt hashing function which addresses this issue. Old passwords are not automatically re-hashed as they are unknown. Replacing the old password scheme is not that easy and needs #10 to be solved. Therefore the old hashing scheme is kept for compatibility reason. Signed-off-by: Knut Ahlers <knut@ahlers.me> Signed-off-by: Knut Ahlers <knut@ahlers.me> closes #14 closes #15
636 lines
18 KiB
Go
636 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:
|
|
current = new(Identity)
|
|
current.Name = pkt.Id
|
|
current.UserId = pkt
|
|
e.Identities[pkt.Id] = current
|
|
|
|
for {
|
|
p, err = packets.Next()
|
|
if err == io.EOF {
|
|
return nil, io.ErrUnexpectedEOF
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sig, ok := p.(*packet.Signature)
|
|
if !ok {
|
|
return nil, errors.StructuralError("user ID packet not followed by self-signature")
|
|
}
|
|
|
|
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
|
|
break
|
|
}
|
|
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.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,
|
|
},
|
|
}
|
|
|
|
// 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)}
|
|
}
|
|
|
|
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
|
|
}
|
|
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. (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
|
|
}
|