OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / golang.org / x / crypto / openpgp / read.go
diff --git a/vendor/golang.org/x/crypto/openpgp/read.go b/vendor/golang.org/x/crypto/openpgp/read.go
new file mode 100644 (file)
index 0000000..6ec664f
--- /dev/null
@@ -0,0 +1,442 @@
+// 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 implements high level operations on OpenPGP messages.
+package openpgp // import "golang.org/x/crypto/openpgp"
+
+import (
+       "crypto"
+       _ "crypto/sha256"
+       "hash"
+       "io"
+       "strconv"
+
+       "golang.org/x/crypto/openpgp/armor"
+       "golang.org/x/crypto/openpgp/errors"
+       "golang.org/x/crypto/openpgp/packet"
+)
+
+// SignatureType is the armor type for a PGP signature.
+var SignatureType = "PGP SIGNATURE"
+
+// readArmored reads an armored block with the given type.
+func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
+       block, err := armor.Decode(r)
+       if err != nil {
+               return
+       }
+
+       if block.Type != expectedType {
+               return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
+       }
+
+       return block.Body, nil
+}
+
+// MessageDetails contains the result of parsing an OpenPGP encrypted and/or
+// signed message.
+type MessageDetails struct {
+       IsEncrypted              bool                // true if the message was encrypted.
+       EncryptedToKeyIds        []uint64            // the list of recipient key ids.
+       IsSymmetricallyEncrypted bool                // true if a passphrase could have decrypted the message.
+       DecryptedWith            Key                 // the private key used to decrypt the message, if any.
+       IsSigned                 bool                // true if the message is signed.
+       SignedByKeyId            uint64              // the key id of the signer, if any.
+       SignedBy                 *Key                // the key of the signer, if available.
+       LiteralData              *packet.LiteralData // the metadata of the contents
+       UnverifiedBody           io.Reader           // the contents of the message.
+
+       // If IsSigned is true and SignedBy is non-zero then the signature will
+       // be verified as UnverifiedBody is read. The signature cannot be
+       // checked until the whole of UnverifiedBody is read so UnverifiedBody
+       // must be consumed until EOF before the data can be trusted. Even if a
+       // message isn't signed (or the signer is unknown) the data may contain
+       // an authentication code that is only checked once UnverifiedBody has
+       // been consumed. Once EOF has been seen, the following fields are
+       // valid. (An authentication code failure is reported as a
+       // SignatureError error when reading from UnverifiedBody.)
+       SignatureError error               // nil if the signature is good.
+       Signature      *packet.Signature   // the signature packet itself, if v4 (default)
+       SignatureV3    *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature
+
+       decrypted io.ReadCloser
+}
+
+// A PromptFunction is used as a callback by functions that may need to decrypt
+// a private key, or prompt for a passphrase. It is called with a list of
+// acceptable, encrypted private keys and a boolean that indicates whether a
+// passphrase is usable. It should either decrypt a private key or return a
+// passphrase to try. If the decrypted private key or given passphrase isn't
+// correct, the function will be called again, forever. Any error returned will
+// be passed up.
+type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
+
+// A keyEnvelopePair is used to store a private key with the envelope that
+// contains a symmetric key, encrypted with that key.
+type keyEnvelopePair struct {
+       key          Key
+       encryptedKey *packet.EncryptedKey
+}
+
+// ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
+// The given KeyRing should contain both public keys (for signature
+// verification) and, possibly encrypted, private keys for decrypting.
+// If config is nil, sensible defaults will be used.
+func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
+       var p packet.Packet
+
+       var symKeys []*packet.SymmetricKeyEncrypted
+       var pubKeys []keyEnvelopePair
+       var se *packet.SymmetricallyEncrypted
+
+       packets := packet.NewReader(r)
+       md = new(MessageDetails)
+       md.IsEncrypted = true
+
+       // The message, if encrypted, starts with a number of packets
+       // containing an encrypted decryption key. The decryption key is either
+       // encrypted to a public key, or with a passphrase. This loop
+       // collects these packets.
+ParsePackets:
+       for {
+               p, err = packets.Next()
+               if err != nil {
+                       return nil, err
+               }
+               switch p := p.(type) {
+               case *packet.SymmetricKeyEncrypted:
+                       // This packet contains the decryption key encrypted with a passphrase.
+                       md.IsSymmetricallyEncrypted = true
+                       symKeys = append(symKeys, p)
+               case *packet.EncryptedKey:
+                       // This packet contains the decryption key encrypted to a public key.
+                       md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
+                       switch p.Algo {
+                       case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal:
+                               break
+                       default:
+                               continue
+                       }
+                       var keys []Key
+                       if p.KeyId == 0 {
+                               keys = keyring.DecryptionKeys()
+                       } else {
+                               keys = keyring.KeysById(p.KeyId)
+                       }
+                       for _, k := range keys {
+                               pubKeys = append(pubKeys, keyEnvelopePair{k, p})
+                       }
+               case *packet.SymmetricallyEncrypted:
+                       se = p
+                       break ParsePackets
+               case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
+                       // This message isn't encrypted.
+                       if len(symKeys) != 0 || len(pubKeys) != 0 {
+                               return nil, errors.StructuralError("key material not followed by encrypted message")
+                       }
+                       packets.Unread(p)
+                       return readSignedMessage(packets, nil, keyring)
+               }
+       }
+
+       var candidates []Key
+       var decrypted io.ReadCloser
+
+       // Now that we have the list of encrypted keys we need to decrypt at
+       // least one of them or, if we cannot, we need to call the prompt
+       // function so that it can decrypt a key or give us a passphrase.
+FindKey:
+       for {
+               // See if any of the keys already have a private key available
+               candidates = candidates[:0]
+               candidateFingerprints := make(map[string]bool)
+
+               for _, pk := range pubKeys {
+                       if pk.key.PrivateKey == nil {
+                               continue
+                       }
+                       if !pk.key.PrivateKey.Encrypted {
+                               if len(pk.encryptedKey.Key) == 0 {
+                                       pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
+                               }
+                               if len(pk.encryptedKey.Key) == 0 {
+                                       continue
+                               }
+                               decrypted, err = se.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
+                               if err != nil && err != errors.ErrKeyIncorrect {
+                                       return nil, err
+                               }
+                               if decrypted != nil {
+                                       md.DecryptedWith = pk.key
+                                       break FindKey
+                               }
+                       } else {
+                               fpr := string(pk.key.PublicKey.Fingerprint[:])
+                               if v := candidateFingerprints[fpr]; v {
+                                       continue
+                               }
+                               candidates = append(candidates, pk.key)
+                               candidateFingerprints[fpr] = true
+                       }
+               }
+
+               if len(candidates) == 0 && len(symKeys) == 0 {
+                       return nil, errors.ErrKeyIncorrect
+               }
+
+               if prompt == nil {
+                       return nil, errors.ErrKeyIncorrect
+               }
+
+               passphrase, err := prompt(candidates, len(symKeys) != 0)
+               if err != nil {
+                       return nil, err
+               }
+
+               // Try the symmetric passphrase first
+               if len(symKeys) != 0 && passphrase != nil {
+                       for _, s := range symKeys {
+                               key, cipherFunc, err := s.Decrypt(passphrase)
+                               if err == nil {
+                                       decrypted, err = se.Decrypt(cipherFunc, key)
+                                       if err != nil && err != errors.ErrKeyIncorrect {
+                                               return nil, err
+                                       }
+                                       if decrypted != nil {
+                                               break FindKey
+                                       }
+                               }
+
+                       }
+               }
+       }
+
+       md.decrypted = decrypted
+       if err := packets.Push(decrypted); err != nil {
+               return nil, err
+       }
+       return readSignedMessage(packets, md, keyring)
+}
+
+// readSignedMessage reads a possibly signed message if mdin is non-zero then
+// that structure is updated and returned. Otherwise a fresh MessageDetails is
+// used.
+func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing) (md *MessageDetails, err error) {
+       if mdin == nil {
+               mdin = new(MessageDetails)
+       }
+       md = mdin
+
+       var p packet.Packet
+       var h hash.Hash
+       var wrappedHash hash.Hash
+FindLiteralData:
+       for {
+               p, err = packets.Next()
+               if err != nil {
+                       return nil, err
+               }
+               switch p := p.(type) {
+               case *packet.Compressed:
+                       if err := packets.Push(p.Body); err != nil {
+                               return nil, err
+                       }
+               case *packet.OnePassSignature:
+                       if !p.IsLast {
+                               return nil, errors.UnsupportedError("nested signatures")
+                       }
+
+                       h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
+                       if err != nil {
+                               md = nil
+                               return
+                       }
+
+                       md.IsSigned = true
+                       md.SignedByKeyId = p.KeyId
+                       keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
+                       if len(keys) > 0 {
+                               md.SignedBy = &keys[0]
+                       }
+               case *packet.LiteralData:
+                       md.LiteralData = p
+                       break FindLiteralData
+               }
+       }
+
+       if md.SignedBy != nil {
+               md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md}
+       } else if md.decrypted != nil {
+               md.UnverifiedBody = checkReader{md}
+       } else {
+               md.UnverifiedBody = md.LiteralData.Body
+       }
+
+       return md, nil
+}
+
+// hashForSignature returns a pair of hashes that can be used to verify a
+// signature. The signature may specify that the contents of the signed message
+// should be preprocessed (i.e. to normalize line endings). Thus this function
+// returns two hashes. The second should be used to hash the message itself and
+// performs any needed preprocessing.
+func hashForSignature(hashId crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
+       if !hashId.Available() {
+               return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashId)))
+       }
+       h := hashId.New()
+
+       switch sigType {
+       case packet.SigTypeBinary:
+               return h, h, nil
+       case packet.SigTypeText:
+               return h, NewCanonicalTextHash(h), nil
+       }
+
+       return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
+}
+
+// checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
+// it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
+// MDC checks.
+type checkReader struct {
+       md *MessageDetails
+}
+
+func (cr checkReader) Read(buf []byte) (n int, err error) {
+       n, err = cr.md.LiteralData.Body.Read(buf)
+       if err == io.EOF {
+               mdcErr := cr.md.decrypted.Close()
+               if mdcErr != nil {
+                       err = mdcErr
+               }
+       }
+       return
+}
+
+// signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
+// the data as it is read. When it sees an EOF from the underlying io.Reader
+// it parses and checks a trailing Signature packet and triggers any MDC checks.
+type signatureCheckReader struct {
+       packets        *packet.Reader
+       h, wrappedHash hash.Hash
+       md             *MessageDetails
+}
+
+func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
+       n, err = scr.md.LiteralData.Body.Read(buf)
+       scr.wrappedHash.Write(buf[:n])
+       if err == io.EOF {
+               var p packet.Packet
+               p, scr.md.SignatureError = scr.packets.Next()
+               if scr.md.SignatureError != nil {
+                       return
+               }
+
+               var ok bool
+               if scr.md.Signature, ok = p.(*packet.Signature); ok {
+                       scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
+               } else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
+                       scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
+               } else {
+                       scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
+                       return
+               }
+
+               // The SymmetricallyEncrypted packet, if any, might have an
+               // unsigned hash of its own. In order to check this we need to
+               // close that Reader.
+               if scr.md.decrypted != nil {
+                       mdcErr := scr.md.decrypted.Close()
+                       if mdcErr != nil {
+                               err = mdcErr
+                       }
+               }
+       }
+       return
+}
+
+// CheckDetachedSignature takes a signed file and a detached signature and
+// returns the signer if the signature is valid. If the signer isn't known,
+// ErrUnknownIssuer is returned.
+func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
+       var issuerKeyId uint64
+       var hashFunc crypto.Hash
+       var sigType packet.SignatureType
+       var keys []Key
+       var p packet.Packet
+
+       packets := packet.NewReader(signature)
+       for {
+               p, err = packets.Next()
+               if err == io.EOF {
+                       return nil, errors.ErrUnknownIssuer
+               }
+               if err != nil {
+                       return nil, err
+               }
+
+               switch sig := p.(type) {
+               case *packet.Signature:
+                       if sig.IssuerKeyId == nil {
+                               return nil, errors.StructuralError("signature doesn't have an issuer")
+                       }
+                       issuerKeyId = *sig.IssuerKeyId
+                       hashFunc = sig.Hash
+                       sigType = sig.SigType
+               case *packet.SignatureV3:
+                       issuerKeyId = sig.IssuerKeyId
+                       hashFunc = sig.Hash
+                       sigType = sig.SigType
+               default:
+                       return nil, errors.StructuralError("non signature packet found")
+               }
+
+               keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
+               if len(keys) > 0 {
+                       break
+               }
+       }
+
+       if len(keys) == 0 {
+               panic("unreachable")
+       }
+
+       h, wrappedHash, err := hashForSignature(hashFunc, sigType)
+       if err != nil {
+               return nil, err
+       }
+
+       if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
+               return nil, err
+       }
+
+       for _, key := range keys {
+               switch sig := p.(type) {
+               case *packet.Signature:
+                       err = key.PublicKey.VerifySignature(h, sig)
+               case *packet.SignatureV3:
+                       err = key.PublicKey.VerifySignatureV3(h, sig)
+               default:
+                       panic("unreachable")
+               }
+
+               if err == nil {
+                       return key.Entity, nil
+               }
+       }
+
+       return nil, err
+}
+
+// CheckArmoredDetachedSignature performs the same actions as
+// CheckDetachedSignature but expects the signature to be armored.
+func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader) (signer *Entity, err error) {
+       body, err := readArmored(signature, SignatureType)
+       if err != nil {
+               return
+       }
+
+       return CheckDetachedSignature(keyring, signed, body)
+}