signature.go 18 KB

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