diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 2dab6ccd7..2c6b00d96 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -41,6 +41,24 @@ struct tls_header { uint16_t length; } __attribute__ (( packed )); +/** TLS server random data */ +union tls_server_random { + /** Random nonce (as used by the key schedule) */ + struct tls_random random; + /** Version downgrade detection */ + struct { + /** Unused */ + uint8_t unused[24]; + /** Magic signature */ + uint8_t magic[7]; + /** Negotiated version (as a delta from TLSv1.1) */ + uint8_t version; + } __attribute__ (( packed )) downgrade; +}; + +/** TLS server downgrade detection magic signature */ +#define TLS_SERVER_DOWNGRADE_MAGIC "DOWNGRD" + /** TLS version 1.1 */ #define TLS_VERSION_TLS_1_1 0x0302 diff --git a/src/net/tls.c b/src/net/tls.c index e53f99777..f31fbbfff 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -190,6 +190,10 @@ FILE_SECBOOT ( PERMITTED ); #define EINFO_EPERM_SAVE \ __einfo_uniqify ( EINFO_EPERM, 0x07, \ "Pre-shared key was not established" ) +#define EPERM_DOWNGRADE __einfo_error ( EINFO_EPERM_DOWNGRADE ) +#define EINFO_EPERM_DOWNGRADE \ + __einfo_uniqify ( EINFO_EPERM, 0x08, \ + "Downgrade attack detected" ) #define EPROTO_VERSION __einfo_error ( EINFO_EPROTO_VERSION ) #define EINFO_EPROTO_VERSION \ __einfo_uniqify ( EINFO_EPROTO, 0x01, \ @@ -2314,10 +2318,11 @@ static int tls_new_hello_request ( struct tls_connection *tls, */ static int tls_new_server_hello ( struct tls_connection *tls, const void *data, size_t len ) { + static const uint8_t downgrade_magic[7] = TLS_SERVER_DOWNGRADE_MAGIC; struct tls_session *session = tls->session; const struct { uint16_t version; - struct tls_random random; + union tls_server_random random; uint8_t session_id_len; uint8_t session_id[0]; } __attribute__ (( packed )) *hello_a = data; @@ -2444,6 +2449,18 @@ static int tls_new_server_hello ( struct tls_connection *tls, DBGC ( tls, "TLS %p using protocol version %d.%d\n", tls, ( version >> 8 ), ( version & 0xff ) ); + /* Check for downgrade attacks */ + if ( ( version < TLS_VERSION_MAX ) && + ( memcmp ( hello_a->random.downgrade.magic, downgrade_magic, + sizeof ( hello_a->random.downgrade.magic ) ) == 0 ) && + ( hello_a->random.downgrade.version < + ( TLS_VERSION_MAX - TLS_VERSION_TLS_1_1 ) ) ) { + DBGC ( tls, "TLS %p detected downgrade attack:\n", tls ); + DBGC_HDA ( tls, 0, &hello_a->random.downgrade, + sizeof ( hello_a->random.downgrade ) ); + return -EPERM_DOWNGRADE; + } + /* Select cipher suite */ if ( ( rc = tls_select_cipher ( tls, hello_b->cipher_suite ) ) != 0 ) return rc;