text: // 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)
  }
  