diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-08-18 13:04:47 +0300 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2014-08-18 13:12:40 +0300 |
commit | 48d50840d53eb62842c0d9b54eab9cd7c9a3a46d (patch) | |
tree | e28deb52b238d509c42eecb25c57634a209b1ed4 /src/backend/libpq/be-secure-openssl.c | |
parent | 2b475c5946bc8a9beaff3f57b45cc440a78561a1 (diff) | |
download | postgresql-48d50840d53eb62842c0d9b54eab9cd7c9a3a46d.tar.gz postgresql-48d50840d53eb62842c0d9b54eab9cd7c9a3a46d.zip |
Reorganize functions in be-secure-openssl.c
Move the functions within the file so that public interface functions come
first, followed by internal functions. Previously, be_tls_write was first,
then internal stuff, and finally the rest of the public interface, which
clearly didn't make much sense.
Per Andres Freund's complaint.
Diffstat (limited to 'src/backend/libpq/be-secure-openssl.c')
-rw-r--r-- | src/backend/libpq/be-secure-openssl.c | 805 |
1 files changed, 408 insertions, 397 deletions
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c index f7bdcb7f10e..8d8f12952a4 100644 --- a/src/backend/libpq/be-secure-openssl.c +++ b/src/backend/libpq/be-secure-openssl.c @@ -75,12 +75,17 @@ #include "utils/memutils.h" +static int my_sock_read(BIO *h, char *buf, int size); +static int my_sock_write(BIO *h, const char *buf, int size); +static BIO_METHOD *my_BIO_s_socket(void); +static int my_SSL_set_fd(Port *port, int fd); static DH *load_dh_file(int keylength); static DH *load_dh_buffer(const char *, size_t); static DH *tmp_dh_cb(SSL *s, int is_export, int keylength); static int verify_cb(int, X509_STORE_CTX *); static void info_cb(const SSL *ssl, int type, int args); +static void initialize_ecdh(void); static const char *SSLerrmessage(void); /* are we in the middle of a renegotiation? */ @@ -153,6 +158,407 @@ AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\ KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\ -----END DH PARAMETERS-----\n"; + +/* ------------------------------------------------------------ */ +/* Public interface */ +/* ------------------------------------------------------------ */ + +/* + * Initialize global SSL context. + */ +void +be_tls_init(void) +{ + struct stat buf; + + STACK_OF(X509_NAME) *root_cert_list = NULL; + + if (!SSL_context) + { +#if SSLEAY_VERSION_NUMBER >= 0x0907000L + OPENSSL_config(NULL); +#endif + SSL_library_init(); + SSL_load_error_strings(); + + /* + * We use SSLv23_method() because it can negotiate use of the highest + * mutually supported protocol version, while alternatives like + * TLSv1_2_method() permit only one specific version. Note that we + * don't actually allow SSL v2 or v3, only TLS protocols (see below). + */ + SSL_context = SSL_CTX_new(SSLv23_method()); + if (!SSL_context) + ereport(FATAL, + (errmsg("could not create SSL context: %s", + SSLerrmessage()))); + + /* + * Disable OpenSSL's moving-write-buffer sanity check, because it + * causes unnecessary failures in nonblocking send cases. + */ + SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); + + /* + * Load and verify server's certificate and private key + */ + if (SSL_CTX_use_certificate_chain_file(SSL_context, + ssl_cert_file) != 1) + ereport(FATAL, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("could not load server certificate file \"%s\": %s", + ssl_cert_file, SSLerrmessage()))); + + if (stat(ssl_key_file, &buf) != 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not access private key file \"%s\": %m", + ssl_key_file))); + + /* + * Require no public access to key file. + * + * XXX temporarily suppress check when on Windows, because there may + * not be proper support for Unix-y file permissions. Need to think + * of a reasonable check to apply on Windows. (See also the data + * directory permission check in postmaster.c) + */ +#if !defined(WIN32) && !defined(__CYGWIN__) + if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) + ereport(FATAL, + (errcode(ERRCODE_CONFIG_FILE_ERROR), + errmsg("private key file \"%s\" has group or world access", + ssl_key_file), + errdetail("Permissions should be u=rw (0600) or less."))); +#endif + + if (SSL_CTX_use_PrivateKey_file(SSL_context, + ssl_key_file, + SSL_FILETYPE_PEM) != 1) + ereport(FATAL, + (errmsg("could not load private key file \"%s\": %s", + ssl_key_file, SSLerrmessage()))); + + if (SSL_CTX_check_private_key(SSL_context) != 1) + ereport(FATAL, + (errmsg("check of private key failed: %s", + SSLerrmessage()))); + } + + /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */ + SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); + SSL_CTX_set_options(SSL_context, + SSL_OP_SINGLE_DH_USE | + SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); + + /* set up ephemeral ECDH keys */ + initialize_ecdh(); + + /* set up the allowed cipher list */ + if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1) + elog(FATAL, "could not set the cipher list (no valid ciphers available)"); + + /* Let server choose order */ + if (SSLPreferServerCiphers) + SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE); + + /* + * Load CA store, so we can verify client certificates if needed. + */ + if (ssl_ca_file[0]) + { + if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 || + (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) + ereport(FATAL, + (errmsg("could not load root certificate file \"%s\": %s", + ssl_ca_file, SSLerrmessage()))); + } + + /*---------- + * Load the Certificate Revocation List (CRL). + * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html + *---------- + */ + if (ssl_crl_file[0]) + { + X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context); + + if (cvstore) + { + /* Set the flags to check against the complete CRL chain */ + if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1) + { + /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ +#ifdef X509_V_FLAG_CRL_CHECK + X509_STORE_set_flags(cvstore, + X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); +#else + ereport(LOG, + (errmsg("SSL certificate revocation list file \"%s\" ignored", + ssl_crl_file), + errdetail("SSL library does not support certificate revocation lists."))); +#endif + } + else + ereport(FATAL, + (errmsg("could not load SSL certificate revocation list file \"%s\": %s", + ssl_crl_file, SSLerrmessage()))); + } + } + + if (ssl_ca_file[0]) + { + /* + * Always ask for SSL client cert, but don't fail if it's not + * presented. We might fail such connections later, depending on what + * we find in pg_hba.conf. + */ + SSL_CTX_set_verify(SSL_context, + (SSL_VERIFY_PEER | + SSL_VERIFY_CLIENT_ONCE), + verify_cb); + + /* Set flag to remember CA store is successfully loaded */ + ssl_loaded_verify_locations = true; + + /* + * Tell OpenSSL to send the list of root certs we trust to clients in + * CertificateRequests. This lets a client with a keystore select the + * appropriate client certificate to send to us. + */ + SSL_CTX_set_client_CA_list(SSL_context, root_cert_list); + } +} + +/* + * Attempt to negotiate SSL connection. + */ +int +be_tls_open_server(Port *port) +{ + int r; + int err; + + Assert(!port->ssl); + Assert(!port->peer); + + if (!(port->ssl = SSL_new(SSL_context))) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not initialize SSL connection: %s", + SSLerrmessage()))); + be_tls_close(port); + return -1; + } + if (!my_SSL_set_fd(port, port->sock)) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not set SSL socket: %s", + SSLerrmessage()))); + be_tls_close(port); + return -1; + } + port->ssl_in_use = true; + +aloop: + r = SSL_accept(port->ssl); + if (r <= 0) + { + err = SSL_get_error(port->ssl, r); + switch (err) + { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: +#ifdef WIN32 + pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), + (err == SSL_ERROR_WANT_READ) ? + FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE, + INFINITE); +#endif + goto aloop; + case SSL_ERROR_SYSCALL: + if (r < 0) + ereport(COMMERROR, + (errcode_for_socket_access(), + errmsg("could not accept SSL connection: %m"))); + else + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: EOF detected"))); + break; + case SSL_ERROR_SSL: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: %s", + SSLerrmessage()))); + break; + case SSL_ERROR_ZERO_RETURN: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("could not accept SSL connection: EOF detected"))); + break; + default: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unrecognized SSL error code: %d", + err))); + break; + } + be_tls_close(port); + return -1; + } + + port->count = 0; + + /* Get client certificate, if available. */ + port->peer = SSL_get_peer_certificate(port->ssl); + + /* and extract the Common Name from it. */ + port->peer_cn = NULL; + port->peer_cert_valid = false; + if (port->peer != NULL) + { + int len; + + len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), + NID_commonName, NULL, 0); + if (len != -1) + { + char *peer_cn; + + peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1); + r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), + NID_commonName, peer_cn, len + 1); + peer_cn[len] = '\0'; + if (r != len) + { + /* shouldn't happen */ + pfree(peer_cn); + be_tls_close(port); + return -1; + } + + /* + * Reject embedded NULLs in certificate common name to prevent + * attacks like CVE-2009-4034. + */ + if (len != strlen(peer_cn)) + { + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("SSL certificate's common name contains embedded null"))); + pfree(peer_cn); + be_tls_close(port); + return -1; + } + + port->peer_cn = peer_cn; + } + port->peer_cert_valid = true; + } + + ereport(DEBUG2, + (errmsg("SSL connection from \"%s\"", + port->peer_cn ? port->peer_cn : "(anonymous)"))); + + /* set up debugging/info callback */ + SSL_CTX_set_info_callback(SSL_context, info_cb); + + return 0; +} + +/* + * Close SSL connection. + */ +void +be_tls_close(Port *port) +{ + if (port->ssl) + { + SSL_shutdown(port->ssl); + SSL_free(port->ssl); + port->ssl = NULL; + port->ssl_in_use = false; + } + + if (port->peer) + { + X509_free(port->peer); + port->peer = NULL; + } + + if (port->peer_cn) + { + pfree(port->peer_cn); + port->peer_cn = NULL; + } +} + +/* + * Read data from a secure connection. + */ +ssize_t +be_tls_read(Port *port, void *ptr, size_t len) +{ + ssize_t n; + int err; + +rloop: + errno = 0; + n = SSL_read(port->ssl, ptr, len); + err = SSL_get_error(port->ssl, n); + switch (err) + { + case SSL_ERROR_NONE: + port->count += n; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + if (port->noblock) + { + errno = EWOULDBLOCK; + n = -1; + break; + } +#ifdef WIN32 + pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), + (err == SSL_ERROR_WANT_READ) ? + FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE, + INFINITE); +#endif + goto rloop; + case SSL_ERROR_SYSCALL: + /* leave it to caller to ereport the value of errno */ + if (n != -1) + { + errno = ECONNRESET; + n = -1; + } + break; + case SSL_ERROR_SSL: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("SSL error: %s", SSLerrmessage()))); + /* fall through */ + case SSL_ERROR_ZERO_RETURN: + errno = ECONNRESET; + n = -1; + break; + default: + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("unrecognized SSL error code: %d", + err))); + errno = ECONNRESET; + n = -1; + break; + } + + return n; +} + /* * Write data to a secure connection. */ @@ -284,7 +690,7 @@ wloop: } /* ------------------------------------------------------------ */ -/* OpenSSL specific code */ +/* Internal functions */ /* ------------------------------------------------------------ */ /* @@ -601,10 +1007,10 @@ info_cb(const SSL *ssl, int type, int args) } } -#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) static void initialize_ecdh(void) { +#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_ECDH) EC_KEY *ecdh; int nid; @@ -621,402 +1027,7 @@ initialize_ecdh(void) SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_ECDH_USE); SSL_CTX_set_tmp_ecdh(SSL_context, ecdh); EC_KEY_free(ecdh); -} -#else -#define initialize_ecdh() -#endif - -/* - * Initialize global SSL context. - */ -void -be_tls_init(void) -{ - struct stat buf; - - STACK_OF(X509_NAME) *root_cert_list = NULL; - - if (!SSL_context) - { -#if SSLEAY_VERSION_NUMBER >= 0x0907000L - OPENSSL_config(NULL); -#endif - SSL_library_init(); - SSL_load_error_strings(); - - /* - * We use SSLv23_method() because it can negotiate use of the highest - * mutually supported protocol version, while alternatives like - * TLSv1_2_method() permit only one specific version. Note that we - * don't actually allow SSL v2 or v3, only TLS protocols (see below). - */ - SSL_context = SSL_CTX_new(SSLv23_method()); - if (!SSL_context) - ereport(FATAL, - (errmsg("could not create SSL context: %s", - SSLerrmessage()))); - - /* - * Disable OpenSSL's moving-write-buffer sanity check, because it - * causes unnecessary failures in nonblocking send cases. - */ - SSL_CTX_set_mode(SSL_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - - /* - * Load and verify server's certificate and private key - */ - if (SSL_CTX_use_certificate_chain_file(SSL_context, - ssl_cert_file) != 1) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("could not load server certificate file \"%s\": %s", - ssl_cert_file, SSLerrmessage()))); - - if (stat(ssl_key_file, &buf) != 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not access private key file \"%s\": %m", - ssl_key_file))); - - /* - * Require no public access to key file. - * - * XXX temporarily suppress check when on Windows, because there may - * not be proper support for Unix-y file permissions. Need to think - * of a reasonable check to apply on Windows. (See also the data - * directory permission check in postmaster.c) - */ -#if !defined(WIN32) && !defined(__CYGWIN__) - if (!S_ISREG(buf.st_mode) || buf.st_mode & (S_IRWXG | S_IRWXO)) - ereport(FATAL, - (errcode(ERRCODE_CONFIG_FILE_ERROR), - errmsg("private key file \"%s\" has group or world access", - ssl_key_file), - errdetail("Permissions should be u=rw (0600) or less."))); #endif - - if (SSL_CTX_use_PrivateKey_file(SSL_context, - ssl_key_file, - SSL_FILETYPE_PEM) != 1) - ereport(FATAL, - (errmsg("could not load private key file \"%s\": %s", - ssl_key_file, SSLerrmessage()))); - - if (SSL_CTX_check_private_key(SSL_context) != 1) - ereport(FATAL, - (errmsg("check of private key failed: %s", - SSLerrmessage()))); - } - - /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */ - SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb); - SSL_CTX_set_options(SSL_context, - SSL_OP_SINGLE_DH_USE | - SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); - - /* set up ephemeral ECDH keys */ - initialize_ecdh(); - - /* set up the allowed cipher list */ - if (SSL_CTX_set_cipher_list(SSL_context, SSLCipherSuites) != 1) - elog(FATAL, "could not set the cipher list (no valid ciphers available)"); - - /* Let server choose order */ - if (SSLPreferServerCiphers) - SSL_CTX_set_options(SSL_context, SSL_OP_CIPHER_SERVER_PREFERENCE); - - /* - * Load CA store, so we can verify client certificates if needed. - */ - if (ssl_ca_file[0]) - { - if (SSL_CTX_load_verify_locations(SSL_context, ssl_ca_file, NULL) != 1 || - (root_cert_list = SSL_load_client_CA_file(ssl_ca_file)) == NULL) - ereport(FATAL, - (errmsg("could not load root certificate file \"%s\": %s", - ssl_ca_file, SSLerrmessage()))); - } - - /*---------- - * Load the Certificate Revocation List (CRL). - * http://searchsecurity.techtarget.com/sDefinition/0,,sid14_gci803160,00.html - *---------- - */ - if (ssl_crl_file[0]) - { - X509_STORE *cvstore = SSL_CTX_get_cert_store(SSL_context); - - if (cvstore) - { - /* Set the flags to check against the complete CRL chain */ - if (X509_STORE_load_locations(cvstore, ssl_crl_file, NULL) == 1) - { - /* OpenSSL 0.96 does not support X509_V_FLAG_CRL_CHECK */ -#ifdef X509_V_FLAG_CRL_CHECK - X509_STORE_set_flags(cvstore, - X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); -#else - ereport(LOG, - (errmsg("SSL certificate revocation list file \"%s\" ignored", - ssl_crl_file), - errdetail("SSL library does not support certificate revocation lists."))); -#endif - } - else - ereport(FATAL, - (errmsg("could not load SSL certificate revocation list file \"%s\": %s", - ssl_crl_file, SSLerrmessage()))); - } - } - - if (ssl_ca_file[0]) - { - /* - * Always ask for SSL client cert, but don't fail if it's not - * presented. We might fail such connections later, depending on what - * we find in pg_hba.conf. - */ - SSL_CTX_set_verify(SSL_context, - (SSL_VERIFY_PEER | - SSL_VERIFY_CLIENT_ONCE), - verify_cb); - - /* Set flag to remember CA store is successfully loaded */ - ssl_loaded_verify_locations = true; - - /* - * Tell OpenSSL to send the list of root certs we trust to clients in - * CertificateRequests. This lets a client with a keystore select the - * appropriate client certificate to send to us. - */ - SSL_CTX_set_client_CA_list(SSL_context, root_cert_list); - } -} - -/* - * Attempt to negotiate SSL connection. - */ -int -be_tls_open_server(Port *port) -{ - int r; - int err; - - Assert(!port->ssl); - Assert(!port->peer); - - if (!(port->ssl = SSL_new(SSL_context))) - { - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not initialize SSL connection: %s", - SSLerrmessage()))); - be_tls_close(port); - return -1; - } - if (!my_SSL_set_fd(port, port->sock)) - { - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not set SSL socket: %s", - SSLerrmessage()))); - be_tls_close(port); - return -1; - } - port->ssl_in_use = true; - -aloop: - r = SSL_accept(port->ssl); - if (r <= 0) - { - err = SSL_get_error(port->ssl, r); - switch (err) - { - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: -#ifdef WIN32 - pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), - (err == SSL_ERROR_WANT_READ) ? - FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE, - INFINITE); -#endif - goto aloop; - case SSL_ERROR_SYSCALL: - if (r < 0) - ereport(COMMERROR, - (errcode_for_socket_access(), - errmsg("could not accept SSL connection: %m"))); - else - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not accept SSL connection: EOF detected"))); - break; - case SSL_ERROR_SSL: - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not accept SSL connection: %s", - SSLerrmessage()))); - break; - case SSL_ERROR_ZERO_RETURN: - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("could not accept SSL connection: EOF detected"))); - break; - default: - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("unrecognized SSL error code: %d", - err))); - break; - } - be_tls_close(port); - return -1; - } - - port->count = 0; - - /* Get client certificate, if available. */ - port->peer = SSL_get_peer_certificate(port->ssl); - - /* and extract the Common Name from it. */ - port->peer_cn = NULL; - port->peer_cert_valid = false; - if (port->peer != NULL) - { - int len; - - len = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), - NID_commonName, NULL, 0); - if (len != -1) - { - char *peer_cn; - - peer_cn = MemoryContextAlloc(TopMemoryContext, len + 1); - r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), - NID_commonName, peer_cn, len + 1); - peer_cn[len] = '\0'; - if (r != len) - { - /* shouldn't happen */ - pfree(peer_cn); - be_tls_close(port); - return -1; - } - - /* - * Reject embedded NULLs in certificate common name to prevent - * attacks like CVE-2009-4034. - */ - if (len != strlen(peer_cn)) - { - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("SSL certificate's common name contains embedded null"))); - pfree(peer_cn); - be_tls_close(port); - return -1; - } - - port->peer_cn = peer_cn; - } - port->peer_cert_valid = true; - } - - ereport(DEBUG2, - (errmsg("SSL connection from \"%s\"", - port->peer_cn ? port->peer_cn : "(anonymous)"))); - - /* set up debugging/info callback */ - SSL_CTX_set_info_callback(SSL_context, info_cb); - - return 0; -} - -/* - * Close SSL connection. - */ -void -be_tls_close(Port *port) -{ - if (port->ssl) - { - SSL_shutdown(port->ssl); - SSL_free(port->ssl); - port->ssl = NULL; - port->ssl_in_use = false; - } - - if (port->peer) - { - X509_free(port->peer); - port->peer = NULL; - } - - if (port->peer_cn) - { - pfree(port->peer_cn); - port->peer_cn = NULL; - } -} - -ssize_t -be_tls_read(Port *port, void *ptr, size_t len) -{ - ssize_t n; - int err; - -rloop: - errno = 0; - n = SSL_read(port->ssl, ptr, len); - err = SSL_get_error(port->ssl, n); - switch (err) - { - case SSL_ERROR_NONE: - port->count += n; - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - if (port->noblock) - { - errno = EWOULDBLOCK; - n = -1; - break; - } -#ifdef WIN32 - pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl), - (err == SSL_ERROR_WANT_READ) ? - FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE, - INFINITE); -#endif - goto rloop; - case SSL_ERROR_SYSCALL: - /* leave it to caller to ereport the value of errno */ - if (n != -1) - { - errno = ECONNRESET; - n = -1; - } - break; - case SSL_ERROR_SSL: - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("SSL error: %s", SSLerrmessage()))); - /* fall through */ - case SSL_ERROR_ZERO_RETURN: - errno = ECONNRESET; - n = -1; - break; - default: - ereport(COMMERROR, - (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("unrecognized SSL error code: %d", - err))); - errno = ECONNRESET; - n = -1; - break; - } - - return n; } /* |