1 /*
2 * Copyright 2024-2025 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #ifndef PCMK__CRM_COMMON_TLS_INTERNAL__H
11 #define PCMK__CRM_COMMON_TLS_INTERNAL__H
12
13 #include <gnutls/gnutls.h> // gnutls_session_t, gnutls_dh_params_t, etc.
14
15 #include <crm/common/ipc_internal.h> // pcmk__client_t
16 #include <crm/common/remote_internal.h> // pcmk__remote_t
17
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21
22 typedef struct {
23 bool server;
24 gnutls_dh_params_t dh_params;
25 gnutls_credentials_type_t cred_type;
26
27 const char *ca_file;
28 const char *cert_file;
29 const char *crl_file;
30 const char *key_file;
31
32 union {
33 gnutls_anon_server_credentials_t anon_s;
34 gnutls_anon_client_credentials_t anon_c;
35 gnutls_certificate_credentials_t cert;
36 gnutls_psk_server_credentials_t psk_s;
37 gnutls_psk_client_credentials_t psk_c;
38 } credentials;
39 } pcmk__tls_t;
40
41 /*!
42 * \internal
43 * \brief Free a previously allocated \p pcmk__tls_t object
44 *
45 * \param[in,out] tls The object to free
46 */
47 void pcmk__free_tls(pcmk__tls_t *tls);
48
49 /*!
50 * \internal
51 * \brief Initialize a new TLS object
52 *
53 * Unlike \p pcmk__new_tls_session, this function is used for creating the
54 * global environment for TLS connections.
55 *
56 * \param[in,out] tls The object to be allocated and initialized
57 * \param[in] server Is this a server or not?
58 * \param[in] cred_type What type of gnutls credentials are in use?
59 * (GNUTLS_CRD_* constants)
60 *
61 * \returns Standard Pacemaker return code
62 */
63 int pcmk__init_tls(pcmk__tls_t **tls, bool server,
64 gnutls_credentials_type_t cred_type);
65
66 /*!
67 * \internal
68 * \brief Initialize Diffie-Hellman parameters for a TLS server
69 *
70 * \param[out] dh_params Parameter object to initialize
71 *
72 * \return Standard Pacemaker return code
73 * \todo The current best practice is to allow the client and server to
74 * negotiate the Diffie-Hellman parameters via a TLS extension (RFC 7919).
75 * However, we have to support both older versions of GnuTLS (<3.6) that
76 * don't support the extension on our side, and older Pacemaker versions
77 * that don't support the extension on the other side. The next best
78 * practice would be to use a known good prime (see RFC 5114 section 2.2),
79 * possibly stored in a file distributed with Pacemaker.
80 */
81 int pcmk__init_tls_dh(gnutls_dh_params_t *dh_params);
82
83 /*!
84 * \internal
85 * \brief Initialize a new TLS session
86 *
87 * \param[in] tls A TLS environment object
88 * \param[in] csock Connected socket for TLS session
89 *
90 * \return Pointer to newly created session object, or NULL on error
91 */
92 gnutls_session_t pcmk__new_tls_session(pcmk__tls_t *tls, int csock);
93
94 int pcmk__tls_get_client_sock(const pcmk__remote_t *remote);
95
96 /*!
97 * \internal
98 * \brief Add the client PSK key to the TLS environment
99 *
100 * This function must be called for all TLS clients that are using PSK for
101 * authentication.
102 *
103 * \param[in,out] tls The TLS environment
104 * \param[in] key The client's PSK key
105 */
106 void pcmk__tls_add_psk_key(pcmk__tls_t *tls, gnutls_datum_t *key);
107
108 /*!
109 * \internal
110 * \brief Register the server's PSK credential fetching callback
111 *
112 * This function must be called for all TLS servers that are using PSK for
113 * authentication.
114 *
115 * \param[in,out] tls The TLS environment
116 * \param[in] cb The server's PSK credential fetching callback
117 */
118 void pcmk__tls_add_psk_callback(pcmk__tls_t *tls,
119 gnutls_psk_server_credentials_function *cb);
120
121 /*!
122 * \internal
123 * \brief Process handshake data from TLS client
124 *
125 * Read as much TLS handshake data as is available.
126 *
127 * \param[in] client Client connection
128 *
129 * \return Standard Pacemaker return code (of particular interest, EAGAIN
130 * if some data was successfully read but more data is needed)
131 */
132 int pcmk__read_handshake_data(const pcmk__client_t *client);
133
134 /*!
135 * \internal
136 * \brief Log if a TLS certificate is near its expiration date
137 *
138 * \param[in] session The gnutls session object after handshaking is
139 * complete
140 */
141 void pcmk__tls_check_cert_expiration(gnutls_session_t session);
142
143 /*!
144 * \internal
145 * \brief Perform client TLS handshake after establishing TCP socket
146 *
147 * \param[in,out] remote Newly established remote connection
148 * \param[in] timeout_sec Abort handshake if not completed within this time
149 * \param[out] gnutls_rc If this is non-NULL, it will be set to the GnuTLS
150 * rc (for logging) if this function returns EPROTO,
151 * otherwise GNUTLS_E_SUCCESS
152 *
153 * \return Standard Pacemaker return code
154 */
155 int pcmk__tls_client_handshake(pcmk__remote_t *remote, int timeout_sec,
156 int *gnutls_rc);
157
158 /*!
159 * \internal
160 * \brief Make a single attempt to perform the client TLS handshake
161 *
162 * \param[in,out] remote Newly established remote connection
163 * \param[out] gnutls_rc If this is non-NULL, it will be set to the GnuTLS
164 * rc (for logging) if this function returns EPROTO,
165 * otherwise GNUTLS_E_SUCCESS
166 *
167 * \return Standard Pacemaker return code
168 */
169 int pcmk__tls_client_try_handshake(pcmk__remote_t *remote, int *gnutls_rc);
170
171 /*!
172 * \internal
173 * \brief Is X509 authentication supported by the environment?
174 *
175 * \return true if the appropriate environment variables are set (see
176 * etc/sysconfig/pacemaker.in), otherwise false
177 */
178 bool pcmk__x509_enabled(void);
179
180 #ifdef __cplusplus
181 }
182 #endif
183
184 #endif // PCMK__CRM_COMMON_TLS_INTERNAL__H