Clear the error queue when dropping a bad DTLS packet.
This regressed in e95d20dcb80523bf9bc6a9c5682856c8371e0a96. EVP_AEAD will push
errors on the error queue (unlike the EVP_CIPHER codepath which checked
everything internally to ssl/ and didn't bother pushing anything). This meant
that a dropped packet would leave junk in the error queue.
Later, when SSL_read returns <= 0 (EOF or EWOULDBLOCK), the non-empty error
queue check in SSL_get_error kicks in and SSL_read looks to have failed.
BUG=https://code.google.com/p/webrtc/issues/detail?id=4214
Change-Id: I1e5e41c77a3e5b71e9eb0c72294abf0da677f840
Reviewed-on: https://boringssl-review.googlesource.com/2982
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 1d3236f..a77ad4e 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -357,7 +357,9 @@
rr->data = rr->input;
if (!s->enc_method->enc(s, 0)) {
- /* For DTLS we simply ignore bad packets. */
+ /* Bad packets are silently dropped in DTLS. Clear the error queue of any
+ * errors decryption may have added. */
+ ERR_clear_error();
rr->length = 0;
s->packet_length = 0;
goto err;
diff --git a/ssl/test/runner/packet_adapter.go b/ssl/test/runner/packet_adapter.go
index 4f36eb1..671b413 100644
--- a/ssl/test/runner/packet_adapter.go
+++ b/ssl/test/runner/packet_adapter.go
@@ -76,3 +76,26 @@
return n, err
}
+
+type damageAdaptor struct {
+ net.Conn
+ damage bool
+}
+
+// newDamageAdaptor wraps a packeted net.Conn. It transforms it into one which
+// optionally damages the final byte of every Write() call.
+func newDamageAdaptor(conn net.Conn) *damageAdaptor {
+ return &damageAdaptor{Conn: conn}
+}
+
+func (d *damageAdaptor) setDamage(damage bool) {
+ d.damage = damage
+}
+
+func (d *damageAdaptor) Write(b []byte) (int, error) {
+ if d.damage && len(b) > 0 {
+ b = append([]byte{}, b...)
+ b[len(b)-1]++
+ }
+ return d.Conn.Write(b)
+}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 3e1e7b4..e298725 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -178,6 +178,9 @@
// replayWrites, if true, configures the underlying transport
// to replay every write it makes in DTLS tests.
replayWrites bool
+ // damageFirstWrite, if true, configures the underlying transport to
+ // damage the final byte of the first application data write.
+ damageFirstWrite bool
// flags, if not empty, contains a list of command-line flags that will
// be passed to the shim program.
flags []string
@@ -612,10 +615,28 @@
shouldFail: true,
expectedError: ":WRONG_CERTIFICATE_TYPE:",
},
+ {
+ name: "TLSFatalBadPackets",
+ damageFirstWrite: true,
+ shouldFail: true,
+ expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets",
+ damageFirstWrite: true,
+ },
+ {
+ protocol: dtls,
+ name: "DTLSIgnoreBadPackets-Async",
+ damageFirstWrite: true,
+ flags: []string{"-async"},
+ },
}
func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, isResume bool) error {
var connDebug *recordingConn
+ var connDamage *damageAdaptor
if *flagDebug {
connDebug = &recordingConn{Conn: conn}
conn = connDebug
@@ -631,6 +652,11 @@
}
}
+ if test.damageFirstWrite {
+ connDamage = newDamageAdaptor(conn)
+ conn = connDamage
+ }
+
if test.sendPrefix != "" {
if _, err := conn.Write([]byte(test.sendPrefix)); err != nil {
return err
@@ -718,6 +744,12 @@
panic("renegotiateCiphers without renegotiate")
}
+ if test.damageFirstWrite {
+ connDamage.setDamage(true)
+ tlsConn.Write([]byte("DAMAGED WRITE"))
+ connDamage.setDamage(false)
+ }
+
if messageLen < 0 {
if test.protocol == dtls {
return fmt.Errorf("messageLen < 0 not supported for DTLS tests")