123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693 |
- 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"
- )
- var PublicKeyType = "PGP PUBLIC KEY BLOCK"
- var PrivateKeyType = "PGP PRIVATE KEY BLOCK"
- type Entity struct {
- PrimaryKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- Identities map[string]*Identity
- Revocations []*packet.Signature
- Subkeys []Subkey
- }
- type Identity struct {
- Name string
- UserId *packet.UserId
- SelfSignature *packet.Signature
- Signatures []*packet.Signature
- }
- type Subkey struct {
- PublicKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- Sig *packet.Signature
- }
- type Key struct {
- Entity *Entity
- PublicKey *packet.PublicKey
- PrivateKey *packet.PrivateKey
- SelfSignature *packet.Signature
- }
- type KeyRing interface {
-
- KeysById(id uint64) []Key
-
-
-
-
- KeysByIdUsage(id uint64, requiredUsage byte) []Key
-
-
- DecryptionKeys() []Key
- }
- 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
- }
- func (e *Entity) encryptionKey(now time.Time) (Key, bool) {
- candidateSubkey := -1
-
- 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
- }
-
-
-
-
- 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
- }
-
- return Key{}, false
- }
- 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
- }
-
-
- 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
- }
- type EntityList []*Entity
- 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
- }
- 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
- }
- 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
- }
- 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)
- }
- 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 {
-
- if _, ok := err.(errors.UnsupportedError); ok {
- lastUnsupportedError = err
- err = readToNextPublicKey(packets)
- } else if _, ok := err.(errors.StructuralError); ok {
-
- 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
- }
- 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
- }
- }
- }
- 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 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:
- if err := addUserID(e, packets, pkt); err != nil {
- return nil, err
- }
- case *packet.Signature:
- if pkt.SigType == packet.SigTypeKeyRevocation {
- revocations = append(revocations, pkt)
- } else if pkt.SigType == packet.SigTypeDirectSignature {
-
-
-
- }
-
-
- 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:
-
- }
- }
- 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 {
-
- return nil, errors.StructuralError("revocation signature signed by alternate key")
- }
- }
- return e, nil
- }
- func addUserID(e *Entity, packets *packet.Reader, pkt *packet.UserId) error {
-
-
-
- identity := new(Identity)
- identity.Name = pkt.Id
- identity.UserId = pkt
- for {
- p, err := packets.Next()
- if err == io.EOF {
- break
- } else if err != nil {
- return err
- }
- sig, ok := p.(*packet.Signature)
- if !ok {
- packets.Unread(p)
- break
- }
- 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 errors.StructuralError("user ID self-signature invalid: " + err.Error())
- }
- identity.SelfSignature = sig
- e.Identities[pkt.Id] = identity
- } else {
- identity.Signatures = append(identity.Signatures, sig)
- }
- }
- return nil
- }
- func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) error {
- var subKey Subkey
- subKey.PublicKey = pub
- subKey.PrivateKey = priv
- for {
- p, err := packets.Next()
- if err == io.EOF {
- break
- } else if err != nil {
- return errors.StructuralError("subkey signature invalid: " + err.Error())
- }
- sig, ok := p.(*packet.Signature)
- if !ok {
- packets.Unread(p)
- break
- }
- if sig.SigType != packet.SigTypeSubkeyBinding && sig.SigType != packet.SigTypeSubkeyRevocation {
- return errors.StructuralError("subkey signature with wrong type")
- }
- if err := e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, sig); err != nil {
- return errors.StructuralError("subkey signature invalid: " + err.Error())
- }
- switch sig.SigType {
- case packet.SigTypeSubkeyRevocation:
- subKey.Sig = sig
- case packet.SigTypeSubkeyBinding:
- if shouldReplaceSubkeySig(subKey.Sig, sig) {
- subKey.Sig = sig
- }
- }
- }
- if subKey.Sig == nil {
- return errors.StructuralError("subkey packet not followed by signature")
- }
- e.Subkeys = append(e.Subkeys, subKey)
- return nil
- }
- func shouldReplaceSubkeySig(existingSig, potentialNewSig *packet.Signature) bool {
- if potentialNewSig == nil {
- return false
- }
- if existingSig == nil {
- return true
- }
- if existingSig.SigType == packet.SigTypeSubkeyRevocation {
- return false
- }
- return potentialNewSig.CreationTime.After(existingSig.CreationTime)
- }
- const defaultRSAKeyBits = 2048
- func NewEntity(name, comment, email string, config *packet.Config) (*Entity, error) {
- creationTime := 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(creationTime, &signingPriv.PublicKey),
- PrivateKey: packet.NewRSAPrivateKey(creationTime, signingPriv),
- Identities: make(map[string]*Identity),
- }
- isPrimaryId := true
- e.Identities[uid.Id] = &Identity{
- Name: uid.Id,
- UserId: uid,
- SelfSignature: &packet.Signature{
- CreationTime: creationTime,
- 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 config != nil && config.DefaultHash != 0 {
- e.Identities[uid.Id].SelfSignature.PreferredHash = []uint8{hashToHashId(config.DefaultHash)}
- }
-
- 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(creationTime, &encryptingPriv.PublicKey),
- PrivateKey: packet.NewRSAPrivateKey(creationTime, encryptingPriv),
- Sig: &packet.Signature{
- CreationTime: creationTime,
- 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
- }
- 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
- }
- 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
- }
- 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
- }
|