picotls, as a TLS 1.3-only stack, determines the Hello version by `supported_versions`. `legacy_version` is checked after determining the TLS version
diff --git a/lib/picotls.c b/lib/picotls.c
index 1355ed7..519ef77 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -3620,8 +3620,8 @@
0)
goto Exit;
- /* check if ClientHello makes sense */
- if (!(ch.legacy_version == 0x0303 && is_supported_version(ch.selected_version))) {
+ /* bail out if CH cannot be handled as TLS 1.3, providing the application the raw CH and SNI, to help them fallback */
+ if (!is_supported_version(ch.selected_version)) {
if (!is_second_flight && tls->ctx->on_client_hello != NULL) {
ptls_on_client_hello_parameters_t params = {
.server_name = ch.server_name,
@@ -3635,6 +3635,15 @@
ret = PTLS_ALERT_PROTOCOL_VERSION;
goto Exit;
}
+
+ /* Check TLS 1.3-specific constraints. Hereafter, we might exit without calling on_client_hello. That's fine because this CH is
+ * ought to be rejected. */
+ if (ch.legacy_version <= 0x0300) {
+ /* RFC 8446 Appendix D.5: any endpoint receiving a Hello message with legacy_version set to 0x0300 MUST abort the handshake
+ * with a "protocol_version" alert. */
+ ret = PTLS_ALERT_PROTOCOL_VERSION;
+ goto Exit;
+ }
if (!(ch.compression_methods.count == 1 && ch.compression_methods.ids[0] == 0)) {
ret = PTLS_ALERT_ILLEGAL_PARAMETER;
goto Exit;