1 /*
2 * Copyright 2024 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 /*!
95 * \internal
96 * \brief Add the client PSK key to the TLS environment
97 *
98 * This function must be called for all TLS clients that are using PSK for
99 * authentication.
100 *
101 * \param[in,out] tls The TLS environment
102 * \param[in] key The client's PSK key
103 */
104 void pcmk__tls_add_psk_key(pcmk__tls_t *tls, gnutls_datum_t *key);
105
106 /*!
107 * \internal
108 * \brief Register the server's PSK credential fetching callback
109 *
110 * This function must be called for all TLS servers that are using PSK for
111 * authentication.
112 *
113 * \param[in,out] tls The TLS environment
114 * \param[in] cb The server's PSK credential fetching callback
115 */
116 void pcmk__tls_add_psk_callback(pcmk__tls_t *tls,
117 gnutls_psk_server_credentials_function *cb);
118
119 /*!
120 * \internal
121 * \brief Process handshake data from TLS client
122 *
123 * Read as much TLS handshake data as is available.
124 *
125 * \param[in] client Client connection
126 *
127 * \return Standard Pacemaker return code (of particular interest, EAGAIN
128 * if some data was successfully read but more data is needed)
129 */
130 int pcmk__read_handshake_data(const pcmk__client_t *client);
131
132 /*!
133 * \internal
134 * \brief Log if a TLS certificate is near its expiration date
135 *
136 * \param[in] session The gnutls session object after handshaking is
137 * complete
138 */
139 void pcmk__tls_check_cert_expiration(gnutls_session_t session);
140
141 /*!
142 * \internal
143 * \brief Perform client TLS handshake after establishing TCP socket
144 *
145 * \param[in,out] remote Newly established remote connection
146 * \param[in] timeout_sec Abort handshake if not completed within this time
147 * \param[out] gnutls_rc If this is non-NULL, it will be set to the GnuTLS
148 * rc (for logging) if this function returns EPROTO,
149 * otherwise GNUTLS_E_SUCCESS
150 *
151 * \return Standard Pacemaker return code
152 */
153 int pcmk__tls_client_handshake(pcmk__remote_t *remote, int timeout_sec,
154 int *gnutls_rc);
155
156 /*!
157 * \internal
158 * \brief Make a single attempt to perform the client TLS handshake
159 *
160 * \param[in,out] remote Newly established remote connection
161 * \param[out] gnutls_rc If this is non-NULL, it will be set to the GnuTLS
162 * rc (for logging) if this function returns EPROTO,
163 * otherwise GNUTLS_E_SUCCESS
164 *
165 * \return Standard Pacemaker return code
166 */
167 int pcmk__tls_client_try_handshake(pcmk__remote_t *remote, int *gnutls_rc);
168
169 /*!
170 * \internal
171 * \brief Is X509 authentication supported by the environment?
172 *
173 * \return true if the appropriate environment variables are set (see
174 * etc/sysconfig/pacemaker.in), otherwise false
175 */
176 bool pcmk__x509_enabled(void);
177
178 #ifdef __cplusplus
179 }
180 #endif
181
182 #endif // PCMK__CRM_COMMON_TLS_INTERNAL__H