case CO_ER_SSL_CRT_FAIL: return "SSL client certificate not trusted";
case CO_ER_SSL_HANDSHAKE: return "SSL handshake failure";
case CO_ER_SSL_HANDSHAKE_HB: return "SSL handshake failure after heartbeat";
+ case CO_ER_SSL_KILLED_HB: return "Stopped a TLSv1 heartbeat attack (CVE-2014-0160)";
case CO_ER_SSL_NO_TARGET: return "Attempt to use SSL on an unknown target (internal error)";
}
return NULL;
CO_ER_SSL_CRT_FAIL, /* client cert verification failed on the certificate */
CO_ER_SSL_HANDSHAKE, /* SSL error during handshake */
CO_ER_SSL_HANDSHAKE_HB, /* SSL error during handshake with heartbeat present */
- CO_ER_SSL_NO_TARGET, /* unkonwn target (not client nor server) */
+ CO_ER_SSL_KILLED_HB, /* Stopped a TLSv1 heartbeat attack (CVE-2014-0160) */
+ CO_ER_SSL_NO_TARGET, /* unknown target (not client nor server) */
};
/* source address settings for outgoing connections */
#ifdef TLS1_RT_HEARTBEAT
/* test heartbeat received (write_p is set to 0
for a received record) */
- if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0))
+ if ((content_type == TLS1_RT_HEARTBEAT) && (write_p == 0)) {
+ const unsigned char *p = buf;
+ unsigned int payload;
+
conn->xprt_st |= SSL_SOCK_RECV_HEARTBEAT;
+
+ /* Check if this is a CVE-2014-0160 exploitation attempt. */
+ if (*p != TLS1_HB_REQUEST)
+ return;
+
+ if (len < 1 + 2 + 16)
+ goto kill_it;
+
+ payload = (p[1] * 256) + p[2];
+ if (1 + 2 + payload + 16 <= len)
+ return; /* OK no problem */
+ kill_it:
+ /* we have a clear heartbleed attack (CVE-2014-0160),
+ * we can't know if the SSL stack is patched, so better
+ * kill the connection before OpenSSL tries to send the
+ * bytes back to the attacker. It will be reported above
+ * as SSL_ERROR_SSL while an other handshake failure with
+ * a heartbeat message will be reported as SSL_ERROR_SYSCALL.
+ */
+ SSLerr(SSL_F_TLS1_HEARTBEAT, SSL_R_SSL_HANDSHAKE_FAILURE);
+ return;
+ }
#endif
}
*/
conn_drain(conn);
if (!conn->err_code)
- conn->err_code = CO_ER_SSL_HANDSHAKE;
+ conn->err_code = (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT) ?
+ CO_ER_SSL_KILLED_HB : CO_ER_SSL_HANDSHAKE;
goto out_error;
}
}
*/
conn_drain(conn);
if (!conn->err_code)
- conn->err_code = CO_ER_SSL_HANDSHAKE;
+ conn->err_code = (conn->xprt_st & SSL_SOCK_RECV_HEARTBEAT) ?
+ CO_ER_SSL_KILLED_HB : CO_ER_SSL_HANDSHAKE;
goto out_error;
}
}