SolidSyslog coverage report
Current view: top level - Platform/MbedTls/Source - SolidSyslogMbedTlsPemBufferCredentials.c (source / functions) Coverage Total Hit
Test: SolidSyslog Lines: 98.9 % 89 88
Test Date: 2026-11-12 23:14:35 Functions: 100.0 % 15 15
Branches: 97.6 % 42 41

             Branch data     Line data    Source code
       1                 :             : /* SPDX-FileCopyrightText: Copyright 2026 Cozens Software Solutions Limited
       2                 :             :  * SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0 OR LicenseRef-PolyForm-Internal-Use-1.0.0 OR LicenseRef-COSOSO-Commercial
       3                 :             :  */
       4                 :             : 
       5                 :             : #include "SolidSyslogMbedTlsPemBufferCredentials.h"
       6                 :             : 
       7                 :             : #include <mbedtls/ctr_drbg.h>
       8                 :             : #include <mbedtls/pk.h>
       9                 :             : #include <mbedtls/ssl.h>
      10                 :             : #include <mbedtls/x509_crt.h>
      11                 :             : #include <stdbool.h>
      12                 :             : #include <stddef.h>
      13                 :             : 
      14                 :             : #include "SolidSyslogErrorCategory.h"
      15                 :             : #include "SolidSyslogMbedTlsCredentialsDefinition.h"
      16                 :             : #include "SolidSyslogMbedTlsPemBufferCredentialsPrivate.h"
      17                 :             : #include "SolidSyslogTlsCredentialsInstalled.h"
      18                 :             : 
      19                 :             : const struct SolidSyslogErrorSource SolidSyslogMbedTlsPemBufferCredentialsErrorSource = {
      20                 :             :     "MbedTlsPemBufferCredentials",
      21                 :             :     SolidSyslogTlsCredentialsErrors_Name
      22                 :             : };
      23                 :             : 
      24                 :             : static bool MbedTlsPemBufferCredentials_Install(
      25                 :             :     struct SolidSyslogMbedTlsCredentials* base,
      26                 :             :     struct mbedtls_ssl_config* conf,
      27                 :             :     struct SolidSyslogTlsCredentialsInstalled* installed
      28                 :             : );
      29                 :             : static inline bool MbedTlsPemBufferCredentials_IsAlreadyInUse(const struct SolidSyslogMbedTlsPemBufferCredentials* self
      30                 :             : );
      31                 :             : static inline bool MbedTlsPemBufferCredentials_ParseTrustAnchors(
      32                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self,
      33                 :             :     struct mbedtls_ssl_config* conf
      34                 :             : );
      35                 :             : static inline void MbedTlsPemBufferCredentials_ConfigureClientIdentity(
      36                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self,
      37                 :             :     struct mbedtls_ssl_config* conf
      38                 :             : );
      39                 :             : static inline bool MbedTlsPemBufferCredentials_HasClientCredential(
      40                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
      41                 :             : );
      42                 :             : static inline bool MbedTlsPemBufferCredentials_HasHalfOfClientCredential(
      43                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
      44                 :             : );
      45                 :             : static inline bool MbedTlsPemBufferCredentials_ClientPemIsTerminated(
      46                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
      47                 :             : );
      48                 :             : static inline bool MbedTlsPemBufferCredentials_ParseClientCredential(struct SolidSyslogMbedTlsPemBufferCredentials* self
      49                 :             : );
      50                 :             : static inline bool MbedTlsPemBufferCredentials_ClientKeyMatchesCertificate(
      51                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self
      52                 :             : );
      53                 :             : static inline bool MbedTlsPemBufferCredentials_IsSupplied(const struct SolidSyslogMbedTlsPemBuffer* pem);
      54                 :             : static inline bool MbedTlsPemBufferCredentials_IsTerminated(const struct SolidSyslogMbedTlsPemBuffer* pem);
      55                 :             : static void MbedTlsPemBufferCredentials_Release(struct SolidSyslogMbedTlsCredentials* base);
      56                 :             : static inline struct SolidSyslogMbedTlsPemBufferCredentials* MbedTlsPemBufferCredentials_SelfFromBase(
      57                 :             :     struct SolidSyslogMbedTlsCredentials* base
      58                 :             : );
      59                 :             : 
      60                 :          33 : void SolidSyslogMbedTlsPemBufferCredentials_Initialise(
      61                 :             :     struct SolidSyslogMbedTlsCredentials* base,
      62                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
      63                 :             : )
      64                 :             : {
      65                 :          33 :     struct SolidSyslogMbedTlsPemBufferCredentials* self = MbedTlsPemBufferCredentials_SelfFromBase(base);
      66                 :          33 :     self->Base.Install = MbedTlsPemBufferCredentials_Install;
      67                 :          33 :     self->Base.Release = MbedTlsPemBufferCredentials_Release;
      68                 :          33 :     self->Config = *config;
      69                 :          33 :     self->OutstandingInstalls = 0U;
      70                 :          33 :     self->InstallHealth = (struct SolidSyslogStreamOpenHealth) {0};
      71                 :          33 :     mbedtls_x509_crt_init(&self->CaChain);
      72                 :          33 :     mbedtls_x509_crt_init(&self->ClientCertChain);
      73                 :          33 :     mbedtls_pk_init(&self->ClientKey);
      74                 :          33 : }
      75                 :             : 
      76                 :         122 : static inline struct SolidSyslogMbedTlsPemBufferCredentials* MbedTlsPemBufferCredentials_SelfFromBase(
      77                 :             :     struct SolidSyslogMbedTlsCredentials* base
      78                 :             : )
      79                 :             : {
      80                 :         122 :     return (struct SolidSyslogMbedTlsPemBufferCredentials*) base;
      81                 :             : }
      82                 :             : 
      83                 :          33 : void SolidSyslogMbedTlsPemBufferCredentials_Cleanup(struct SolidSyslogMbedTlsCredentials* base)
      84                 :             : {
      85                 :          33 :     MbedTlsPemBufferCredentials_Release(base);
      86                 :          33 : }
      87                 :             : 
      88                 :             : /* Parsed here rather than at Create, so the material exists only for a
      89                 :             :  * connection actually being made. Every Install is answered by a Release, which
      90                 :             :  * is where it goes again. */
      91                 :          39 : static bool MbedTlsPemBufferCredentials_Install(
      92                 :             :     struct SolidSyslogMbedTlsCredentials* base,
      93                 :             :     struct mbedtls_ssl_config* conf,
      94                 :             :     struct SolidSyslogTlsCredentialsInstalled* installed
      95                 :             : )
      96                 :             : {
      97                 :          39 :     struct SolidSyslogMbedTlsPemBufferCredentials* self = MbedTlsPemBufferCredentials_SelfFromBase(base);
      98                 :          39 :     installed->TrustAnchorsInstalled = false;
      99                 :          39 :     installed->Fingerprints = self->Config.PeerFingerprints;
     100                 :          39 :     installed->FingerprintCount = self->Config.PeerFingerprintCount;
     101                 :          39 :     self->OutstandingInstalls++;
     102                 :          39 :     bool ok = !MbedTlsPemBufferCredentials_IsAlreadyInUse(self);
     103         [ +  + ]:          39 :     if (!ok)
     104                 :             :     {
     105                 :           4 :         MbedTlsPemBufferCredentials_ReportInstallFailure(
     106                 :             :             self,
     107                 :             :             SOLIDSYSLOG_SEVERITY_ERROR,
     108                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
     109                 :             :             SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_ALREADY_IN_USE
     110                 :             :         );
     111                 :             :     }
     112         [ +  + ]:          35 :     else if (MbedTlsPemBufferCredentials_IsSupplied(&self->Config.CaPem))
     113                 :             :     {
     114                 :          34 :         installed->TrustAnchorsInstalled = MbedTlsPemBufferCredentials_ParseTrustAnchors(self, conf);
     115                 :          34 :         ok = installed->TrustAnchorsInstalled;
     116                 :             :     }
     117                 :             :     else
     118                 :             :     {
     119                 :             :         /* No anchors configured is legitimate - a pin alone can authorise. */
     120                 :             :     }
     121         [ +  + ]:          39 :     if (ok)
     122                 :             :     {
     123                 :          24 :         SolidSyslogStreamOpenHealth_Opened(&self->InstallHealth);
     124                 :          24 :         MbedTlsPemBufferCredentials_ConfigureClientIdentity(self, conf);
     125                 :             :     }
     126                 :          39 :     return ok;
     127                 :             : }
     128                 :             : 
     129                 :             : /* One slot holds the parsed material for one connection. A second stream
     130                 :             :  * sharing this source would parse over material the first is still using, so
     131                 :             :  * it is refused and its Open fails; the sender retries, and succeeds once the
     132                 :             :  * first connection closes. */
     133                 :          39 : static inline bool MbedTlsPemBufferCredentials_IsAlreadyInUse(const struct SolidSyslogMbedTlsPemBufferCredentials* self)
     134                 :             : {
     135                 :          39 :     return self->OutstandingInstalls > 1U;
     136                 :             : }
     137                 :             : 
     138                 :             : /* No fault in our own credential stops delivery: the collector is the
     139                 :             :  * enforcement point for it, and one that requires a client certificate refuses
     140                 :             :  * the handshake anyway. Every failure here leaves nothing installed, so the
     141                 :             :  * connection continues server-authenticated rather than half-presenting a
     142                 :             :  * credential. Whatever was parsed before the fault is released with the rest at
     143                 :             :  * Close. */
     144                 :          24 : static inline void MbedTlsPemBufferCredentials_ConfigureClientIdentity(
     145                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self,
     146                 :             :     struct mbedtls_ssl_config* conf
     147                 :             : )
     148                 :             : {
     149         [ +  + ]:          24 :     if (MbedTlsPemBufferCredentials_HasClientCredential(&self->Config))
     150                 :             :     {
     151         [ +  + ]:          13 :         if (MbedTlsPemBufferCredentials_ClientPemIsTerminated(&self->Config) == false)
     152                 :             :         {
     153                 :           3 :             MbedTlsPemBufferCredentials_Report(
     154                 :             :                 SOLIDSYSLOG_SEVERITY_WARNING,
     155                 :             :                 SOLIDSYSLOG_CAT_BAD_CONFIG,
     156                 :             :                 SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_PEM_NOT_TERMINATED
     157                 :             :             );
     158                 :             :         }
     159         [ +  + ]:          10 :         else if (MbedTlsPemBufferCredentials_ParseClientCredential(self) == false)
     160                 :             :         {
     161                 :           3 :             MbedTlsPemBufferCredentials_Report(
     162                 :             :                 SOLIDSYSLOG_SEVERITY_WARNING,
     163                 :             :                 SOLIDSYSLOG_CAT_BAD_CONFIG,
     164                 :             :                 SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_NOT_PARSED
     165                 :             :             );
     166                 :             :         }
     167         [ +  + ]:           7 :         else if (MbedTlsPemBufferCredentials_ClientKeyMatchesCertificate(self) == false)
     168                 :             :         {
     169                 :           1 :             MbedTlsPemBufferCredentials_Report(
     170                 :             :                 SOLIDSYSLOG_SEVERITY_WARNING,
     171                 :             :                 SOLIDSYSLOG_CAT_BAD_CONFIG,
     172                 :             :                 SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_MISMATCHED
     173                 :             :             );
     174                 :             :         }
     175                 :             :         /* Only MBEDTLS_ERR_SSL_ALLOC_FAILED, which returns before the key_cert
     176                 :             :          * node is appended, so nothing is left half-configured. */
     177         [ -  + ]:           6 :         else if (mbedtls_ssl_conf_own_cert(conf, &self->ClientCertChain, &self->ClientKey) != 0)
     178                 :             :         {
     179                 :           0 :             MbedTlsPemBufferCredentials_Report(
     180                 :             :                 SOLIDSYSLOG_SEVERITY_WARNING,
     181                 :             :                 SOLIDSYSLOG_CAT_BAD_CONFIG,
     182                 :             :                 SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_NOT_INSTALLED
     183                 :             :             );
     184                 :             :         }
     185                 :             :         else
     186                 :             :         {
     187                 :             :             /* Parsed, paired and installed - the credential will be presented. */
     188                 :             :         }
     189                 :             :     }
     190         [ +  + ]:          11 :     else if (MbedTlsPemBufferCredentials_HasHalfOfClientCredential(&self->Config))
     191                 :             :     {
     192                 :           1 :         MbedTlsPemBufferCredentials_Report(
     193                 :             :             SOLIDSYSLOG_SEVERITY_WARNING,
     194                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
     195                 :             :             SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_INCOMPLETE
     196                 :             :         );
     197                 :             :     }
     198                 :             :     else
     199                 :             :     {
     200                 :             :         /* Neither supplied - server-authenticated TLS is the deliberate case. */
     201                 :             :     }
     202                 :          24 : }
     203                 :             : 
     204                 :          24 : static inline bool MbedTlsPemBufferCredentials_HasClientCredential(
     205                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
     206                 :             : )
     207                 :             : {
     208   [ +  +  +  + ]:          38 :     return MbedTlsPemBufferCredentials_IsSupplied(&config->ClientCertPem) &&
     209                 :          14 :            MbedTlsPemBufferCredentials_IsSupplied(&config->ClientKeyPem);
     210                 :             : }
     211                 :             : 
     212                 :             : /* One half without the other. The integrator asked for mutual TLS and will not
     213                 :             :  * get it, so it is reported rather than read as a decision to go without. */
     214                 :          11 : static inline bool MbedTlsPemBufferCredentials_HasHalfOfClientCredential(
     215                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
     216                 :             : )
     217                 :             : {
     218                 :          22 :     return MbedTlsPemBufferCredentials_IsSupplied(&config->ClientCertPem) !=
     219                 :          11 :            MbedTlsPemBufferCredentials_IsSupplied(&config->ClientKeyPem);
     220                 :             : }
     221                 :             : 
     222                 :             : /* Both halves, because a certificate whose key is unusable is no more use than
     223                 :             :  * neither. */
     224                 :          13 : static inline bool MbedTlsPemBufferCredentials_ClientPemIsTerminated(
     225                 :             :     const struct SolidSyslogMbedTlsPemBufferCredentialsConfig* config
     226                 :             : )
     227                 :             : {
     228   [ +  +  +  + ]:          24 :     return MbedTlsPemBufferCredentials_IsTerminated(&config->ClientCertPem) &&
     229                 :          11 :            MbedTlsPemBufferCredentials_IsTerminated(&config->ClientKeyPem);
     230                 :             : }
     231                 :             : 
     232                 :          10 : static inline bool MbedTlsPemBufferCredentials_ParseClientCredential(struct SolidSyslogMbedTlsPemBufferCredentials* self
     233                 :             : )
     234                 :             : {
     235                 :          10 :     return (mbedtls_x509_crt_parse(
     236                 :             :                 &self->ClientCertChain,
     237                 :             :                 self->Config.ClientCertPem.Bytes,
     238                 :             :                 self->Config.ClientCertPem.Length
     239   [ +  +  +  + ]:          19 :             ) == 0) &&
     240                 :           9 :            (mbedtls_pk_parse_key(
     241                 :             :                 &self->ClientKey,
     242                 :             :                 self->Config.ClientKeyPem.Bytes,
     243                 :             :                 self->Config.ClientKeyPem.Length,
     244                 :             :                 NULL,
     245                 :             :                 0U,
     246                 :             :                 mbedtls_ctr_drbg_random,
     247                 :           9 :                 self->Config.Rng
     248                 :             :             ) == 0);
     249                 :             : }
     250                 :             : 
     251                 :             : /* mbedtls_ssl_conf_own_cert does not check the pair it is handed, and names this
     252                 :             :  * function in its own documentation as the way to check it. */
     253                 :           7 : static inline bool MbedTlsPemBufferCredentials_ClientKeyMatchesCertificate(
     254                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self
     255                 :             : )
     256                 :             : {
     257                 :           7 :     return mbedtls_pk_check_pair(
     258                 :           7 :                &self->ClientCertChain.pk,
     259                 :           7 :                &self->ClientKey,
     260                 :             :                mbedtls_ctr_drbg_random,
     261                 :           7 :                self->Config.Rng
     262                 :           7 :            ) == 0;
     263                 :             : }
     264                 :             : 
     265                 :             : /* Mbed TLS reads a certificate buffer whose last byte is not NUL as DER, so a
     266                 :             :  * length given as strlen rather than strlen + 1 fails as "not a certificate"
     267                 :             :  * and says nothing about the length. The check is one byte inside the declared
     268                 :             :  * extent, and it names the fault the integrator actually made. */
     269                 :          34 : static inline bool MbedTlsPemBufferCredentials_ParseTrustAnchors(
     270                 :             :     struct SolidSyslogMbedTlsPemBufferCredentials* self,
     271                 :             :     struct mbedtls_ssl_config* conf
     272                 :             : )
     273                 :             : {
     274                 :          34 :     bool parsed = false;
     275         [ +  + ]:          34 :     if (MbedTlsPemBufferCredentials_IsTerminated(&self->Config.CaPem) == false)
     276                 :             :     {
     277                 :           4 :         MbedTlsPemBufferCredentials_ReportInstallFailure(
     278                 :             :             self,
     279                 :             :             SOLIDSYSLOG_SEVERITY_ERROR,
     280                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
     281                 :             :             SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_PEM_NOT_TERMINATED
     282                 :             :         );
     283                 :             :     }
     284         [ +  + ]:          30 :     else if (mbedtls_x509_crt_parse(&self->CaChain, self->Config.CaPem.Bytes, self->Config.CaPem.Length) != 0)
     285                 :             :     {
     286                 :           7 :         MbedTlsPemBufferCredentials_ReportInstallFailure(
     287                 :             :             self,
     288                 :             :             SOLIDSYSLOG_SEVERITY_ERROR,
     289                 :             :             SOLIDSYSLOG_CAT_BAD_CONFIG,
     290                 :             :             SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_TRUST_ANCHORS_NOT_PARSED
     291                 :             :         );
     292                 :             :     }
     293                 :             :     else
     294                 :             :     {
     295                 :          23 :         mbedtls_ssl_conf_ca_chain(conf, &self->CaChain, NULL);
     296                 :          23 :         parsed = true;
     297                 :             :     }
     298                 :          34 :     return parsed;
     299                 :             : }
     300                 :             : 
     301                 :             : /* A NULL buffer is the documented way to say "not supplied". A pointer with an
     302                 :             :  * unusable extent is a mistake instead, and is reported rather than read as a
     303                 :             :  * decision to go without - the integrator who made it believes the material is
     304                 :             :  * in force. */
     305                 :          95 : static inline bool MbedTlsPemBufferCredentials_IsSupplied(const struct SolidSyslogMbedTlsPemBuffer* pem)
     306                 :             : {
     307                 :          95 :     return pem->Bytes != NULL;
     308                 :             : }
     309                 :             : 
     310                 :             : /* Guards its own read: a zero length has no last byte to test, and would index
     311                 :             :  * at SIZE_MAX. */
     312                 :          58 : static inline bool MbedTlsPemBufferCredentials_IsTerminated(const struct SolidSyslogMbedTlsPemBuffer* pem)
     313                 :             : {
     314   [ +  +  +  + ]:          58 :     return (pem->Length > 0U) && (pem->Bytes[pem->Length - 1U] == (unsigned char) '\0');
     315                 :             : }
     316                 :             : 
     317                 :             : /* Freeing is what wipes: mbedtls_pk_free zeroises the key context and every
     318                 :             :  * limb of the private key, and mbedtls_x509_crt_free zeroises the DER it
     319                 :             :  * decoded. Both leave the structs in the state an init produces, so the next
     320                 :             :  * Install parses into them again, and a second Release is harmless. */
     321                 :          50 : static void MbedTlsPemBufferCredentials_Release(struct SolidSyslogMbedTlsCredentials* base)
     322                 :             : {
     323                 :          50 :     struct SolidSyslogMbedTlsPemBufferCredentials* self = MbedTlsPemBufferCredentials_SelfFromBase(base);
     324         [ +  + ]:          50 :     if (self->OutstandingInstalls > 0U)
     325                 :             :     {
     326                 :          39 :         self->OutstandingInstalls--;
     327                 :             :     }
     328         [ +  + ]:          50 :     if (self->OutstandingInstalls == 0U)
     329                 :             :     {
     330                 :          46 :         mbedtls_x509_crt_free(&self->CaChain);
     331                 :          46 :         mbedtls_x509_crt_free(&self->ClientCertChain);
     332                 :          46 :         mbedtls_pk_free(&self->ClientKey);
     333                 :             :     }
     334                 :          50 : }
        

Generated by: LCOV version 2.0-1