Skip to content

Bug: connection spamming with mTLS v1.3 #145

@thedevbirb

Description

@thedevbirb

With TLS v1.3, some checks are postponed after TLS handshake, but before receiving any traffic. Some of those include client authentication checks. This means, from the client perspective, that a connection can become active for a very short timeframe, and then be closed right after .

On a req/rep socket pair, if the client (req) provides an invalid certificate, then we might see a scenario like this:

2025-12-17T10:59:03.086987Z  INFO req_driver{id="req-6" addr=[::1]:59516}:connect: msg_socket::req::driver: connected
2025-12-17T10:59:03.087068Z ERROR rep_driver{local_addr=[::1]:59516}: msg_socket::rep::driver: failed to accept incoming connection e=Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_process_client_certificate", reason: "certificate verify failed", file: "ssl/statem/statem_srvr.c", line: 3753 }]))) })
2025-12-17T10:59:03.087089Z  WARN req_driver{id="req-7" addr=[::1]:59516}: msg_socket::req::driver: failed to read from connection, resetting connection state e=Io(Custom { kind: Other, error: Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167773208, library: "SSL routines", function: "ssl3_read_bytes", reason: "tlsv1 alert unknown ca", file: "ssl/record/rec_layer_s3.c", line: 916, data: "SSL alert number 48" }]))) } })
2025-12-17T10:59:03.087117Z  WARN req_driver{id="req-4" addr=[::1]:59516}: msg_socket::req::driver: failed to read from connection, resetting connection state e=Io(Custom { kind: Other, error: Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167773208, library: "SSL routines", function: "ssl3_read_bytes", reason: "tlsv1 alert unknown ca", file: "ssl/record/rec_layer_s3.c", line: 916, data: "SSL alert number 48" }]))) } })
2025-12-17T10:59:03.087740Z  WARN req_driver{id="req-6" addr=[::1]:59516}: msg_socket::req::driver: failed to read from connection, resetting connection state e=Io(Custom { kind: Other, error: Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167773208, library: "SSL routines", function: "ssl3_read_bytes", reason: "tlsv1 alert unknown ca", file: "ssl/record/rec_layer_s3.c", line: 916, data: "SSL alert number 48" }]))) } })
2025-12-17T10:59:03.109064Z DEBUG req_driver{id="req-2" addr=[::1]:59516}:connect: msg_socket::req::driver: trying connection backoff=40ms
2025-12-17T10:59:03.109109Z DEBUG req_driver{id="req-6" addr=[::1]:59516}:connect: msg_socket::req::driver: trying connection backoff=40ms
2025-12-17T10:59:03.109123Z DEBUG req_driver{id="req-7" addr=[::1]:59516}:connect: msg_socket::req::driver: trying connection backoff=40ms
2025-12-17T10:59:03.109168Z DEBUG req_driver{id="req-4" addr=[::1]:59516}:connect: msg_socket::req::driver: trying connection backoff=40ms
2025-12-17T10:59:03.113270Z  INFO req_driver{id="req-6" addr=[::1]:59516}:connect: msg_socket::req::driver: connected
2025-12-17T10:59:03.114032Z  INFO req_driver{id="req-7" addr=[::1]:59516}:connect: msg_socket::req::driver: connected
2025-12-17T10:59:03.114060Z ERROR rep_driver{local_addr=[::1]:59516}: msg_socket::rep::driver: failed to accept incoming connection e=Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_process_client_certificate", reason: "certificate verify failed", file: "ssl/statem/statem_srvr.c", line: 3753 }]))) })
2025-12-17T10:59:03.114741Z  INFO req_driver{id="req-2" addr=[::1]:59516}:connect: msg_socket::req::driver: connected
2025-12-17T10:59:03.115356Z  INFO req_driver{id="req-4" addr=[::1]:59516}:connect: msg_socket::req::driver: connected
2025-12-17T10:59:03.115421Z ERROR rep_driver{local_addr=[::1]:59516}: msg_socket::rep::driver: failed to accept incoming connection e=Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_process_client_certificate", reason: "certificate verify failed", file: "ssl/statem/statem_srvr.c", line: 3753 }]))) })
2025-12-17T10:59:03.115476Z ERROR rep_driver{local_addr=[::1]:59516}: msg_socket::rep::driver: failed to accept incoming connection e=Ssl(Error { code: ErrorCode(1), cause: Some(Ssl(ErrorStack([Error { code: 167772294, library: "SSL routines", function: "tls_process_client_certificate", reason: "certificate verify failed", file: "ssl/statem/statem_srvr.c", line: 3753 }]))) })

When we fail to read from the underlying transport, we reset_connection state starting with a short backoff of 40ms, and this results in the server being spammed with connection requests. Ideally, the condition which assess whether a connection it established should be modified to reflect these post-handshake checks, but a quicker solution could also be to just start with a longer backoff depending on the error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions