/* * Attempt to negotiate SSL connection. */ static int open_server_SSL(Port *port) { Assert(!port->ssl); Assert(!port->peer); if (!(port->ssl = SSL_new(SSL_context)) || !my_SSL_set_fd(port->ssl, port->sock) || SSL_accept(port->ssl) <= 0) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not initialize SSL connection: %s", SSLerrmessage()))); close_SSL(port); return -1; } port->count = 0; /* get client certificate, if available. */ port->peer = SSL_get_peer_certificate(port->ssl); if (port->peer == NULL) { strncpy(port->peer_dn, "(anonymous)", sizeof(port->peer_dn)); strncpy(port->peer_cn, "(anonymous)", sizeof(port->peer_cn)); } else { X509_NAME_oneline(X509_get_subject_name(port->peer), port->peer_dn, sizeof(port->peer_dn)); port->peer_dn[sizeof(port->peer_dn) - 1] = '\0'; X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, port->peer_cn, sizeof(port->peer_cn)); port->peer_cn[sizeof(port->peer_cn) - 1] = '\0'; } ereport(DEBUG2, (errmsg("SSL connection from \"%s\"", port->peer_cn))); /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); return 0; }
/* * Attempt to negotiate SSL connection. */ static int open_server_SSL(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()))); close_SSL(port); return -1; } if (!my_SSL_set_fd(port->ssl, port->sock)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not set SSL socket: %s", SSLerrmessage()))); close_SSL(port); return -1; } 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; } close_SSL(port); return -1; } port->count = 0; /* get client certificate, if available. */ port->peer = SSL_get_peer_certificate(port->ssl); if (port->peer == NULL) { strlcpy(port->peer_dn, "(anonymous)", sizeof(port->peer_dn)); strlcpy(port->peer_cn, "(anonymous)", sizeof(port->peer_cn)); } else { X509_NAME_oneline(X509_get_subject_name(port->peer), port->peer_dn, sizeof(port->peer_dn)); port->peer_dn[sizeof(port->peer_dn) - 1] = '\0'; r = X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer), NID_commonName, port->peer_cn, sizeof(port->peer_cn)); port->peer_cn[sizeof(port->peer_cn) - 1] = '\0'; if (r == -1) { /* Unable to get the CN, set it to blank so it can't be used */ port->peer_cn[0] = '\0'; } else { /* * Reject embedded NULLs in certificate common name to prevent * attacks like CVE-2009-4034. */ if (r != strlen(port->peer_cn)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("SSL certificate's common name contains embedded null"))); close_SSL(port); return -1; } } } ereport(DEBUG2, (errmsg("SSL connection from \"%s\"", port->peer_cn))); /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); return 0; }
/* * Attempt to negotiate SSL connection. */ static int open_server_SSL(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()))); close_SSL(port); return -1; } if (!my_SSL_set_fd(port->ssl, port->sock)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not set SSL socket: %s", SSLerrmessage()))); close_SSL(port); return -1; } 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; } close_SSL(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; 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); close_SSL(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); close_SSL(port); return -1; } port->peer_cn = peer_cn; } } 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; }
int be_tls_open_server(Port *port) { int r; int err; int waitfor; unsigned long ecode; Assert(!port->ssl); Assert(!port->peer); if (!SSL_context) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not initialize SSL connection: SSL context not set up"))); return -1; } if (!(port->ssl = SSL_new(SSL_context))) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not initialize SSL connection: %s", SSLerrmessage(ERR_get_error())))); return -1; } if (!my_SSL_set_fd(port, port->sock)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("could not set SSL socket: %s", SSLerrmessage(ERR_get_error())))); return -1; } port->ssl_in_use = true; aloop: /* * Prepare to call SSL_get_error() by clearing thread's OpenSSL error * queue. In general, the current thread's error queue must be empty * before the TLS/SSL I/O operation is attempted, or SSL_get_error() will * not work reliably. An extension may have failed to clear the * per-thread error queue following another call to an OpenSSL I/O * routine. */ ERR_clear_error(); r = SSL_accept(port->ssl); if (r <= 0) { err = SSL_get_error(port->ssl, r); /* * Other clients of OpenSSL in the backend may fail to call * ERR_get_error(), but we always do, so as to not cause problems for * OpenSSL clients that don't call ERR_clear_error() defensively. Be * sure that this happens by calling now. SSL_get_error() relies on * the OpenSSL per-thread error queue being intact, so this is the * earliest possible point ERR_get_error() may be called. */ ecode = ERR_get_error(); switch (err) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* not allowed during connection establishment */ Assert(!port->noblock); /* * No need to care about timeouts/interrupts here. At this * point authentication_timeout still employs * StartupPacketTimeoutHandler() which directly exits. */ if (err == SSL_ERROR_WANT_READ) waitfor = WL_SOCKET_READABLE | WL_EXIT_ON_PM_DEATH; else waitfor = WL_SOCKET_WRITEABLE | WL_EXIT_ON_PM_DEATH; (void) WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0, WAIT_EVENT_SSL_OPEN_SERVER); 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(ecode)))); 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; } return -1; } /* 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); 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); return -1; } port->peer_cn = peer_cn; } port->peer_cert_valid = true; } /* set up debugging/info callback */ SSL_CTX_set_info_callback(SSL_context, info_cb); return 0; }
/* * Attempt to negotiate SSL connection. */ int be_tls_open_server(Port *port) { int r; int err; int waitfor; 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: /* not allowed during connection establishment */ Assert(!port->noblock); /* * No need to care about timeouts/interrupts here. At this * point authentication_timeout still employs * StartupPacketTimeoutHandler() which directly exits. */ if (err == SSL_ERROR_WANT_READ) waitfor = WL_SOCKET_READABLE; else waitfor = WL_SOCKET_WRITEABLE; WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0); 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; }