summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/openpgp/keys.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/openpgp/keys.go')
-rw-r--r--src/pkg/crypto/openpgp/keys.go280
1 files changed, 280 insertions, 0 deletions
diff --git a/src/pkg/crypto/openpgp/keys.go b/src/pkg/crypto/openpgp/keys.go
new file mode 100644
index 000000000..ecaa86f28
--- /dev/null
+++ b/src/pkg/crypto/openpgp/keys.go
@@ -0,0 +1,280 @@
+// 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/openpgp/error"
+ "crypto/openpgp/packet"
+ "io"
+ "os"
+)
+
+// PublicKeyType is the armor type for a PGP public key.
+var PublicKeyType = "PGP PUBLIC 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
+ 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
+ // DecryptionKeys returns all private keys that are valid for
+ // decryption.
+ DecryptionKeys() []Key
+}
+
+// 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
+}
+
+// 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, os.Error) {
+ body, err := readArmored(r, PublicKeyType)
+ if err != nil {
+ return nil, err
+ }
+
+ return ReadKeyRing(body)
+}
+
+// ReadKeyRing reads one or more public/private keys, ignoring unsupported keys.
+func ReadKeyRing(r io.Reader) (el EntityList, err os.Error) {
+ packets := packet.NewReader(r)
+
+ for {
+ var e *Entity
+ e, err = readEntity(packets)
+ if err != nil {
+ if _, ok := err.(error.UnsupportedError); ok {
+ err = readToNextPublicKey(packets)
+ }
+ if err == os.EOF {
+ err = nil
+ return
+ }
+ if err != nil {
+ el = nil
+ return
+ }
+ } else {
+ el = append(el, e)
+ }
+ }
+ 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 os.Error) {
+ var p packet.Packet
+ for {
+ p, err = packets.Next()
+ if err == os.EOF {
+ return
+ } else if err != nil {
+ if _, ok := err.(error.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, os.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, error.StructuralError("first packet was not a public/private key")
+ } else {
+ e.PrimaryKey = &e.PrivateKey.PublicKey
+ }
+ }
+
+ var current *Identity
+EachPacket:
+ for {
+ p, err := packets.Next()
+ if err == os.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
+ p, err = packets.Next()
+ if err == os.EOF {
+ err = io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ if _, ok := err.(error.UnsupportedError); ok {
+ return nil, err
+ }
+ return nil, error.StructuralError("identity self-signature invalid: " + err.String())
+ }
+ current.SelfSignature, ok = p.(*packet.Signature)
+ if !ok {
+ return nil, error.StructuralError("user ID packet not followed by self signature")
+ }
+ if current.SelfSignature.SigType != packet.SigTypePositiveCert {
+ return nil, error.StructuralError("user ID self-signature with wrong type")
+ }
+ if err = e.PrimaryKey.VerifyUserIdSignature(pkt.Id, current.SelfSignature); err != nil {
+ return nil, error.StructuralError("user ID self-signature invalid: " + err.String())
+ }
+ case *packet.Signature:
+ if current == nil {
+ return nil, error.StructuralError("signature packet found before user id packet")
+ }
+ 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, error.StructuralError("entity without any identities")
+ }
+
+ return e, nil
+}
+
+func addSubkey(e *Entity, packets *packet.Reader, pub *packet.PublicKey, priv *packet.PrivateKey) os.Error {
+ var subKey Subkey
+ subKey.PublicKey = pub
+ subKey.PrivateKey = priv
+ p, err := packets.Next()
+ if err == os.EOF {
+ return io.ErrUnexpectedEOF
+ }
+ if err != nil {
+ return error.StructuralError("subkey signature invalid: " + err.String())
+ }
+ var ok bool
+ subKey.Sig, ok = p.(*packet.Signature)
+ if !ok {
+ return error.StructuralError("subkey packet not followed by signature")
+ }
+ if subKey.Sig.SigType != packet.SigTypeSubkeyBinding {
+ return error.StructuralError("subkey signature with wrong type")
+ }
+ err = e.PrimaryKey.VerifyKeySignature(subKey.PublicKey, subKey.Sig)
+ if err != nil {
+ return error.StructuralError("subkey signature invalid: " + err.String())
+ }
+ e.Subkeys = append(e.Subkeys, subKey)
+ return nil
+}