Skip to content

Commit b8a0f4b

Browse files
maxtacobradfitz
authored andcommitted
openpgp: Allow V3 signatures in messages
Previously, only V4 signatures were allowed in PGP messages, and attempts to digest a message with a V3 signature would yield an `errors.StructuralError("LiteralData not followed by Signature")`. This patch fixes this shortcoming, by trying to consume either signature type and verifying accordingly. Change-Id: I27c8ea781b75b0f7dfc42c01e7de40f3323e9579 Reviewed-on: https://go-review.googlesource.com/14794 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 9e7f5dc commit b8a0f4b

File tree

2 files changed

+86
-5
lines changed

2 files changed

+86
-5
lines changed

openpgp/read.go

+8-5
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ type MessageDetails struct {
5656
// been consumed. Once EOF has been seen, the following fields are
5757
// valid. (An authentication code failure is reported as a
5858
// SignatureError error when reading from UnverifiedBody.)
59-
SignatureError error // nil if the signature is good.
60-
Signature *packet.Signature // the signature packet itself.
59+
SignatureError error // nil if the signature is good.
60+
Signature *packet.Signature // the signature packet itself, if v4 (default)
61+
SignatureV3 *packet.SignatureV3 // the signature packet if it is a v2 or v3 signature
6162

6263
decrypted io.ReadCloser
6364
}
@@ -334,13 +335,15 @@ func (scr *signatureCheckReader) Read(buf []byte) (n int, err error) {
334335
}
335336

336337
var ok bool
337-
if scr.md.Signature, ok = p.(*packet.Signature); !ok {
338+
if scr.md.Signature, ok = p.(*packet.Signature); ok {
339+
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
340+
} else if scr.md.SignatureV3, ok = p.(*packet.SignatureV3); ok {
341+
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignatureV3(scr.h, scr.md.SignatureV3)
342+
} else {
338343
scr.md.SignatureError = errors.StructuralError("LiteralData not followed by Signature")
339344
return
340345
}
341346

342-
scr.md.SignatureError = scr.md.SignedBy.PublicKey.VerifySignature(scr.h, scr.md.Signature)
343-
344347
// The SymmetricallyEncrypted packet, if any, might have an
345348
// unsigned hash of its own. In order to check this we need to
346349
// close that Reader.

openpgp/read_test.go

+78
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"strings"
1414
"testing"
1515

16+
"golang.org/x/crypto/openpgp/armor"
1617
"golang.org/x/crypto/openpgp/errors"
1718
)
1819

@@ -433,6 +434,50 @@ func TestIssue11504(t *testing.T) {
433434
testReadMessageError(t, "9303000130303030303030303030983002303030303030030000000130")
434435
}
435436

