@ -61,6 +61,7 @@
# include "libpq/libpq.h"
# include "miscadmin.h"
# include "pgstat.h"
# include "storage/fd.h"
# include "storage/latch.h"
# include "tcop/tcopprot.h"
# include "utils/memutils.h"
@ -71,13 +72,12 @@ 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_file ( char * filename , bool isServerStart ) ;
static DH * load_dh_buffer ( const char * , size_t ) ;
static DH * generate_dh_parameters ( int prime_len , int generator ) ;
static DH * tmp_dh_cb ( SSL * s , int is_export , int keylength ) ;
static int ssl_passwd_cb ( char * buf , int size , int rwflag , void * userdata ) ;
static int verify_cb ( int , X509_STORE_CTX * ) ;
static void info_cb ( const SSL * ssl , int type , int args ) ;
static bool initialize_dh ( SSL_CTX * context , bool isServerStart ) ;
static bool initialize_ecdh ( SSL_CTX * context , bool isServerStart ) ;
static const char * SSLerrmessage ( unsigned long ecode ) ;
@ -96,17 +96,14 @@ static bool ssl_passwd_cb_called = false;
* 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 .
* EDH even if the DBA has not provided custom DH parameters .
*
* 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 .
*
* Alternatively , 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 .
* Very uncool . Alternatively , the system could refuse to start
* if a DH parameters is not specified , 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
@ -114,19 +111,6 @@ static bool ssl_passwd_cb_called = false;
* for suggestions .
*/
static 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 \
@ -137,21 +121,6 @@ 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 / 1 wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH \ n \
AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL \ n \
KWbuHn491xNO25CQWMtem80uKw + pTnisBRF / 454 n1Jnhub144YRBoN8CAQI = \ n \
- - - - - END DH PARAMETERS - - - - - \ n " ;
/* ------------------------------------------------------------ */
/* Public interface */
@ -316,13 +285,14 @@ be_tls_init(bool isServerStart)
goto error ;
}
/* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
SSL_CTX_set_tmp_dh_callback ( context , tmp_dh_cb ) ;
/* disallow SSL v2/v3 */
SSL_CTX_set_options ( context ,
SSL_OP_SINGLE_DH_USE |
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 ) ;
/* set up ephemeral ECDH keys */
/* set up ephemeral DH and ECDH keys */
if ( ! initialize_dh ( context , isServerStart ) )
goto error ;
if ( ! initialize_ecdh ( context , isServerStart ) )
goto error ;
@ -918,53 +888,57 @@ err:
* what we expect it to contain .
*/
static DH *
load_dh_file ( int keylength )
load_dh_file ( char * filename , bool isServerStart )
{
FILE * fp ;
char fnbuf [ MAXPGPATH ] ;
DH * dh = NULL ;
int codes ;
/* attempt to open file. It's not an error if it doesn't exist. */
snprintf ( fnbuf , sizeof ( fnbuf ) , " dh%d.pem " , keylength ) ;
if ( ( fp = fopen ( fnbuf , " r " ) ) = = NULL )
if ( ( fp = AllocateFile ( filename , " r " ) ) = = NULL )
{
ereport ( isServerStart ? FATAL : LOG ,
( errcode_for_file_access ( ) ,
errmsg ( " could not open DH parameters file \" %s \" : %m " ,
filename ) ) ) ;
return NULL ;
}
/* flock(fileno(fp), LOCK_SH); */
dh = PEM_read_DHparams ( fp , NULL , NULL , NULL ) ;
/* flock(fileno(fp), LOCK_UN); */
fclose ( fp ) ;
FreeFile ( fp ) ;
/* is the prime the correct size? */
if ( dh ! = NULL & & 8 * DH_size ( dh ) < keylength )
if ( dh = = NULL )
{
elog ( LOG , " DH errors (%s): %d bits expected, %d bits found " ,
fnbuf , keylength , 8 * DH_size ( dh ) ) ;
dh = NULL ;
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
errmsg ( " could not load DH parameters file: %s " ,
SSLerrmessage ( ERR_get_error ( ) ) ) ) ) ;
return NULL ;
}
/* make sure the DH parameters are usable */
if ( dh ! = NULL )
if ( DH_check ( dh , & codes ) = = 0 )
{
if ( DH_check ( dh , & codes ) = = 0 )
{
elog ( LOG , " DH_check error (%s): %s " , fnbuf ,
SSLerrmessage ( ERR_get_error ( ) ) ) ;
return NULL ;
}
if ( codes & DH_CHECK_P_NOT_PRIME )
{
elog ( LOG , " DH error (%s): p is not prime " , fnbuf ) ;
return NULL ;
}
if ( ( codes & DH_NOT_SUITABLE_GENERATOR ) & &
( codes & DH_CHECK_P_NOT_SAFE_PRIME ) )
{
elog ( LOG ,
" DH error (%s): neither suitable generator or safe prime " ,
fnbuf ) ;
return NULL ;
}
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
errmsg ( " invalid DH parameters: %s " ,
SSLerrmessage ( ERR_get_error ( ) ) ) ) ) ;
return NULL ;
}
if ( codes & DH_CHECK_P_NOT_PRIME )
{
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
errmsg ( " invalid DH parameters: p is not prime " ) ) ) ;
return NULL ;
}
if ( ( codes & DH_NOT_SUITABLE_GENERATOR ) & &
( codes & DH_CHECK_P_NOT_SAFE_PRIME ) )
{
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
errmsg ( " invalid DH parameters: neither suitable generator or safe prime " ) ) ) ;
return NULL ;
}
return dh ;
@ -995,102 +969,6 @@ load_dh_buffer(const char *buffer, size_t len)
return dh ;
}
/*
* Generate DH parameters .
*
* Last resort if we can ' t load precomputed nor hardcoded
* parameters .
*/
static DH *
generate_dh_parameters ( int prime_len , int generator )
{
DH * dh ;
if ( ( dh = DH_new ( ) ) = = NULL )
return NULL ;
if ( DH_generate_parameters_ex ( dh , prime_len , generator , NULL ) )
return dh ;
DH_free ( dh ) ;
return NULL ;
}
/*
* Generate an ephemeral DH key . Because this can take a long
* time to compute , we can use precomputed parameters of the
* common key sizes .
*
* Since few sites will bother to precompute these parameter
* files , we also provide a fallback to the parameters provided
* by the OpenSSL project .
*
* These values can be static ( once loaded or computed ) since
* the OpenSSL library can efficiently generate random keys from
* the information provided .
*/
static DH *
tmp_dh_cb ( SSL * s , int is_export , int keylength )
{
DH * r = NULL ;
static DH * dh = NULL ;
static DH * dh512 = NULL ;
static DH * dh1024 = NULL ;
static DH * dh2048 = NULL ;
static DH * dh4096 = NULL ;
switch ( keylength )
{
case 512 :
if ( dh512 = = NULL )
dh512 = load_dh_file ( keylength ) ;
if ( dh512 = = NULL )
dh512 = load_dh_buffer ( file_dh512 , sizeof file_dh512 ) ;
r = dh512 ;
break ;
case 1024 :
if ( dh1024 = = NULL )
dh1024 = load_dh_file ( keylength ) ;
if ( dh1024 = = NULL )
dh1024 = load_dh_buffer ( file_dh1024 , sizeof file_dh1024 ) ;
r = dh1024 ;
break ;
case 2048 :
if ( dh2048 = = NULL )
dh2048 = load_dh_file ( keylength ) ;
if ( dh2048 = = NULL )
dh2048 = load_dh_buffer ( file_dh2048 , sizeof file_dh2048 ) ;
r = dh2048 ;
break ;
case 4096 :
if ( dh4096 = = NULL )
dh4096 = load_dh_file ( keylength ) ;
if ( dh4096 = = NULL )
dh4096 = load_dh_buffer ( file_dh4096 , sizeof file_dh4096 ) ;
r = dh4096 ;
break ;
default :
if ( dh = = NULL )
dh = load_dh_file ( keylength ) ;
r = dh ;
}
/* this may take a long time, but it may be necessary... */
if ( r = = NULL | | 8 * DH_size ( r ) < keylength )
{
ereport ( DEBUG2 ,
( errmsg_internal ( " DH: generating parameters (%d bits) " ,
keylength ) ) ) ;
r = generate_dh_parameters ( keylength , DH_GENERATOR_2 ) ;
}
return r ;
}
/*
* Passphrase collection callback
*
@ -1172,6 +1050,54 @@ info_cb(const SSL *ssl, int type, int args)
}
}
/*
* Set DH parameters for generating ephemeral DH keys . The
* DH parameters can take a long time to compute , so they must be
* precomputed .
*
* Since few sites will bother to create a parameter file , we also
* also provide a fallback to the parameters provided by the
* OpenSSL project .
*
* These values can be static ( once loaded or computed ) since the
* OpenSSL library can efficiently generate random keys from the
* information provided .
*/
static bool
initialize_dh ( SSL_CTX * context , bool isServerStart )
{
DH * dh = NULL ;
SSL_CTX_set_options ( context , SSL_OP_SINGLE_DH_USE ) ;
if ( ssl_dh_params_file [ 0 ] )
dh = load_dh_file ( ssl_dh_params_file , isServerStart ) ;
if ( ! dh )
dh = load_dh_buffer ( file_dh2048 , sizeof file_dh2048 ) ;
if ( ! dh )
{
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
( errmsg ( " DH: could not load DH parameters " ) ) ) ) ;
return false ;
}
if ( SSL_CTX_set_tmp_dh ( context , dh ) ! = 1 )
{
ereport ( isServerStart ? FATAL : LOG ,
( errcode ( ERRCODE_CONFIG_FILE_ERROR ) ,
( errmsg ( " DH: could not set DH parameters: %s " ,
SSLerrmessage ( ERR_get_error ( ) ) ) ) ) ) ;
return false ;
}
return true ;
}
/*
* Set ECDH parameters for generating ephemeral Elliptic Curve DH
* keys . This is much simpler than the DH parameters , as we just
* need to provide the name of the curve to OpenSSL .
*/
static bool
initialize_ecdh ( SSL_CTX * context , bool isServerStart )
{