diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c index 69d0f0425..0cb0ba454 100644 --- a/ssl/d1_pkt.c +++ b/ssl/d1_pkt.c @@ -664,10 +664,11 @@ start: /* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by * ssl3_get_finished. */ - if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE) { - /* We now have application data between CCS and Finished. Most likely the - * packets were reordered on their way, so buffer the application data for - * later processing rather than dropping the connection. */ + if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE && + rr->type != SSL3_RT_ALERT) { + /* We now have an unexpected record between CCS and Finished. Most likely + * the packets were reordered on their way, so buffer the application data + * for later processing rather than dropping the connection. */ if (dtls1_buffer_record(s, &(s->d1->buffered_app_data), rr->seq_num) < 0) { OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, ERR_R_INTERNAL_ERROR); return -1; diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index d96e2c77d..1bf71413e 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -815,9 +815,10 @@ start: /* we now have a packet which can be read and processed */ - if (s->s3->change_cipher_spec /* set when we receive ChangeCipherSpec, - * reset by ssl3_get_finished */ - && rr->type != SSL3_RT_HANDSHAKE) { + /* |change_cipher_spec is set when we receive a ChangeCipherSpec and reset by + * ssl3_get_finished. */ + if (s->s3->change_cipher_spec && rr->type != SSL3_RT_HANDSHAKE && + rr->type != SSL3_RT_ALERT) { al = SSL_AD_UNEXPECTED_MESSAGE; OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED); diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 4aead4ec5..b8cc44acb 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -610,6 +610,10 @@ type ProtocolBugs struct { // be sent immediately after ChangeCipherSpec. AppDataAfterChangeCipherSpec []byte + // AlertAfterChangeCipherSpec, if non-zero, causes an alert to be sent + // immediately after ChangeCipherSpec. + AlertAfterChangeCipherSpec alert + // TimeoutSchedule is the schedule of packet drops and simulated // timeouts for before each handshake leg from the peer. TimeoutSchedule []time.Duration diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index 17cfc01fd..a4fab0c2d 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -863,6 +863,10 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error { if c.config.Bugs.AppDataAfterChangeCipherSpec != nil { c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec) } + if c.config.Bugs.AlertAfterChangeCipherSpec != 0 { + c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec) + return errors.New("tls: simulating post-CCS alert") + } if !c.config.Bugs.SkipFinished { c.writeRecord(recordTypeHandshake, postCCSBytes) diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index e1d49e5fb..9085fafb7 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -854,6 +854,10 @@ func (hs *serverHandshakeState) sendFinished() error { if c.config.Bugs.AppDataAfterChangeCipherSpec != nil { c.writeRecord(recordTypeApplicationData, c.config.Bugs.AppDataAfterChangeCipherSpec) } + if c.config.Bugs.AlertAfterChangeCipherSpec != 0 { + c.sendAlert(c.config.Bugs.AlertAfterChangeCipherSpec) + return errors.New("tls: simulating post-CCS alert") + } if !c.config.Bugs.SkipFinished { c.writeRecord(recordTypeHandshake, postCCSBytes) diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index dc27513c6..d1dbe8710 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -690,6 +690,27 @@ var testCases = []testCase{ }, }, }, + { + name: "AlertAfterChangeCipherSpec", + config: Config{ + Bugs: ProtocolBugs{ + AlertAfterChangeCipherSpec: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, + { + protocol: dtls, + name: "AlertAfterChangeCipherSpec-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + AlertAfterChangeCipherSpec: alertRecordOverflow, + }, + }, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }, { protocol: dtls, name: "ReorderHandshakeFragments-Small-DTLS",