⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 be-secure.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * be-secure.c *	  functions related to setting up a secure connection to the frontend. *	  Secure connections are expected to provide confidentiality, *	  message integrity and endpoint authentication. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/libpq/be-secure.c,v 1.59.2.2 2006/05/12 22:44:43 tgl Exp $ * *	  Since the server static private key ($DataDir/server.key) *	  will normally be stored unencrypted so that the database *	  backend can restart automatically, it is important that *	  we select an algorithm that continues to provide confidentiality *	  even if the attacker has the server's private key.  Empheral *	  DH (EDH) keys provide this, and in fact provide Perfect Forward *	  Secrecy (PFS) except for situations where the session can *	  be hijacked during a periodic handshake/renegotiation. *	  Even that backdoor can be closed if client certificates *	  are used (since the imposter will be unable to successfully *	  complete renegotiation). * *	  N.B., the static private key should still be protected to *	  the largest extent possible, to minimize the risk of *	  impersonations. * *	  Another benefit of EDH is that it allows the backend and *	  clients to use DSA keys.	DSA keys can only provide digital *	  signatures, not encryption, and are often acceptable in *	  jurisdictions where RSA keys are unacceptable. * *	  The downside to EDH is that it makes it impossible to *	  use ssldump(1) if there's a problem establishing an SSL *	  session.	In this case you'll need to temporarily disable *	  EDH by commenting out the callback. * *	  ... * *	  Because the risk of cryptanalysis increases as large *	  amounts of data are sent with the same session key, the *	  session keys are periodically renegotiated. * * PATCH LEVEL *	  milestone 1: fix basic coding errors *	  [*] existing SSL code pulled out of existing files. *	  [*] SSL_get_error() after SSL_read() and SSL_write(), *		  SSL_shutdown(), default to TLSv1. * *	  milestone 2: provide endpoint authentication (server) *	  [*] client verifies server cert *	  [*] client verifies server hostname * *	  milestone 3: improve confidentially, support perfect forward secrecy *	  [ ] use 'random' file, read from '/dev/urandom?' *	  [*] emphermal DH keys, default values *	  [*] periodic renegotiation *	  [*] private key permissions * *	  milestone 4: provide endpoint authentication (client) *	  [*] server verifies client certificates * *	  milestone 5: provide informational callbacks *	  [*] provide informational callbacks * *	  other changes *	  [ ] tcp-wrappers *	  [ ] more informative psql * *------------------------------------------------------------------------- */#include "postgres.h"#include <sys/stat.h>#include <signal.h>#include <fcntl.h>#include <ctype.h>#include <sys/socket.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#include <arpa/inet.h>#endif#ifdef USE_SSL#include <openssl/ssl.h>#include <openssl/dh.h>#endif#include "libpq/libpq.h"#include "miscadmin.h"#include "tcop/tcopprot.h"#ifdef USE_SSL#define ROOT_CERT_FILE			"root.crt"#define SERVER_CERT_FILE		"server.crt"#define SERVER_PRIVATE_KEY_FILE "server.key"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 int	initialize_SSL(void);static void destroy_SSL(void);static int	open_server_SSL(Port *);static void close_SSL(Port *);static const char *SSLerrmessage(void);#endif#ifdef USE_SSL/* *	How much data can be sent across a secure connection *	(total in both directions) before we require renegotiation. */#define RENEGOTIATION_LIMIT (512 * 1024 * 1024)static SSL_CTX *SSL_context = NULL;#endif/* ------------------------------------------------------------ *//*						 Hardcoded values						*//* ------------------------------------------------------------ *//* *	Hardcoded DH parameters, used in empheral DH keying. *	As discussed above, EDH protects the confidentiality of *	sessions even if the static private key is compromised, *	so we are *highly* motivated to ensure that we can use *	EDH even if the DBA... or an attacker... deletes the *	$DataDir/dh*.pem files. * *	We could refuse SSL connections unless a good DH parameter *	file exists, but some clients may quietly renegotiate an *	unsecured connection without fully informing the user. *	Very uncool. * *	Alternately, the backend could attempt to load these files *	on startup if SSL is enabled - and refuse to start if any *	do not exist - but this would tend to piss off DBAs. * *	If you want to create your own hardcoded DH parameters *	for fun and profit, review "Assigned Number for SKIP *	Protocols" (http://www.skip-vpn.org/spec/numbers.html) *	for suggestions. */#ifdef USE_SSLstatic const char file_dh512[] ="-----BEGIN DH PARAMETERS-----\n\MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\-----END DH PARAMETERS-----\n";static const char file_dh1024[] ="-----BEGIN DH PARAMETERS-----\n\MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\-----END DH PARAMETERS-----\n";static const char file_dh2048[] ="-----BEGIN DH PARAMETERS-----\n\MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\-----END DH PARAMETERS-----\n";static const char file_dh4096[] ="-----BEGIN DH PARAMETERS-----\n\MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\-----END DH PARAMETERS-----\n";#endif/* ------------------------------------------------------------ *//*			 Procedures common to all secure sessions			*//* ------------------------------------------------------------ *//* *	Initialize global context */intsecure_initialize(void){	int			r = 0;#ifdef USE_SSL	r = initialize_SSL();#endif	return r;}/* *	Destroy global context */voidsecure_destroy(void){#ifdef USE_SSL	destroy_SSL();#endif}/* *	Attempt to negotiate secure session. */intsecure_open_server(Port *port){	int			r = 0;#ifdef USE_SSL	r = open_server_SSL(port);#endif	return r;}/* *	Close secure session. */voidsecure_close(Port *port){#ifdef USE_SSL	if (port->ssl)		close_SSL(port);#endif}/* *	Read data from a secure connection. */ssize_tsecure_read(Port *port, void *ptr, size_t len){	ssize_t		n;#ifdef USE_SSL	if (port->ssl)	{		int			err;rloop:		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:#ifdef WIN32				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),											(err == SSL_ERROR_WANT_READ) ?								   FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE);#endif				goto rloop;			case SSL_ERROR_SYSCALL:				if (n == -1)					ereport(COMMERROR,							(errcode_for_socket_access(),							 errmsg("SSL SYSCALL error: %m")));				else				{					ereport(COMMERROR,							(errcode(ERRCODE_PROTOCOL_VIOLATION),							 errmsg("SSL SYSCALL error: EOF detected")));					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)));				n = -1;				break;		}	}	else#endif	{		prepare_for_client_read();		n = recv(port->sock, ptr, len, 0);		client_read_ended();	}	return n;}/* *	Write data to a secure connection. */ssize_tsecure_write(Port *port, void *ptr, size_t len){	ssize_t		n;#ifdef USE_SSL	if (port->ssl)	{		int			err;		if (port->count > RENEGOTIATION_LIMIT)		{			SSL_set_session_id_context(port->ssl, (void *) &SSL_context,									   sizeof(SSL_context));			if (SSL_renegotiate(port->ssl) <= 0)				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("SSL renegotiation failure")));			if (SSL_do_handshake(port->ssl) <= 0)				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("SSL renegotiation failure")));			if (port->ssl->state != SSL_ST_OK)				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("SSL failed to send renegotiation request")));			port->ssl->state |= SSL_ST_ACCEPT;			SSL_do_handshake(port->ssl);			if (port->ssl->state != SSL_ST_OK)				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("SSL renegotiation failure")));			port->count = 0;		}wloop:		n = SSL_write(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:#ifdef WIN32				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),											(err == SSL_ERROR_WANT_READ) ?								   FD_READ | FD_CLOSE : FD_WRITE | FD_CLOSE);#endif				goto wloop;			case SSL_ERROR_SYSCALL:				if (n == -1)					ereport(COMMERROR,							(errcode_for_socket_access(),							 errmsg("SSL SYSCALL error: %m")));				else				{					ereport(COMMERROR,							(errcode(ERRCODE_PROTOCOL_VIOLATION),							 errmsg("SSL SYSCALL error: EOF detected")));					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)));				n = -1;				break;		}	}	else#endif		n = send(port->sock, ptr, len, 0);	return n;}/* ------------------------------------------------------------ *//*						  SSL specific code						*//* ------------------------------------------------------------ */#ifdef USE_SSL/* * Private substitute BIO: this wraps the SSL library's standard socket BIO * so that we can enable and disable interrupts just while calling recv(). * We cannot have interrupts occurring while the bulk of openssl runs, * because it uses malloc() and possibly other non-reentrant libc facilities. * * As of openssl 0.9.7, we can use the reasonably clean method of interposing * a wrapper around the standard socket BIO's sock_read() method.  This relies * on the fact that sock_read() doesn't call anything non-reentrant, in fact * not much of anything at all except recv().  If this ever changes we'd * probably need to duplicate the code of sock_read() in order to push the * interrupt enable/disable down yet another level. */static bool my_bio_initialized = false;static BIO_METHOD my_bio_methods;static int	(*std_sock_read) (BIO *h, char *buf, int size);static intmy_sock_read(BIO *h, char *buf, int size){	int			res;	prepare_for_client_read();	res = std_sock_read(h, buf, size);	client_read_ended();	return res;}static BIO_METHOD *my_BIO_s_socket(void){	if (!my_bio_initialized)	{		memcpy(&my_bio_methods, BIO_s_socket(), sizeof(BIO_METHOD));		std_sock_read = my_bio_methods.bread;		my_bio_methods.bread = my_sock_read;		my_bio_initialized = true;	}	return &my_bio_methods;}/* This should exactly match openssl's SSL_set_fd except for using my BIO */static intmy_SSL_set_fd(SSL *s, int fd){	int			ret = 0;	BIO		   *bio = NULL;	bio = BIO_new(my_BIO_s_socket());	if (bio == NULL)	{		SSLerr(SSL_F_SSL_SET_FD, ERR_R_BUF_LIB);		goto err;	}	BIO_set_fd(bio, fd, BIO_NOCLOSE);	SSL_set_bio(s, bio, bio);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -