goto f_err;
}
- /* We do this immediately so we know what format the ServerHello is in */
- protverr = ssl_choose_client_version(s, sversion);
+ /* load the server random */
+ if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+ al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
+ goto f_err;
+ }
+
+ /*
+ * We do this immediately so we know what format the ServerHello is in.
+ * Must be done after reading the random data so we can check for the
+ * TLSv1.3 downgrade sentinels
+ */
+ protverr = ssl_choose_client_version(s, sversion, 1, &al);
if (protverr != 0) {
- al = SSL_AD_PROTOCOL_VERSION;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, protverr);
goto f_err;
}
goto f_err;
}
- /* load the server hello data */
- /* load the server random */
- if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
- al = SSL_AD_DECODE_ERROR;
- SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
- goto f_err;
- }
-
/* Get the session-id. */
if (!SSL_IS_TLS13(s)) {
if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
s->hello_retry_request = 1;
/* This will fail if it doesn't choose TLSv1.3+ */
- errorcode = ssl_choose_client_version(s, sversion);
+ errorcode = ssl_choose_client_version(s, sversion, 0, &al);
if (errorcode != 0) {
- al = SSL_AD_PROTOCOL_VERSION;
SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, errorcode);
goto f_err;
}
*
* @s: client SSL handle.
* @version: The proposed version from the server's HELLO.
+ * @checkdgrd: Whether to check the downgrade sentinels in the server_random
+ * @al: Where to store any alert value that may be generated
*
* Returns 0 on success or an SSL error reason number on failure.
*/
-int ssl_choose_client_version(SSL *s, int version)
+int ssl_choose_client_version(SSL *s, int version, int checkdgrd, int *al)
{
const version_info *vent;
const version_info *table;
+ int highver = 0;
/* TODO(TLS1.3): Remove this before release */
if (version == TLS1_3_VERSION_DRAFT)
version = TLS1_3_VERSION;
+ if (s->hello_retry_request && version != TLS1_3_VERSION) {
+ *al = SSL_AD_PROTOCOL_VERSION;
+ return SSL_R_WRONG_SSL_VERSION;
+ }
+
switch (s->method->version) {
default:
- if (version != s->version)
+ if (version != s->version) {
+ *al = SSL_AD_PROTOCOL_VERSION;
return SSL_R_WRONG_SSL_VERSION;
+ }
/*
* If this SSL handle is not from a version flexible method we don't
* (and never did) check min/max, FIPS or Suite B constraints. Hope
for (vent = table; vent->version != 0; ++vent) {
const SSL_METHOD *method;
int err;
+#ifndef OPENSSL_NO_TLS13DOWNGRADE
+ static const unsigned char tls11downgrade[] = {
+ 0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
+ };
+ static const unsigned char tls12downgrade[] = {
+ 0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
+ };
+#endif
- if (version != vent->version)
- continue;
if (vent->cmeth == NULL)
- break;
- if (s->hello_retry_request && version != TLS1_3_VERSION)
- return SSL_R_WRONG_SSL_VERSION;
+ continue;
+
+ if (highver != 0 && version != vent->version)
+ continue;
method = vent->cmeth();
err = ssl_method_error(s, method);
- if (err != 0)
- return err;
+ if (err != 0) {
+ if (version == vent->version) {
+ *al = SSL_AD_PROTOCOL_VERSION;
+ return err;
+ }
+
+ continue;
+ }
+ if (highver == 0)
+ highver = vent->version;
+
+ if (version != vent->version)
+ continue;
+
+#ifndef OPENSSL_NO_TLS13DOWNGRADE
+ /* Check for downgrades */
+ if (checkdgrd) {
+ if (version == TLS1_2_VERSION && highver > version) {
+ if (memcmp(tls12downgrade,
+ s->s3->server_random + SSL3_RANDOM_SIZE
+ - sizeof(tls12downgrade),
+ sizeof(tls12downgrade)) == 0) {
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return SSL_R_INAPPROPRIATE_FALLBACK;
+ }
+ } else if (!SSL_IS_DTLS(s)
+ && version < TLS1_2_VERSION
+ && highver > version) {
+ if (memcmp(tls11downgrade,
+ s->s3->server_random + SSL3_RANDOM_SIZE
+ - sizeof(tls11downgrade),
+ sizeof(tls11downgrade)) == 0) {
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return SSL_R_INAPPROPRIATE_FALLBACK;
+ }
+ }
+ }
+#endif
+
s->method = method;
s->version = version;
return 0;
}
+ *al = SSL_AD_PROTOCOL_VERSION;
return SSL_R_UNSUPPORTED_PROTOCOL;
}