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 "SolidSyslogOpenSslPemFileCredentials.h"
6 : :
7 : : #include <stdbool.h>
8 : : #include <stddef.h>
9 : :
10 : : #include <openssl/ssl.h>
11 : :
12 : : #include "SolidSyslogOpenSslCredentialsDefinition.h"
13 : : #include "SolidSyslogErrorCategory.h"
14 : : #include "SolidSyslogOpenSslPemFileCredentialsPrivate.h"
15 : : #include "SolidSyslogTlsCredentialsInstalled.h"
16 : :
17 : : const struct SolidSyslogErrorSource SolidSyslogOpenSslPemFileCredentialsErrorSource = {
18 : : "OpenSslPemFileCredentials",
19 : : SolidSyslogTlsCredentialsErrors_Name
20 : : };
21 : :
22 : : static bool OpenSslPemFileCredentials_Install(
23 : : struct SolidSyslogOpenSslCredentials* base,
24 : : SSL_CTX* ctx,
25 : : struct SolidSyslogTlsCredentialsInstalled* installed
26 : : );
27 : : static inline void OpenSslPemFileCredentials_ConfigureClientIdentity(
28 : : SSL_CTX* ctx,
29 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
30 : : );
31 : : static inline bool OpenSslPemFileCredentials_HasClientCredential(
32 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
33 : : );
34 : : static inline bool OpenSslPemFileCredentials_HasHalfOfClientCredential(
35 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
36 : : );
37 : : static inline void OpenSslPemFileCredentials_LoadClientCredential(
38 : : SSL_CTX* ctx,
39 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
40 : : );
41 : : static void OpenSslPemFileCredentials_Release(struct SolidSyslogOpenSslCredentials* base);
42 : : static inline struct SolidSyslogOpenSslPemFileCredentials* OpenSslPemFileCredentials_SelfFromBase(
43 : : struct SolidSyslogOpenSslCredentials* base
44 : : );
45 : :
46 : 57 : void SolidSyslogOpenSslPemFileCredentials_Initialise(
47 : : struct SolidSyslogOpenSslCredentials* base,
48 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
49 : : )
50 : : {
51 : 57 : struct SolidSyslogOpenSslPemFileCredentials* self = OpenSslPemFileCredentials_SelfFromBase(base);
52 : 57 : self->Base.Install = OpenSslPemFileCredentials_Install;
53 : 57 : self->Base.Release = OpenSslPemFileCredentials_Release;
54 : 57 : self->Config = *config;
55 : 57 : self->InstallHealth = (struct SolidSyslogStreamOpenHealth) {0};
56 : 57 : }
57 : :
58 : 112 : static inline struct SolidSyslogOpenSslPemFileCredentials* OpenSslPemFileCredentials_SelfFromBase(
59 : : struct SolidSyslogOpenSslCredentials* base
60 : : )
61 : : {
62 : 112 : return (struct SolidSyslogOpenSslPemFileCredentials*) base;
63 : : }
64 : :
65 : : /* Trust anchors are named by path and opened by OpenSSL - this library performs
66 : : * no file handling of its own, so the PEM bytes never pass through it. The
67 : : * paths are re-read here rather than at Create, so a credential replaced while
68 : : * the device runs is picked up on the next connection. */
69 : 55 : static bool OpenSslPemFileCredentials_Install(
70 : : struct SolidSyslogOpenSslCredentials* base,
71 : : SSL_CTX* ctx,
72 : : struct SolidSyslogTlsCredentialsInstalled* installed
73 : : )
74 : : {
75 : 55 : struct SolidSyslogOpenSslPemFileCredentials* self = OpenSslPemFileCredentials_SelfFromBase(base);
76 : 55 : bool ok = true;
77 : 55 : installed->TrustAnchorsInstalled = false;
78 : 55 : installed->Fingerprints = self->Config.PeerFingerprints;
79 : 55 : installed->FingerprintCount = self->Config.PeerFingerprintCount;
80 [ + + ]: 55 : if (self->Config.CaBundlePath != NULL)
81 : : {
82 : 44 : installed->TrustAnchorsInstalled = SSL_CTX_load_verify_locations(ctx, self->Config.CaBundlePath, NULL) == 1;
83 : 44 : ok = installed->TrustAnchorsInstalled;
84 [ + + ]: 44 : if (!ok)
85 : : {
86 : 8 : OpenSslPemFileCredentials_ReportInstallFailure(
87 : : self,
88 : : SOLIDSYSLOG_SEVERITY_ERROR,
89 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
90 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_TRUST_ANCHORS_NOT_LOADED
91 : : );
92 : : }
93 : : }
94 [ + + ]: 55 : if (ok)
95 : : {
96 : 47 : SolidSyslogStreamOpenHealth_Opened(&self->InstallHealth);
97 : : }
98 : 55 : OpenSslPemFileCredentials_ConfigureClientIdentity(ctx, &self->Config);
99 : 55 : return ok;
100 : : }
101 : :
102 : : /* No fault in our own credential stops delivery: the collector is the
103 : : * enforcement point for it, and one that requires a client certificate refuses
104 : : * the handshake anyway. OpenSSL presents a certificate only where both halves
105 : : * are installed and paired, so a credential it will not take degrades to
106 : : * server-authenticated TLS rather than being half-presented. */
107 : 55 : static inline void OpenSslPemFileCredentials_ConfigureClientIdentity(
108 : : SSL_CTX* ctx,
109 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
110 : : )
111 : : {
112 [ + + ]: 55 : if (OpenSslPemFileCredentials_HasClientCredential(config))
113 : : {
114 : 7 : OpenSslPemFileCredentials_LoadClientCredential(ctx, config);
115 : : }
116 [ + + ]: 48 : else if (OpenSslPemFileCredentials_HasHalfOfClientCredential(config))
117 : : {
118 : 1 : OpenSslPemFileCredentials_Report(
119 : : SOLIDSYSLOG_SEVERITY_WARNING,
120 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
121 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_INCOMPLETE
122 : : );
123 : : }
124 : : else
125 : : {
126 : : /* Neither supplied - server-authenticated TLS is the deliberate case. */
127 : : }
128 : 55 : }
129 : :
130 : 55 : static inline bool OpenSslPemFileCredentials_HasClientCredential(
131 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
132 : : )
133 : : {
134 [ + + + + ]: 55 : return (config->ClientCertChainPath != NULL) && (config->ClientKeyPath != NULL);
135 : : }
136 : :
137 : : /* One half without the other. The integrator asked for mutual TLS and will not
138 : : * get it, so it is reported rather than read as a decision to go without. */
139 : 48 : static inline bool OpenSslPemFileCredentials_HasHalfOfClientCredential(
140 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
141 : : )
142 : : {
143 : 48 : return (config->ClientCertChainPath != NULL) != (config->ClientKeyPath != NULL);
144 : : }
145 : :
146 : : /* A key that does not match its certificate is refused by SSL_CTX_use_PrivateKey_file
147 : : * itself where both are of the same type, so it reaches the explicit pairing check
148 : : * only as a cross-type pair. The two are reported apart where OpenSSL tells them
149 : : * apart, and a mismatch it hides inside the load is reported as one that would
150 : : * not install. */
151 : 7 : static inline void OpenSslPemFileCredentials_LoadClientCredential(
152 : : SSL_CTX* ctx,
153 : : const struct SolidSyslogOpenSslPemFileCredentialsConfig* config
154 : : )
155 : : {
156 [ + + + + ]: 12 : bool installed = (SSL_CTX_use_certificate_chain_file(ctx, config->ClientCertChainPath) == 1) &&
157 : 5 : (SSL_CTX_use_PrivateKey_file(ctx, config->ClientKeyPath, SSL_FILETYPE_PEM) == 1);
158 [ + + ]: 7 : if (installed == false)
159 : : {
160 : 3 : OpenSslPemFileCredentials_Report(
161 : : SOLIDSYSLOG_SEVERITY_WARNING,
162 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
163 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_NOT_INSTALLED
164 : : );
165 : : }
166 [ + + ]: 4 : else if (SSL_CTX_check_private_key(ctx) != 1)
167 : : {
168 : 1 : OpenSslPemFileCredentials_Report(
169 : : SOLIDSYSLOG_SEVERITY_WARNING,
170 : : SOLIDSYSLOG_CAT_BAD_CONFIG,
171 : : SOLIDSYSLOG_TLS_CREDENTIALS_ERROR_CLIENT_CREDENTIAL_MISMATCHED
172 : : );
173 : : }
174 : : else
175 : : {
176 : : /* Installed and paired - the credential will be presented. */
177 : : }
178 : 7 : }
179 : :
180 : : /* Nothing to release. This backend holds paths, and OpenSSL owns what it parsed
181 : : * from them: the SSL_CTX the stream frees at Close takes the certificate and the
182 : : * key with it. A backend that parses material itself - one reading a PEM buffer,
183 : : * or unwrapping a key - is where Release does real work. */
184 : 37 : static void OpenSslPemFileCredentials_Release(struct SolidSyslogOpenSslCredentials* base)
185 : : {
186 : : (void) base;
187 : 37 : }
|