Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * be-secure-openssl.c
4 : : * functions for OpenSSL support in the backend.
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/backend/libpq/be-secure-openssl.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : : #include "postgres.h"
18 : :
19 : : #include <sys/stat.h>
20 : : #include <signal.h>
21 : : #include <fcntl.h>
22 : : #include <ctype.h>
23 : : #include <sys/socket.h>
24 : : #include <unistd.h>
25 : : #include <netdb.h>
26 : : #include <netinet/in.h>
27 : : #include <netinet/tcp.h>
28 : : #include <arpa/inet.h>
29 : :
30 : : #include "common/string.h"
31 : : #include "libpq/libpq.h"
32 : : #include "miscadmin.h"
33 : : #include "pgstat.h"
34 : : #include "storage/fd.h"
35 : : #include "storage/latch.h"
36 : : #include "tcop/tcopprot.h"
37 : : #include "utils/builtins.h"
38 : : #include "utils/memutils.h"
39 : :
40 : : /*
41 : : * These SSL-related #includes must come after all system-provided headers.
42 : : * This ensures that OpenSSL can take care of conflicts with Windows'
43 : : * <wincrypt.h> by #undef'ing the conflicting macros. (We don't directly
44 : : * include <wincrypt.h>, but some other Windows headers do.)
45 : : */
46 : : #include "common/openssl.h"
47 : : #include <openssl/conf.h>
48 : : #include <openssl/dh.h>
49 : : #ifndef OPENSSL_NO_ECDH
50 : : #include <openssl/ec.h>
51 : : #endif
52 : : #include <openssl/x509v3.h>
53 : :
54 : :
55 : : /* default init hook can be overridden by a shared library */
56 : : static void default_openssl_tls_init(SSL_CTX *context, bool isServerStart);
57 : : openssl_tls_init_hook_typ openssl_tls_init_hook = default_openssl_tls_init;
58 : :
59 : : static int my_sock_read(BIO *h, char *buf, int size);
60 : : static int my_sock_write(BIO *h, const char *buf, int size);
61 : : static BIO_METHOD *my_BIO_s_socket(void);
62 : : static int my_SSL_set_fd(Port *port, int fd);
63 : :
64 : : static DH *load_dh_file(char *filename, bool isServerStart);
65 : : static DH *load_dh_buffer(const char *buffer, size_t len);
66 : : static int ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdata);
67 : : static int dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
68 : : static int verify_cb(int ok, X509_STORE_CTX *ctx);
69 : : static void info_cb(const SSL *ssl, int type, int args);
70 : : static int alpn_cb(SSL *ssl,
71 : : const unsigned char **out,
72 : : unsigned char *outlen,
73 : : const unsigned char *in,
74 : : unsigned int inlen,
75 : : void *userdata);
76 : : static bool initialize_dh(SSL_CTX *context, bool isServerStart);
77 : : static bool initialize_ecdh(SSL_CTX *context, bool isServerStart);
78 : : static const char *SSLerrmessage(unsigned long ecode);
79 : :
80 : : static char *X509_NAME_to_cstring(X509_NAME *name);
81 : :
82 : : static SSL_CTX *SSL_context = NULL;
83 : : static bool SSL_initialized = false;
84 : : static bool dummy_ssl_passwd_cb_called = false;
85 : : static bool ssl_is_server_start;
86 : :
87 : : static int ssl_protocol_version_to_openssl(int v);
88 : : static const char *ssl_protocol_version_to_string(int v);
89 : :
90 : : /* for passing data back from verify_cb() */
91 : : static const char *cert_errdetail;
92 : :
93 : : /* ------------------------------------------------------------ */
94 : : /* Public interface */
95 : : /* ------------------------------------------------------------ */
96 : :
97 : : int
2657 tgl@sss.pgh.pa.us 98 :CBC 28 : be_tls_init(bool isServerStart)
99 : : {
100 : : SSL_CTX *context;
1483 michael@paquier.xyz 101 : 28 : int ssl_ver_min = -1;
102 : 28 : int ssl_ver_max = -1;
103 : :
104 : : /* This stuff need be done only once. */
2659 tgl@sss.pgh.pa.us 105 [ + + ]: 28 : if (!SSL_initialized)
106 : : {
107 : : #ifdef HAVE_OPENSSL_INIT_SSL
2768 heikki.linnakangas@i 108 : 27 : OPENSSL_init_ssl(OPENSSL_INIT_LOAD_CONFIG, NULL);
109 : : #else
110 : : OPENSSL_config(NULL);
111 : : SSL_library_init();
112 : : SSL_load_error_strings();
113 : : #endif
2659 tgl@sss.pgh.pa.us 114 : 27 : SSL_initialized = true;
115 : : }
116 : :
117 : : /*
118 : : * Create a new SSL context into which we'll load all the configuration
119 : : * settings. If we fail partway through, we can avoid memory leakage by
120 : : * freeing this context; we don't install it as active until the end.
121 : : *
122 : : * We use SSLv23_method() because it can negotiate use of the highest
123 : : * mutually supported protocol version, while alternatives like
124 : : * TLSv1_2_method() permit only one specific version. Note that we don't
125 : : * actually allow SSL v2 or v3, only TLS protocols (see below).
126 : : */
127 : 28 : context = SSL_CTX_new(SSLv23_method());
128 [ - + ]: 28 : if (!context)
129 : : {
2657 tgl@sss.pgh.pa.us 130 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
131 : : (errmsg("could not create SSL context: %s",
132 : : SSLerrmessage(ERR_get_error()))));
2659 133 : 0 : goto error;
134 : : }
135 : :
136 : : /*
137 : : * Disable OpenSSL's moving-write-buffer sanity check, because it causes
138 : : * unnecessary failures in nonblocking send cases.
139 : : */
2659 tgl@sss.pgh.pa.us 140 :CBC 28 : SSL_CTX_set_mode(context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
141 : :
142 : : /*
143 : : * Call init hook (usually to set password callback)
144 : : */
1431 145 : 28 : (*openssl_tls_init_hook) (context, isServerStart);
146 : :
147 : : /* used by the callback */
2239 peter_e@gmx.net 148 : 28 : ssl_is_server_start = isServerStart;
149 : :
150 : : /*
151 : : * Load and verify server's certificate and private key
152 : : */
2659 tgl@sss.pgh.pa.us 153 [ - + ]: 28 : if (SSL_CTX_use_certificate_chain_file(context, ssl_cert_file) != 1)
154 : : {
2657 tgl@sss.pgh.pa.us 155 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
156 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
157 : : errmsg("could not load server certificate file \"%s\": %s",
158 : : ssl_cert_file, SSLerrmessage(ERR_get_error()))));
2659 159 : 0 : goto error;
160 : : }
161 : :
2277 peter_e@gmx.net 162 [ - + ]:CBC 28 : if (!check_ssl_key_file_permissions(ssl_key_file, isServerStart))
2659 tgl@sss.pgh.pa.us 163 :UBC 0 : goto error;
164 : :
165 : : /*
166 : : * OK, try to load the private key file.
167 : : */
2239 peter_e@gmx.net 168 :CBC 28 : dummy_ssl_passwd_cb_called = false;
169 : :
2659 tgl@sss.pgh.pa.us 170 [ + + ]: 28 : if (SSL_CTX_use_PrivateKey_file(context,
171 : : ssl_key_file,
172 : : SSL_FILETYPE_PEM) != 1)
173 : : {
2239 peter_e@gmx.net 174 [ - + ]: 2 : if (dummy_ssl_passwd_cb_called)
2657 tgl@sss.pgh.pa.us 175 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
176 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
177 : : errmsg("private key file \"%s\" cannot be reloaded because it requires a passphrase",
178 : : ssl_key_file)));
179 : : else
2657 tgl@sss.pgh.pa.us 180 [ + - + - ]:CBC 2 : ereport(isServerStart ? FATAL : LOG,
181 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
182 : : errmsg("could not load private key file \"%s\": %s",
183 : : ssl_key_file, SSLerrmessage(ERR_get_error()))));
2659 tgl@sss.pgh.pa.us 184 :UBC 0 : goto error;
185 : : }
186 : :
2659 tgl@sss.pgh.pa.us 187 [ - + ]:CBC 26 : if (SSL_CTX_check_private_key(context) != 1)
188 : : {
2657 tgl@sss.pgh.pa.us 189 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
190 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
191 : : errmsg("check of private key failed: %s",
192 : : SSLerrmessage(ERR_get_error()))));
2659 193 : 0 : goto error;
194 : : }
195 : :
1972 peter_e@gmx.net 196 [ + - ]:CBC 26 : if (ssl_min_protocol_version)
197 : : {
1483 michael@paquier.xyz 198 : 26 : ssl_ver_min = ssl_protocol_version_to_openssl(ssl_min_protocol_version);
199 : :
200 [ - + ]: 26 : if (ssl_ver_min == -1)
201 : : {
1483 michael@paquier.xyz 202 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
203 : : /*- translator: first %s is a GUC option name, second %s is its value */
204 : : (errmsg("%s setting \"%s\" not supported by this build",
205 : : "ssl_min_protocol_version",
206 : : GetConfigOption("ssl_min_protocol_version",
207 : : false, false))));
1892 peter@eisentraut.org 208 : 0 : goto error;
209 : : }
210 : :
1483 michael@paquier.xyz 211 [ - + ]:CBC 26 : if (!SSL_CTX_set_min_proto_version(context, ssl_ver_min))
212 : : {
1660 peter@eisentraut.org 213 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
214 : : (errmsg("could not set minimum SSL protocol version")));
215 : 0 : goto error;
216 : : }
217 : : }
218 : :
1972 peter_e@gmx.net 219 [ + + ]:CBC 26 : if (ssl_max_protocol_version)
220 : : {
1483 michael@paquier.xyz 221 : 1 : ssl_ver_max = ssl_protocol_version_to_openssl(ssl_max_protocol_version);
222 : :
223 [ - + ]: 1 : if (ssl_ver_max == -1)
224 : : {
1483 michael@paquier.xyz 225 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
226 : : /*- translator: first %s is a GUC option name, second %s is its value */
227 : : (errmsg("%s setting \"%s\" not supported by this build",
228 : : "ssl_max_protocol_version",
229 : : GetConfigOption("ssl_max_protocol_version",
230 : : false, false))));
1892 peter@eisentraut.org 231 : 0 : goto error;
232 : : }
233 : :
1483 michael@paquier.xyz 234 [ - + ]:CBC 1 : if (!SSL_CTX_set_max_proto_version(context, ssl_ver_max))
235 : : {
1660 peter@eisentraut.org 236 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
237 : : (errmsg("could not set maximum SSL protocol version")));
238 : 0 : goto error;
239 : : }
240 : : }
241 : :
242 : : /* Check compatibility of min/max protocols */
1483 michael@paquier.xyz 243 [ + - + + ]:CBC 26 : if (ssl_min_protocol_version &&
244 : : ssl_max_protocol_version)
245 : : {
246 : : /*
247 : : * No need to check for invalid values (-1) for each protocol number
248 : : * as the code above would have already generated an error.
249 : : */
250 [ + - ]: 1 : if (ssl_ver_min > ssl_ver_max)
251 : : {
252 [ + - + - ]: 1 : ereport(isServerStart ? FATAL : LOG,
253 : : (errmsg("could not set SSL protocol version range"),
254 : : errdetail("%s cannot be higher than %s",
255 : : "ssl_min_protocol_version",
256 : : "ssl_max_protocol_version")));
1445 michael@paquier.xyz 257 :UBC 0 : goto error;
258 : : }
259 : : }
260 : :
261 : : /* disallow SSL session tickets */
2445 tgl@sss.pgh.pa.us 262 :CBC 25 : SSL_CTX_set_options(context, SSL_OP_NO_TICKET);
263 : :
264 : : /* disallow SSL session caching, too */
265 : 25 : SSL_CTX_set_session_cache_mode(context, SSL_SESS_CACHE_OFF);
266 : :
267 : : /* disallow SSL compression */
1132 michael@paquier.xyz 268 : 25 : SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION);
269 : :
270 : : #ifdef SSL_OP_NO_RENEGOTIATION
271 : :
272 : : /*
273 : : * Disallow SSL renegotiation, option available since 1.1.0h. This
274 : : * concerns only TLSv1.2 and older protocol versions, as TLSv1.3 has no
275 : : * support for renegotiation.
276 : : */
1055 277 : 25 : SSL_CTX_set_options(context, SSL_OP_NO_RENEGOTIATION);
278 : : #endif
279 : :
280 : : /* set up ephemeral DH and ECDH keys */
2449 heikki.linnakangas@i 281 [ - + ]: 25 : if (!initialize_dh(context, isServerStart))
2449 heikki.linnakangas@i 282 :UBC 0 : goto error;
2657 tgl@sss.pgh.pa.us 283 [ - + ]:CBC 25 : if (!initialize_ecdh(context, isServerStart))
2659 tgl@sss.pgh.pa.us 284 :UBC 0 : goto error;
285 : :
286 : : /* set up the allowed cipher list */
2659 tgl@sss.pgh.pa.us 287 [ - + ]:CBC 25 : if (SSL_CTX_set_cipher_list(context, SSLCipherSuites) != 1)
288 : : {
2657 tgl@sss.pgh.pa.us 289 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
290 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
291 : : errmsg("could not set the cipher list (no valid ciphers available)")));
2659 292 : 0 : goto error;
293 : : }
294 : :
295 : : /* Let server choose order */
3527 heikki.linnakangas@i 296 [ + - ]:CBC 25 : if (SSLPreferServerCiphers)
2659 tgl@sss.pgh.pa.us 297 : 25 : SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE);
298 : :
299 : : /*
300 : : * Load CA store, so we can verify client certificates if needed.
301 : : */
3527 heikki.linnakangas@i 302 [ + + ]: 25 : if (ssl_ca_file[0])
303 : : {
304 : : STACK_OF(X509_NAME) * root_cert_list;
305 : :
2659 tgl@sss.pgh.pa.us 306 [ + - - + ]: 42 : if (SSL_CTX_load_verify_locations(context, ssl_ca_file, NULL) != 1 ||
3527 heikki.linnakangas@i 307 : 21 : (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL)
308 : : {
2657 tgl@sss.pgh.pa.us 309 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
310 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
311 : : errmsg("could not load root certificate file \"%s\": %s",
312 : : ssl_ca_file, SSLerrmessage(ERR_get_error()))));
2659 313 : 0 : goto error;
314 : : }
315 : :
316 : : /*
317 : : * Tell OpenSSL to send the list of root certs we trust to clients in
318 : : * CertificateRequests. This lets a client with a keystore select the
319 : : * appropriate client certificate to send to us. Also, this ensures
320 : : * that the SSL context will "own" the root_cert_list and remember to
321 : : * free it when no longer needed.
322 : : */
1125 tgl@sss.pgh.pa.us 323 :CBC 21 : SSL_CTX_set_client_CA_list(context, root_cert_list);
324 : :
325 : : /*
326 : : * Always ask for SSL client cert, but don't fail if it's not
327 : : * presented. We might fail such connections later, depending on what
328 : : * we find in pg_hba.conf.
329 : : */
330 : 21 : SSL_CTX_set_verify(context,
331 : : (SSL_VERIFY_PEER |
332 : : SSL_VERIFY_CLIENT_ONCE),
333 : : verify_cb);
334 : : }
335 : :
336 : : /*----------
337 : : * Load the Certificate Revocation List (CRL).
338 : : * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html
339 : : *----------
340 : : */
1151 peter@eisentraut.org 341 [ + + - + ]: 25 : if (ssl_crl_file[0] || ssl_crl_dir[0])
342 : : {
2659 tgl@sss.pgh.pa.us 343 : 21 : X509_STORE *cvstore = SSL_CTX_get_cert_store(context);
344 : :
3527 heikki.linnakangas@i 345 [ + - ]: 21 : if (cvstore)
346 : : {
347 : : /* Set the flags to check against the complete CRL chain */
1151 peter@eisentraut.org 348 [ + - ]: 42 : if (X509_STORE_load_locations(cvstore,
349 [ + - ]: 21 : ssl_crl_file[0] ? ssl_crl_file : NULL,
1125 tgl@sss.pgh.pa.us 350 [ + + ]: 21 : ssl_crl_dir[0] ? ssl_crl_dir : NULL)
351 : : == 1)
352 : : {
3527 heikki.linnakangas@i 353 : 21 : X509_STORE_set_flags(cvstore,
354 : : X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
355 : : }
1151 peter@eisentraut.org 356 [ # # ]:UBC 0 : else if (ssl_crl_dir[0] == 0)
357 : : {
2657 tgl@sss.pgh.pa.us 358 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
359 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
360 : : errmsg("could not load SSL certificate revocation list file \"%s\": %s",
361 : : ssl_crl_file, SSLerrmessage(ERR_get_error()))));
2659 362 : 0 : goto error;
363 : : }
1151 peter@eisentraut.org 364 [ # # ]: 0 : else if (ssl_crl_file[0] == 0)
365 : : {
366 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
367 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
368 : : errmsg("could not load SSL certificate revocation list directory \"%s\": %s",
369 : : ssl_crl_dir, SSLerrmessage(ERR_get_error()))));
370 : 0 : goto error;
371 : : }
372 : : else
373 : : {
374 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
375 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
376 : : errmsg("could not load SSL certificate revocation list file \"%s\" or directory \"%s\": %s",
377 : : ssl_crl_file, ssl_crl_dir,
378 : : SSLerrmessage(ERR_get_error()))));
379 : 0 : goto error;
380 : : }
381 : : }
382 : : }
383 : :
384 : : /*
385 : : * Success! Replace any existing SSL_context.
386 : : */
2659 tgl@sss.pgh.pa.us 387 [ - + ]:CBC 25 : if (SSL_context)
2659 tgl@sss.pgh.pa.us 388 :UBC 0 : SSL_CTX_free(SSL_context);
389 : :
2659 tgl@sss.pgh.pa.us 390 :CBC 25 : SSL_context = context;
391 : :
392 : : /*
393 : : * Set flag to remember whether CA store has been loaded into SSL_context.
394 : : */
395 [ + + ]: 25 : if (ssl_ca_file[0])
396 : 21 : ssl_loaded_verify_locations = true;
397 : : else
398 : 4 : ssl_loaded_verify_locations = false;
399 : :
400 : 25 : return 0;
401 : :
402 : : /* Clean up by releasing working context. */
2659 tgl@sss.pgh.pa.us 403 :UBC 0 : error:
404 [ # # ]: 0 : if (context)
405 : 0 : SSL_CTX_free(context);
406 : 0 : return -1;
407 : : }
408 : :
409 : : void
2659 tgl@sss.pgh.pa.us 410 :CBC 125 : be_tls_destroy(void)
411 : : {
412 [ + + ]: 125 : if (SSL_context)
2659 tgl@sss.pgh.pa.us 413 :GBC 1 : SSL_CTX_free(SSL_context);
2659 tgl@sss.pgh.pa.us 414 :CBC 125 : SSL_context = NULL;
415 : 125 : ssl_loaded_verify_locations = false;
3534 heikki.linnakangas@i 416 : 125 : }
417 : :
418 : : int
3527 419 : 185 : be_tls_open_server(Port *port)
420 : : {
421 : : int r;
422 : : int err;
423 : : int waitfor;
424 : : unsigned long ecode;
425 : : bool give_proto_hint;
426 : :
427 [ - + ]: 185 : Assert(!port->ssl);
428 [ - + ]: 185 : Assert(!port->peer);
429 : :
2659 tgl@sss.pgh.pa.us 430 [ - + ]: 185 : if (!SSL_context)
431 : : {
2659 tgl@sss.pgh.pa.us 432 [ # # ]:UBC 0 : ereport(COMMERROR,
433 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
434 : : errmsg("could not initialize SSL connection: SSL context not set up")));
435 : 0 : return -1;
436 : : }
437 : :
438 : : /* set up debugging/info callback */
1178 michael@paquier.xyz 439 :CBC 185 : SSL_CTX_set_info_callback(SSL_context, info_cb);
440 : :
441 : : /* enable ALPN */
6 heikki.linnakangas@i 442 :GNC 185 : SSL_CTX_set_alpn_select_cb(SSL_context, alpn_cb, port);
443 : :
3527 heikki.linnakangas@i 444 [ - + ]:CBC 185 : if (!(port->ssl = SSL_new(SSL_context)))
445 : : {
3527 heikki.linnakangas@i 446 [ # # ]:UBC 0 : ereport(COMMERROR,
447 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
448 : : errmsg("could not initialize SSL connection: %s",
449 : : SSLerrmessage(ERR_get_error()))));
450 : 0 : return -1;
451 : : }
3527 heikki.linnakangas@i 452 [ - + ]:CBC 185 : if (!my_SSL_set_fd(port, port->sock))
453 : : {
3527 heikki.linnakangas@i 454 [ # # ]:UBC 0 : ereport(COMMERROR,
455 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
456 : : errmsg("could not set SSL socket: %s",
457 : : SSLerrmessage(ERR_get_error()))));
458 : 0 : return -1;
459 : : }
3527 heikki.linnakangas@i 460 :CBC 185 : port->ssl_in_use = true;
461 : :
462 : 653 : aloop:
463 : :
464 : : /*
465 : : * Prepare to call SSL_get_error() by clearing thread's OpenSSL error
466 : : * queue. In general, the current thread's error queue must be empty
467 : : * before the TLS/SSL I/O operation is attempted, or SSL_get_error() will
468 : : * not work reliably. An extension may have failed to clear the
469 : : * per-thread error queue following another call to an OpenSSL I/O
470 : : * routine.
471 : : */
125 tgl@sss.pgh.pa.us 472 : 653 : errno = 0;
2928 peter_e@gmx.net 473 : 653 : ERR_clear_error();
3527 heikki.linnakangas@i 474 : 653 : r = SSL_accept(port->ssl);
475 [ + + ]: 653 : if (r <= 0)
476 : : {
477 : 486 : err = SSL_get_error(port->ssl, r);
478 : :
479 : : /*
480 : : * Other clients of OpenSSL in the backend may fail to call
481 : : * ERR_get_error(), but we always do, so as to not cause problems for
482 : : * OpenSSL clients that don't call ERR_clear_error() defensively. Be
483 : : * sure that this happens by calling now. SSL_get_error() relies on
484 : : * the OpenSSL per-thread error queue being intact, so this is the
485 : : * earliest possible point ERR_get_error() may be called.
486 : : */
2928 peter_e@gmx.net 487 : 486 : ecode = ERR_get_error();
3527 heikki.linnakangas@i 488 [ + + + - : 486 : switch (err)
- ]
489 : : {
490 : 468 : case SSL_ERROR_WANT_READ:
491 : : case SSL_ERROR_WANT_WRITE:
492 : : /* not allowed during connection establishment */
3358 andres@anarazel.de 493 [ - + ]: 468 : Assert(!port->noblock);
494 : :
495 : : /*
496 : : * No need to care about timeouts/interrupts here. At this
497 : : * point authentication_timeout still employs
498 : : * StartupPacketTimeoutHandler() which directly exits.
499 : : */
500 [ + - ]: 468 : if (err == SSL_ERROR_WANT_READ)
1967 tmunro@postgresql.or 501 : 468 : waitfor = WL_SOCKET_READABLE | WL_EXIT_ON_PM_DEATH;
502 : : else
1967 tmunro@postgresql.or 503 :UBC 0 : waitfor = WL_SOCKET_WRITEABLE | WL_EXIT_ON_PM_DEATH;
504 : :
1969 tmunro@postgresql.or 505 :CBC 468 : (void) WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0,
506 : : WAIT_EVENT_SSL_OPEN_SERVER);
3527 heikki.linnakangas@i 507 : 468 : goto aloop;
508 : 4 : case SSL_ERROR_SYSCALL:
125 tgl@sss.pgh.pa.us 509 [ + - - + ]: 4 : if (r < 0 && errno != 0)
3527 heikki.linnakangas@i 510 [ # # ]:UBC 0 : ereport(COMMERROR,
511 : : (errcode_for_socket_access(),
512 : : errmsg("could not accept SSL connection: %m")));
513 : : else
3527 heikki.linnakangas@i 514 [ + - ]:CBC 4 : ereport(COMMERROR,
515 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
516 : : errmsg("could not accept SSL connection: EOF detected")));
517 : 4 : break;
518 : 14 : case SSL_ERROR_SSL:
1387 tgl@sss.pgh.pa.us 519 : 14 : switch (ERR_GET_REASON(ecode))
520 : : {
521 : : /*
522 : : * UNSUPPORTED_PROTOCOL, WRONG_VERSION_NUMBER, and
523 : : * TLSV1_ALERT_PROTOCOL_VERSION have been observed
524 : : * when trying to communicate with an old OpenSSL
525 : : * library, or when the client and server specify
526 : : * disjoint protocol ranges. NO_PROTOCOLS_AVAILABLE
527 : : * occurs if there's a local misconfiguration (which
528 : : * can happen despite our checks, if openssl.cnf
529 : : * injects a limit we didn't account for). It's not
530 : : * very clear what would make OpenSSL return the other
531 : : * codes listed here, but a hint about protocol
532 : : * versions seems like it's appropriate for all.
533 : : */
1387 tgl@sss.pgh.pa.us 534 :UBC 0 : case SSL_R_NO_PROTOCOLS_AVAILABLE:
535 : : case SSL_R_UNSUPPORTED_PROTOCOL:
536 : : case SSL_R_BAD_PROTOCOL_VERSION_NUMBER:
537 : : case SSL_R_UNKNOWN_PROTOCOL:
538 : : case SSL_R_UNKNOWN_SSL_VERSION:
539 : : case SSL_R_UNSUPPORTED_SSL_VERSION:
540 : : case SSL_R_WRONG_SSL_VERSION:
541 : : case SSL_R_WRONG_VERSION_NUMBER:
542 : : case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION:
543 : : #ifdef SSL_R_VERSION_TOO_HIGH
544 : : case SSL_R_VERSION_TOO_HIGH:
545 : : case SSL_R_VERSION_TOO_LOW:
546 : : #endif
547 : 0 : give_proto_hint = true;
548 : 0 : break;
1387 tgl@sss.pgh.pa.us 549 :CBC 14 : default:
550 : 14 : give_proto_hint = false;
551 : 14 : break;
552 : : }
3527 heikki.linnakangas@i 553 [ + - + + : 14 : ereport(COMMERROR,
- + - - -
- ]
554 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
555 : : errmsg("could not accept SSL connection: %s",
556 : : SSLerrmessage(ecode)),
557 : : cert_errdetail ? errdetail_internal("%s", cert_errdetail) : 0,
558 : : give_proto_hint ?
559 : : errhint("This may indicate that the client does not support any SSL protocol version between %s and %s.",
560 : : ssl_min_protocol_version ?
561 : : ssl_protocol_version_to_string(ssl_min_protocol_version) :
562 : : MIN_OPENSSL_TLS_VERSION,
563 : : ssl_max_protocol_version ?
564 : : ssl_protocol_version_to_string(ssl_max_protocol_version) :
565 : : MAX_OPENSSL_TLS_VERSION) : 0));
639 peter@eisentraut.org 566 : 14 : cert_errdetail = NULL;
3527 heikki.linnakangas@i 567 : 14 : break;
3527 heikki.linnakangas@i 568 :UBC 0 : case SSL_ERROR_ZERO_RETURN:
569 [ # # ]: 0 : ereport(COMMERROR,
570 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
571 : : errmsg("could not accept SSL connection: EOF detected")));
572 : 0 : break;
573 : 0 : default:
574 [ # # ]: 0 : ereport(COMMERROR,
575 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
576 : : errmsg("unrecognized SSL error code: %d",
577 : : err)));
578 : 0 : break;
579 : : }
3527 heikki.linnakangas@i 580 :CBC 18 : return -1;
581 : : }
582 : :
583 : : /* Get the protocol selected by ALPN */
6 heikki.linnakangas@i 584 :GNC 167 : port->alpn_used = false;
585 : : {
586 : : const unsigned char *selected;
587 : : unsigned int len;
588 : :
589 : 167 : SSL_get0_alpn_selected(port->ssl, &selected, &len);
590 : :
591 : : /* If ALPN is used, check that we negotiated the expected protocol */
592 [ + - ]: 167 : if (selected != NULL)
593 : : {
594 [ + - ]: 167 : if (len == strlen(PG_ALPN_PROTOCOL) &&
595 [ + - ]: 167 : memcmp(selected, PG_ALPN_PROTOCOL, strlen(PG_ALPN_PROTOCOL)) == 0)
596 : : {
597 : 167 : port->alpn_used = true;
598 : : }
599 : : else
600 : : {
601 : : /* shouldn't happen */
6 heikki.linnakangas@i 602 [ # # ]:UNC 0 : ereport(COMMERROR,
603 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
604 : : errmsg("received SSL connection request with unexpected ALPN protocol")));
605 : : }
606 : : }
607 : : }
608 : :
609 : : /* Get client certificate, if available. */
3527 heikki.linnakangas@i 610 :CBC 167 : port->peer = SSL_get_peer_certificate(port->ssl);
611 : :
612 : : /* and extract the Common Name and Distinguished Name from it. */
613 : 167 : port->peer_cn = NULL;
1112 andrew@dunslane.net 614 : 167 : port->peer_dn = NULL;
3527 heikki.linnakangas@i 615 : 167 : port->peer_cert_valid = false;
616 [ + + ]: 167 : if (port->peer != NULL)
617 : : {
618 : : int len;
1112 andrew@dunslane.net 619 : 29 : X509_NAME *x509name = X509_get_subject_name(port->peer);
620 : : char *peer_dn;
621 : 29 : BIO *bio = NULL;
622 : 29 : BUF_MEM *bio_buf = NULL;
623 : :
624 : 29 : len = X509_NAME_get_text_by_NID(x509name, NID_commonName, NULL, 0);
3527 heikki.linnakangas@i 625 [ + - ]: 29 : if (len != -1)
626 : : {
627 : : char *peer_cn;
628 : :
629 : 29 : peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1);
1112 andrew@dunslane.net 630 : 29 : r = X509_NAME_get_text_by_NID(x509name, NID_commonName, peer_cn,
631 : : len + 1);
3527 heikki.linnakangas@i 632 : 29 : peer_cn[len] = '\0';
633 [ - + ]: 29 : if (r != len)
634 : : {
635 : : /* shouldn't happen */
3527 heikki.linnakangas@i 636 :UBC 0 : pfree(peer_cn);
637 : 0 : return -1;
638 : : }
639 : :
640 : : /*
641 : : * Reject embedded NULLs in certificate common name to prevent
642 : : * attacks like CVE-2009-4034.
643 : : */
3527 heikki.linnakangas@i 644 [ - + ]:CBC 29 : if (len != strlen(peer_cn))
645 : : {
3527 heikki.linnakangas@i 646 [ # # ]:UBC 0 : ereport(COMMERROR,
647 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
648 : : errmsg("SSL certificate's common name contains embedded null")));
649 : 0 : pfree(peer_cn);
650 : 0 : return -1;
651 : : }
652 : :
3527 heikki.linnakangas@i 653 :CBC 29 : port->peer_cn = peer_cn;
654 : : }
655 : :
1112 andrew@dunslane.net 656 : 29 : bio = BIO_new(BIO_s_mem());
657 [ - + ]: 29 : if (!bio)
658 : : {
205 dgustafsson@postgres 659 [ # # ]:UBC 0 : if (port->peer_cn != NULL)
660 : : {
661 : 0 : pfree(port->peer_cn);
662 : 0 : port->peer_cn = NULL;
663 : : }
1112 andrew@dunslane.net 664 : 0 : return -1;
665 : : }
666 : :
667 : : /*
668 : : * RFC2253 is the closest thing to an accepted standard format for
669 : : * DNs. We have documented how to produce this format from a
670 : : * certificate. It uses commas instead of slashes for delimiters,
671 : : * which make regular expression matching a bit easier. Also note that
672 : : * it prints the Subject fields in reverse order.
673 : : */
205 dgustafsson@postgres 674 [ + - - + ]:CBC 58 : if (X509_NAME_print_ex(bio, x509name, 0, XN_FLAG_RFC2253) == -1 ||
675 : 29 : BIO_get_mem_ptr(bio, &bio_buf) <= 0)
676 : : {
1112 andrew@dunslane.net 677 :UBC 0 : BIO_free(bio);
205 dgustafsson@postgres 678 [ # # ]: 0 : if (port->peer_cn != NULL)
679 : : {
680 : 0 : pfree(port->peer_cn);
681 : 0 : port->peer_cn = NULL;
682 : : }
1112 andrew@dunslane.net 683 : 0 : return -1;
684 : : }
1112 andrew@dunslane.net 685 :CBC 29 : peer_dn = MemoryContextAlloc(TopMemoryContext, bio_buf->length + 1);
686 : 29 : memcpy(peer_dn, bio_buf->data, bio_buf->length);
687 : 29 : len = bio_buf->length;
688 : 29 : BIO_free(bio);
689 : 29 : peer_dn[len] = '\0';
690 [ - + ]: 29 : if (len != strlen(peer_dn))
691 : : {
1112 andrew@dunslane.net 692 [ # # ]:UBC 0 : ereport(COMMERROR,
693 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
694 : : errmsg("SSL certificate's distinguished name contains embedded null")));
695 : 0 : pfree(peer_dn);
205 dgustafsson@postgres 696 [ # # ]: 0 : if (port->peer_cn != NULL)
697 : : {
698 : 0 : pfree(port->peer_cn);
699 : 0 : port->peer_cn = NULL;
700 : : }
1112 andrew@dunslane.net 701 : 0 : return -1;
702 : : }
703 : :
1112 andrew@dunslane.net 704 :CBC 29 : port->peer_dn = peer_dn;
705 : :
3527 heikki.linnakangas@i 706 : 29 : port->peer_cert_valid = true;
707 : : }
708 : :
709 : 167 : return 0;
710 : : }
711 : :
712 : : void
713 : 185 : be_tls_close(Port *port)
714 : : {
715 [ + - ]: 185 : if (port->ssl)
716 : : {
717 : 185 : SSL_shutdown(port->ssl);
718 : 185 : SSL_free(port->ssl);
719 : 185 : port->ssl = NULL;
720 : 185 : port->ssl_in_use = false;
721 : : }
722 : :
723 [ + + ]: 185 : if (port->peer)
724 : : {
725 : 29 : X509_free(port->peer);
726 : 29 : port->peer = NULL;
727 : : }
728 : :
729 [ + + ]: 185 : if (port->peer_cn)
730 : : {
731 : 29 : pfree(port->peer_cn);
732 : 29 : port->peer_cn = NULL;
733 : : }
734 : :
1112 andrew@dunslane.net 735 [ + + ]: 185 : if (port->peer_dn)
736 : : {
737 : 29 : pfree(port->peer_dn);
738 : 29 : port->peer_dn = NULL;
739 : : }
3534 heikki.linnakangas@i 740 : 185 : }
741 : :
742 : : ssize_t
3348 743 : 782 : be_tls_read(Port *port, void *ptr, size_t len, int *waitfor)
744 : : {
745 : : ssize_t n;
746 : : int err;
747 : : unsigned long ecode;
748 : :
3527 749 : 782 : errno = 0;
2928 peter_e@gmx.net 750 : 782 : ERR_clear_error();
3527 heikki.linnakangas@i 751 : 782 : n = SSL_read(port->ssl, ptr, len);
752 : 782 : err = SSL_get_error(port->ssl, n);
2928 peter_e@gmx.net 753 [ + + - + ]: 782 : ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
3527 heikki.linnakangas@i 754 [ + + - - : 782 : switch (err)
- + - ]
755 : : {
756 : 416 : case SSL_ERROR_NONE:
757 : : /* a-ok */
3534 758 : 416 : break;
3527 759 : 349 : case SSL_ERROR_WANT_READ:
3348 760 : 349 : *waitfor = WL_SOCKET_READABLE;
761 : 349 : errno = EWOULDBLOCK;
762 : 349 : n = -1;
763 : 349 : break;
3527 heikki.linnakangas@i 764 :UBC 0 : case SSL_ERROR_WANT_WRITE:
3348 765 : 0 : *waitfor = WL_SOCKET_WRITEABLE;
766 : 0 : errno = EWOULDBLOCK;
767 : 0 : n = -1;
768 : 0 : break;
3527 769 : 0 : case SSL_ERROR_SYSCALL:
770 : : /* leave it to caller to ereport the value of errno */
125 tgl@sss.pgh.pa.us 771 [ # # # # ]: 0 : if (n != -1 || errno == 0)
772 : : {
3527 heikki.linnakangas@i 773 : 0 : errno = ECONNRESET;
774 : 0 : n = -1;
775 : : }
3534 776 : 0 : break;
3527 777 : 0 : case SSL_ERROR_SSL:
778 [ # # ]: 0 : ereport(COMMERROR,
779 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
780 : : errmsg("SSL error: %s", SSLerrmessage(ecode))));
781 : 0 : errno = ECONNRESET;
782 : 0 : n = -1;
3534 783 : 0 : break;
2477 heikki.linnakangas@i 784 :CBC 17 : case SSL_ERROR_ZERO_RETURN:
785 : : /* connection was cleanly shut down by peer */
786 : 17 : n = 0;
787 : 17 : break;
3534 heikki.linnakangas@i 788 :UBC 0 : default:
3527 789 [ # # ]: 0 : ereport(COMMERROR,
790 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
791 : : errmsg("unrecognized SSL error code: %d",
792 : : err)));
793 : 0 : errno = ECONNRESET;
794 : 0 : n = -1;
3534 795 : 0 : break;
796 : : }
797 : :
3527 heikki.linnakangas@i 798 :CBC 782 : return n;
799 : : }
800 : :
801 : : ssize_t
3348 802 : 292 : be_tls_write(Port *port, void *ptr, size_t len, int *waitfor)
803 : : {
804 : : ssize_t n;
805 : : int err;
806 : : unsigned long ecode;
807 : :
3527 808 : 292 : errno = 0;
2928 peter_e@gmx.net 809 : 292 : ERR_clear_error();
3527 heikki.linnakangas@i 810 : 292 : n = SSL_write(port->ssl, ptr, len);
811 : 292 : err = SSL_get_error(port->ssl, n);
2928 peter_e@gmx.net 812 [ + - - + ]: 292 : ecode = (err != SSL_ERROR_NONE || n < 0) ? ERR_get_error() : 0;
3527 heikki.linnakangas@i 813 [ + - - - : 292 : switch (err)
- - - ]
814 : : {
815 : 292 : case SSL_ERROR_NONE:
816 : : /* a-ok */
817 : 292 : break;
3527 heikki.linnakangas@i 818 :UBC 0 : case SSL_ERROR_WANT_READ:
3348 819 : 0 : *waitfor = WL_SOCKET_READABLE;
820 : 0 : errno = EWOULDBLOCK;
821 : 0 : n = -1;
822 : 0 : break;
3527 823 : 0 : case SSL_ERROR_WANT_WRITE:
3348 824 : 0 : *waitfor = WL_SOCKET_WRITEABLE;
825 : 0 : errno = EWOULDBLOCK;
826 : 0 : n = -1;
827 : 0 : break;
3527 828 : 0 : case SSL_ERROR_SYSCALL:
829 : :
830 : : /*
831 : : * Leave it to caller to ereport the value of errno. However, if
832 : : * errno is still zero then assume it's a read EOF situation, and
833 : : * report ECONNRESET. (This seems possible because SSL_write can
834 : : * also do reads.)
835 : : */
125 tgl@sss.pgh.pa.us 836 [ # # # # ]: 0 : if (n != -1 || errno == 0)
837 : : {
3527 heikki.linnakangas@i 838 : 0 : errno = ECONNRESET;
839 : 0 : n = -1;
840 : : }
841 : 0 : break;
842 : 0 : case SSL_ERROR_SSL:
843 [ # # ]: 0 : ereport(COMMERROR,
844 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
845 : : errmsg("SSL error: %s", SSLerrmessage(ecode))));
2477 846 : 0 : errno = ECONNRESET;
847 : 0 : n = -1;
848 : 0 : break;
3527 849 : 0 : case SSL_ERROR_ZERO_RETURN:
850 : :
851 : : /*
852 : : * the SSL connection was closed, leave it to the caller to
853 : : * ereport it
854 : : */
855 : 0 : errno = ECONNRESET;
856 : 0 : n = -1;
857 : 0 : break;
858 : 0 : default:
859 [ # # ]: 0 : ereport(COMMERROR,
860 : : (errcode(ERRCODE_PROTOCOL_VIOLATION),
861 : : errmsg("unrecognized SSL error code: %d",
862 : : err)));
863 : 0 : errno = ECONNRESET;
864 : 0 : n = -1;
865 : 0 : break;
866 : : }
867 : :
3527 heikki.linnakangas@i 868 :CBC 292 : return n;
869 : : }
870 : :
871 : : /* ------------------------------------------------------------ */
872 : : /* Internal functions */
873 : : /* ------------------------------------------------------------ */
874 : :
875 : : /*
876 : : * Private substitute BIO: this does the sending and receiving using send() and
877 : : * recv() instead. This is so that we can enable and disable interrupts
878 : : * just while calling recv(). We cannot have interrupts occurring while
879 : : * the bulk of OpenSSL runs, because it uses malloc() and possibly other
880 : : * non-reentrant libc facilities. We also need to call send() and recv()
881 : : * directly so it gets passed through the socket/signals layer on Win32.
882 : : *
883 : : * These functions are closely modelled on the standard socket BIO in OpenSSL;
884 : : * see sock_read() and sock_write() in OpenSSL's crypto/bio/bss_sock.c.
885 : : */
886 : :
887 : : static BIO_METHOD *my_bio_methods = NULL;
888 : :
889 : : static int
890 : 3383 : my_sock_read(BIO *h, char *buf, int size)
891 : : {
892 : 3383 : int res = 0;
893 : :
894 [ + - ]: 3383 : if (buf != NULL)
895 : : {
138 tgl@sss.pgh.pa.us 896 : 3383 : res = secure_raw_read(((Port *) BIO_get_app_data(h)), buf, size);
3527 heikki.linnakangas@i 897 : 3383 : BIO_clear_retry_flags(h);
898 [ + + ]: 3383 : if (res <= 0)
899 : : {
900 : : /* If we were interrupted, tell caller to retry */
3358 andres@anarazel.de 901 [ + - + + : 821 : if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
- + ]
902 : : {
3527 heikki.linnakangas@i 903 : 817 : BIO_set_retry_read(h);
904 : : }
905 : : }
906 : : }
907 : :
908 : 3383 : return res;
909 : : }
910 : :
911 : : static int
912 : 1156 : my_sock_write(BIO *h, const char *buf, int size)
913 : : {
914 : 1156 : int res = 0;
915 : :
138 tgl@sss.pgh.pa.us 916 : 1156 : res = secure_raw_write(((Port *) BIO_get_app_data(h)), buf, size);
3527 heikki.linnakangas@i 917 : 1156 : BIO_clear_retry_flags(h);
918 [ + + ]: 1156 : if (res <= 0)
919 : : {
920 : : /* If we were interrupted, tell caller to retry */
3358 andres@anarazel.de 921 [ + - + - : 11 : if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)
- + ]
922 : : {
3527 heikki.linnakangas@i 923 :UBC 0 : BIO_set_retry_write(h);
924 : : }
925 : : }
926 : :
3527 heikki.linnakangas@i 927 :CBC 1156 : return res;
928 : : }
929 : :
930 : : static BIO_METHOD *
931 : 185 : my_BIO_s_socket(void)
932 : : {
2768 933 [ + - ]: 185 : if (!my_bio_methods)
934 : : {
935 : 185 : BIO_METHOD *biom = (BIO_METHOD *) BIO_s_socket();
936 : : #ifdef HAVE_BIO_METH_NEW
937 : : int my_bio_index;
938 : :
939 : 185 : my_bio_index = BIO_get_new_index();
940 [ - + ]: 185 : if (my_bio_index == -1)
2768 heikki.linnakangas@i 941 :UBC 0 : return NULL;
971 dgustafsson@postgres 942 :CBC 185 : my_bio_index |= (BIO_TYPE_DESCRIPTOR | BIO_TYPE_SOURCE_SINK);
2768 heikki.linnakangas@i 943 : 185 : my_bio_methods = BIO_meth_new(my_bio_index, "PostgreSQL backend socket");
944 [ - + ]: 185 : if (!my_bio_methods)
2768 heikki.linnakangas@i 945 :UBC 0 : return NULL;
2768 heikki.linnakangas@i 946 [ + - + - ]:CBC 370 : if (!BIO_meth_set_write(my_bio_methods, my_sock_write) ||
947 [ + - ]: 370 : !BIO_meth_set_read(my_bio_methods, my_sock_read) ||
948 [ + - ]: 370 : !BIO_meth_set_gets(my_bio_methods, BIO_meth_get_gets(biom)) ||
949 [ + - ]: 370 : !BIO_meth_set_puts(my_bio_methods, BIO_meth_get_puts(biom)) ||
950 [ + - ]: 370 : !BIO_meth_set_ctrl(my_bio_methods, BIO_meth_get_ctrl(biom)) ||
951 [ + - ]: 370 : !BIO_meth_set_create(my_bio_methods, BIO_meth_get_create(biom)) ||
2489 tgl@sss.pgh.pa.us 952 [ - + ]: 370 : !BIO_meth_set_destroy(my_bio_methods, BIO_meth_get_destroy(biom)) ||
2768 heikki.linnakangas@i 953 : 185 : !BIO_meth_set_callback_ctrl(my_bio_methods, BIO_meth_get_callback_ctrl(biom)))
954 : : {
2768 heikki.linnakangas@i 955 :UBC 0 : BIO_meth_free(my_bio_methods);
956 : 0 : my_bio_methods = NULL;
957 : 0 : return NULL;
958 : : }
959 : : #else
960 : : my_bio_methods = malloc(sizeof(BIO_METHOD));
961 : : if (!my_bio_methods)
962 : : return NULL;
963 : : memcpy(my_bio_methods, biom, sizeof(BIO_METHOD));
964 : : my_bio_methods->bread = my_sock_read;
965 : : my_bio_methods->bwrite = my_sock_write;
966 : : #endif
967 : : }
2768 heikki.linnakangas@i 968 :CBC 185 : return my_bio_methods;
969 : : }
970 : :
971 : : /* This should exactly match OpenSSL's SSL_set_fd except for using my BIO */
972 : : static int
3527 973 : 185 : my_SSL_set_fd(Port *port, int fd)
974 : : {
975 : 185 : int ret = 0;
976 : : BIO *bio;
977 : : BIO_METHOD *bio_method;
978 : :
2768 979 : 185 : bio_method = my_BIO_s_socket();
980 [ - + ]: 185 : if (bio_method == NULL)
981 : : {
2768 heikki.linnakangas@i 982 :UBC 0 : SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
983 : 0 : goto err;
984 : : }
2768 heikki.linnakangas@i 985 :CBC 185 : bio = BIO_new(bio_method);
986 : :
3527 987 [ - + ]: 185 : if (bio == NULL)
988 : : {
3527 heikki.linnakangas@i 989 :UBC 0 : SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);
990 : 0 : goto err;
991 : : }
138 tgl@sss.pgh.pa.us 992 :CBC 185 : BIO_set_app_data(bio, port);
993 : :
3527 heikki.linnakangas@i 994 : 185 : BIO_set_fd(bio, fd, BIO_NOCLOSE);
995 : 185 : SSL_set_bio(port->ssl, bio, bio);
996 : 185 : ret = 1;
997 : 185 : err:
998 : 185 : return ret;
999 : : }
1000 : :
1001 : : /*
1002 : : * Load precomputed DH parameters.
1003 : : *
1004 : : * To prevent "downgrade" attacks, we perform a number of checks
1005 : : * to verify that the DBA-generated DH parameters file contains
1006 : : * what we expect it to contain.
1007 : : */
1008 : : static DH *
2449 heikki.linnakangas@i 1009 :UBC 0 : load_dh_file(char *filename, bool isServerStart)
1010 : : {
1011 : : FILE *fp;
3527 1012 : 0 : DH *dh = NULL;
1013 : : int codes;
1014 : :
1015 : : /* attempt to open file. It's not an error if it doesn't exist. */
2449 1016 [ # # ]: 0 : if ((fp = AllocateFile(filename, "r")) == NULL)
1017 : : {
1018 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
1019 : : (errcode_for_file_access(),
1020 : : errmsg("could not open DH parameters file \"%s\": %m",
1021 : : filename)));
3527 1022 : 0 : return NULL;
1023 : : }
1024 : :
1025 : 0 : dh = PEM_read_DHparams(fp, NULL, NULL, NULL);
2449 1026 : 0 : FreeFile(fp);
1027 : :
1028 [ # # ]: 0 : if (dh == NULL)
1029 : : {
1030 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
1031 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1032 : : errmsg("could not load DH parameters file: %s",
1033 : : SSLerrmessage(ERR_get_error()))));
1034 : 0 : return NULL;
1035 : : }
1036 : :
1037 : : /* make sure the DH parameters are usable */
1038 [ # # ]: 0 : if (DH_check(dh, &codes) == 0)
1039 : : {
1040 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
1041 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1042 : : errmsg("invalid DH parameters: %s",
1043 : : SSLerrmessage(ERR_get_error()))));
1121 tgl@sss.pgh.pa.us 1044 : 0 : DH_free(dh);
2449 heikki.linnakangas@i 1045 : 0 : return NULL;
1046 : : }
1047 [ # # ]: 0 : if (codes & DH_CHECK_P_NOT_PRIME)
1048 : : {
1049 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
1050 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1051 : : errmsg("invalid DH parameters: p is not prime")));
1121 tgl@sss.pgh.pa.us 1052 : 0 : DH_free(dh);
2449 heikki.linnakangas@i 1053 : 0 : return NULL;
1054 : : }
1055 [ # # ]: 0 : if ((codes & DH_NOT_SUITABLE_GENERATOR) &&
1056 [ # # ]: 0 : (codes & DH_CHECK_P_NOT_SAFE_PRIME))
1057 : : {
1058 [ # # # # ]: 0 : ereport(isServerStart ? FATAL : LOG,
1059 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1060 : : errmsg("invalid DH parameters: neither suitable generator or safe prime")));
1121 tgl@sss.pgh.pa.us 1061 : 0 : DH_free(dh);
2449 heikki.linnakangas@i 1062 : 0 : return NULL;
1063 : : }
1064 : :
3527 1065 : 0 : return dh;
1066 : : }
1067 : :
1068 : : /*
1069 : : * Load hardcoded DH parameters.
1070 : : *
1071 : : * If DH parameters cannot be loaded from a specified file, we can load
1072 : : * the hardcoded DH parameters supplied with the backend to prevent
1073 : : * problems.
1074 : : */
1075 : : static DH *
3527 heikki.linnakangas@i 1076 :CBC 25 : load_dh_buffer(const char *buffer, size_t len)
1077 : : {
1078 : : BIO *bio;
1079 : 25 : DH *dh = NULL;
1080 : :
1902 peter@eisentraut.org 1081 : 25 : bio = BIO_new_mem_buf(unconstify(char *, buffer), len);
3527 heikki.linnakangas@i 1082 [ - + ]: 25 : if (bio == NULL)
3527 heikki.linnakangas@i 1083 :UBC 0 : return NULL;
3527 heikki.linnakangas@i 1084 :CBC 25 : dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
1085 [ - + ]: 25 : if (dh == NULL)
3527 heikki.linnakangas@i 1086 [ # # ]:UBC 0 : ereport(DEBUG2,
1087 : : (errmsg_internal("DH load buffer: %s",
1088 : : SSLerrmessage(ERR_get_error()))));
3527 heikki.linnakangas@i 1089 :CBC 25 : BIO_free(bio);
1090 : :
1091 : 25 : return dh;
1092 : : }
1093 : :
1094 : : /*
1095 : : * Passphrase collection callback using ssl_passphrase_command
1096 : : */
1097 : : static int
2239 peter_e@gmx.net 1098 : 4 : ssl_external_passwd_cb(char *buf, int size, int rwflag, void *userdata)
1099 : : {
1100 : : /* same prompt as OpenSSL uses internally */
1101 : 4 : const char *prompt = "Enter PEM pass phrase:";
1102 : :
1103 [ - + ]: 4 : Assert(rwflag == 0);
1104 : :
1105 : 4 : return run_ssl_passphrase_command(prompt, ssl_is_server_start, buf, size);
1106 : : }
1107 : :
1108 : : /*
1109 : : * Dummy passphrase callback
1110 : : *
1111 : : * If OpenSSL is told to use a passphrase-protected server key, by default
1112 : : * it will issue a prompt on /dev/tty and try to read a key from there.
1113 : : * That's no good during a postmaster SIGHUP cycle, not to mention SSL context
1114 : : * reload in an EXEC_BACKEND postmaster child. So override it with this dummy
1115 : : * function that just returns an empty passphrase, guaranteeing failure.
1116 : : */
1117 : : static int
2239 peter_e@gmx.net 1118 :UBC 0 : dummy_ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
1119 : : {
1120 : : /* Set flag to change the error message we'll report */
1121 : 0 : dummy_ssl_passwd_cb_called = true;
1122 : : /* And return empty string */
2658 tgl@sss.pgh.pa.us 1123 [ # # ]: 0 : Assert(size > 0);
1124 : 0 : buf[0] = '\0';
1125 : 0 : return 0;
1126 : : }
1127 : :
1128 : : /*
1129 : : * Examines the provided certificate name, and if it's too long to log or
1130 : : * contains unprintable ASCII, escapes and truncates it. The return value is
1131 : : * always a new palloc'd string. (The input string is still modified in place,
1132 : : * for ease of implementation.)
1133 : : */
1134 : : static char *
579 peter@eisentraut.org 1135 :CBC 10 : prepare_cert_name(char *name)
1136 : : {
639 1137 : 10 : size_t namelen = strlen(name);
579 1138 : 10 : char *truncated = name;
1139 : :
1140 : : /*
1141 : : * Common Names are 64 chars max, so for a common case where the CN is the
1142 : : * last field, we can still print the longest possible CN with a
1143 : : * 7-character prefix (".../CN=[64 chars]"), for a reasonable limit of 71
1144 : : * characters.
1145 : : */
1146 : : #define MAXLEN 71
1147 : :
1148 [ + + ]: 10 : if (namelen > MAXLEN)
1149 : : {
1150 : : /*
1151 : : * Keep the end of the name, not the beginning, since the most
1152 : : * specific field is likely to give users the most information.
1153 : : */
1154 : 1 : truncated = name + namelen - MAXLEN;
1155 : 1 : truncated[0] = truncated[1] = truncated[2] = '.';
1156 : 1 : namelen = MAXLEN;
1157 : : }
1158 : :
1159 : : #undef MAXLEN
1160 : :
1161 : 10 : return pg_clean_ascii(truncated, 0);
1162 : : }
1163 : :
1164 : : /*
1165 : : * Certificate verification callback
1166 : : *
1167 : : * This callback allows us to examine intermediate problems during
1168 : : * verification, for later logging.
1169 : : *
1170 : : * This callback also allows us to override the default acceptance
1171 : : * criteria (e.g., accepting self-signed or expired certs), but
1172 : : * for now we accept the default checks.
1173 : : */
1174 : : static int
3527 heikki.linnakangas@i 1175 : 92 : verify_cb(int ok, X509_STORE_CTX *ctx)
1176 : : {
1177 : : int depth;
1178 : : int errcode;
1179 : : const char *errstring;
1180 : : StringInfoData str;
1181 : : X509 *cert;
1182 : :
639 peter@eisentraut.org 1183 [ + + ]: 92 : if (ok)
1184 : : {
1185 : : /* Nothing to do for the successful case. */
1186 : 87 : return ok;
1187 : : }
1188 : :
1189 : : /* Pull all the information we have on the verification failure. */
1190 : 5 : depth = X509_STORE_CTX_get_error_depth(ctx);
1191 : 5 : errcode = X509_STORE_CTX_get_error(ctx);
1192 : 5 : errstring = X509_verify_cert_error_string(errcode);
1193 : :
1194 : 5 : initStringInfo(&str);
1195 : 5 : appendStringInfo(&str,
1196 : 5 : _("Client certificate verification failed at depth %d: %s."),
1197 : : depth, errstring);
1198 : :
1199 : 5 : cert = X509_STORE_CTX_get_current_cert(ctx);
1200 [ + - ]: 5 : if (cert)
1201 : : {
1202 : : char *subject,
1203 : : *issuer;
1204 : : char *sub_prepared,
1205 : : *iss_prepared;
1206 : : char *serialno;
1207 : : ASN1_INTEGER *sn;
1208 : : BIGNUM *b;
1209 : :
1210 : : /*
1211 : : * Get the Subject and Issuer for logging, but don't let maliciously
1212 : : * huge certs flood the logs, and don't reflect non-ASCII bytes into
1213 : : * it either.
1214 : : */
1215 : 5 : subject = X509_NAME_to_cstring(X509_get_subject_name(cert));
579 1216 : 5 : sub_prepared = prepare_cert_name(subject);
1217 : 5 : pfree(subject);
1218 : :
639 1219 : 5 : issuer = X509_NAME_to_cstring(X509_get_issuer_name(cert));
579 1220 : 5 : iss_prepared = prepare_cert_name(issuer);
1221 : 5 : pfree(issuer);
1222 : :
1223 : : /*
1224 : : * Pull the serial number, too, in case a Subject is still ambiguous.
1225 : : * This mirrors be_tls_get_peer_serial().
1226 : : */
639 1227 : 5 : sn = X509_get_serialNumber(cert);
1228 : 5 : b = ASN1_INTEGER_to_BN(sn, NULL);
1229 : 5 : serialno = BN_bn2dec(b);
1230 : :
1231 : 5 : appendStringInfoChar(&str, '\n');
1232 [ - + ]: 5 : appendStringInfo(&str,
1233 : 5 : _("Failed certificate data (unverified): subject \"%s\", serial number %s, issuer \"%s\"."),
579 peter@eisentraut.org 1234 :UBC 0 : sub_prepared, serialno ? serialno : _("unknown"),
1235 : : iss_prepared);
1236 : :
639 peter@eisentraut.org 1237 :CBC 5 : BN_free(b);
1238 : 5 : OPENSSL_free(serialno);
579 1239 : 5 : pfree(iss_prepared);
1240 : 5 : pfree(sub_prepared);
1241 : : }
1242 : :
1243 : : /* Store our detail message to be logged later. */
639 1244 : 5 : cert_errdetail = str.data;
1245 : :
3527 heikki.linnakangas@i 1246 : 5 : return ok;
1247 : : }
1248 : :
1249 : : /*
1250 : : * This callback is used to copy SSL information messages
1251 : : * into the PostgreSQL log.
1252 : : */
1253 : : static void
1254 : 4629 : info_cb(const SSL *ssl, int type, int args)
1255 : : {
1256 : : const char *desc;
1257 : :
1178 michael@paquier.xyz 1258 : 4629 : desc = SSL_state_string_long(ssl);
1259 : :
3527 heikki.linnakangas@i 1260 [ + + + + : 4629 : switch (type)
- - + +
- ]
1261 : : {
1262 : 185 : case SSL_CB_HANDSHAKE_START:
1263 [ - + ]: 185 : ereport(DEBUG4,
1264 : : (errmsg_internal("SSL: handshake start: \"%s\"", desc)));
3534 1265 : 185 : break;
3527 1266 : 167 : case SSL_CB_HANDSHAKE_DONE:
1267 [ - + ]: 167 : ereport(DEBUG4,
1268 : : (errmsg_internal("SSL: handshake done: \"%s\"", desc)));
3534 1269 : 167 : break;
3527 1270 : 3434 : case SSL_CB_ACCEPT_LOOP:
1271 [ - + ]: 3434 : ereport(DEBUG4,
1272 : : (errmsg_internal("SSL: accept loop: \"%s\"", desc)));
3534 1273 : 3434 : break;
3527 1274 : 653 : case SSL_CB_ACCEPT_EXIT:
1275 [ - + ]: 653 : ereport(DEBUG4,
1276 : : (errmsg_internal("SSL: accept exit (%d): \"%s\"", args, desc)));
1277 : 653 : break;
3527 heikki.linnakangas@i 1278 :UBC 0 : case SSL_CB_CONNECT_LOOP:
1279 [ # # ]: 0 : ereport(DEBUG4,
1280 : : (errmsg_internal("SSL: connect loop: \"%s\"", desc)));
1281 : 0 : break;
1282 : 0 : case SSL_CB_CONNECT_EXIT:
1283 [ # # ]: 0 : ereport(DEBUG4,
1284 : : (errmsg_internal("SSL: connect exit (%d): \"%s\"", args, desc)));
1285 : 0 : break;
3527 heikki.linnakangas@i 1286 :CBC 26 : case SSL_CB_READ_ALERT:
1287 [ - + ]: 26 : ereport(DEBUG4,
1288 : : (errmsg_internal("SSL: read alert (0x%04x): \"%s\"", args, desc)));
1289 : 26 : break;
1290 : 164 : case SSL_CB_WRITE_ALERT:
1291 [ - + ]: 164 : ereport(DEBUG4,
1292 : : (errmsg_internal("SSL: write alert (0x%04x): \"%s\"", args, desc)));
3534 1293 : 164 : break;
1294 : : }
3527 1295 : 4629 : }
1296 : :
1297 : : /* See pqcomm.h comments on OpenSSL implementation of ALPN (RFC 7301) */
1298 : : static const unsigned char alpn_protos[] = PG_ALPN_PROTOCOL_VECTOR;
1299 : :
1300 : : /*
1301 : : * Server callback for ALPN negotiation. We use the standard "helper" function
1302 : : * even though currently we only accept one value.
1303 : : */
1304 : : static int
6 heikki.linnakangas@i 1305 :GNC 360 : alpn_cb(SSL *ssl,
1306 : : const unsigned char **out,
1307 : : unsigned char *outlen,
1308 : : const unsigned char *in,
1309 : : unsigned int inlen,
1310 : : void *userdata)
1311 : : {
1312 : : /*
1313 : : * Why does OpenSSL provide a helper function that requires a nonconst
1314 : : * vector when the callback is declared to take a const vector? What are
1315 : : * we to do with that?
1316 : : */
1317 : : int retval;
1318 : :
1319 [ - + ]: 360 : Assert(userdata != NULL);
1320 [ - + ]: 360 : Assert(out != NULL);
1321 [ - + ]: 360 : Assert(outlen != NULL);
1322 [ - + ]: 360 : Assert(in != NULL);
1323 : :
1324 : 360 : retval = SSL_select_next_proto((unsigned char **) out, outlen,
1325 : : alpn_protos, sizeof(alpn_protos),
1326 : : in, inlen);
1327 [ + - + - : 360 : if (*out == NULL || *outlen > sizeof(alpn_protos) || *outlen <= 0)
- + ]
6 heikki.linnakangas@i 1328 :UNC 0 : return SSL_TLSEXT_ERR_NOACK; /* can't happen */
1329 : :
6 heikki.linnakangas@i 1330 [ + - ]:GNC 360 : if (retval == OPENSSL_NPN_NEGOTIATED)
1331 : 360 : return SSL_TLSEXT_ERR_OK;
6 heikki.linnakangas@i 1332 [ # # ]:UNC 0 : else if (retval == OPENSSL_NPN_NO_OVERLAP)
1333 : 0 : return SSL_TLSEXT_ERR_NOACK;
1334 : : else
1335 : 0 : return SSL_TLSEXT_ERR_NOACK;
1336 : : }
1337 : :
1338 : :
1339 : : /*
1340 : : * Set DH parameters for generating ephemeral DH keys. The
1341 : : * DH parameters can take a long time to compute, so they must be
1342 : : * precomputed.
1343 : : *
1344 : : * Since few sites will bother to create a parameter file, we also
1345 : : * provide a fallback to the parameters provided by the OpenSSL
1346 : : * project.
1347 : : *
1348 : : * These values can be static (once loaded or computed) since the
1349 : : * OpenSSL library can efficiently generate random keys from the
1350 : : * information provided.
1351 : : */
1352 : : static bool
2449 heikki.linnakangas@i 1353 :CBC 25 : initialize_dh(SSL_CTX *context, bool isServerStart)
1354 : : {
1355 : 25 : DH *dh = NULL;
1356 : :
1357 : 25 : SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
1358 : :
1359 [ - + ]: 25 : if (ssl_dh_params_file[0])
2449 heikki.linnakangas@i 1360 :UBC 0 : dh = load_dh_file(ssl_dh_params_file, isServerStart);
2449 heikki.linnakangas@i 1361 [ + - ]:CBC 25 : if (!dh)
2277 peter_e@gmx.net 1362 : 25 : dh = load_dh_buffer(FILE_DH2048, sizeof(FILE_DH2048));
2449 heikki.linnakangas@i 1363 [ - + ]: 25 : if (!dh)
1364 : : {
2449 heikki.linnakangas@i 1365 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
1366 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1367 : : errmsg("DH: could not load DH parameters")));
1368 : 0 : return false;
1369 : : }
1370 : :
2449 heikki.linnakangas@i 1371 [ - + ]:CBC 25 : if (SSL_CTX_set_tmp_dh(context, dh) != 1)
1372 : : {
2449 heikki.linnakangas@i 1373 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
1374 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1375 : : errmsg("DH: could not set DH parameters: %s",
1376 : : SSLerrmessage(ERR_get_error()))));
1583 michael@paquier.xyz 1377 : 0 : DH_free(dh);
2449 heikki.linnakangas@i 1378 : 0 : return false;
1379 : : }
1380 : :
1583 michael@paquier.xyz 1381 :CBC 25 : DH_free(dh);
2449 heikki.linnakangas@i 1382 : 25 : return true;
1383 : : }
1384 : :
1385 : : /*
1386 : : * Set ECDH parameters for generating ephemeral Elliptic Curve DH
1387 : : * keys. This is much simpler than the DH parameters, as we just
1388 : : * need to provide the name of the curve to OpenSSL.
1389 : : */
1390 : : static bool
2657 tgl@sss.pgh.pa.us 1391 : 25 : initialize_ecdh(SSL_CTX *context, bool isServerStart)
1392 : : {
1393 : : #ifndef OPENSSL_NO_ECDH
1394 : : EC_KEY *ecdh;
1395 : : int nid;
1396 : :
3527 heikki.linnakangas@i 1397 : 25 : nid = OBJ_sn2nid(SSLECDHCurve);
1398 [ - + ]: 25 : if (!nid)
1399 : : {
2657 tgl@sss.pgh.pa.us 1400 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
1401 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1402 : : errmsg("ECDH: unrecognized curve name: %s", SSLECDHCurve)));
2659 1403 : 0 : return false;
1404 : : }
1405 : :
3527 heikki.linnakangas@i 1406 :CBC 25 : ecdh = EC_KEY_new_by_curve_name(nid);
1407 [ - + ]: 25 : if (!ecdh)
1408 : : {
2657 tgl@sss.pgh.pa.us 1409 [ # # # # ]:UBC 0 : ereport(isServerStart ? FATAL : LOG,
1410 : : (errcode(ERRCODE_CONFIG_FILE_ERROR),
1411 : : errmsg("ECDH: could not create key")));
2659 1412 : 0 : return false;
1413 : : }
1414 : :
2659 tgl@sss.pgh.pa.us 1415 :CBC 25 : SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
1416 : 25 : SSL_CTX_set_tmp_ecdh(context, ecdh);
3527 heikki.linnakangas@i 1417 : 25 : EC_KEY_free(ecdh);
1418 : : #endif
1419 : :
2659 tgl@sss.pgh.pa.us 1420 : 25 : return true;
1421 : : }
1422 : :
1423 : : /*
1424 : : * Obtain reason string for passed SSL errcode
1425 : : *
1426 : : * ERR_get_error() is used by caller to get errcode to pass here.
1427 : : *
1428 : : * Some caution is needed here since ERR_reason_error_string will return NULL
1429 : : * if it doesn't recognize the error code, or (in OpenSSL >= 3) if the code
1430 : : * represents a system errno value. We don't want to return NULL ever.
1431 : : */
1432 : : static const char *
2928 peter_e@gmx.net 1433 : 16 : SSLerrmessage(unsigned long ecode)
1434 : : {
1435 : : const char *errreason;
1436 : : static char errbuf[36];
1437 : :
1438 [ - + ]: 16 : if (ecode == 0)
3534 heikki.linnakangas@i 1439 :UBC 0 : return _("no SSL error reported");
2928 peter_e@gmx.net 1440 :CBC 16 : errreason = ERR_reason_error_string(ecode);
3534 heikki.linnakangas@i 1441 [ + - ]: 16 : if (errreason != NULL)
1442 : 16 : return errreason;
1443 : :
1444 : : /*
1445 : : * In OpenSSL 3.0.0 and later, ERR_reason_error_string randomly refuses to
1446 : : * map system errno values. We can cover that shortcoming with this bit
1447 : : * of code. Older OpenSSL versions don't have the ERR_SYSTEM_ERROR macro,
1448 : : * but that's okay because they don't have the shortcoming either.
1449 : : */
1450 : : #ifdef ERR_SYSTEM_ERROR
38 tgl@sss.pgh.pa.us 1451 [ # # ]:UBC 0 : if (ERR_SYSTEM_ERROR(ecode))
1452 : 0 : return strerror(ERR_GET_REASON(ecode));
1453 : : #endif
1454 : :
1455 : : /* No choice but to report the numeric ecode */
2928 peter_e@gmx.net 1456 : 0 : snprintf(errbuf, sizeof(errbuf), _("SSL error code %lu"), ecode);
3534 heikki.linnakangas@i 1457 : 0 : return errbuf;
1458 : : }
1459 : :
1460 : : int
3290 magnus@hagander.net 1461 :CBC 254 : be_tls_get_cipher_bits(Port *port)
1462 : : {
1463 : : int bits;
1464 : :
1465 [ + - ]: 254 : if (port->ssl)
1466 : : {
1467 : 254 : SSL_get_cipher_bits(port->ssl, &bits);
1468 : 254 : return bits;
1469 : : }
1470 : : else
3290 magnus@hagander.net 1471 :UBC 0 : return 0;
1472 : : }
1473 : :
1474 : : const char *
2271 peter_e@gmx.net 1475 :CBC 255 : be_tls_get_version(Port *port)
1476 : : {
3290 magnus@hagander.net 1477 [ + - ]: 255 : if (port->ssl)
2271 peter_e@gmx.net 1478 : 255 : return SSL_get_version(port->ssl);
1479 : : else
2271 peter_e@gmx.net 1480 :UBC 0 : return NULL;
1481 : : }
1482 : :
1483 : : const char *
2271 peter_e@gmx.net 1484 :CBC 255 : be_tls_get_cipher(Port *port)
1485 : : {
3290 magnus@hagander.net 1486 [ + - ]: 255 : if (port->ssl)
2271 peter_e@gmx.net 1487 : 255 : return SSL_get_cipher(port->ssl);
1488 : : else
2271 peter_e@gmx.net 1489 :UBC 0 : return NULL;
1490 : : }
1491 : :
1492 : : void
1899 peter@eisentraut.org 1493 :CBC 127 : be_tls_get_peer_subject_name(Port *port, char *ptr, size_t len)
1494 : : {
3290 magnus@hagander.net 1495 [ + + ]: 127 : if (port->peer)
1496 : 27 : strlcpy(ptr, X509_NAME_to_cstring(X509_get_subject_name(port->peer)), len);
1497 : : else
1498 : 100 : ptr[0] = '\0';
1499 : 127 : }
1500 : :
1501 : : void
1899 peter@eisentraut.org 1502 : 128 : be_tls_get_peer_issuer_name(Port *port, char *ptr, size_t len)
1503 : : {
1504 [ + + ]: 128 : if (port->peer)
1505 : 28 : strlcpy(ptr, X509_NAME_to_cstring(X509_get_issuer_name(port->peer)), len);
1506 : : else
1507 : 100 : ptr[0] = '\0';
1508 : 128 : }
1509 : :
1510 : : void
1511 : 128 : be_tls_get_peer_serial(Port *port, char *ptr, size_t len)
1512 : : {
1513 [ + + ]: 128 : if (port->peer)
1514 : : {
1515 : : ASN1_INTEGER *serial;
1516 : : BIGNUM *b;
1517 : : char *decimal;
1518 : :
1519 : 28 : serial = X509_get_serialNumber(port->peer);
1520 : 28 : b = ASN1_INTEGER_to_BN(serial, NULL);
1521 : 28 : decimal = BN_bn2dec(b);
1522 : :
1523 : 28 : BN_free(b);
1524 : 28 : strlcpy(ptr, decimal, len);
1525 : 28 : OPENSSL_free(decimal);
1526 : : }
1527 : : else
1528 : 100 : ptr[0] = '\0';
1529 : 128 : }
1530 : :
1531 : : char *
2292 peter_e@gmx.net 1532 : 4 : be_tls_get_certificate_hash(Port *port, size_t *len)
1533 : : {
1534 : : X509 *server_cert;
1535 : : char *cert_hash;
1536 : 4 : const EVP_MD *algo_type = NULL;
1537 : : unsigned char hash[EVP_MAX_MD_SIZE]; /* size for SHA-512 */
1538 : : unsigned int hash_size;
1539 : : int algo_nid;
1540 : :
1541 : 4 : *len = 0;
1542 : 4 : server_cert = SSL_get_certificate(port->ssl);
1543 [ - + ]: 4 : if (server_cert == NULL)
2292 peter_e@gmx.net 1544 :UBC 0 : return NULL;
1545 : :
1546 : : /*
1547 : : * Get the signature algorithm of the certificate to determine the hash
1548 : : * algorithm to use for the result. Prefer X509_get_signature_info(),
1549 : : * introduced in OpenSSL 1.1.1, which can handle RSA-PSS signatures.
1550 : : */
1551 : : #if HAVE_X509_GET_SIGNATURE_INFO
424 michael@paquier.xyz 1552 [ - + ]:CBC 4 : if (!X509_get_signature_info(server_cert, &algo_nid, NULL, NULL, NULL))
1553 : : #else
1554 : : if (!OBJ_find_sigid_algs(X509_get_signature_nid(server_cert),
1555 : : &algo_nid, NULL))
1556 : : #endif
2292 peter_e@gmx.net 1557 [ # # ]:UBC 0 : elog(ERROR, "could not determine server certificate signature algorithm");
1558 : :
1559 : : /*
1560 : : * The TLS server's certificate bytes need to be hashed with SHA-256 if
1561 : : * its signature algorithm is MD5 or SHA-1 as per RFC 5929
1562 : : * (https://tools.ietf.org/html/rfc5929#section-4.1). If something else
1563 : : * is used, the same hash as the signature algorithm is used.
1564 : : */
2292 peter_e@gmx.net 1565 [ - + ]:CBC 4 : switch (algo_nid)
1566 : : {
2292 peter_e@gmx.net 1567 :UBC 0 : case NID_md5:
1568 : : case NID_sha1:
1569 : 0 : algo_type = EVP_sha256();
1570 : 0 : break;
2292 peter_e@gmx.net 1571 :CBC 4 : default:
1572 : 4 : algo_type = EVP_get_digestbynid(algo_nid);
1573 [ - + ]: 4 : if (algo_type == NULL)
2292 peter_e@gmx.net 1574 [ # # ]:UBC 0 : elog(ERROR, "could not find digest for NID %s",
1575 : : OBJ_nid2sn(algo_nid));
2292 peter_e@gmx.net 1576 :CBC 4 : break;
1577 : : }
1578 : :
1579 : : /* generate and save the certificate hash */
1580 [ - + ]: 4 : if (!X509_digest(server_cert, algo_type, hash, &hash_size))
2292 peter_e@gmx.net 1581 [ # # ]:UBC 0 : elog(ERROR, "could not generate server certificate hash");
1582 : :
2292 peter_e@gmx.net 1583 :CBC 4 : cert_hash = palloc(hash_size);
1584 : 4 : memcpy(cert_hash, hash, hash_size);
1585 : 4 : *len = hash_size;
1586 : :
1587 : 4 : return cert_hash;
1588 : : }
1589 : :
1590 : : /*
1591 : : * Convert an X509 subject name to a cstring.
1592 : : *
1593 : : */
1594 : : static char *
3290 magnus@hagander.net 1595 : 65 : X509_NAME_to_cstring(X509_NAME *name)
1596 : : {
1597 : 65 : BIO *membuf = BIO_new(BIO_s_mem());
1598 : : int i,
1599 : : nid,
1600 : 65 : count = X509_NAME_entry_count(name);
1601 : : X509_NAME_ENTRY *e;
1602 : : ASN1_STRING *v;
1603 : : const char *field_name;
1604 : : size_t size;
1605 : : char nullterm;
1606 : : char *sp;
1607 : : char *dp;
1608 : : char *result;
1609 : :
1258 1610 [ - + ]: 65 : if (membuf == NULL)
1258 magnus@hagander.net 1611 [ # # ]:UBC 0 : ereport(ERROR,
1612 : : (errcode(ERRCODE_OUT_OF_MEMORY),
1613 : : errmsg("could not create BIO")));
1614 : :
3290 magnus@hagander.net 1615 :CBC 65 : (void) BIO_set_close(membuf, BIO_CLOSE);
1616 [ + + ]: 141 : for (i = 0; i < count; i++)
1617 : : {
1618 : 76 : e = X509_NAME_get_entry(name, i);
1619 : 76 : nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
1258 1620 [ - + ]: 76 : if (nid == NID_undef)
1258 magnus@hagander.net 1621 [ # # ]:UBC 0 : ereport(ERROR,
1622 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1623 : : errmsg("could not get NID for ASN1_OBJECT object")));
3290 magnus@hagander.net 1624 :CBC 76 : v = X509_NAME_ENTRY_get_data(e);
1625 : 76 : field_name = OBJ_nid2sn(nid);
1258 1626 [ - + ]: 76 : if (field_name == NULL)
3290 magnus@hagander.net 1627 :UBC 0 : field_name = OBJ_nid2ln(nid);
1258 magnus@hagander.net 1628 [ - + ]:CBC 76 : if (field_name == NULL)
1258 magnus@hagander.net 1629 [ # # ]:UBC 0 : ereport(ERROR,
1630 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1631 : : errmsg("could not convert NID %d to an ASN1_OBJECT structure", nid)));
3290 magnus@hagander.net 1632 :CBC 76 : BIO_printf(membuf, "/%s=", field_name);
1633 : 76 : ASN1_STRING_print_ex(membuf, v,
1634 : : ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
1635 : : | ASN1_STRFLGS_UTF8_CONVERT));
1636 : : }
1637 : :
1638 : : /* ensure null termination of the BIO's content */
1639 : 65 : nullterm = '\0';
1640 : 65 : BIO_write(membuf, &nullterm, 1);
1641 : 65 : size = BIO_get_mem_data(membuf, &sp);
1642 : 65 : dp = pg_any_to_server(sp, size - 1, PG_UTF8);
1643 : :
1644 : 65 : result = pstrdup(dp);
1645 [ - + ]: 65 : if (dp != sp)
3290 magnus@hagander.net 1646 :UBC 0 : pfree(dp);
1258 magnus@hagander.net 1647 [ - + ]:CBC 65 : if (BIO_free(membuf) != 1)
1258 magnus@hagander.net 1648 [ # # ]:UBC 0 : elog(ERROR, "could not free OpenSSL BIO structure");
1649 : :
3290 magnus@hagander.net 1650 :CBC 65 : return result;
1651 : : }
1652 : :
1653 : : /*
1654 : : * Convert TLS protocol version GUC enum to OpenSSL values
1655 : : *
1656 : : * This is a straightforward one-to-one mapping, but doing it this way makes
1657 : : * the definitions of ssl_min_protocol_version and ssl_max_protocol_version
1658 : : * independent of OpenSSL availability and version.
1659 : : *
1660 : : * If a version is passed that is not supported by the current OpenSSL
1661 : : * version, then we return -1. If a nonnegative value is returned,
1662 : : * subsequent code can assume it's working with a supported version.
1663 : : *
1664 : : * Note: this is rather similar to libpq's routine in fe-secure-openssl.c,
1665 : : * so make sure to update both routines if changing this one.
1666 : : */
1667 : : static int
1483 michael@paquier.xyz 1668 : 27 : ssl_protocol_version_to_openssl(int v)
1669 : : {
1972 peter_e@gmx.net 1670 [ - - + + : 27 : switch (v)
- - ]
1671 : : {
1972 peter_e@gmx.net 1672 :UBC 0 : case PG_TLS_ANY:
1673 : 0 : return 0;
1674 : 0 : case PG_TLS1_VERSION:
1675 : 0 : return TLS1_VERSION;
1972 peter_e@gmx.net 1676 :CBC 1 : case PG_TLS1_1_VERSION:
1677 : : #ifdef TLS1_1_VERSION
1678 : 1 : return TLS1_1_VERSION;
1679 : : #else
1680 : : break;
1681 : : #endif
1682 : 26 : case PG_TLS1_2_VERSION:
1683 : : #ifdef TLS1_2_VERSION
1684 : 26 : return TLS1_2_VERSION;
1685 : : #else
1686 : : break;
1687 : : #endif
1972 peter_e@gmx.net 1688 :UBC 0 : case PG_TLS1_3_VERSION:
1689 : : #ifdef TLS1_3_VERSION
1690 : 0 : return TLS1_3_VERSION;
1691 : : #else
1692 : : break;
1693 : : #endif
1694 : : }
1695 : :
1696 : 0 : return -1;
1697 : : }
1698 : :
1699 : : /*
1700 : : * Likewise provide a mapping to strings.
1701 : : */
1702 : : static const char *
1387 tgl@sss.pgh.pa.us 1703 : 0 : ssl_protocol_version_to_string(int v)
1704 : : {
1705 [ # # # # : 0 : switch (v)
# # ]
1706 : : {
1707 : 0 : case PG_TLS_ANY:
1708 : 0 : return "any";
1709 : 0 : case PG_TLS1_VERSION:
1710 : 0 : return "TLSv1";
1711 : 0 : case PG_TLS1_1_VERSION:
1712 : 0 : return "TLSv1.1";
1713 : 0 : case PG_TLS1_2_VERSION:
1714 : 0 : return "TLSv1.2";
1715 : 0 : case PG_TLS1_3_VERSION:
1716 : 0 : return "TLSv1.3";
1717 : : }
1718 : :
1719 : 0 : return "(unrecognized)";
1720 : : }
1721 : :
1722 : :
1723 : : static void
1481 andrew@dunslane.net 1724 :CBC 25 : default_openssl_tls_init(SSL_CTX *context, bool isServerStart)
1725 : : {
1726 [ + + ]: 25 : if (isServerStart)
1727 : : {
1728 [ + + ]: 23 : if (ssl_passphrase_command[0])
1729 : 4 : SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb);
1730 : : }
1731 : : else
1732 : : {
1481 andrew@dunslane.net 1733 [ - + - - ]:GBC 2 : if (ssl_passphrase_command[0] && ssl_passphrase_command_supports_reload)
1481 andrew@dunslane.net 1734 :UBC 0 : SSL_CTX_set_default_passwd_cb(context, ssl_external_passwd_cb);
1735 : : else
1736 : :
1737 : : /*
1738 : : * If reloading and no external command is configured, override
1739 : : * OpenSSL's default handling of passphrase-protected files,
1740 : : * because we don't want to prompt for a passphrase in an
1741 : : * already-running server.
1742 : : */
1481 andrew@dunslane.net 1743 :GBC 2 : SSL_CTX_set_default_passwd_cb(context, dummy_ssl_passwd_cb);
1744 : : }
1481 andrew@dunslane.net 1745 :CBC 25 : }
|