Hi,
On the Morse Micro CMSIS Pack 1.9.0 of mbedTLS (v3.6.x), an outbound TLS 1.2 handshake completes correctly up through ServerHelloDone, but the subsequent ChangeCipherSpec and Finished records are emitted with the SSL 3.0 wire version (03 00) instead of TLS 1.2 (03 03). Strict clients (OpenSSL s_client, Python ssl) reject this with fatal protocol_version / WRONG_VERSION_NUMBER and abort.
The root cause is that ssl->tls_version is clobbered to 0x0300 between the CCS state and the Finished state — almost certainly due to the fork’s badmac_seen_or_in_hsfraglen union member aliasing a neighboring field in mbedtls_ssl_context.
Debug evidence:
output record: msgtype = 20, version = [3:3], msglen = zu
0000: 14 03 03 00 01 01 <-- CCS correct
output record: msgtype = 22, version = [3:0], msglen = zu
0000: 16 03 00 00 28 ... <-- Finished WRONG
Client sees:
SSL routines:tls_validate_record_header:wrong version number
Where it goes wrong: library/ssl_msg.c, mbedtls_ssl_write_record():
mbedtls_ssl_protocol_version tls_ver = ssl->tls_version; // <-- 0x0300 here
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
if (tls_ver == MBEDTLS_SSL_VERSION_TLS1_3) {
tls_ver = MBEDTLS_SSL_VERSION_TLS1_2;
}
#endif
mbedtls_ssl_write_version(ssl->out_hdr + 1, ssl->conf->transport, tls_ver);
I did a small patch which made things work:
mbedtls_ssl_protocol_version tls_ver = ssl->tls_version;
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
if (tls_ver == MBEDTLS_SSL_VERSION_TLS1_3) {
tls_ver = MBEDTLS_SSL_VERSION_TLS1_2;
}
#endif
/* Force the TLS 1.2 wire version. The fork clobbers ssl->tls_version
* to 0x0300 on the CCS -> Finished transition, causing strict clients
* to abort with a fatal protocol_version alert. */
if (tls_ver != MBEDTLS_SSL_VERSION_TLS1_2) {
tls_ver = MBEDTLS_SSL_VERSION_TLS1_2;
}
mbedtls_ssl_write_version(ssl->out_hdr + 1, ssl->conf->transport, tls_ver);
I hope this doesn’t affect is anything uses this and this is patched in next cmsis version.