github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/openpgp/packet/signature.go (about)

     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 packet
     6  
     7  import (
     8  	"bytes"
     9  	"crypto"
    10  	"crypto/dsa"
    11  	"crypto/rsa"
    12  	"encoding/binary"
    13  	"hash"
    14  	"io"
    15  	"strconv"
    16  	"time"
    17  
    18  	"golang.org/x/crypto/openpgp/errors"
    19  	"golang.org/x/crypto/openpgp/s2k"
    20  )
    21  
    22  const (
    23  	// See RFC 4880, section 5.2.3.21 for details.
    24  	KeyFlagCertify = 1 << iota
    25  	KeyFlagSign
    26  	KeyFlagEncryptCommunications
    27  	KeyFlagEncryptStorage
    28  )
    29  
    30  // Signature represents a signature. See RFC 4880, section 5.2.
    31  type Signature struct {
    32  	SigType    SignatureType
    33  	PubKeyAlgo PublicKeyAlgorithm
    34  	Hash       crypto.Hash
    35  
    36  	// HashSuffix is extra data that is hashed in after the signed data.
    37  	HashSuffix []byte
    38  	// HashTag contains the first two bytes of the hash for fast rejection
    39  	// of bad signed data.
    40  	HashTag      [2]byte
    41  	CreationTime time.Time
    42  
    43  	RSASignature         parsedMPI
    44  	DSASigR, DSASigS     parsedMPI
    45  	ECDSASigR, ECDSASigS parsedMPI
    46  
    47  	// rawSubpackets contains the unparsed subpackets, in order.
    48  	rawSubpackets []outputSubpacket
    49  
    50  	// The following are optional so are nil when not included in the
    51  	// signature.
    52  
    53  	SigLifetimeSecs, KeyLifetimeSecs                        *uint32
    54  	PreferredSymmetric, PreferredHash, PreferredCompression []uint8
    55  	IssuerKeyId                                             *uint64
    56  	IsPrimaryId                                             *bool
    57  
    58  	// FlagsValid is set if any flags were given. See RFC 4880, section
    59  	// 5.2.3.21 for details.
    60  	FlagsValid                                                           bool
    61  	FlagCertify, FlagSign, FlagEncryptCommunications, FlagEncryptStorage bool
    62  
    63  	// RevocationReason is set if this signature has been revoked.
    64  	// See RFC 4880, section 5.2.3.23 for details.
    65  	RevocationReason     *uint8
    66  	RevocationReasonText string
    67  
    68  	// MDC is set if this signature has a feature packet that indicates
    69  	// support for MDC subpackets.
    70  	MDC bool
    71  
    72  	// EmbeddedSignature, if non-nil, is a signature of the parent key, by
    73  	// this key. This prevents an attacker from claiming another's signing
    74  	// subkey as their own.
    75  	EmbeddedSignature *Signature
    76  
    77  	outSubpackets []outputSubpacket
    78  }
    79  
    80  func (sig *Signature) parse(r io.Reader) (err error) {
    81  	// RFC 4880, section 5.2.3
    82  	var buf [5]byte
    83  	_, err = readFull(r, buf[:1])
    84  	if err != nil {
    85  		return
    86  	}
    87  	if buf[0] != 4 {
    88  		err = errors.UnsupportedError("signature packet version " + strconv.Itoa(int(buf[0])))
    89  		return
    90  	}
    91  
    92  	_, err = readFull(r, buf[:5])
    93  	if err != nil {
    94  		return
    95  	}
    96  	sig.SigType = SignatureType(buf[0])
    97  	sig.PubKeyAlgo = PublicKeyAlgorithm(buf[1])
    98  	switch sig.PubKeyAlgo {
    99  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly, PubKeyAlgoDSA, PubKeyAlgoECDSA:
   100  	default:
   101  		err = errors.UnsupportedError("public key algorithm " + strconv.Itoa(int(sig.PubKeyAlgo)))
   102  		return
   103  	}
   104  
   105  	var ok bool
   106  	sig.Hash, ok = s2k.HashIdToHash(buf[2])
   107  	if !ok {
   108  		return errors.UnsupportedError("hash function " + strconv.Itoa(int(buf[2])))
   109  	}
   110  
   111  	hashedSubpacketsLength := int(buf[3])<<8 | int(buf[4])
   112  	l := 6 + hashedSubpacketsLength
   113  	sig.HashSuffix = make([]byte, l+6)
   114  	sig.HashSuffix[0] = 4
   115  	copy(sig.HashSuffix[1:], buf[:5])
   116  	hashedSubpackets := sig.HashSuffix[6:l]
   117  	_, err = readFull(r, hashedSubpackets)
   118  	if err != nil {
   119  		return
   120  	}
   121  	// See RFC 4880, section 5.2.4
   122  	trailer := sig.HashSuffix[l:]
   123  	trailer[0] = 4
   124  	trailer[1] = 0xff
   125  	trailer[2] = uint8(l >> 24)
   126  	trailer[3] = uint8(l >> 16)
   127  	trailer[4] = uint8(l >> 8)
   128  	trailer[5] = uint8(l)
   129  
   130  	err = parseSignatureSubpackets(sig, hashedSubpackets, true)
   131  	if err != nil {
   132  		return
   133  	}
   134  
   135  	_, err = readFull(r, buf[:2])
   136  	if err != nil {
   137  		return
   138  	}
   139  	unhashedSubpacketsLength := int(buf[0])<<8 | int(buf[1])
   140  	unhashedSubpackets := make([]byte, unhashedSubpacketsLength)
   141  	_, err = readFull(r, unhashedSubpackets)
   142  	if err != nil {
   143  		return
   144  	}
   145  	err = parseSignatureSubpackets(sig, unhashedSubpackets, false)
   146  	if err != nil {
   147  		return
   148  	}
   149  
   150  	_, err = readFull(r, sig.HashTag[:2])
   151  	if err != nil {
   152  		return
   153  	}
   154  
   155  	switch sig.PubKeyAlgo {
   156  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
   157  		sig.RSASignature.bytes, sig.RSASignature.bitLength, err = readMPI(r)
   158  	case PubKeyAlgoDSA:
   159  		sig.DSASigR.bytes, sig.DSASigR.bitLength, err = readMPI(r)
   160  		if err == nil {
   161  			sig.DSASigS.bytes, sig.DSASigS.bitLength, err = readMPI(r)
   162  		}
   163  	case PubKeyAlgoECDSA:
   164  		sig.ECDSASigR.bytes, sig.ECDSASigR.bitLength, err = readMPI(r)
   165  		if err == nil {
   166  			sig.ECDSASigS.bytes, sig.ECDSASigS.bitLength, err = readMPI(r)
   167  		}
   168  	default:
   169  		panic("unreachable")
   170  	}
   171  	return
   172  }
   173  
   174  // parseSignatureSubpackets parses subpackets of the main signature packet. See
   175  // RFC 4880, section 5.2.3.1.
   176  func parseSignatureSubpackets(sig *Signature, subpackets []byte, isHashed bool) (err error) {
   177  	for len(subpackets) > 0 {
   178  		subpackets, err = parseSignatureSubpacket(sig, subpackets, isHashed)
   179  		if err != nil {
   180  			return
   181  		}
   182  	}
   183  
   184  	if sig.CreationTime.IsZero() {
   185  		err = errors.StructuralError("no creation time in signature")
   186  	}
   187  
   188  	return
   189  }
   190  
   191  type signatureSubpacketType uint8
   192  
   193  const (
   194  	creationTimeSubpacket        signatureSubpacketType = 2
   195  	signatureExpirationSubpacket signatureSubpacketType = 3
   196  	keyExpirationSubpacket       signatureSubpacketType = 9
   197  	prefSymmetricAlgosSubpacket  signatureSubpacketType = 11
   198  	issuerSubpacket              signatureSubpacketType = 16
   199  	prefHashAlgosSubpacket       signatureSubpacketType = 21
   200  	prefCompressionSubpacket     signatureSubpacketType = 22
   201  	primaryUserIdSubpacket       signatureSubpacketType = 25
   202  	keyFlagsSubpacket            signatureSubpacketType = 27
   203  	reasonForRevocationSubpacket signatureSubpacketType = 29
   204  	featuresSubpacket            signatureSubpacketType = 30
   205  	embeddedSignatureSubpacket   signatureSubpacketType = 32
   206  )
   207  
   208  // parseSignatureSubpacket parses a single subpacket. len(subpacket) is >= 1.
   209  func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (rest []byte, err error) {
   210  	// RFC 4880, section 5.2.3.1
   211  	var (
   212  		length     uint32
   213  		packetType signatureSubpacketType
   214  		isCritical bool
   215  	)
   216  	switch {
   217  	case subpacket[0] < 192:
   218  		length = uint32(subpacket[0])
   219  		subpacket = subpacket[1:]
   220  	case subpacket[0] < 255:
   221  		if len(subpacket) < 2 {
   222  			goto Truncated
   223  		}
   224  		length = uint32(subpacket[0]-192)<<8 + uint32(subpacket[1]) + 192
   225  		subpacket = subpacket[2:]
   226  	default:
   227  		if len(subpacket) < 5 {
   228  			goto Truncated
   229  		}
   230  		length = uint32(subpacket[1])<<24 |
   231  			uint32(subpacket[2])<<16 |
   232  			uint32(subpacket[3])<<8 |
   233  			uint32(subpacket[4])
   234  		subpacket = subpacket[5:]
   235  	}
   236  	if length > uint32(len(subpacket)) {
   237  		goto Truncated
   238  	}
   239  	rest = subpacket[length:]
   240  	subpacket = subpacket[:length]
   241  	if len(subpacket) == 0 {
   242  		err = errors.StructuralError("zero length signature subpacket")
   243  		return
   244  	}
   245  	packetType = signatureSubpacketType(subpacket[0] & 0x7f)
   246  	isCritical = subpacket[0]&0x80 == 0x80
   247  	subpacket = subpacket[1:]
   248  	sig.rawSubpackets = append(sig.rawSubpackets, outputSubpacket{isHashed, packetType, isCritical, subpacket})
   249  	switch packetType {
   250  	case creationTimeSubpacket:
   251  		if !isHashed {
   252  			err = errors.StructuralError("signature creation time in non-hashed area")
   253  			return
   254  		}
   255  		if len(subpacket) != 4 {
   256  			err = errors.StructuralError("signature creation time not four bytes")
   257  			return
   258  		}
   259  		t := binary.BigEndian.Uint32(subpacket)
   260  		sig.CreationTime = time.Unix(int64(t), 0)
   261  	case signatureExpirationSubpacket:
   262  		// Signature expiration time, section 5.2.3.10
   263  		if !isHashed {
   264  			return
   265  		}
   266  		if len(subpacket) != 4 {
   267  			err = errors.StructuralError("expiration subpacket with bad length")
   268  			return
   269  		}
   270  		sig.SigLifetimeSecs = new(uint32)
   271  		*sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket)
   272  	case keyExpirationSubpacket:
   273  		// Key expiration time, section 5.2.3.6
   274  		if !isHashed {
   275  			return
   276  		}
   277  		if len(subpacket) != 4 {
   278  			err = errors.StructuralError("key expiration subpacket with bad length")
   279  			return
   280  		}
   281  		sig.KeyLifetimeSecs = new(uint32)
   282  		*sig.KeyLifetimeSecs = binary.BigEndian.Uint32(subpacket)
   283  	case prefSymmetricAlgosSubpacket:
   284  		// Preferred symmetric algorithms, section 5.2.3.7
   285  		if !isHashed {
   286  			return
   287  		}
   288  		sig.PreferredSymmetric = make([]byte, len(subpacket))
   289  		copy(sig.PreferredSymmetric, subpacket)
   290  	case issuerSubpacket:
   291  		// Issuer, section 5.2.3.5
   292  		if len(subpacket) != 8 {
   293  			err = errors.StructuralError("issuer subpacket with bad length")
   294  			return
   295  		}
   296  		sig.IssuerKeyId = new(uint64)
   297  		*sig.IssuerKeyId = binary.BigEndian.Uint64(subpacket)
   298  	case prefHashAlgosSubpacket:
   299  		// Preferred hash algorithms, section 5.2.3.8
   300  		if !isHashed {
   301  			return
   302  		}
   303  		sig.PreferredHash = make([]byte, len(subpacket))
   304  		copy(sig.PreferredHash, subpacket)
   305  	case prefCompressionSubpacket:
   306  		// Preferred compression algorithms, section 5.2.3.9
   307  		if !isHashed {
   308  			return
   309  		}
   310  		sig.PreferredCompression = make([]byte, len(subpacket))
   311  		copy(sig.PreferredCompression, subpacket)
   312  	case primaryUserIdSubpacket:
   313  		// Primary User ID, section 5.2.3.19
   314  		if !isHashed {
   315  			return
   316  		}
   317  		if len(subpacket) != 1 {
   318  			err = errors.StructuralError("primary user id subpacket with bad length")
   319  			return
   320  		}
   321  		sig.IsPrimaryId = new(bool)
   322  		if subpacket[0] > 0 {
   323  			*sig.IsPrimaryId = true
   324  		}
   325  	case keyFlagsSubpacket:
   326  		// Key flags, section 5.2.3.21
   327  		if !isHashed {
   328  			return
   329  		}
   330  		if len(subpacket) == 0 {
   331  			err = errors.StructuralError("empty key flags subpacket")
   332  			return
   333  		}
   334  		sig.FlagsValid = true
   335  		if subpacket[0]&KeyFlagCertify != 0 {
   336  			sig.FlagCertify = true
   337  		}
   338  		if subpacket[0]&KeyFlagSign != 0 {
   339  			sig.FlagSign = true
   340  		}
   341  		if subpacket[0]&KeyFlagEncryptCommunications != 0 {
   342  			sig.FlagEncryptCommunications = true
   343  		}
   344  		if subpacket[0]&KeyFlagEncryptStorage != 0 {
   345  			sig.FlagEncryptStorage = true
   346  		}
   347  	case reasonForRevocationSubpacket:
   348  		// Reason For Revocation, section 5.2.3.23
   349  		if !isHashed {
   350  			return
   351  		}
   352  		if len(subpacket) == 0 {
   353  			err = errors.StructuralError("empty revocation reason subpacket")
   354  			return
   355  		}
   356  		sig.RevocationReason = new(uint8)
   357  		*sig.RevocationReason = subpacket[0]
   358  		sig.RevocationReasonText = string(subpacket[1:])
   359  	case featuresSubpacket:
   360  		// Features subpacket, section 5.2.3.24 specifies a very general
   361  		// mechanism for OpenPGP implementations to signal support for new
   362  		// features. In practice, the subpacket is used exclusively to
   363  		// indicate support for MDC-protected encryption.
   364  		sig.MDC = len(subpacket) >= 1 && subpacket[0]&1 == 1
   365  	case embeddedSignatureSubpacket:
   366  		// Only usage is in signatures that cross-certify
   367  		// signing subkeys. section 5.2.3.26 describes the
   368  		// format, with its usage described in section 11.1
   369  		if sig.EmbeddedSignature != nil {
   370  			err = errors.StructuralError("Cannot have multiple embedded signatures")
   371  			return
   372  		}
   373  		sig.EmbeddedSignature = new(Signature)
   374  		// Embedded signatures are required to be v4 signatures see
   375  		// section 12.1. However, we only parse v4 signatures in this
   376  		// file anyway.
   377  		if err := sig.EmbeddedSignature.parse(bytes.NewBuffer(subpacket)); err != nil {
   378  			return nil, err
   379  		}
   380  		if sigType := sig.EmbeddedSignature.SigType; sigType != SigTypePrimaryKeyBinding {
   381  			return nil, errors.StructuralError("cross-signature has unexpected type " + strconv.Itoa(int(sigType)))
   382  		}
   383  	default:
   384  		if isCritical {
   385  			err = errors.UnsupportedError("unknown critical signature subpacket type " + strconv.Itoa(int(packetType)))
   386  			return
   387  		}
   388  	}
   389  	return
   390  
   391  Truncated:
   392  	err = errors.StructuralError("signature subpacket truncated")
   393  	return
   394  }
   395  
   396  // subpacketLengthLength returns the length, in bytes, of an encoded length value.
   397  func subpacketLengthLength(length int) int {
   398  	if length < 192 {
   399  		return 1
   400  	}
   401  	if length < 16320 {
   402  		return 2
   403  	}
   404  	return 5
   405  }
   406  
   407  // serializeSubpacketLength marshals the given length into to.
   408  func serializeSubpacketLength(to []byte, length int) int {
   409  	// RFC 4880, Section 4.2.2.
   410  	if length < 192 {
   411  		to[0] = byte(length)
   412  		return 1
   413  	}
   414  	if length < 16320 {
   415  		length -= 192
   416  		to[0] = byte((length >> 8) + 192)
   417  		to[1] = byte(length)
   418  		return 2
   419  	}
   420  	to[0] = 255
   421  	to[1] = byte(length >> 24)
   422  	to[2] = byte(length >> 16)
   423  	to[3] = byte(length >> 8)
   424  	to[4] = byte(length)
   425  	return 5
   426  }
   427  
   428  // subpacketsLength returns the serialized length, in bytes, of the given
   429  // subpackets.
   430  func subpacketsLength(subpackets []outputSubpacket, hashed bool) (length int) {
   431  	for _, subpacket := range subpackets {
   432  		if subpacket.hashed == hashed {
   433  			length += subpacketLengthLength(len(subpacket.contents) + 1)
   434  			length += 1 // type byte
   435  			length += len(subpacket.contents)
   436  		}
   437  	}
   438  	return
   439  }
   440  
   441  // serializeSubpackets marshals the given subpackets into to.
   442  func serializeSubpackets(to []byte, subpackets []outputSubpacket, hashed bool) {
   443  	for _, subpacket := range subpackets {
   444  		if subpacket.hashed == hashed {
   445  			n := serializeSubpacketLength(to, len(subpacket.contents)+1)
   446  			to[n] = byte(subpacket.subpacketType)
   447  			to = to[1+n:]
   448  			n = copy(to, subpacket.contents)
   449  			to = to[n:]
   450  		}
   451  	}
   452  	return
   453  }
   454  
   455  // KeyExpired returns whether sig is a self-signature of a key that has
   456  // expired.
   457  func (sig *Signature) KeyExpired(currentTime time.Time) bool {
   458  	if sig.KeyLifetimeSecs == nil {
   459  		return false
   460  	}
   461  	expiry := sig.CreationTime.Add(time.Duration(*sig.KeyLifetimeSecs) * time.Second)
   462  	return currentTime.After(expiry)
   463  }
   464  
   465  // buildHashSuffix constructs the HashSuffix member of sig in preparation for signing.
   466  func (sig *Signature) buildHashSuffix() (err error) {
   467  	hashedSubpacketsLen := subpacketsLength(sig.outSubpackets, true)
   468  
   469  	var ok bool
   470  	l := 6 + hashedSubpacketsLen
   471  	sig.HashSuffix = make([]byte, l+6)
   472  	sig.HashSuffix[0] = 4
   473  	sig.HashSuffix[1] = uint8(sig.SigType)
   474  	sig.HashSuffix[2] = uint8(sig.PubKeyAlgo)
   475  	sig.HashSuffix[3], ok = s2k.HashToHashId(sig.Hash)
   476  	if !ok {
   477  		sig.HashSuffix = nil
   478  		return errors.InvalidArgumentError("hash cannot be represented in OpenPGP: " + strconv.Itoa(int(sig.Hash)))
   479  	}
   480  	sig.HashSuffix[4] = byte(hashedSubpacketsLen >> 8)
   481  	sig.HashSuffix[5] = byte(hashedSubpacketsLen)
   482  	serializeSubpackets(sig.HashSuffix[6:l], sig.outSubpackets, true)
   483  	trailer := sig.HashSuffix[l:]
   484  	trailer[0] = 4
   485  	trailer[1] = 0xff
   486  	trailer[2] = byte(l >> 24)
   487  	trailer[3] = byte(l >> 16)
   488  	trailer[4] = byte(l >> 8)
   489  	trailer[5] = byte(l)
   490  	return
   491  }
   492  
   493  func (sig *Signature) signPrepareHash(h hash.Hash) (digest []byte, err error) {
   494  	err = sig.buildHashSuffix()
   495  	if err != nil {
   496  		return
   497  	}
   498  
   499  	h.Write(sig.HashSuffix)
   500  	digest = h.Sum(nil)
   501  	copy(sig.HashTag[:], digest)
   502  	return
   503  }
   504  
   505  // Sign signs a message with a private key. The hash, h, must contain
   506  // the hash of the message to be signed and will be mutated by this function.
   507  // On success, the signature is stored in sig. Call Serialize to write it out.
   508  // If config is nil, sensible defaults will be used.
   509  func (sig *Signature) Sign(h hash.Hash, priv *PrivateKey, config *Config) (err error) {
   510  	sig.outSubpackets = sig.buildSubpackets()
   511  	digest, err := sig.signPrepareHash(h)
   512  	if err != nil {
   513  		return
   514  	}
   515  
   516  	switch priv.PubKeyAlgo {
   517  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
   518  		sig.RSASignature.bytes, err = rsa.SignPKCS1v15(config.Random(), priv.PrivateKey.(*rsa.PrivateKey), sig.Hash, digest)
   519  		sig.RSASignature.bitLength = uint16(8 * len(sig.RSASignature.bytes))
   520  	case PubKeyAlgoDSA:
   521  		dsaPriv := priv.PrivateKey.(*dsa.PrivateKey)
   522  
   523  		// Need to truncate hashBytes to match FIPS 186-3 section 4.6.
   524  		subgroupSize := (dsaPriv.Q.BitLen() + 7) / 8
   525  		if len(digest) > subgroupSize {
   526  			digest = digest[:subgroupSize]
   527  		}
   528  		r, s, err := dsa.Sign(config.Random(), dsaPriv, digest)
   529  		if err == nil {
   530  			sig.DSASigR.bytes = r.Bytes()
   531  			sig.DSASigR.bitLength = uint16(8 * len(sig.DSASigR.bytes))
   532  			sig.DSASigS.bytes = s.Bytes()
   533  			sig.DSASigS.bitLength = uint16(8 * len(sig.DSASigS.bytes))
   534  		}
   535  	default:
   536  		err = errors.UnsupportedError("public key algorithm: " + strconv.Itoa(int(sig.PubKeyAlgo)))
   537  	}
   538  
   539  	return
   540  }
   541  
   542  // SignUserId computes a signature from priv, asserting that pub is a valid
   543  // key for the identity id.  On success, the signature is stored in sig. Call
   544  // Serialize to write it out.
   545  // If config is nil, sensible defaults will be used.
   546  func (sig *Signature) SignUserId(id string, pub *PublicKey, priv *PrivateKey, config *Config) error {
   547  	h, err := userIdSignatureHash(id, pub, sig.Hash)
   548  	if err != nil {
   549  		return nil
   550  	}
   551  	return sig.Sign(h, priv, config)
   552  }
   553  
   554  // SignKey computes a signature from priv, asserting that pub is a subkey. On
   555  // success, the signature is stored in sig. Call Serialize to write it out.
   556  // If config is nil, sensible defaults will be used.
   557  func (sig *Signature) SignKey(pub *PublicKey, priv *PrivateKey, config *Config) error {
   558  	h, err := keySignatureHash(&priv.PublicKey, pub, sig.Hash)
   559  	if err != nil {
   560  		return err
   561  	}
   562  	return sig.Sign(h, priv, config)
   563  }
   564  
   565  // Serialize marshals sig to w. Sign, SignUserId or SignKey must have been
   566  // called first.
   567  func (sig *Signature) Serialize(w io.Writer) (err error) {
   568  	if len(sig.outSubpackets) == 0 {
   569  		sig.outSubpackets = sig.rawSubpackets
   570  	}
   571  	if sig.RSASignature.bytes == nil && sig.DSASigR.bytes == nil && sig.ECDSASigR.bytes == nil {
   572  		return errors.InvalidArgumentError("Signature: need to call Sign, SignUserId or SignKey before Serialize")
   573  	}
   574  
   575  	sigLength := 0
   576  	switch sig.PubKeyAlgo {
   577  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
   578  		sigLength = 2 + len(sig.RSASignature.bytes)
   579  	case PubKeyAlgoDSA:
   580  		sigLength = 2 + len(sig.DSASigR.bytes)
   581  		sigLength += 2 + len(sig.DSASigS.bytes)
   582  	case PubKeyAlgoECDSA:
   583  		sigLength = 2 + len(sig.ECDSASigR.bytes)
   584  		sigLength += 2 + len(sig.ECDSASigS.bytes)
   585  	default:
   586  		panic("impossible")
   587  	}
   588  
   589  	unhashedSubpacketsLen := subpacketsLength(sig.outSubpackets, false)
   590  	length := len(sig.HashSuffix) - 6 /* trailer not included */ +
   591  		2 /* length of unhashed subpackets */ + unhashedSubpacketsLen +
   592  		2 /* hash tag */ + sigLength
   593  	err = serializeHeader(w, packetTypeSignature, length)
   594  	if err != nil {
   595  		return
   596  	}
   597  
   598  	_, err = w.Write(sig.HashSuffix[:len(sig.HashSuffix)-6])
   599  	if err != nil {
   600  		return
   601  	}
   602  
   603  	unhashedSubpackets := make([]byte, 2+unhashedSubpacketsLen)
   604  	unhashedSubpackets[0] = byte(unhashedSubpacketsLen >> 8)
   605  	unhashedSubpackets[1] = byte(unhashedSubpacketsLen)
   606  	serializeSubpackets(unhashedSubpackets[2:], sig.outSubpackets, false)
   607  
   608  	_, err = w.Write(unhashedSubpackets)
   609  	if err != nil {
   610  		return
   611  	}
   612  	_, err = w.Write(sig.HashTag[:])
   613  	if err != nil {
   614  		return
   615  	}
   616  
   617  	switch sig.PubKeyAlgo {
   618  	case PubKeyAlgoRSA, PubKeyAlgoRSASignOnly:
   619  		err = writeMPIs(w, sig.RSASignature)
   620  	case PubKeyAlgoDSA:
   621  		err = writeMPIs(w, sig.DSASigR, sig.DSASigS)
   622  	case PubKeyAlgoECDSA:
   623  		err = writeMPIs(w, sig.ECDSASigR, sig.ECDSASigS)
   624  	default:
   625  		panic("impossible")
   626  	}
   627  	return
   628  }
   629  
   630  // outputSubpacket represents a subpacket to be marshaled.
   631  type outputSubpacket struct {
   632  	hashed        bool // true if this subpacket is in the hashed area.
   633  	subpacketType signatureSubpacketType
   634  	isCritical    bool
   635  	contents      []byte
   636  }
   637  
   638  func (sig *Signature) buildSubpackets() (subpackets []outputSubpacket) {
   639  	creationTime := make([]byte, 4)
   640  	binary.BigEndian.PutUint32(creationTime, uint32(sig.CreationTime.Unix()))
   641  	subpackets = append(subpackets, outputSubpacket{true, creationTimeSubpacket, false, creationTime})
   642  
   643  	if sig.IssuerKeyId != nil {
   644  		keyId := make([]byte, 8)
   645  		binary.BigEndian.PutUint64(keyId, *sig.IssuerKeyId)
   646  		subpackets = append(subpackets, outputSubpacket{true, issuerSubpacket, false, keyId})
   647  	}
   648  
   649  	if sig.SigLifetimeSecs != nil && *sig.SigLifetimeSecs != 0 {
   650  		sigLifetime := make([]byte, 4)
   651  		binary.BigEndian.PutUint32(sigLifetime, *sig.SigLifetimeSecs)
   652  		subpackets = append(subpackets, outputSubpacket{true, signatureExpirationSubpacket, true, sigLifetime})
   653  	}
   654  
   655  	// Key flags may only appear in self-signatures or certification signatures.
   656  
   657  	if sig.FlagsValid {
   658  		var flags byte
   659  		if sig.FlagCertify {
   660  			flags |= KeyFlagCertify
   661  		}
   662  		if sig.FlagSign {
   663  			flags |= KeyFlagSign
   664  		}
   665  		if sig.FlagEncryptCommunications {
   666  			flags |= KeyFlagEncryptCommunications
   667  		}
   668  		if sig.FlagEncryptStorage {
   669  			flags |= KeyFlagEncryptStorage
   670  		}
   671  		subpackets = append(subpackets, outputSubpacket{true, keyFlagsSubpacket, false, []byte{flags}})
   672  	}
   673  
   674  	// The following subpackets may only appear in self-signatures
   675  
   676  	if sig.KeyLifetimeSecs != nil && *sig.KeyLifetimeSecs != 0 {
   677  		keyLifetime := make([]byte, 4)
   678  		binary.BigEndian.PutUint32(keyLifetime, *sig.KeyLifetimeSecs)
   679  		subpackets = append(subpackets, outputSubpacket{true, keyExpirationSubpacket, true, keyLifetime})
   680  	}
   681  
   682  	if sig.IsPrimaryId != nil && *sig.IsPrimaryId {
   683  		subpackets = append(subpackets, outputSubpacket{true, primaryUserIdSubpacket, false, []byte{1}})
   684  	}
   685  
   686  	if len(sig.PreferredSymmetric) > 0 {
   687  		subpackets = append(subpackets, outputSubpacket{true, prefSymmetricAlgosSubpacket, false, sig.PreferredSymmetric})
   688  	}
   689  
   690  	if len(sig.PreferredHash) > 0 {
   691  		subpackets = append(subpackets, outputSubpacket{true, prefHashAlgosSubpacket, false, sig.PreferredHash})
   692  	}
   693  
   694  	if len(sig.PreferredCompression) > 0 {
   695  		subpackets = append(subpackets, outputSubpacket{true, prefCompressionSubpacket, false, sig.PreferredCompression})
   696  	}
   697  
   698  	return
   699  }