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 "SolidSyslogMbedTlsHandleCredentials.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 "SolidSyslogMbedTlsHandleCredentialsPrivate.h"
17 : : #include "SolidSyslogTlsCredentialsInstalled.h"
18 : :
19 : : const struct SolidSyslogErrorSource SolidSyslogMbedTlsHandleCredentialsErrorSource = {
20 : : "MbedTlsHandleCredentials",
21 : : SolidSyslogTlsCredentialsErrors_Name
22 : : };
23 : :
24 : : static bool MbedTlsHandleCredentials_Install(
25 : : struct SolidSyslogMbedTlsCredentials* base,
26 : : struct mbedtls_ssl_config* conf,
27 : : struct SolidSyslogTlsCredentialsInstalled* installed
28 : : );
29 : : static inline void MbedTlsHandleCredentials_ConfigureClientIdentity(
30 : : struct mbedtls_ssl_config* conf,
31 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
32 : : );
33 : : static inline bool MbedTlsHandleCredentials_HasClientCredential(
34 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
35 : : );
36 : : static inline bool MbedTlsHandleCredentials_ClientKeyMatchesCertificate(
37 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
38 : : );
39 : : static inline bool MbedTlsHandleCredentials_HasHalfOfClientCredential(
40 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
41 : : );
42 : : static void MbedTlsHandleCredentials_Release(struct SolidSyslogMbedTlsCredentials* base);
43 : : static inline struct SolidSyslogMbedTlsHandleCredentials* MbedTlsHandleCredentials_SelfFromBase(
44 : : struct SolidSyslogMbedTlsCredentials* base
45 : : );
46 : :
47 : 51 : void SolidSyslogMbedTlsHandleCredentials_Initialise(
48 : : struct SolidSyslogMbedTlsCredentials* base,
49 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
50 : : )
51 : : {
52 : 51 : struct SolidSyslogMbedTlsHandleCredentials* self = MbedTlsHandleCredentials_SelfFromBase(base);
53 : 51 : self->Base.Install = MbedTlsHandleCredentials_Install;
54 : 51 : self->Base.Release = MbedTlsHandleCredentials_Release;
55 : 51 : self->Config = *config;
56 : 51 : }
57 : :
58 : 98 : static inline struct SolidSyslogMbedTlsHandleCredentials* MbedTlsHandleCredentials_SelfFromBase(
59 : : struct SolidSyslogMbedTlsCredentials* base
60 : : )
61 : : {
62 : 98 : return (struct SolidSyslogMbedTlsHandleCredentials*) base;
63 : : }
64 : :
65 : : /* The handles are installed on every connection rather than held on the
66 : : * ssl_config across them, because mbedtls_ssl_config_free at Close takes the
67 : : * key_cert nodes with it - each Open builds the configuration again from what
68 : : * the integrator still owns. */
69 : 47 : static bool MbedTlsHandleCredentials_Install(
70 : : struct SolidSyslogMbedTlsCredentials* base,
71 : : struct mbedtls_ssl_config* conf,
72 : : struct SolidSyslogTlsCredentialsInstalled* installed
73 : : )
74 : : {
75 : 47 : struct SolidSyslogMbedTlsHandleCredentials* self = MbedTlsHandleCredentials_SelfFromBase(base);
76 : 47 : installed->TrustAnchorsInstalled = self->Config.CaChain != NULL;
77 : 47 : installed->Fingerprints = self->Config.PeerFingerprints;
78 : 47 : installed->FingerprintCount = self->Config.PeerFingerprintCount;
79 [ + + ]: 47 : if (installed->TrustAnchorsInstalled)
80 : : {
81 : 37 : mbedtls_ssl_conf_ca_chain(conf, self->Config.CaChain, NULL);
82 : : }
83 : 47 : MbedTlsHandleCredentials_ConfigureClientIdentity(conf, &self->Config);
84 : 47 : return true;
85 : : }
86 : :
87 : : /* No fault in our own credential stops delivery: the collector is the
88 : : * enforcement point for it, and one that requires a client certificate refuses
89 : : * the handshake anyway. Every failure here leaves nothing installed, so the
90 : : * connection continues server-authenticated rather than half-presenting a
91 : : * credential. */
92 : 47 : static inline void MbedTlsHandleCredentials_ConfigureClientIdentity(
93 : : struct mbedtls_ssl_config* conf,
94 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
95 : : )
96 : : {
97 [ + + ]: 47 : if (MbedTlsHandleCredentials_HasClientCredential(config))
98 : : {
99 [ + + ]: 9 : if (MbedTlsHandleCredentials_ClientKeyMatchesCertificate(config) == false)
100 : : {
101 : 2 : MbedTlsHandleCredentials_Report(
102 : : SOLIDSYSLOG_SEVERITY_WARNING,
103 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
104 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_MISMATCHED
105 : : );
106 : : }
107 : : /* Only MBEDTLS_ERR_SSL_ALLOC_FAILED, which returns before the key_cert
108 : : * node is appended, so nothing is left half-configured. */
109 [ + + ]: 7 : else if (mbedtls_ssl_conf_own_cert(conf, config->ClientCertChain, config->ClientKey) != 0)
110 : : {
111 : 2 : MbedTlsHandleCredentials_Report(
112 : : SOLIDSYSLOG_SEVERITY_WARNING,
113 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
114 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_NOT_INSTALLED
115 : : );
116 : : }
117 : : else
118 : : {
119 : : /* Paired and installed - the credential will be presented. */
120 : : }
121 : : }
122 [ + + ]: 38 : else if (MbedTlsHandleCredentials_HasHalfOfClientCredential(config))
123 : : {
124 : 3 : MbedTlsHandleCredentials_Report(
125 : : SOLIDSYSLOG_SEVERITY_WARNING,
126 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
127 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_INCOMPLETE
128 : : );
129 : : }
130 : : else
131 : : {
132 : : /* Neither supplied - server-authenticated TLS is the deliberate case. */
133 : : }
134 : 47 : }
135 : :
136 : 47 : static inline bool MbedTlsHandleCredentials_HasClientCredential(
137 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
138 : : )
139 : : {
140 [ + + + + ]: 47 : return (config->ClientCertChain != NULL) && (config->ClientKey != NULL);
141 : : }
142 : :
143 : : /* mbedtls_ssl_conf_own_cert does not check the pair it is handed, and names this
144 : : * function in its own documentation as the way to check it. */
145 : 9 : static inline bool MbedTlsHandleCredentials_ClientKeyMatchesCertificate(
146 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
147 : : )
148 : : {
149 : 9 : return mbedtls_pk_check_pair(
150 : 9 : &config->ClientCertChain->pk,
151 : 9 : config->ClientKey,
152 : : mbedtls_ctr_drbg_random,
153 : 9 : config->Rng
154 : 9 : ) == 0;
155 : : }
156 : :
157 : : /* One half without the other. The integrator asked for mutual TLS and will not
158 : : * get it, so it is reported rather than read as a decision to go without. */
159 : 38 : static inline bool MbedTlsHandleCredentials_HasHalfOfClientCredential(
160 : : const struct SolidSyslogMbedTlsHandleCredentialsConfig* config
161 : : )
162 : : {
163 : 38 : return (config->ClientCertChain != NULL) != (config->ClientKey != NULL);
164 : : }
165 : :
166 : : /* Nothing to release. This backend carries handles the integrator built and
167 : : * still owns, and the ssl_config the stream frees at Close lets go of them. A
168 : : * backend that acquires material itself - one parsing a PEM buffer, or
169 : : * unwrapping a key - is where Release does real work. */
170 : 30 : static void MbedTlsHandleCredentials_Release(struct SolidSyslogMbedTlsCredentials* base)
171 : : {
172 : : (void) base;
173 : 30 : }
|