Fix memory leak when decoding corrupt tickets.
This is CVE-2014-3567 from upstream. See https://www.openssl.org/news/secadv_20141015.txt Change-Id: I9aad422bf1b8055cb251c7ff9346cf47a448a815 Reviewed-on: https://boringssl-review.googlesource.com/1970 Reviewed-by: David Benjamin <davidben@chromium.org> Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
88333ef7d7
commit
3831173740
@ -2379,7 +2379,10 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
|
|||||||
HMAC_Final(&hctx, tick_hmac, NULL);
|
HMAC_Final(&hctx, tick_hmac, NULL);
|
||||||
HMAC_CTX_cleanup(&hctx);
|
HMAC_CTX_cleanup(&hctx);
|
||||||
if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
|
if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
return 2;
|
return 2;
|
||||||
|
}
|
||||||
/* Attempt to decrypt session data */
|
/* Attempt to decrypt session data */
|
||||||
/* Move p after IV to start of encrypted ticket, update length */
|
/* Move p after IV to start of encrypted ticket, update length */
|
||||||
p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
|
p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
|
||||||
|
@ -464,6 +464,14 @@ type ProtocolBugs struct {
|
|||||||
// AllowSessionVersionMismatch causes the server to resume sessions
|
// AllowSessionVersionMismatch causes the server to resume sessions
|
||||||
// regardless of the version associated with the session.
|
// regardless of the version associated with the session.
|
||||||
AllowSessionVersionMismatch bool
|
AllowSessionVersionMismatch bool
|
||||||
|
|
||||||
|
// CorruptTicket causes a client to corrupt a session ticket before
|
||||||
|
// sending it in a resume handshake.
|
||||||
|
CorruptTicket bool
|
||||||
|
|
||||||
|
// OversizedSessionId causes the session id that is sent with a ticket
|
||||||
|
// resumption attempt to be too large (33 bytes).
|
||||||
|
OversizedSessionId bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) serverInit() {
|
func (c *Config) serverInit() {
|
||||||
|
@ -148,10 +148,25 @@ NextCipherSuite:
|
|||||||
|
|
||||||
if session != nil {
|
if session != nil {
|
||||||
hello.sessionTicket = session.sessionTicket
|
hello.sessionTicket = session.sessionTicket
|
||||||
|
if c.config.Bugs.CorruptTicket {
|
||||||
|
hello.sessionTicket = make([]byte, len(session.sessionTicket))
|
||||||
|
copy(hello.sessionTicket, session.sessionTicket)
|
||||||
|
if len(hello.sessionTicket) > 0 {
|
||||||
|
offset := 40
|
||||||
|
if offset > len(hello.sessionTicket) {
|
||||||
|
offset = len(hello.sessionTicket) - 1
|
||||||
|
}
|
||||||
|
hello.sessionTicket[offset] ^= 0x40
|
||||||
|
}
|
||||||
|
}
|
||||||
// A random session ID is used to detect when the
|
// A random session ID is used to detect when the
|
||||||
// server accepted the ticket and is resuming a session
|
// server accepted the ticket and is resuming a session
|
||||||
// (see RFC 5077).
|
// (see RFC 5077).
|
||||||
hello.sessionId = make([]byte, 16)
|
sessionIdLen := 16
|
||||||
|
if c.config.Bugs.OversizedSessionId {
|
||||||
|
sessionIdLen = 33
|
||||||
|
}
|
||||||
|
hello.sessionId = make([]byte, sessionIdLen)
|
||||||
if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
|
if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil {
|
||||||
c.sendAlert(alertInternalError)
|
c.sendAlert(alertInternalError)
|
||||||
return errors.New("tls: short read from Rand: " + err.Error())
|
return errors.New("tls: short read from Rand: " + err.Error())
|
||||||
|
@ -649,6 +649,10 @@ func openSocketPair() (shimEnd *os.File, conn net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runTest(test *testCase, buildDir string) error {
|
func runTest(test *testCase, buildDir string) error {
|
||||||
|
if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) {
|
||||||
|
panic("Error expected without shouldFail in " + test.name)
|
||||||
|
}
|
||||||
|
|
||||||
shimEnd, conn := openSocketPair()
|
shimEnd, conn := openSocketPair()
|
||||||
shimEndResume, connResume := openSocketPair()
|
shimEndResume, connResume := openSocketPair()
|
||||||
|
|
||||||
@ -1542,6 +1546,31 @@ func addExtensionTests() {
|
|||||||
expectedNextProtoType: alpn,
|
expectedNextProtoType: alpn,
|
||||||
resumeSession: true,
|
resumeSession: true,
|
||||||
})
|
})
|
||||||
|
// Resume with a corrupt ticket.
|
||||||
|
testCases = append(testCases, testCase{
|
||||||
|
testType: serverTest,
|
||||||
|
name: "CorruptTicket",
|
||||||
|
config: Config{
|
||||||
|
Bugs: ProtocolBugs{
|
||||||
|
CorruptTicket: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resumeSession: true,
|
||||||
|
flags: []string{"-expect-session-miss"},
|
||||||
|
})
|
||||||
|
// Resume with an oversized session id.
|
||||||
|
testCases = append(testCases, testCase{
|
||||||
|
testType: serverTest,
|
||||||
|
name: "OversizedSessionId",
|
||||||
|
config: Config{
|
||||||
|
Bugs: ProtocolBugs{
|
||||||
|
OversizedSessionId: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resumeSession: true,
|
||||||
|
shouldFail: true,
|
||||||
|
expectedError: ":DECODE_ERROR:",
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func addResumptionVersionTests() {
|
func addResumptionVersionTests() {
|
||||||
|
Loading…
Reference in New Issue
Block a user