Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1385917 - Enable different Content Type for ServerHello. r=mt
  • Loading branch information
ekr committed Aug 1, 2017
1 parent 7e6d9cb commit 0875aae
Show file tree
Hide file tree
Showing 14 changed files with 152 additions and 7 deletions.
1 change: 1 addition & 0 deletions cpputil/tls_parser.h
Expand Up @@ -24,6 +24,7 @@ const uint8_t kTlsChangeCipherSpecType = 20;
const uint8_t kTlsAlertType = 21;
const uint8_t kTlsHandshakeType = 22;
const uint8_t kTlsApplicationDataType = 23;
const uint8_t kTlsAltHandshakeType = 24;

const uint8_t kTlsHandshakeClientHello = 1;
const uint8_t kTlsHandshakeServerHello = 2;
Expand Down
27 changes: 27 additions & 0 deletions gtests/ssl_gtest/ssl_loopback_unittest.cc
Expand Up @@ -323,6 +323,33 @@ TEST_F(TlsConnectStreamTls13, NegotiateShortHeaders) {
Connect();
}

TEST_F(TlsConnectStreamTls13, ClientAltHandshakeType) {
client_->SetAltHandshakeTypeEnabled();
auto filter = std::make_shared<TlsHeaderRecorder>();
server_->SetPacketFilter(filter);
Connect();
ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
}

TEST_F(TlsConnectStreamTls13, ServerAltHandshakeType) {
server_->SetAltHandshakeTypeEnabled();
auto filter = std::make_shared<TlsHeaderRecorder>();
server_->SetPacketFilter(filter);
Connect();
ASSERT_EQ(kTlsHandshakeType, filter->header(0)->content_type());
}

TEST_F(TlsConnectStreamTls13, BothAltHandshakeType) {
client_->SetAltHandshakeTypeEnabled();
server_->SetAltHandshakeTypeEnabled();
auto filter = std::make_shared<TlsHeaderRecorder>();
server_->SetTlsRecordFilter(filter);
filter->EnableDecryption();
Connect();
ASSERT_EQ(kTlsAltHandshakeType, filter->header(0)->content_type());
ASSERT_EQ(kTlsHandshakeType, filter->header(1)->content_type());
}

INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGeneric,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
Expand Down
8 changes: 8 additions & 0 deletions gtests/ssl_gtest/tls_agent.cc
Expand Up @@ -10,6 +10,7 @@
#include "pk11func.h"
#include "ssl.h"
#include "sslerr.h"
#include "sslexp.h"
#include "sslproto.h"
#include "tls_parser.h"

Expand Down Expand Up @@ -414,6 +415,13 @@ void TlsAgent::SetShortHeadersEnabled() {
EXPECT_EQ(SECSuccess, rv);
}

void TlsAgent::SetAltHandshakeTypeEnabled() {
EXPECT_TRUE(EnsureTlsSetup());

SECStatus rv = SSL_UseAltServerHelloType(ssl_fd(), true);
EXPECT_EQ(SECSuccess, rv);
}

