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