Skip to content

Commit

Permalink
Optionally allow reading messages without MDC (#130)
Browse files Browse the repository at this point in the history
Add config option `InsecureAllowUnauthenticatedMessages` to optionally
allow reading messages without an MDC (authentication tag).
This is meant only for reading very old legacy messages.
The decrypted message contents of such messages should not be trusted or
automatically processed.
  • Loading branch information
aksdb authored Sep 30, 2022
1 parent 4b6e5c5 commit c6815a8
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 4 deletions.
16 changes: 16 additions & 0 deletions openpgp/packet/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ type Config struct {
// when producing a generic certification signature onto an existing user ID.
// The identity must be present in the signer Entity.
SigningIdentity string
// InsecureAllowUnauthenticatedMessages controls, whether it is tolerated to read
// encrypted messages without Modification Detection Code (MDC).
// MDC is mandated by the IETF OpenPGP Crypto Refresh draft and has long been implemented
// in most OpenPGP implementations. Messages without MDC are considered unnecessarily
// insecure and should be prevented whenever possible.
// In case one needs to deal with messages from very old OpenPGP implementations, there
// might be no other way than to tolerate the missing MDC. Setting this flag, allows this
// mode of operation. It should be considered a measure of last resort.
InsecureAllowUnauthenticatedMessages bool
}

func (c *Config) Random() io.Reader {
Expand Down Expand Up @@ -186,3 +195,10 @@ func (c *Config) SigningUserId() string {
}
return c.SigningIdentity
}

func (c *Config) AllowUnauthenticatedMessages() bool {
if c == nil {
return false
}
return c.InsecureAllowUnauthenticatedMessages
}
2 changes: 0 additions & 2 deletions openpgp/packet/symmetrically_encrypted.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
if buf[0] != symmetricallyEncryptedVersion {
return errors.UnsupportedError("unknown SymmetricallyEncrypted version")
}
} else {
return errors.UnsupportedError("Symmetrically encrypted packets without MDC are not supported")
}
se.Contents = r
return nil
Expand Down
10 changes: 8 additions & 2 deletions openpgp/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,14 @@ ParsePackets:
pubKeys = append(pubKeys, keyEnvelopePair{k, p})
}
}
case *packet.SymmetricallyEncrypted, *packet.AEADEncrypted:
edp = p.(packet.EncryptedDataPacket)
case *packet.SymmetricallyEncrypted:
if !p.MDC && !config.AllowUnauthenticatedMessages() {
return nil, errors.UnsupportedError("message is not authenticated")
}
edp = p
break ParsePackets
case *packet.AEADEncrypted:
edp = p
break ParsePackets
case *packet.Compressed, *packet.LiteralData, *packet.OnePassSignature:
// This message isn't encrypted.
Expand Down
53 changes: 53 additions & 0 deletions openpgp/read_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -716,3 +716,56 @@ func TestCorruptedMessageWrongLength(t *testing.T) {
t.Errorf("Expected error '%s', but got error '%s'", expectedErr, err)
}
}

func TestMessageWithoutMdc(t *testing.T) {
armored, err := os.Open("test_data/aead-ocb-asym-key.asc")
if err != nil {
t.Fatal(err)
}
defer armored.Close()

el, err := ReadArmoredKeyRing(armored)
if err != nil {
t.Fatal(err)
}

armoredMessageWithoutMdc, err := ioutil.ReadFile("test_data/sym-message-without-mdc.asc")
if err != nil {
t.Fatal(err)
}

t.Run("fails with InsecureAllowUnauthenticatedMessages disabled", func(t *testing.T) {
messageWithoutMdc, err := armor.Decode(bytes.NewReader(armoredMessageWithoutMdc))
if err != nil {
t.Fatal(err)
}

_, err = ReadMessage(messageWithoutMdc.Body, el, nil, nil)
if err == nil {
t.Fatal("reading the message should have failed")
}
})

t.Run("succeeds with InsecureAllowUnauthenticatedMessages enabled", func(t *testing.T) {
messageWithoutMdc, err := armor.Decode(bytes.NewReader(armoredMessageWithoutMdc))
if err != nil {
t.Fatal(err)
}

md, err := ReadMessage(messageWithoutMdc.Body, el, nil, &packet.Config{
InsecureAllowUnauthenticatedMessages: true,
})
if err != nil {
t.Fatal("reading the message should have worked")
}

b, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
t.Fatal("reading the message should have worked")
}

if !bytes.Equal(b, []byte("message without mdc\n")) {
t.Error("unexpected message content")
}
})
}
8 changes: 8 additions & 0 deletions openpgp/test_data/sym-message-without-mdc.asc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN PGP MESSAGE-----

hF4DaLVM+JXUh9ESAQdA7E42KKhtMn7vjYN+CIcoM4QMXODako4DQPYLwhYjHTow
hBVmQWk+WyyDjqB2yZEJPVTDYSvebBynwCGN9AFR6u5dXjFqtNNX6EJEJBzLLL2+
yUMNiMt8/ujn4y4GNaZEbFdf4+K/oQbz6fvQgNipWZGg2Ys0foHi50EzhTDyVG7s
nwkVrIpSuhaZLoqzxbizw5o6YVMc
=//7h
-----END PGP MESSAGE-----

0 comments on commit c6815a8

Please # to comment.