void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
vrange_.min = minver;
vrange_.max = maxver;
Expand Down
1 change: 1 addition & 0 deletions gtests/ssl_gtest/tls_agent.h
Expand Up @@ -127,6 +127,7 @@ class TlsAgent : public PollTarget {
void Set0RttEnabled(bool en);
void SetFallbackSCSVEnabled(bool en);
void SetShortHeadersEnabled();
void SetAltHandshakeTypeEnabled();
void SetVersionRange(uint16_t minver, uint16_t maxver);
void GetVersionRange(uint16_t* minver, uint16_t* maxver);
void CheckPreliminaryInfo();
Expand Down
18 changes: 17 additions & 1 deletion gtests/ssl_gtest/tls_filter.cc
Expand Up @@ -227,7 +227,8 @@ PacketFilter::Action TlsHandshakeFilter::FilterRecord(
const TlsRecordHeader& record_header, const DataBuffer& input,
DataBuffer* output) {
// Check that the first byte is as requested.
if (record_header.content_type() != kTlsHandshakeType) {
if ((record_header.content_type() != kTlsHandshakeType) &&
(record_header.content_type() != kTlsAltHandshakeType)) {
return KEEP;
}

Expand Down Expand Up @@ -369,6 +370,20 @@ PacketFilter::Action TlsConversationRecorder::FilterRecord(
return KEEP;
}

PacketFilter::Action TlsHeaderRecorder::FilterRecord(
const TlsRecordHeader& header, const DataBuffer& input,
DataBuffer* output) {
headers_.push_back(header);
return KEEP;
}

const TlsRecordHeader* TlsHeaderRecorder::header(size_t index) {
if (index > headers_.size() + 1) {
return nullptr;
}
return &headers_[index];
}

PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
DataBuffer* output) {
DataBuffer in(input);
Expand All @@ -378,6 +393,7 @@ PacketFilter::Action ChainedPacketFilter::Filter(const DataBuffer& input,
if (action == DROP) {
return DROP;
}

if (action == CHANGE) {
in = *output;
changed = true;
Expand Down
15 changes: 14 additions & 1 deletion gtests/ssl_gtest/tls_filter.h
Expand Up @@ -133,6 +133,7 @@ inline std::ostream& operator<<(std::ostream& stream, TlsRecordHeader& hdr) {
stream << "Alert";
break;
case kTlsHandshakeType:
case kTlsAltHandshakeType:
stream << "Handshake";
break;
case kTlsApplicationDataType:
Expand Down Expand Up @@ -230,7 +231,19 @@ class TlsConversationRecorder : public TlsRecordFilter {
DataBuffer* output);

private:
DataBuffer& buffer_;
DataBuffer buffer_;
};

// Make a copy of the records
class TlsHeaderRecorder : public TlsRecordFilter {
public:
virtual PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& input,
DataBuffer* output);
const TlsRecordHeader* header(size_t index);

private:
std::vector<TlsRecordHeader> headers_;
};

// Runs multiple packet filters in series.
Expand Down
16 changes: 15 additions & 1 deletion lib/ssl/ssl3con.c
Expand Up @@ -2977,6 +2977,7 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
ssl_SEND_FLAG_CAP_RECORD_VERSION;
PRInt32 count = -1;
SECStatus rv;
SSL3ContentType ct = content_handshake;

PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
Expand All @@ -2990,7 +2991,12 @@ ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
count = ssl3_SendRecord(ss, NULL, content_handshake,
/* Maybe send the first message with alt handshake type. */
if (ss->ssl3.hs.altHandshakeType) {
ct = content_alt_handshake;
ss->ssl3.hs.altHandshakeType = PR_FALSE;
}
count = ssl3_SendRecord(ss, NULL, ct,
ss->sec.ci.sendBuf.buf,
ss->sec.ci.sendBuf.len, flags);
if (count < 0) {
Expand Down Expand Up @@ -12729,6 +12735,14 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf)
*/
ssl_GetSSL3HandshakeLock(ss);

/* Special case: allow alt content type for TLS 1.3 ServerHello. */
if ((rType == content_alt_handshake) &&
(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) &&
(ss->ssl3.hs.ws == wait_server_hello) &&
(ss->opt.enableAltHandshaketype) &&
(!IS_DTLS(ss))) {
rType = content_handshake;
}
/* All the functions called in this switch MUST set error code if
** they return SECFailure or SECWouldBlock.
*/
Expand Down
3 changes: 2 additions & 1 deletion lib/ssl/ssl3prot.h
Expand Up @@ -41,7 +41,8 @@ typedef enum {
content_change_cipher_spec = 20,
content_alert = 21,
content_handshake = 22,
content_application_data = 23
content_application_data = 23,
content_alt_handshake = 24
} SSL3ContentType;

typedef struct {
Expand Down
10 changes: 10 additions & 0 deletions lib/ssl/sslexp.h
Expand Up @@ -22,6 +22,16 @@ SEC_BEGIN_PROTOS
? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
: SECFailure)

/* Allow the ServerHello to be record type 24. Experiment to test:
* https://github.com/tlswg/tls13-spec/pull/1051
* This will either become part of the standard or be disabled
* after we have tested it.
*/
#define SSL_UseAltServerHelloType(fd, enable) \
SSL_EXPERIMENTAL_API("SSL_UseAltServerHelloType", \
(PRFileDesc * _fd, PRBool _enable), \
(fd, enable))

SEC_END_PROTOS

#endif /* __sslexp_h_ */
2 changes: 2 additions & 0 deletions lib/ssl/sslimpl.h
Expand Up @@ -298,6 +298,7 @@ typedef struct sslOptionsStr {
unsigned int requireDHENamedGroups : 1;
unsigned int enable0RttData : 1;
unsigned int enableShortHeaders : 1;
unsigned int enableAltHandshaketype : 1;
} sslOptions;

typedef enum { sslHandshakingUndetermined = 0,
Expand Down Expand Up @@ -883,6 +884,7 @@ typedef struct SSL3HandshakeStateStr {
ssl3KEADef kea_def_mutable; /* Used to hold the writable kea_def
* we use for TLS 1.3 */
PRBool shortHeaders; /* Assigned if we are doing short headers. */
PRBool altHandshakeType; /* Assigned if we are doing the wrapped handshake. */
} SSL3HandshakeState;

/*
Expand Down
6 changes: 4 additions & 2 deletions lib/ssl/sslsock.c
Expand Up @@ -81,10 +81,11 @@ static sslOptions ssl_defaults = {
PR_FALSE, /* requireDHENamedGroups */
PR_FALSE, /* enable0RttData */
#ifdef NSS_ENABLE_TLS13_SHORT_HEADERS
PR_TRUE /* enableShortHeaders */
PR_TRUE, /* enableShortHeaders */
#else
PR_FALSE /* enableShortHeaders */
PR_FALSE, /* enableShortHeaders */
#endif
PR_FALSE /* enableAltHandshaketype */
};

/*
Expand Down Expand Up @@ -3867,6 +3868,7 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
EXP(UseAltServerHelloType),
#endif
{ "", NULL }
};
Expand Down
36 changes: 36 additions & 0 deletions lib/ssl/tls13con.c
Expand Up @@ -4475,6 +4475,17 @@ tls13_EncodeDraftVersion(SSL3ProtocolVersion version)
return (PRUint16)version;
}

PRUint16
tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version)
{
#ifdef TLS_1_3_DRAFT_VERSION
if (version == SSL_LIBRARY_VERSION_TLS_1_3) {
return 0x7a00 | TLS_1_3_DRAFT_VERSION;
}
#endif
return (PRUint16)version;
}

/* Pick the highest version we support that is also advertised. */
SECStatus
tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
Expand All @@ -4496,6 +4507,7 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
PRUint16 wire = tls13_EncodeDraftVersion(version);
PRUint16 alt_wire = tls13_EncodeAltDraftVersion(version);
unsigned long offset;

for (offset = 0; offset < versions.len; offset += 2) {
Expand All @@ -4505,9 +4517,33 @@ tls13_NegotiateVersion(sslSocket *ss, const TLSExtension *supported_versions)
ss->version = version;
return SECSuccess;
}
if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss) &&
supported == alt_wire) {
ss->version = version;
ss->ssl3.hs.altHandshakeType = PR_TRUE;
return SECSuccess;
}
}
}

FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_VERSION, protocol_version);
return SECFailure;
}

