Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/boringssl.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/err/ssl.errordata1
-rw-r--r--include/openssl/ssl.h1
-rw-r--r--ssl/d1_both.c19
-rw-r--r--ssl/dtls_method.c33
-rw-r--r--ssl/internal.h20
-rw-r--r--ssl/t1_enc.c7
-rw-r--r--ssl/test/runner/common.go8
-rw-r--r--ssl/test/runner/dtls.go6
-rw-r--r--ssl/test/runner/handshake_client.go5
-rw-r--r--ssl/test/runner/handshake_server.go5
-rw-r--r--ssl/test/runner/runner.go21
-rw-r--r--ssl/tls_method.c25
-rw-r--r--ssl/tls_record.c23
13 files changed, 132 insertions, 42 deletions
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index f211a24f..f9d557e6 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -19,6 +19,7 @@ SSL,117,BAD_SSL_FILETYPE
SSL,118,BAD_WRITE_RETRY
SSL,119,BIO_NOT_SET
SSL,120,BN_LIB
+SSL,255,BUFFERED_MESSAGES_ON_CIPHER_CHANGE
SSL,121,BUFFER_TOO_SMALL
SSL,122,CA_DN_LENGTH_MISMATCH
SSL,123,CA_DN_TOO_LONG
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index cb5a65f6..44026aa5 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4714,6 +4714,7 @@ OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method);
#define SSL_R_UNSUPPORTED_PROTOCOL_FOR_CUSTOM_KEY 252
#define SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS 253
#define SSL_R_DOWNGRADE_DETECTED 254
+#define SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE 255
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 2248f8cd..331703ad 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -256,7 +256,7 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start,
/* dtls1_is_current_message_complete returns one if the current handshake
* message is complete and zero otherwise. */
-static int dtls1_is_current_message_complete(SSL *ssl) {
+static int dtls1_is_current_message_complete(const SSL *ssl) {
hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
SSL_MAX_HANDSHAKE_FLIGHT];
return frag != NULL && frag->reassembly == NULL;
@@ -457,13 +457,26 @@ int dtls1_hash_current_message(SSL *ssl) {
}
void dtls_clear_incoming_messages(SSL *ssl) {
- size_t i;
- for (i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
+ for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
dtls1_hm_fragment_free(ssl->d1->incoming_messages[i]);
ssl->d1->incoming_messages[i] = NULL;
}
}
+int dtls_has_incoming_messages(const SSL *ssl) {
+ /* This function may not be called if there is a pending |dtls1_get_message|
+ * operation. */
+ assert(dtls1_is_current_message_complete(ssl));
+
+ size_t current = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT;
+ for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) {
+ if (i != current && ssl->d1->incoming_messages[i] != NULL) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr,
CBS *out_body) {
memset(out_hdr, 0x00, sizeof(struct hm_header_st));
diff --git a/ssl/dtls_method.c b/ssl/dtls_method.c
index 09c7d407..16ad684f 100644
--- a/ssl/dtls_method.c
+++ b/ssl/dtls_method.c
@@ -57,8 +57,10 @@
#include <openssl/ssl.h>
#include <assert.h>
+#include <string.h>
#include <openssl/buf.h>
+#include <openssl/err.h>
#include "internal.h"
@@ -100,6 +102,35 @@ static void dtls1_finish_handshake(SSL *ssl) {
dtls_clear_incoming_messages(ssl);
}
+static int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ /* Cipher changes are illegal when there are buffered incoming messages. */
+ if (dtls_has_incoming_messages(ssl)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFERED_MESSAGES_ON_CIPHER_CHANGE);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ SSL_AEAD_CTX_free(aead_ctx);
+ return 0;
+ }
+
+ ssl->d1->r_epoch++;
+ memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
+ memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ ssl->s3->aead_read_ctx = aead_ctx;
+ return 1;
+}
+
+static int dtls1_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ ssl->d1->w_epoch++;
+ memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
+ sizeof(ssl->s3->write_sequence));
+ memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ ssl->s3->aead_write_ctx = aead_ctx;
+ return 1;
+}
+
static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
1 /* is_dtls */,
TLS1_1_VERSION,
@@ -124,6 +155,8 @@ static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
dtls1_send_change_cipher_spec,
dtls1_expect_flight,
dtls1_received_flight,
+ dtls1_set_read_state,
+ dtls1_set_write_state,
};
const SSL_METHOD *DTLS_method(void) {
diff --git a/ssl/internal.h b/ssl/internal.h
index d2cb04c5..5620c53b 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -446,14 +446,6 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
uint8_t type, const uint8_t *in, size_t in_len,
enum dtls1_use_epoch_t use_epoch);
-/* ssl_set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes
- * ownership of |aead_ctx|. */
-void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
-
-/* ssl_set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes
- * ownership of |aead_ctx|. */
-void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
-
/* ssl_process_alert processes |in| as an alert and updates |ssl|'s shutdown
* state. It returns one of |ssl_open_record_discard|, |ssl_open_record_error|,
* |ssl_open_record_close_notify|, or |ssl_open_record_fatal_alert| as
@@ -658,6 +650,10 @@ size_t ssl_max_handshake_message_len(const SSL *ssl);
/* dtls_clear_incoming_messages releases all buffered incoming messages. */
void dtls_clear_incoming_messages(SSL *ssl);
+/* dtls_has_incoming_messages returns one if there are buffered incoming
+ * messages ahead of the current message and zero otherwise. */
+int dtls_has_incoming_messages(const SSL *ssl);
+
typedef struct dtls_outgoing_message_st {
uint8_t *data;
uint32_t len;
@@ -913,6 +909,14 @@ struct ssl_protocol_method_st {
/* received_flight is called when the handshake has received a flight of
* messages from the peer. */
void (*received_flight)(SSL *ssl);
+ /* set_read_state sets |ssl|'s read cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. It returns one on success and zero if changing the
+ * read state is forbidden at this point. */
+ int (*set_read_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
+ /* set_write_state sets |ssl|'s write cipher state to |aead_ctx|. It takes
+ * ownership of |aead_ctx|. It returns one on success and zero if changing the
+ * write state is forbidden at this point. */
+ int (*set_write_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx);
};
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 453adf34..053196dc 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -313,11 +313,10 @@ int tls1_change_cipher_state(SSL *ssl, int which) {
}
if (is_read) {
- ssl_set_read_state(ssl, aead_ctx);
- } else {
- ssl_set_write_state(ssl, aead_ctx);
+ return ssl->method->set_read_state(ssl, aead_ctx);
}
- return 1;
+
+ return ssl->method->set_write_state(ssl, aead_ctx);
}
size_t SSL_get_key_block_len(const SSL *ssl) {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 841bc8fd..e7bc9bdf 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -512,6 +512,10 @@ type ProtocolBugs struct {
// messages.
FragmentAcrossChangeCipherSpec bool
+ // SendUnencryptedFinished, if true, causes the Finished message to be
+ // send unencrypted before ChangeCipherSpec rather than after it.
+ SendUnencryptedFinished bool
+
// SendV2ClientHello causes the client to send a V2ClientHello
// instead of a normal ClientHello.
SendV2ClientHello bool
@@ -709,6 +713,10 @@ type ProtocolBugs struct {
// Finished and will trigger a spurious retransmit.)
ReorderHandshakeFragments bool
+ // ReverseHandshakeFragments, if true, causes handshake fragments in
+ // DTLS to be reversed within a flight.
+ ReverseHandshakeFragments bool
+
// MixCompleteMessageWithFragments, if true, causes handshake
// messages in DTLS to redundantly both fragment the message
// and include a copy of the full one.
diff --git a/ssl/test/runner/dtls.go b/ssl/test/runner/dtls.go
index 48b8a1b2..b873ae6d 100644
--- a/ssl/test/runner/dtls.go
+++ b/ssl/test/runner/dtls.go
@@ -254,6 +254,12 @@ func (c *Conn) dtlsFlushHandshake() error {
tmp[i] = fragments[perm[i]]
}
fragments = tmp
+ } else if c.config.Bugs.ReverseHandshakeFragments {
+ tmp := make([][]byte, len(fragments))
+ for i := range tmp {
+ tmp[i] = fragments[len(fragments)-i-1]
+ }
+ fragments = tmp
}
maxRecordLen := c.config.Bugs.PackHandshakeFragments
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index bc8c1d0a..a357c1fa 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -1206,6 +1206,9 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
if c.config.Bugs.FragmentAcrossChangeCipherSpec {
c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
postCCSBytes = postCCSBytes[5:]
+ } else if c.config.Bugs.SendUnencryptedFinished {
+ c.writeRecord(recordTypeHandshake, postCCSBytes)
+ postCCSBytes = nil
}
c.flushHandshake()
@@ -1226,7 +1229,7 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
return errors.New("tls: simulating post-CCS alert")
}
- if !c.config.Bugs.SkipFinished {
+ if !c.config.Bugs.SkipFinished && len(postCCSBytes) > 0 {
c.writeRecord(recordTypeHandshake, postCCSBytes)
c.flushHandshake()
}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 2cdfbee0..50f9b7c3 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -1261,6 +1261,9 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
if c.config.Bugs.FragmentAcrossChangeCipherSpec {
c.writeRecord(recordTypeHandshake, postCCSBytes[:5])
postCCSBytes = postCCSBytes[5:]
+ } else if c.config.Bugs.SendUnencryptedFinished {
+ c.writeRecord(recordTypeHandshake, postCCSBytes)
+ postCCSBytes = nil
}
c.flushHandshake()
@@ -1280,7 +1283,7 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
return errors.New("tls: simulating post-CCS alert")
}
- if !c.config.Bugs.SkipFinished {
+ if !c.config.Bugs.SkipFinished && len(postCCSBytes) > 0 {
c.writeRecord(recordTypeHandshake, postCCSBytes)
c.flushHandshake()
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 5393b5b1..a222021c 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -6175,8 +6175,6 @@ func addChangeCipherSpecTests() {
// rejected. Test both with and without handshake packing to handle both
// when the partial post-CCS message is in its own record and when it is
// attached to the pre-CCS message.
- //
- // TODO(davidben): Fix and test DTLS as well.
for _, packed := range []bool{false, true} {
var suffix string
if packed {
@@ -6260,6 +6258,25 @@ func addChangeCipherSpecTests() {
})
}
+ // Test that, in DTLS, ChangeCipherSpec is not allowed when there are
+ // messages in the handshake queue. Do this by testing the server
+ // reading the client Finished, reversing the flight so Finished comes
+ // first.
+ testCases = append(testCases, testCase{
+ protocol: dtls,
+ testType: serverTest,
+ name: "SendUnencryptedFinished-DTLS",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendUnencryptedFinished: true,
+ ReverseHandshakeFragments: true,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":BUFFERED_MESSAGES_ON_CIPHER_CHANGE:",
+ })
+
// Test that early ChangeCipherSpecs are handled correctly.
testCases = append(testCases, testCase{
testType: serverTest,
diff --git a/ssl/tls_method.c b/ssl/tls_method.c
index 17905a9f..ccf4f988 100644
--- a/ssl/tls_method.c
+++ b/ssl/tls_method.c
@@ -56,6 +56,9 @@
#include <openssl/ssl.h>
+#include <assert.h>
+#include <string.h>
+
#include <openssl/buf.h>
#include "internal.h"
@@ -89,6 +92,26 @@ static void ssl3_finish_handshake(SSL *ssl) {
ssl->init_num = 0;
}
+static int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ /* TODO(davidben): In TLS 1.3, cipher changes are not always preceeded by a
+ * ChangeCipherSpec, so this must become a runtime check. */
+ assert(ssl->s3->rrec.length == 0);
+
+ memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
+ ssl->s3->aead_read_ctx = aead_ctx;
+ return 1;
+}
+
+static int ssl3_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
+ memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
+
+ SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
+ ssl->s3->aead_write_ctx = aead_ctx;
+ return 1;
+}
+
static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
0 /* is_dtls */,
SSL3_VERSION,
@@ -113,6 +136,8 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
ssl3_send_change_cipher_spec,
ssl3_expect_flight,
ssl3_received_flight,
+ ssl3_set_read_state,
+ ssl3_set_write_state,
};
const SSL_METHOD *TLS_method(void) {
diff --git a/ssl/tls_record.c b/ssl/tls_record.c
index e357ed98..38979589 100644
--- a/ssl/tls_record.c
+++ b/ssl/tls_record.c
@@ -406,29 +406,6 @@ int tls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out,
return 1;
}
-void ssl_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
- if (SSL_IS_DTLS(ssl)) {
- ssl->d1->r_epoch++;
- memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap));
- }
- memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence));
-
- SSL_AEAD_CTX_free(ssl->s3->aead_read_ctx);
- ssl->s3->aead_read_ctx = aead_ctx;
-}
-
-void ssl_set_write_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) {
- if (SSL_IS_DTLS(ssl)) {
- ssl->d1->w_epoch++;
- memcpy(ssl->d1->last_write_sequence, ssl->s3->write_sequence,
- sizeof(ssl->s3->write_sequence));
- }
- memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence));
-
- SSL_AEAD_CTX_free(ssl->s3->aead_write_ctx);
- ssl->s3->aead_write_ctx = aead_ctx;
-}
-
enum ssl_open_record_t ssl_process_alert(SSL *ssl, uint8_t *out_alert,
const uint8_t *in, size_t in_len) {
/* Alerts records may not contain fragmented or multiple alerts. */