diff --git a/openpgp/packet/signature.go b/openpgp/packet/signature.go index 420625386..b643ed6e7 100644 --- a/openpgp/packet/signature.go +++ b/openpgp/packet/signature.go @@ -331,6 +331,7 @@ type signatureSubpacketType uint8 const ( creationTimeSubpacket signatureSubpacketType = 2 signatureExpirationSubpacket signatureSubpacketType = 3 + exportableCertSubpacket signatureSubpacketType = 4 trustSubpacket signatureSubpacketType = 5 regularExpressionSubpacket signatureSubpacketType = 6 keyExpirationSubpacket signatureSubpacketType = 9 @@ -418,6 +419,11 @@ func parseSignatureSubpacket(sig *Signature, subpacket []byte, isHashed bool) (r } sig.SigLifetimeSecs = new(uint32) *sig.SigLifetimeSecs = binary.BigEndian.Uint32(subpacket) + case exportableCertSubpacket: + if subpacket[0] == 0 { + err = errors.UnsupportedError("signature with non-exportable certification") + return + } case trustSubpacket: if len(subpacket) != 2 { err = errors.StructuralError("trust subpacket with bad length") diff --git a/openpgp/packet/signature_test.go b/openpgp/packet/signature_test.go index 20a5e17f7..5443243f2 100644 --- a/openpgp/packet/signature_test.go +++ b/openpgp/packet/signature_test.go @@ -324,6 +324,29 @@ func TestSignatureWithTrustAndRegex(t *testing.T) { } } +func TestCanParseSignatureWithExportableCert(t *testing.T) { + packet, err := Read(readerFromHex(signatureWithExportableCertHex)) + if err != nil { + t.Error(err) + return + } + + _, ok := packet.(*Signature) + if !ok { + t.Errorf("failed to parse, got: %#v", packet) + } +} + +func TestCannotParseSignatureWithNonExportableCert(t *testing.T) { + _, err := Read(readerFromHex(signatureWithNonExportableCertHex)) + if err == nil { + t.Errorf("did not receive an error when expected") + } + if err.Error() != "openpgp: unsupported feature: signature with non-exportable certification" { + t.Errorf("unexpected error while parsing: %v", err) + } +} + const onePassSignatureDataHex = `c40d03000201ab105c91af38fb1501` const signatureDataHex = "c2c05c04000102000605024cb45112000a0910ab105c91af38fb158f8d07ff5596ea368c5efe015bed6e78348c0f033c931d5f2ce5db54ce7f2a7e4b4ad64db758d65a7a71773edeab7ba2a9e0908e6a94a1175edd86c1d843279f045b021a6971a72702fcbd650efc393c5474d5b59a15f96d2eaad4c4c426797e0dcca2803ef41c6ff234d403eec38f31d610c344c06f2401c262f0993b2e66cad8a81ebc4322c723e0d4ba09fe917e8777658307ad8329adacba821420741009dfe87f007759f0982275d028a392c6ed983a0d846f890b36148c7358bdb8a516007fac760261ecd06076813831a36d0459075d1befa245ae7f7fb103d92ca759e9498fe60ef8078a39a3beda510deea251ea9f0a7f0df6ef42060f20780360686f3e400e" @@ -335,3 +358,7 @@ const signatureWithTrustRegexHex = "c2bd0410010800310502886e09001621040f0bfb42b3 const signatureWithBadTrustRegexHex = "c2bc0410010800300502886e09001621040f0bfb42b3b08bece556fffcc181c053de849bf20385013c0e862a2e6578616d706c652e636f6d00007e7103fe3fa66963f7a91ceb297286f57bab38446ba591215a9d6589ab6ec0d930438a4d79f80a52440e017dc6dd03f7425ccc1e059edda2b32f4975501eacc5676f216e56c568b75442c3efc750425f0d5276c7611ef838ce3f015f4de0969b4710aac8a76fcf2d48dd0749e937099b55ab77d93132e9777ba3b8cf89f908c2dbfff838" const positiveCertSignatureDataHex = "c2c0b304130108005d050b0908070206150a09080b020416020301021e010217802418686b70733a2f2f686b70732e706f6f6c2e736b732d6b6579736572766572732e6e65741621045ef9b8a44d89b32f94f3e9333679666422d0f62605025b2cc122021b2f000a09103679666422d0f62668e1080098b71f59ce893769ccb603344290e89df8f12d6ea906cc1c2b166c61a02679070744565f8280712b4e6bdfd482b758ef935655f1674c8f3633ab173d27cbe31e46368a8255134ecc5249ad66324cc4f6a79f160459b326711cfdc35032aac0903657a934f80f79768786ddd6554aa8d385c03adbee17c4e3e2831752d4910077da3b1f5562d267a57540a1c2b0dd2d96ed055c06098599b2390d61cfa37c6d19d9d63749fb3c3cfe0036fd959ba616eb23486216563fed8fdd19f96f5da9943db1698705fb688c1354c379ef01de307c4a0ac016e6385324cb0a7b49cfeee8961a289c8fa4c81d0e24e00969039db223a9835e8b86a8d85df645175f8aa0f8f2" + +const signatureWithExportableCertHex = "c2c07404130102001e050263fde196050903c3b880021b26030b0309021601041508090a028401000a09101bf1d93a68a8b208342b07ff6f59f5a882d148c481b877b434271b2e844e0dd783d9eb5534aac51170024382089cf07194a1835c72177d677a7ce04a614c1f85ccf5972d08ebabdfefefbe9d0f2b9f0a0a010c0889d9ab43ec99ccaddf76f7a96d91c49256ae23078a22469fd2a3d1d2ccfb30eb4f137e8c893731163e8f7aa18abb6a72ebfbab71ac8946f991d0a10d0293bc275183f67567c709bdd7e035d16c3cb2d14565b8baccaf721a3e1ed59385fc4b248648bdf7072a07ed693caf9179ea980fa8f89bef9c6819870c0074aa0419bf80e073863fe4cfe144a3083586d05f3ce8277d891dc11aa157dd133ac8d2dab4e8095affe6f3d3be673d2392c9177102374f51c56199dd3c05" + +const signatureWithNonExportableCertHex = "c2c07404130102001e050263fde196050903c3b880021b26030b0309021601041508090a028400000a09101bf1d93a68a8b208342b07ff6f59f5a882d148c481b877b434271b2e844e0dd783d9eb5534aac51170024382089cf07194a1835c72177d677a7ce04a614c1f85ccf5972d08ebabdfefefbe9d0f2b9f0a0a010c0889d9ab43ec99ccaddf76f7a96d91c49256ae23078a22469fd2a3d1d2ccfb30eb4f137e8c893731163e8f7aa18abb6a72ebfbab71ac8946f991d0a10d0293bc275183f67567c709bdd7e035d16c3cb2d14565b8baccaf721a3e1ed59385fc4b248648bdf7072a07ed693caf9179ea980fa8f89bef9c6819870c0074aa0419bf80e073863fe4cfe144a3083586d05f3ce8277d891dc11aa157dd133ac8d2dab4e8095affe6f3d3be673d2392c9177102374f51c56199dd3c05"