437+
// TestSignatureV3Message tests the verification of V3 signature, generated
438+
// with a modern V4-style key. Some people have their clients set to generate
439+
// V3 signatures, so it's useful to be able to verify them.
440+
func TestSignatureV3Message(t *testing.T) {
441+
sig, err := armor.Decode(strings.NewReader(signedMessageV3))
442+
if err != nil {
443+
t.Error(err)
444+
return
445+
}
446+
key, err := ReadArmoredKeyRing(strings.NewReader(keyV4forVerifyingSignedMessageV3))
447+
if err != nil {
448+
t.Error(err)
449+
return
450+
}
451+
md, err := ReadMessage(sig.Body, key, nil, nil)
452+
if err != nil {
453+
t.Error(err)
454+
return
455+
}
456+
457+
_, err = ioutil.ReadAll(md.UnverifiedBody)
458+
if err != nil {
459+
t.Error(err)
460+
return
461+
}
462+
463+
// We'll see a sig error here after reading in the UnverifiedBody above,
464+
// if there was one to see.
465+
if err = md.SignatureError; err != nil {
466+
t.Error(err)
467+
return
468+
}
469+
470+
if md.SignatureV3 == nil {
471+
t.Errorf("No available signature after checking signature")
472+
return
473+
}
474+
if md.Signature != nil {
475+
t.Errorf("Did not expect a signature V4 back")
476+
return
477+
}
478+
return
479+
}
480+
436481
const testKey1KeyId = 0xA34D7E18C20C31BB
437482
const testKey3KeyId = 0x338934250CCC0360
438483
const testKeyP256KeyId = 0xd44a2c495918513e
@@ -533,3 +578,36 @@ const unknownHashFunctionHex = `8a00000040040001990006050253863c24000a09103b4fe6
533578
const missingHashFunctionHex = `8a00000040040001030006050253863c24000a09103b4fe6acc0b21f32ffff0101010101010101010101010101010101010101010101010101010101010101010101010101`
534579

535580
const campbellQuine = `a0b001000300fcffa0b001000d00f2ff000300fcffa0b001000d00f2ff8270a01c00000500faff8270a01c00000500faff000500faff001400ebff8270a01c00000500faff000500faff001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400001400ebff428821c400000000ffff000000ffff000b00f4ff428821c400000000ffff000000ffff000b00f4ff0233214c40000100feff000233214c40000100feff0000`
581+
582+
const keyV4forVerifyingSignedMessageV3 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
583+
Comment: GPGTools - https://gpgtools.org
584+
585+
mI0EVfxoFQEEAMBIqmbDfYygcvP6Phr1wr1XI41IF7Qixqybs/foBF8qqblD9gIY
586+
BKpXjnBOtbkcVOJ0nljd3/sQIfH4E0vQwK5/4YRQSI59eKOqd6Fx+fWQOLG+uu6z
587+
tewpeCj9LLHvibx/Sc7VWRnrznia6ftrXxJ/wHMezSab3tnGC0YPVdGNABEBAAG0
588+
JEdvY3J5cHRvIFRlc3QgS2V5IDx0aGVtYXhAZ21haWwuY29tPoi5BBMBCgAjBQJV
589+
/GgVAhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQeXnQmhdGW9PFVAP+
590+
K7TU0qX5ArvIONIxh/WAweyOk884c5cE8f+3NOPOOCRGyVy0FId5A7MmD5GOQh4H
591+
JseOZVEVCqlmngEvtHZb3U1VYtVGE5WZ+6rQhGsMcWP5qaT4soYwMBlSYxgYwQcx
592+
YhN9qOr292f9j2Y//TTIJmZT4Oa+lMxhWdqTfX+qMgG4jQRV/GgVAQQArhFSiij1
593+
b+hT3dnapbEU+23Z1yTu1DfF6zsxQ4XQWEV3eR8v+8mEDDNcz8oyyF56k6UQ3rXi
594+
UMTIwRDg4V6SbZmaFbZYCOwp/EmXJ3rfhm7z7yzXj2OFN22luuqbyVhuL7LRdB0M
595+
pxgmjXb4tTvfgKd26x34S+QqUJ7W6uprY4sAEQEAAYifBBgBCgAJBQJV/GgVAhsM
596+
AAoJEHl50JoXRlvT7y8D/02ckx4OMkKBZo7viyrBw0MLG92i+DC2bs35PooHR6zz
597+
786mitjOp5z2QWNLBvxC70S0qVfCIz8jKupO1J6rq6Z8CcbLF3qjm6h1omUBf8Nd
598+
EfXKD2/2HV6zMKVknnKzIEzauh+eCKS2CeJUSSSryap/QLVAjRnckaES/OsEWhNB
599+
=RZia
600+
-----END PGP PUBLIC KEY BLOCK-----
601+
`
602+
603+
const signedMessageV3 = `-----BEGIN PGP MESSAGE-----
604+
Comment: GPGTools - https://gpgtools.org
605+
606+
owGbwMvMwMVYWXlhlrhb9GXG03JJDKF/MtxDMjKLFYAoUaEktbhEITe1uDgxPVWP
607+
q5NhKjMrWAVcC9evD8z/bF/uWNjqtk/X3y5/38XGRQHm/57rrDRYuGnTw597Xqka
608+
uM3137/hH3Os+Jf2dc0fXOITKwJvXJvecPVs0ta+Vg7ZO1MLn8w58Xx+6L58mbka
609+
DGHyU9yTueZE8D+QF/Tz28Y78dqtF56R1VPn9Xw4uJqrWYdd7b3vIZ1V6R4Nh05d
610+
iT57d/OhWwA=
611+
=hG7R
612+
-----END PGP MESSAGE-----
613+
`

0 commit comments

Comments
 (0)