SECStatus
SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable)
{
sslSocket *ss;

ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSLExp_UseAltServerHelloType",
SSL_GETPID(), fd));
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}

ss->opt.enableAltHandshaketype = enable;

return SECSuccess;
}
3 changes: 2 additions & 1 deletion lib/ssl/tls13con.h
Expand Up @@ -81,9 +81,10 @@ SECStatus tls13_HandleEndOfEarlyData(sslSocket *ss);
SECStatus tls13_HandleEarlyApplicationData(sslSocket *ss, sslBuffer *origBuf);
PRBool tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid);
PRUint16 tls13_EncodeDraftVersion(SSL3ProtocolVersion version);
PRUint16 tls13_DecodeDraftVersion(PRUint16 version);
PRUint16 tls13_EncodeAltDraftVersion(SSL3ProtocolVersion version);
SECStatus tls13_NegotiateVersion(sslSocket *ss,
const TLSExtension *supported_versions);
SECStatus tls13_SendNewSessionTicket(sslSocket *ss);
SECStatus SSLExp_UseAltServerHelloType(PRFileDesc *fd, PRBool enable);

#endif /* __tls13con_h_ */
13 changes: 13 additions & 0 deletions lib/ssl/tls13exthandle.c
Expand Up @@ -896,6 +896,10 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
extensions_len = 2 + 2 + 1 +
2 * (ss->vrange.max - ss->vrange.min + 1);

if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
extensions_len += 2;
}

if (maxBytes < (PRUint32)extensions_len) {
PORT_Assert(0);
return 0;
Expand All @@ -914,6 +918,15 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
if (rv != SECSuccess)
return -1;

if (ss->opt.enableAltHandshaketype && !IS_DTLS(ss)) {
rv = ssl3_ExtAppendHandshakeNumber(
ss, tls13_EncodeAltDraftVersion(
SSL_LIBRARY_VERSION_TLS_1_3),
2);
if (rv != SECSuccess)
return -1;
}

for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
rv = ssl3_ExtAppendHandshakeNumber(
ss, tls13_EncodeDraftVersion(version), 2);
Expand Down

0 comments on commit 0875aae

Please sign in to comment.