From a953695b2393c7bd57120b8b19236a90cdfddd10 Mon Sep 17 00:00:00 2001 From: David Cozens Date: Thu, 4 Jun 2026 21:47:46 +0100 Subject: [PATCH] feat: S12.28 surface TLS peer-hostname verification when ServerName is NULL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both TLS adapters (OpenSSL, mbedTLS) bound the peer identity to the certificate only when ServerName was set, so a NULL ServerName completed the handshake against any cert chaining to a trusted CA — a silent, MITM-class default with no diagnostic. Make the unverified-peer case observable: - ServerName == NULL -> WARNING (BAD_CONFIG / *_SERVER_NAME_NOT_SET), still connect chain-only (preserves the closed-network / IP-pinning use case). - ServerName == "" -> deliberate opt-out: connect chain-only, no diagnostic. - Non-empty ServerName -> SNI + identity check, unchanged. Reuses the existing *_SERVER_NAME_NOT_SET detail at WARNING severity; no public error-enum change. Documents that "no DNS" does not force NULL ServerName in both header comments and docs/integrating-mbedtls.md. Closes #529 Co-Authored-By: Claude Opus 4.8 (1M context) --- DEVLOG.md | 31 +++++++++ .../Interface/SolidSyslogMbedTlsStream.h | 5 +- .../MbedTls/Source/SolidSyslogMbedTlsStream.c | 23 ++++++- .../OpenSsl/Interface/SolidSyslogTlsStream.h | 5 +- .../OpenSsl/Source/SolidSyslogTlsStream.c | 20 +++++- .../MbedTls/SolidSyslogMbedTlsStreamTest.cpp | 64 ++++++++++++++++++- Tests/SolidSyslogTlsStreamTest.cpp | 64 +++++++++++++++++-- docs/integrating-mbedtls.md | 2 +- misra_suppressions.txt | 6 +- 9 files changed, 202 insertions(+), 18 deletions(-) diff --git a/DEVLOG.md b/DEVLOG.md index 9dc8c8cb..6774c18e 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -1,5 +1,36 @@ # Dev Log +## 2026-06-04 — S12.28 TLS peer-hostname verification surfaced when ServerName is NULL + +Closes the High-severity finding from the pre-0.1.0 security audit: both TLS adapters +(OpenSSL, mbedTLS) bound the peer identity to the certificate only when `ServerName` was +set, so a NULL `ServerName` connected against *any* CA-issued cert — a silent, MITM-class +default with no diagnostic. Now the unverified-peer case is observable. + +### Decisions + +- **NULL warns, `""` opts out (Model chosen with David).** `ServerName == NULL` emits a + `WARNING` (`BAD_CONFIG` / `*_SERVER_NAME_NOT_SET`) and still connects chain-only, + preserving the closed-network / IP-pinning use case. `ServerName == ""` is the deliberate + opt-out — connect chain-only, no diagnostic. A non-empty name verifies as before. +- **Key insight surfaced in the design discussion: "no DNS" ≠ "no hostname verification".** + Identity binding (`SSL_set1_host` / `mbedtls_ssl_set_hostname`) is a string check against + the cert and needs no DNS. An IP-pinned target can still set `ServerName` to the name (or + IP SAN) on its cert and get full MITM protection. Documented in `integrating-mbedtls.md` + and both `ServerName` header comments. +- **Reused the existing `*_SERVER_NAME_NOT_SET` detail at WARNING severity** rather than + adding a new enum value — the name fits the NULL case and severity is the discriminator + (ERROR = a provided name couldn't be applied → unwound; WARNING = no name → connected + unverified). No public error-enum change. +- TDD across both adapters; a few existing handshake-failure tests had to set a `ServerName` + so the new NULL-warning didn't double-fire alongside their single expected error. + +### Deferred + +- IP-SAN verification (`X509_VERIFY_PARAM_set1_ip` / mbedTLS equivalent) for IP-literal + targets — `SSL_set1_host` is name-based. A possible follow-up if integrators want verified + IP-pinning rather than the `""` opt-out. + ## 2026-06-04 — S21.04 BlockDevice owns its block size Closes the last open thread under E21 (Port-Time Configurability). Block size moves diff --git a/Platform/MbedTls/Interface/SolidSyslogMbedTlsStream.h b/Platform/MbedTls/Interface/SolidSyslogMbedTlsStream.h index 2ab2f8eb..31605b15 100644 --- a/Platform/MbedTls/Interface/SolidSyslogMbedTlsStream.h +++ b/Platform/MbedTls/Interface/SolidSyslogMbedTlsStream.h @@ -26,7 +26,10 @@ EXTERN_C_BEGIN void* HandshakeTimeoutContext; /* passed through to GetHandshakeTimeoutMs; NULL is fine */ struct mbedtls_ctr_drbg_context* Rng; /* seeded CTR-DRBG — caller owns */ struct mbedtls_x509_crt* CaChain; /* trust anchors — caller owns */ - const char* ServerName; /* SNI + cert hostname check; NULL to skip */ + const char* ServerName; /* SNI + peer-identity check. A non-empty name is verified against the + cert (SAN/CN). NULL connects chain-only but emits a WARNING — the peer + is unverified (MITM-class). "" is the deliberate opt-out (IP-pinning / + private CA): connect chain-only, no diagnostic. */ struct mbedtls_x509_crt* ClientCertChain; /* leaf (+ intermediates); NULL = no mTLS */ struct mbedtls_pk_context* ClientKey; /* matching private key; NULL = no mTLS */ }; diff --git a/Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c b/Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c index 3343fe6d..153b1acf 100644 --- a/Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c +++ b/Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c @@ -191,9 +191,22 @@ static inline bool MbedTlsStream_BindContextToConfig(struct SolidSyslogMbedTlsSt static inline bool MbedTlsStream_ConfigureExpectedHostname(struct SolidSyslogMbedTlsStream* self) { bool ok = true; - if (self->Config.ServerName != NULL) + const char* serverName = self->Config.ServerName; + if (serverName == NULL) { - ok = mbedtls_ssl_set_hostname(&self->SslContext, self->Config.ServerName) == 0; + /* No expected identity supplied — the handshake will accept any cert that + * chains to a trusted CA, so the peer is unverified. Surface it as a + * WARNING (still connect, preserving the IP-pinned / closed-network case) + * rather than swallowing the MITM-class default silently. S12.28. */ + MbedTlsStream_Report( + SOLIDSYSLOG_SEVERITY_WARNING, + SOLIDSYSLOG_CAT_BAD_CONFIG, + MBEDTLSSTREAM_ERROR_SERVER_NAME_NOT_SET + ); + } + else if (serverName[0] != '\0') + { + ok = mbedtls_ssl_set_hostname(&self->SslContext, serverName) == 0; if (!ok) { MbedTlsStream_Report( @@ -203,6 +216,12 @@ static inline bool MbedTlsStream_ConfigureExpectedHostname(struct SolidSyslogMbe ); } } + else + { + /* Empty string is the deliberate opt-out: the integrator has no name to + * verify against (IP-pinning / private CA) and has said so explicitly, so + * connect chain-only without a diagnostic. */ + } return ok; } diff --git a/Platform/OpenSsl/Interface/SolidSyslogTlsStream.h b/Platform/OpenSsl/Interface/SolidSyslogTlsStream.h index 73dafd0c..101301ae 100644 --- a/Platform/OpenSsl/Interface/SolidSyslogTlsStream.h +++ b/Platform/OpenSsl/Interface/SolidSyslogTlsStream.h @@ -18,7 +18,10 @@ EXTERN_C_BEGIN GetHandshakeTimeoutMs; /* NULL → use SOLIDSYSLOG_TLS_HANDSHAKE_TIMEOUT_MS tunable */ void* HandshakeTimeoutContext; /* passed through to GetHandshakeTimeoutMs; NULL is fine */ const char* CaBundlePath; /* PEM file of trust anchors */ - const char* ServerName; /* SNI + cert hostname check; NULL to skip */ + const char* ServerName; /* SNI + peer-identity check. A non-empty name is verified against the + cert (SAN/CN). NULL connects chain-only but emits a WARNING — the peer + is unverified (MITM-class). "" is the deliberate opt-out (IP-pinning / + private CA): connect chain-only, no diagnostic. */ const char* CipherList; /* TLS 1.2 cipher list; NULL = OpenSSL default */ const char* ClientCertChainPath; /* PEM: leaf cert (+ intermediates); NULL = no mTLS */ const char* ClientKeyPath; /* PEM: matching private key; NULL = no mTLS */ diff --git a/Platform/OpenSsl/Source/SolidSyslogTlsStream.c b/Platform/OpenSsl/Source/SolidSyslogTlsStream.c index e8cc817b..11675c8a 100644 --- a/Platform/OpenSsl/Source/SolidSyslogTlsStream.c +++ b/Platform/OpenSsl/Source/SolidSyslogTlsStream.c @@ -387,10 +387,18 @@ static inline long TlsStream_TransportBioCtrl(BIO* bio, int cmd, long larg, void static inline bool TlsStream_ConfigureExpectedHostname(struct SolidSyslogTlsStream* self) { bool ok = true; - if (self->Config.ServerName != NULL) + const char* serverName = self->Config.ServerName; + if (serverName == NULL) { - ok = (SSL_set_tlsext_host_name(self->Ssl, self->Config.ServerName) == 1) && - (SSL_set1_host(self->Ssl, self->Config.ServerName) == 1); + /* No expected identity supplied — the handshake will accept any cert that + * chains to a trusted CA, so the peer is unverified. Surface it as a + * WARNING (still connect, preserving the IP-pinned / closed-network case) + * rather than swallowing the MITM-class default silently. S12.28. */ + TlsStream_Report(SOLIDSYSLOG_SEVERITY_WARNING, SOLIDSYSLOG_CAT_BAD_CONFIG, TLSSTREAM_ERROR_SERVER_NAME_NOT_SET); + } + else if (serverName[0] != '\0') + { + ok = (SSL_set_tlsext_host_name(self->Ssl, serverName) == 1) && (SSL_set1_host(self->Ssl, serverName) == 1); if (!ok) { TlsStream_Report( @@ -400,6 +408,12 @@ static inline bool TlsStream_ConfigureExpectedHostname(struct SolidSyslogTlsStre ); } } + else + { + /* Empty string is the deliberate opt-out: the integrator has no name to + * verify against (IP-pinning / private CA) and has said so explicitly, so + * connect chain-only without a diagnostic. */ + } return ok; } diff --git a/Tests/MbedTls/SolidSyslogMbedTlsStreamTest.cpp b/Tests/MbedTls/SolidSyslogMbedTlsStreamTest.cpp index fdbb5e90..8851e808 100644 --- a/Tests/MbedTls/SolidSyslogMbedTlsStreamTest.cpp +++ b/Tests/MbedTls/SolidSyslogMbedTlsStreamTest.cpp @@ -274,8 +274,12 @@ TEST(SolidSyslogMbedTlsStream, OpenRetriesHandshakeOnWantWrite) TEST(SolidSyslogMbedTlsStream, OpenClosesTransportAndFreesSslStateWhenHandshakeBudgetExhausts) { - /* mbedtls_ssl_handshake always returns WANT_READ — handshake never makes + /* ServerName set so the handshake timeout is the only error source (a NULL + * ServerName would also emit the unverified-peer WARNING). + * mbedtls_ssl_handshake always returns WANT_READ — handshake never makes * progress, so the bounded budget should expire and Open returns false. */ + config.ServerName = "syslog.example.com"; + ReCreateHandleWithUpdatedConfig(); ArrangePersistentHandshakeError(MBEDTLS_ERR_SSL_WANT_READ); CHECK_FALSE(SolidSyslogStream_Open(handle, addr)); @@ -339,8 +343,11 @@ TEST(SolidSyslogMbedTlsStream, SecondOpenAfterFailedFirstOpenSucceeds) TEST(SolidSyslogMbedTlsStream, OpenClosesTransportAndFreesSslStateWhenHandshakeFailsHard) { - /* Non-WANT error (e.g. a verify/connection failure) is fail-fast — no + /* ServerName set so the handshake hard error is the only error source. + * Non-WANT error (e.g. a verify/connection failure) is fail-fast — no * retry budget burn, no Sleep. */ + config.ServerName = "syslog.example.com"; + ReCreateHandleWithUpdatedConfig(); ArrangePersistentHandshakeError(MBEDTLS_ERR_SSL_BAD_INPUT_DATA); CHECK_FALSE(SolidSyslogStream_Open(handle, addr)); @@ -716,6 +723,59 @@ TEST(SolidSyslogMbedTlsStream, OpenSkipsHostnameWhenServerNameIsNull) LONGS_EQUAL(0, MbedTlsFake_SslSetHostnameCallCount()); } +TEST(SolidSyslogMbedTlsStream, OpenWarnsWhenServerNameIsNull) + +{ + /* setup() left config.ServerName at NULL — peer identity is unverified, which + * the library must surface rather than swallow (S12.28). */ + SolidSyslogStream_Open(handle, addr); + + CALLED_FAKE(ErrorHandlerFake_Handle, ONCE); + POINTERS_EQUAL(&MbedTlsStreamErrorSource, ErrorHandlerFake_LastSource()); + UNSIGNED_LONGS_EQUAL(SOLIDSYSLOG_CAT_BAD_CONFIG, ErrorHandlerFake_LastCategory()); + UNSIGNED_LONGS_EQUAL(MBEDTLSSTREAM_ERROR_SERVER_NAME_NOT_SET, ErrorHandlerFake_LastDetail()); + LONGS_EQUAL(SOLIDSYSLOG_SEVERITY_WARNING, ErrorHandlerFake_LastSeverity()); +} + +TEST(SolidSyslogMbedTlsStream, OpenStillConnectsWhenServerNameIsNull) + +{ + /* The unverified-peer WARNING is observable but non-fatal — the IP-pinned / + * closed-network use case must still connect. */ + CHECK_TRUE(SolidSyslogStream_Open(handle, addr)); + LONGS_EQUAL(0, StreamFake_CloseCallCount(transport)); +} + +TEST(SolidSyslogMbedTlsStream, OpenDoesNotWarnWhenServerNameIsEmpty) + +{ + /* Empty string is the deliberate opt-out — no diagnostic. */ + config.ServerName = ""; + ReCreateHandleWithUpdatedConfig(); + SolidSyslogStream_Open(handle, addr); + + CALLED_FAKE(ErrorHandlerFake_Handle, NEVER); +} + +TEST(SolidSyslogMbedTlsStream, OpenSkipsHostnameSetupWhenServerNameIsEmpty) + +{ + config.ServerName = ""; + ReCreateHandleWithUpdatedConfig(); + SolidSyslogStream_Open(handle, addr); + + LONGS_EQUAL(0, MbedTlsFake_SslSetHostnameCallCount()); +} + +TEST(SolidSyslogMbedTlsStream, OpenConnectsWhenServerNameIsEmpty) + +{ + config.ServerName = ""; + ReCreateHandleWithUpdatedConfig(); + + CHECK_TRUE(SolidSyslogStream_Open(handle, addr)); +} + /* ------------------------------------------------------------------------- * mTLS client identity wiring. When the integrator supplies both a * ClientCertChain and a ClientKey, Open must call mbedtls_ssl_conf_own_cert diff --git a/Tests/SolidSyslogTlsStreamTest.cpp b/Tests/SolidSyslogTlsStreamTest.cpp index 933d1e7e..85a113fa 100644 --- a/Tests/SolidSyslogTlsStreamTest.cpp +++ b/Tests/SolidSyslogTlsStreamTest.cpp @@ -374,6 +374,50 @@ TEST(SolidSyslogTlsStream, OpenSkipsHostnameSetupWhenServerNameIsNull) POINTERS_EQUAL(NULL, OpenSslFake_LastSet1Host()); } +TEST(SolidSyslogTlsStream, OpenWarnsWhenServerNameIsNull) +{ + /* Default config.ServerName is NULL — peer identity is unverified, which the + * library must surface rather than swallow (S12.28). */ + SolidSyslogStream_Open(stream, addr); + CALLED_FAKE(ErrorHandlerFake_Handle, ONCE); + POINTERS_EQUAL(&TlsStreamErrorSource, ErrorHandlerFake_LastSource()); + UNSIGNED_LONGS_EQUAL(SOLIDSYSLOG_CAT_BAD_CONFIG, ErrorHandlerFake_LastCategory()); + UNSIGNED_LONGS_EQUAL(TLSSTREAM_ERROR_SERVER_NAME_NOT_SET, ErrorHandlerFake_LastDetail()); + LONGS_EQUAL(SOLIDSYSLOG_SEVERITY_WARNING, ErrorHandlerFake_LastSeverity()); +} + +TEST(SolidSyslogTlsStream, OpenStillConnectsWhenServerNameIsNull) +{ + /* The unverified-peer WARNING is observable but non-fatal — the IP-pinned / + * closed-network use case must still connect. */ + CHECK_TRUE(SolidSyslogStream_Open(stream, addr)); + LONGS_EQUAL(0, StreamFake_CloseCallCount(transport)); +} + +TEST(SolidSyslogTlsStream, OpenDoesNotWarnWhenServerNameIsEmpty) +{ + /* Empty string is the deliberate opt-out — no diagnostic. */ + config.ServerName = ""; + ReCreateStreamWithUpdatedConfig(); + SolidSyslogStream_Open(stream, addr); + CALLED_FAKE(ErrorHandlerFake_Handle, NEVER); +} + +TEST(SolidSyslogTlsStream, OpenSkipsHostnameSetupWhenServerNameIsEmpty) +{ + config.ServerName = ""; + ReCreateStreamWithUpdatedConfig(); + SolidSyslogStream_Open(stream, addr); + POINTERS_EQUAL(NULL, OpenSslFake_LastSet1Host()); +} + +TEST(SolidSyslogTlsStream, OpenConnectsWhenServerNameIsEmpty) +{ + config.ServerName = ""; + ReCreateStreamWithUpdatedConfig(); + CHECK_TRUE(SolidSyslogStream_Open(stream, addr)); +} + TEST(SolidSyslogTlsStream, OpenAttachesTransportAsBioData) { SolidSyslogStream_Open(stream, addr); @@ -687,9 +731,13 @@ TEST(SolidSyslogTlsStream, OpenReturnsTrueOnHappyPath) TEST(SolidSyslogTlsStream, OpenReturnsFalseWhenHandshakeFails) { - /* Default OpenSslFake_SetConnectFails(true) returns -1 from SSL_connect - * and SSL_get_error reports SSL_ERROR_SSL (the default for SetGetErrorReturn) - * — a non-retryable hard error, which is the HANDSHAKE_REJECTED branch. */ + /* ServerName set so the handshake stage is the only error source (a NULL + * ServerName would also emit the unverified-peer WARNING). Default + * OpenSslFake_SetConnectFails(true) returns -1 from SSL_connect and + * SSL_get_error reports SSL_ERROR_SSL (the default for SetGetErrorReturn) — + * a non-retryable hard error, which is the HANDSHAKE_REJECTED branch. */ + config.ServerName = "logs.example"; + ReCreateStreamWithUpdatedConfig(); OpenSslFake_SetConnectFails(true); OpenSslFake_SetGetErrorReturn(SSL_ERROR_SSL); CHECK_FALSE(SolidSyslogStream_Open(stream, addr)); @@ -1158,8 +1206,11 @@ TEST(SolidSyslogTlsStream, OpenRetriesHandshakeOnWantWrite) TEST(SolidSyslogTlsStream, OpenFailsWhenHandshakeNeverCompletes) { - /* SSL_connect always returns -1 with WANT_READ — handshake never makes + /* ServerName set so the handshake timeout is the only error source. + SSL_connect always returns -1 with WANT_READ — handshake never makes progress, so the bounded budget should expire and Open returns false. */ + config.ServerName = "logs.example"; + ReCreateStreamWithUpdatedConfig(); ArrangePersistentHandshakeError(SSL_ERROR_WANT_READ); CHECK_FALSE(SolidSyslogStream_Open(stream, addr)); CHECK_OPEN_UNWOUND_WITH_ERROR( @@ -1200,7 +1251,10 @@ TEST(SolidSyslogTlsStream, GetterReceivesNullContextWhenContextNotConfigured) TEST(SolidSyslogTlsStream, OpenFailsImmediatelyOnHardSslError) { - /* Non-WANT error (e.g. SSL_ERROR_SSL) is fail-fast — no retry budget burn. */ + /* ServerName set so the handshake hard error is the only error source. + Non-WANT error (e.g. SSL_ERROR_SSL) is fail-fast — no retry budget burn. */ + config.ServerName = "logs.example"; + ReCreateStreamWithUpdatedConfig(); ArrangePersistentHandshakeError(SSL_ERROR_SSL); CHECK_FALSE(SolidSyslogStream_Open(stream, addr)); CALLED_FAKE(OpenSslFake_Connect, ONCE); diff --git a/docs/integrating-mbedtls.md b/docs/integrating-mbedtls.md index f340a210..545c03b1 100644 --- a/docs/integrating-mbedtls.md +++ b/docs/integrating-mbedtls.md @@ -44,7 +44,7 @@ the per-context mbedTLS handles passed through | `GetHandshakeTimeoutMs` / `HandshakeTimeoutContext` | You (optional) | Per-instance accessor pair for the bounded handshake budget. `NULL` falls back to the `SOLIDSYSLOG_TLS_HANDSHAKE_TIMEOUT_MS` compile-time tunable (default 5000 ms). Install when you need to runtime-tune the handshake deadline — slow peers on a constrained link, or per-tenant policy from your existing configuration store. The accessor is called on every `Open`. See [S12.17 #282](https://github.com/DavidCozens/solid-syslog/issues/282). | | `Rng` | You | `mbedtls_ctr_drbg_context*` you seeded yourself. The adapter calls `mbedtls_ctr_drbg_random` against it. Required. | | `CaChain` | You | `mbedtls_x509_crt*` you parsed yourself (from filesystem, baked-in PEM, HSM, whatever fits your build). Required. | -| `ServerName` | You | SNI + cert hostname check string. `NULL` skips the name check; only appropriate for closed networks where IP-pinning replaces hostname identity. | +| `ServerName` | You | SNI + peer-identity check string. A non-empty name is verified against the server certificate (SAN/CN), rejecting any other CA-issued cert. `NULL` connects but the peer is **unverified** (any cert chaining to a trusted CA is accepted — MITM-class), so the library emits a `WARNING` (`BAD_CONFIG` / `MBEDTLSSTREAM_ERROR_SERVER_NAME_NOT_SET`). Note that having no DNS does **not** force this: an IP-pinned target can still set `ServerName` to the name (or IP SAN) on its certificate and get full identity verification. Use `""` only as a deliberate opt-out for closed networks / private CAs where there is genuinely no name to verify — it connects chain-only with no diagnostic. | | `ClientCertChain` / `ClientKey` | You | `mbedtls_x509_crt*` + `mbedtls_pk_context*` for mTLS. Both `NULL` = server-auth-only TLS. Both non-`NULL` = mTLS. Supplying only one is treated as "no client cert" — the adapter never half-configures. | The full struct shape lives in diff --git a/misra_suppressions.txt b/misra_suppressions.txt index 3cbc2454..c47880b8 100644 --- a/misra_suppressions.txt +++ b/misra_suppressions.txt @@ -86,8 +86,8 @@ misra-c2012-11.5:Platform/LwipRaw/Source/SolidSyslogLwipRawDnsResolver.c:149 misra-c2012-11.5:Platform/LwipRaw/Source/SolidSyslogLwipRawDnsResolver.c:211 misra-c2012-11.5:Platform/LwipRaw/Source/SolidSyslogLwipRawTcpStream.c:143 misra-c2012-11.5:Platform/LwipRaw/Source/SolidSyslogLwipRawTcpStream.c:151 -misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:275 -misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:287 +misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:294 +misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:306 misra-c2012-11.5:Platform/Windows/Source/SolidSyslogWinsockDatagram.c:142 misra-c2012-11.5:Platform/Windows/Source/SolidSyslogWinsockTcpStream.c:357 misra-c2012-11.5:Platform/Windows/Source/SolidSyslogWinsockTcpStream.c:377 @@ -199,5 +199,5 @@ misra-c2012-8.9:Core/Source/SolidSyslogFileBlockDevice.c:20 # D.013 — Rule 11.5: void* ↔ unsigned char* at third-party byte-buffer API boundaries # See docs/misra-deviations.md#d013 -misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:312 misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:331 +misra-c2012-11.5:Platform/MbedTls/Source/SolidSyslogMbedTlsStream.c:350