...

Source file src/github.com/ProtonMail/go-crypto/openpgp/read.go

Documentation: github.com/ProtonMail/go-crypto/openpgp

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package openpgp implements high level operations on OpenPGP messages.
     6  package openpgp // import "github.com/ProtonMail/go-crypto/openpgp"
     7  
     8  import (
     9  	"crypto"
    10  	_ "crypto/sha256"
    11  	_ "crypto/sha512"
    12  	"hash"
    13  	"io"
    14  	"strconv"
    15  
    16  	"github.com/ProtonMail/go-crypto/openpgp/armor"
    17  	"github.com/ProtonMail/go-crypto/openpgp/errors"
    18  	"github.com/ProtonMail/go-crypto/openpgp/internal/algorithm"
    19  	"github.com/ProtonMail/go-crypto/openpgp/packet"
    20  	_ "golang.org/x/crypto/sha3"
    21  )
    22  
    23  // SignatureType is the armor type for a PGP signature.
    24  var SignatureType = "PGP SIGNATURE"
    25  
    26  // readArmored reads an armored block with the given type.
    27  func readArmored(r io.Reader, expectedType string) (body io.Reader, err error) {
    28  	block, err := armor.Decode(r)
    29  	if err != nil {
    30  		return
    31  	}
    32  
    33  	if block.Type != expectedType {
    34  		return nil, errors.InvalidArgumentError("expected '" + expectedType + "', got: " + block.Type)
    35  	}
    36  
    37  	return block.Body, nil
    38  }
    39  
    40  // MessageDetails contains the result of parsing an OpenPGP encrypted and/or
    41  // signed message.
    42  type MessageDetails struct {
    43  	IsEncrypted              bool                // true if the message was encrypted.
    44  	EncryptedToKeyIds        []uint64            // the list of recipient key ids.
    45  	IsSymmetricallyEncrypted bool                // true if a passphrase could have decrypted the message.
    46  	DecryptedWith            Key                 // the private key used to decrypt the message, if any.
    47  	IsSigned                 bool                // true if the message is signed.
    48  	SignedByKeyId            uint64              // the key id of the signer, if any.
    49  	SignedBy                 *Key                // the key of the signer, if available.
    50  	LiteralData              *packet.LiteralData // the metadata of the contents
    51  	UnverifiedBody           io.Reader           // the contents of the message.
    52  
    53  	// If IsSigned is true and SignedBy is non-zero then the signature will
    54  	// be verified as UnverifiedBody is read. The signature cannot be
    55  	// checked until the whole of UnverifiedBody is read so UnverifiedBody
    56  	// must be consumed until EOF before the data can be trusted. Even if a
    57  	// message isn't signed (or the signer is unknown) the data may contain
    58  	// an authentication code that is only checked once UnverifiedBody has
    59  	// been consumed. Once EOF has been seen, the following fields are
    60  	// valid. (An authentication code failure is reported as a
    61  	// SignatureError error when reading from UnverifiedBody.)
    62  	Signature            *packet.Signature   // the signature packet itself.
    63  	SignatureError       error               // nil if the signature is good.
    64  	UnverifiedSignatures []*packet.Signature // all other unverified signature packets.
    65  
    66  	decrypted io.ReadCloser
    67  }
    68  
    69  // A PromptFunction is used as a callback by functions that may need to decrypt
    70  // a private key, or prompt for a passphrase. It is called with a list of
    71  // acceptable, encrypted private keys and a boolean that indicates whether a
    72  // passphrase is usable. It should either decrypt a private key or return a
    73  // passphrase to try. If the decrypted private key or given passphrase isn't
    74  // correct, the function will be called again, forever. Any error returned will
    75  // be passed up.
    76  type PromptFunction func(keys []Key, symmetric bool) ([]byte, error)
    77  
    78  // A keyEnvelopePair is used to store a private key with the envelope that
    79  // contains a symmetric key, encrypted with that key.
    80  type keyEnvelopePair struct {
    81  	key          Key
    82  	encryptedKey *packet.EncryptedKey
    83  }
    84  
    85  // ReadMessage parses an OpenPGP message that may be signed and/or encrypted.
    86  // The given KeyRing should contain both public keys (for signature
    87  // verification) and, possibly encrypted, private keys for decrypting.
    88  // If config is nil, sensible defaults will be used.
    89  func ReadMessage(r io.Reader, keyring KeyRing, prompt PromptFunction, config *packet.Config) (md *MessageDetails, err error) {
    90  	var p packet.Packet
    91  
    92  	var symKeys []*packet.SymmetricKeyEncrypted
    93  	var pubKeys []keyEnvelopePair
    94  	// Integrity protected encrypted packet: SymmetricallyEncrypted or AEADEncrypted
    95  	var edp packet.EncryptedDataPacket
    96  
    97  	packets := packet.NewReader(r)
    98  	md = new(MessageDetails)
    99  	md.IsEncrypted = true
   100  
   101  	// The message, if encrypted, starts with a number of packets
   102  	// containing an encrypted decryption key. The decryption key is either
   103  	// encrypted to a public key, or with a passphrase. This loop
   104  	// collects these packets.
   105  ParsePackets:
   106  	for {
   107  		p, err = packets.Next()
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  		switch p := p.(type) {
   112  		case *packet.SymmetricKeyEncrypted:
   113  			// This packet contains the decryption key encrypted with a passphrase.
   114  			md.IsSymmetricallyEncrypted = true
   115  			symKeys = append(symKeys, p)
   116  		case *packet.EncryptedKey:
   117  			// This packet contains the decryption key encrypted to a public key.
   118  			md.EncryptedToKeyIds = append(md.EncryptedToKeyIds, p.KeyId)
   119  			switch p.Algo {
   120  			case packet.PubKeyAlgoRSA, packet.PubKeyAlgoRSAEncryptOnly, packet.PubKeyAlgoElGamal, packet.PubKeyAlgoECDH:
   121  				break
   122  			default:
   123  				continue
   124  			}
   125  			if keyring != nil {
   126  				var keys []Key
   127  				if p.KeyId == 0 {
   128  					keys = keyring.DecryptionKeys()
   129  				} else {
   130  					keys = keyring.KeysById(p.KeyId)
   131  				}
   132  				for _, k := range keys {
   133  					pubKeys = append(pubKeys, keyEnvelopePair{k, p})
   134  				}
   135  			}
   136  		case *packet.SymmetricallyEncrypted:
   137  			if !p.IntegrityProtected && !config.AllowUnauthenticatedMessages() {
   138  				return nil, errors.UnsupportedError("message is not integrity protected")
   139  			}
   140  			edp = p
   141  			break ParsePackets
   142  		case *packet.AEADEncrypted:
   143  			edp = p
   144  			break ParsePackets
   145  		case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
   146  			// This message isn't encrypted.
   147  			if len(symKeys) != 0 || len(pubKeys) != 0 {
   148  				return nil, errors.StructuralError("key material not followed by encrypted message")
   149  			}
   150  			packets.Unread(p)
   151  			return readSignedMessage(packets, nil, keyring, config)
   152  		}
   153  	}
   154  
   155  	var candidates []Key
   156  	var decrypted io.ReadCloser
   157  
   158  	// Now that we have the list of encrypted keys we need to decrypt at
   159  	// least one of them or, if we cannot, we need to call the prompt
   160  	// function so that it can decrypt a key or give us a passphrase.
   161  FindKey:
   162  	for {
   163  		// See if any of the keys already have a private key available
   164  		candidates = candidates[:0]
   165  		candidateFingerprints := make(map[string]bool)
   166  
   167  		for _, pk := range pubKeys {
   168  			if pk.key.PrivateKey == nil {
   169  				continue
   170  			}
   171  			if !pk.key.PrivateKey.Encrypted {
   172  				if len(pk.encryptedKey.Key) == 0 {
   173  					errDec := pk.encryptedKey.Decrypt(pk.key.PrivateKey, config)
   174  					if errDec != nil {
   175  						continue
   176  					}
   177  				}
   178  				// Try to decrypt symmetrically encrypted
   179  				decrypted, err = edp.Decrypt(pk.encryptedKey.CipherFunc, pk.encryptedKey.Key)
   180  				if err != nil && err != errors.ErrKeyIncorrect {
   181  					return nil, err
   182  				}
   183  				if decrypted != nil {
   184  					md.DecryptedWith = pk.key
   185  					break FindKey
   186  				}
   187  			} else {
   188  				fpr := string(pk.key.PublicKey.Fingerprint[:])
   189  				if v := candidateFingerprints[fpr]; v {
   190  					continue
   191  				}
   192  				candidates = append(candidates, pk.key)
   193  				candidateFingerprints[fpr] = true
   194  			}
   195  		}
   196  
   197  		if len(candidates) == 0 && len(symKeys) == 0 {
   198  			return nil, errors.ErrKeyIncorrect
   199  		}
   200  
   201  		if prompt == nil {
   202  			return nil, errors.ErrKeyIncorrect
   203  		}
   204  
   205  		passphrase, err := prompt(candidates, len(symKeys) != 0)
   206  		if err != nil {
   207  			return nil, err
   208  		}
   209  
   210  		// Try the symmetric passphrase first
   211  		if len(symKeys) != 0 && passphrase != nil {
   212  			for _, s := range symKeys {
   213  				key, cipherFunc, err := s.Decrypt(passphrase)
   214  				// In v4, on wrong passphrase, session key decryption is very likely to result in an invalid cipherFunc:
   215  				// only for < 5% of cases we will proceed to decrypt the data
   216  				if err == nil {
   217  					decrypted, err = edp.Decrypt(cipherFunc, key)
   218  					if err != nil {
   219  						return nil, err
   220  					}
   221  					if decrypted != nil {
   222  						break FindKey
   223  					}
   224  				}
   225  			}
   226  		}
   227  	}
   228  
   229  	md.decrypted = decrypted
   230  	if err := packets.Push(decrypted); err != nil {
   231  		return nil, err
   232  	}
   233  	mdFinal, sensitiveParsingErr := readSignedMessage(packets, md, keyring, config)
   234  	if sensitiveParsingErr != nil {
   235  		return nil, errors.StructuralError("parsing error")
   236  	}
   237  	return mdFinal, nil
   238  }
   239  
   240  // readSignedMessage reads a possibly signed message if mdin is non-zero then
   241  // that structure is updated and returned. Otherwise a fresh MessageDetails is
   242  // used.
   243  func readSignedMessage(packets *packet.Reader, mdin *MessageDetails, keyring KeyRing, config *packet.Config) (md *MessageDetails, err error) {
   244  	if mdin == nil {
   245  		mdin = new(MessageDetails)
   246  	}
   247  	md = mdin
   248  
   249  	var p packet.Packet
   250  	var h hash.Hash
   251  	var wrappedHash hash.Hash
   252  	var prevLast bool
   253  FindLiteralData:
   254  	for {
   255  		p, err = packets.Next()
   256  		if err != nil {
   257  			return nil, err
   258  		}
   259  		switch p := p.(type) {
   260  		case *packet.Compressed:
   261  			if err := packets.Push(p.Body); err != nil {
   262  				return nil, err
   263  			}
   264  		case *packet.OnePassSignature:
   265  			if prevLast {
   266  				return nil, errors.UnsupportedError("nested signature packets")
   267  			}
   268  
   269  			if p.IsLast {
   270  				prevLast = true
   271  			}
   272  
   273  			h, wrappedHash, err = hashForSignature(p.Hash, p.SigType)
   274  			if err != nil {
   275  				md.SignatureError = err
   276  			}
   277  
   278  			md.IsSigned = true
   279  			md.SignedByKeyId = p.KeyId
   280  			if keyring != nil {
   281  				keys := keyring.KeysByIdUsage(p.KeyId, packet.KeyFlagSign)
   282  				if len(keys) > 0 {
   283  					md.SignedBy = &keys[0]
   284  				}
   285  			}
   286  		case *packet.LiteralData:
   287  			md.LiteralData = p
   288  			break FindLiteralData
   289  		}
   290  	}
   291  
   292  	if md.IsSigned && md.SignatureError == nil {
   293  		md.UnverifiedBody = &signatureCheckReader{packets, h, wrappedHash, md, config}
   294  	} else if md.decrypted != nil {
   295  		md.UnverifiedBody = checkReader{md}
   296  	} else {
   297  		md.UnverifiedBody = md.LiteralData.Body
   298  	}
   299  
   300  	return md, nil
   301  }
   302  
   303  // hashForSignature returns a pair of hashes that can be used to verify a
   304  // signature. The signature may specify that the contents of the signed message
   305  // should be preprocessed (i.e. to normalize line endings). Thus this function
   306  // returns two hashes. The second should be used to hash the message itself and
   307  // performs any needed preprocessing.
   308  func hashForSignature(hashFunc crypto.Hash, sigType packet.SignatureType) (hash.Hash, hash.Hash, error) {
   309  	if _, ok := algorithm.HashToHashIdWithSha1(hashFunc); !ok {
   310  		return nil, nil, errors.UnsupportedError("unsupported hash function")
   311  	}
   312  	if !hashFunc.Available() {
   313  		return nil, nil, errors.UnsupportedError("hash not available: " + strconv.Itoa(int(hashFunc)))
   314  	}
   315  	h := hashFunc.New()
   316  
   317  	switch sigType {
   318  	case packet.SigTypeBinary:
   319  		return h, h, nil
   320  	case packet.SigTypeText:
   321  		return h, NewCanonicalTextHash(h), nil
   322  	}
   323  
   324  	return nil, nil, errors.UnsupportedError("unsupported signature type: " + strconv.Itoa(int(sigType)))
   325  }
   326  
   327  // checkReader wraps an io.Reader from a LiteralData packet. When it sees EOF
   328  // it closes the ReadCloser from any SymmetricallyEncrypted packet to trigger
   329  // MDC checks.
   330  type checkReader struct {
   331  	md *MessageDetails
   332  }
   333  
   334  func (cr checkReader) Read(buf []byte) (int, error) {
   335  	n, sensitiveParsingError := cr.md.LiteralData.Body.Read(buf)
   336  	if sensitiveParsingError == io.EOF {
   337  		mdcErr := cr.md.decrypted.Close()
   338  		if mdcErr != nil {
   339  			return n, mdcErr
   340  		}
   341  		return n, io.EOF
   342  	}
   343  
   344  	if sensitiveParsingError != nil {
   345  		return n, errors.StructuralError("parsing error")
   346  	}
   347  
   348  	return n, nil
   349  }
   350  
   351  // signatureCheckReader wraps an io.Reader from a LiteralData packet and hashes
   352  // the data as it is read. When it sees an EOF from the underlying io.Reader
   353  // it parses and checks a trailing Signature packet and triggers any MDC checks.
   354  type signatureCheckReader struct {
   355  	packets        *packet.Reader
   356  	h, wrappedHash hash.Hash
   357  	md             *MessageDetails
   358  	config         *packet.Config
   359  }
   360  
   361  func (scr *signatureCheckReader) Read(buf []byte) (int, error) {
   362  	n, sensitiveParsingError := scr.md.LiteralData.Body.Read(buf)
   363  
   364  	// Hash only if required
   365  	if scr.md.SignedBy != nil {
   366  		scr.wrappedHash.Write(buf[:n])
   367  	}
   368  
   369  	if sensitiveParsingError == io.EOF {
   370  		var p packet.Packet
   371  		var readError error
   372  		var sig *packet.Signature
   373  
   374  		p, readError = scr.packets.Next()
   375  		for readError == nil {
   376  			var ok bool
   377  			if sig, ok = p.(*packet.Signature); ok {
   378  				if sig.Version == 5 && (sig.SigType == 0x00 || sig.SigType == 0x01) {
   379  					sig.Metadata = scr.md.LiteralData
   380  				}
   381  
   382  				// If signature KeyID matches
   383  				if scr.md.SignedBy != nil && *sig.IssuerKeyId == scr.md.SignedByKeyId {
   384  					key := scr.md.SignedBy
   385  					signatureError := key.PublicKey.VerifySignature(scr.h, sig)
   386  					if signatureError == nil {
   387  						signatureError = checkSignatureDetails(key, sig, scr.config)
   388  					}
   389  					scr.md.Signature = sig
   390  					scr.md.SignatureError = signatureError
   391  				} else {
   392  					scr.md.UnverifiedSignatures = append(scr.md.UnverifiedSignatures, sig)
   393  				}
   394  			}
   395  
   396  			p, readError = scr.packets.Next()
   397  		}
   398  
   399  		if scr.md.SignedBy != nil && scr.md.Signature == nil {
   400  			if scr.md.UnverifiedSignatures == nil {
   401  				scr.md.SignatureError = errors.StructuralError("LiteralData not followed by signature")
   402  			} else {
   403  				scr.md.SignatureError = errors.StructuralError("No matching signature found")
   404  			}
   405  		}
   406  
   407  		// The SymmetricallyEncrypted packet, if any, might have an
   408  		// unsigned hash of its own. In order to check this we need to
   409  		// close that Reader.
   410  		if scr.md.decrypted != nil {
   411  			mdcErr := scr.md.decrypted.Close()
   412  			if mdcErr != nil {
   413  				return n, mdcErr
   414  			}
   415  		}
   416  		return n, io.EOF
   417  	}
   418  
   419  	if sensitiveParsingError != nil {
   420  		return n, errors.StructuralError("parsing error")
   421  	}
   422  
   423  	return n, nil
   424  }
   425  
   426  // VerifyDetachedSignature takes a signed file and a detached signature and
   427  // returns the signature packet and the entity the signature was signed by,
   428  // if any, and a possible signature verification error.
   429  // If the signer isn't known, ErrUnknownIssuer is returned.
   430  func VerifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
   431  	var expectedHashes []crypto.Hash
   432  	return verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
   433  }
   434  
   435  // VerifyDetachedSignatureAndHash performs the same actions as
   436  // VerifyDetachedSignature and checks that the expected hash functions were used.
   437  func VerifyDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
   438  	return verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
   439  }
   440  
   441  // CheckDetachedSignature takes a signed file and a detached signature and
   442  // returns the entity the signature was signed by, if any, and a possible
   443  // signature verification error. If the signer isn't known,
   444  // ErrUnknownIssuer is returned.
   445  func CheckDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
   446  	var expectedHashes []crypto.Hash
   447  	return CheckDetachedSignatureAndHash(keyring, signed, signature, expectedHashes, config)
   448  }
   449  
   450  // CheckDetachedSignatureAndHash performs the same actions as
   451  // CheckDetachedSignature and checks that the expected hash functions were used.
   452  func CheckDetachedSignatureAndHash(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (signer *Entity, err error) {
   453  	_, signer, err = verifyDetachedSignature(keyring, signed, signature, expectedHashes, config)
   454  	return
   455  }
   456  
   457  func verifyDetachedSignature(keyring KeyRing, signed, signature io.Reader, expectedHashes []crypto.Hash, config *packet.Config) (sig *packet.Signature, signer *Entity, err error) {
   458  	var issuerKeyId uint64
   459  	var hashFunc crypto.Hash
   460  	var sigType packet.SignatureType
   461  	var keys []Key
   462  	var p packet.Packet
   463  
   464  	expectedHashesLen := len(expectedHashes)
   465  	packets := packet.NewReader(signature)
   466  	for {
   467  		p, err = packets.Next()
   468  		if err == io.EOF {
   469  			return nil, nil, errors.ErrUnknownIssuer
   470  		}
   471  		if err != nil {
   472  			return nil, nil, err
   473  		}
   474  
   475  		var ok bool
   476  		sig, ok = p.(*packet.Signature)
   477  		if !ok {
   478  			return nil, nil, errors.StructuralError("non signature packet found")
   479  		}
   480  		if sig.IssuerKeyId == nil {
   481  			return nil, nil, errors.StructuralError("signature doesn't have an issuer")
   482  		}
   483  		issuerKeyId = *sig.IssuerKeyId
   484  		hashFunc = sig.Hash
   485  		sigType = sig.SigType
   486  
   487  		for i, expectedHash := range expectedHashes {
   488  			if hashFunc == expectedHash {
   489  				break
   490  			}
   491  			if i+1 == expectedHashesLen {
   492  				return nil, nil, errors.StructuralError("hash algorithm mismatch with cleartext message headers")
   493  			}
   494  		}
   495  
   496  		keys = keyring.KeysByIdUsage(issuerKeyId, packet.KeyFlagSign)
   497  		if len(keys) > 0 {
   498  			break
   499  		}
   500  	}
   501  
   502  	if len(keys) == 0 {
   503  		panic("unreachable")
   504  	}
   505  
   506  	h, wrappedHash, err := hashForSignature(hashFunc, sigType)
   507  	if err != nil {
   508  		return nil, nil, err
   509  	}
   510  
   511  	if _, err := io.Copy(wrappedHash, signed); err != nil && err != io.EOF {
   512  		return nil, nil, err
   513  	}
   514  
   515  	for _, key := range keys {
   516  		err = key.PublicKey.VerifySignature(h, sig)
   517  		if err == nil {
   518  			return sig, key.Entity, checkSignatureDetails(&key, sig, config)
   519  		}
   520  	}
   521  
   522  	return nil, nil, err
   523  }
   524  
   525  // CheckArmoredDetachedSignature performs the same actions as
   526  // CheckDetachedSignature but expects the signature to be armored.
   527  func CheckArmoredDetachedSignature(keyring KeyRing, signed, signature io.Reader, config *packet.Config) (signer *Entity, err error) {
   528  	body, err := readArmored(signature, SignatureType)
   529  	if err != nil {
   530  		return
   531  	}
   532  
   533  	return CheckDetachedSignature(keyring, signed, body, config)
   534  }
   535  
   536  // checkSignatureDetails returns an error if:
   537  //   - The signature (or one of the binding signatures mentioned below)
   538  //     has a unknown critical notation data subpacket
   539  //   - The primary key of the signing entity is revoked
   540  //   - The primary identity is revoked
   541  //   - The signature is expired
   542  //   - The primary key of the signing entity is expired according to the
   543  //     primary identity binding signature
   544  //
   545  // ... or, if the signature was signed by a subkey and:
   546  //   - The signing subkey is revoked
   547  //   - The signing subkey is expired according to the subkey binding signature
   548  //   - The signing subkey binding signature is expired
   549  //   - The signing subkey cross-signature is expired
   550  //
   551  // NOTE: The order of these checks is important, as the caller may choose to
   552  // ignore ErrSignatureExpired or ErrKeyExpired errors, but should never
   553  // ignore any other errors.
   554  //
   555  // TODO: Also return an error if:
   556  // - The primary key is expired according to a direct-key signature
   557  // - (For V5 keys only:) The direct-key signature (exists and) is expired
   558  func checkSignatureDetails(key *Key, signature *packet.Signature, config *packet.Config) error {
   559  	now := config.Now()
   560  	primaryIdentity := key.Entity.PrimaryIdentity()
   561  	signedBySubKey := key.PublicKey != key.Entity.PrimaryKey
   562  	sigsToCheck := []*packet.Signature{signature, primaryIdentity.SelfSignature}
   563  	if signedBySubKey {
   564  		sigsToCheck = append(sigsToCheck, key.SelfSignature, key.SelfSignature.EmbeddedSignature)
   565  	}
   566  	for _, sig := range sigsToCheck {
   567  		for _, notation := range sig.Notations {
   568  			if notation.IsCritical && !config.KnownNotation(notation.Name) {
   569  				return errors.SignatureError("unknown critical notation: " + notation.Name)
   570  			}
   571  		}
   572  	}
   573  	if key.Entity.Revoked(now) || // primary key is revoked
   574  		(signedBySubKey && key.Revoked(now)) || // subkey is revoked
   575  		primaryIdentity.Revoked(now) { // primary identity is revoked
   576  		return errors.ErrKeyRevoked
   577  	}
   578  	if key.Entity.PrimaryKey.KeyExpired(primaryIdentity.SelfSignature, now) { // primary key is expired
   579  		return errors.ErrKeyExpired
   580  	}
   581  	if signedBySubKey {
   582  		if key.PublicKey.KeyExpired(key.SelfSignature, now) { // subkey is expired
   583  			return errors.ErrKeyExpired
   584  		}
   585  	}
   586  	for _, sig := range sigsToCheck {
   587  		if sig.SigExpired(now) { // any of the relevant signatures are expired
   588  			return errors.ErrSignatureExpired
   589  		}
   590  	}
   591  	return nil
   592  }
   593  

View as plain text