6161#include "libpq/libpq.h"
6262#include "miscadmin.h"
6363#include "pgstat.h"
64+ #include "storage/fd.h"
6465#include "storage/latch.h"
6566#include "tcop/tcopprot.h"
6667#include "utils/memutils.h"
@@ -71,13 +72,12 @@ static int my_sock_write(BIO *h, const char *buf, int size);
7172static BIO_METHOD * my_BIO_s_socket (void );
7273static int my_SSL_set_fd (Port * port , int fd );
7374
74- static DH * load_dh_file (int keylength );
75+ static DH * load_dh_file (char * filename , bool isServerStart );
7576static DH * load_dh_buffer (const char * , size_t );
76- static DH * generate_dh_parameters (int prime_len , int generator );
77- static DH * tmp_dh_cb (SSL * s , int is_export , int keylength );
7877static int ssl_passwd_cb (char * buf , int size , int rwflag , void * userdata );
7978static int verify_cb (int , X509_STORE_CTX * );
8079static void info_cb (const SSL * ssl , int type , int args );
80+ static bool initialize_dh (SSL_CTX * context , bool isServerStart );
8181static bool initialize_ecdh (SSL_CTX * context , bool isServerStart );
8282static const char * SSLerrmessage (unsigned long ecode );
8383
@@ -96,37 +96,21 @@ static bool ssl_passwd_cb_called = false;
9696 * As discussed above, EDH protects the confidentiality of
9797 * sessions even if the static private key is compromised,
9898 * so we are *highly* motivated to ensure that we can use
99- * EDH even if the DBA... or an attacker... deletes the
100- * $DataDir/dh*.pem files.
99+ * EDH even if the DBA has not provided custom DH parameters.
101100 *
102101 * We could refuse SSL connections unless a good DH parameter
103102 * file exists, but some clients may quietly renegotiate an
104103 * unsecured connection without fully informing the user.
105- * Very uncool.
106- *
107- * Alternatively, the backend could attempt to load these files
108- * on startup if SSL is enabled - and refuse to start if any
109- * do not exist - but this would tend to piss off DBAs.
104+ * Very uncool. Alternatively, the system could refuse to start
105+ * if a DH parameters is not specified, but this would tend to
106+ * piss off DBAs.
110107 *
111108 * If you want to create your own hardcoded DH parameters
112109 * for fun and profit, review "Assigned Number for SKIP
113110 * Protocols" (http://www.skip-vpn.org/spec/numbers.html)
114111 * for suggestions.
115112 */
116113
117- static const char file_dh512 [] =
118- "-----BEGIN DH PARAMETERS-----\n\
119- MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\
120- XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\
121- -----END DH PARAMETERS-----\n" ;
122-
123- static const char file_dh1024 [] =
124- "-----BEGIN DH PARAMETERS-----\n\
125- MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\
126- jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\
127- ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\
128- -----END DH PARAMETERS-----\n" ;
129-
130114static const char file_dh2048 [] =
131115"-----BEGIN DH PARAMETERS-----\n\
132116MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\
@@ -137,21 +121,6 @@ Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\
137121CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\
138122-----END DH PARAMETERS-----\n" ;
139123
140- static const char file_dh4096 [] =
141- "-----BEGIN DH PARAMETERS-----\n\
142- MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\
143- l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\
144- Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\
145- Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\
146- VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\
147- alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\
148- sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\
149- ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\
150- OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\
151- AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\
152- KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\
153- -----END DH PARAMETERS-----\n" ;
154-
155124
156125/* ------------------------------------------------------------ */
157126/* Public interface */
@@ -316,13 +285,14 @@ be_tls_init(bool isServerStart)
316285 goto error ;
317286 }
318287
319- /* set up ephemeral DH keys, and disallow SSL v2/v3 while at it */
320- SSL_CTX_set_tmp_dh_callback (context , tmp_dh_cb );
288+ /* disallow SSL v2/v3 */
321289 SSL_CTX_set_options (context ,
322290 SSL_OP_SINGLE_DH_USE |
323291 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 );
324292
325- /* set up ephemeral ECDH keys */
293+ /* set up ephemeral DH and ECDH keys */
294+ if (!initialize_dh (context , isServerStart ))
295+ goto error ;
326296 if (!initialize_ecdh (context , isServerStart ))
327297 goto error ;
328298
@@ -918,53 +888,57 @@ my_SSL_set_fd(Port *port, int fd)
918888 * what we expect it to contain.
919889 */
920890static DH *
921- load_dh_file (int keylength )
891+ load_dh_file (char * filename , bool isServerStart )
922892{
923893 FILE * fp ;
924- char fnbuf [MAXPGPATH ];
925894 DH * dh = NULL ;
926895 int codes ;
927896
928897 /* attempt to open file. It's not an error if it doesn't exist. */
929- snprintf (fnbuf , sizeof (fnbuf ), "dh%d.pem" , keylength );
930- if ((fp = fopen (fnbuf , "r" )) == NULL )
898+ if ((fp = AllocateFile (filename , "r" )) == NULL )
899+ {
900+ ereport (isServerStart ? FATAL : LOG ,
901+ (errcode_for_file_access (),
902+ errmsg ("could not open DH parameters file \"%s\": %m" ,
903+ filename )));
931904 return NULL ;
905+ }
932906
933- /* flock(fileno(fp), LOCK_SH); */
934907 dh = PEM_read_DHparams (fp , NULL , NULL , NULL );
935- /* flock(fileno(fp), LOCK_UN); */
936- fclose (fp );
908+ FreeFile (fp );
937909
938- /* is the prime the correct size? */
939- if (dh != NULL && 8 * DH_size (dh ) < keylength )
910+ if (dh == NULL )
940911 {
941- elog (LOG , "DH errors (%s): %d bits expected, %d bits found" ,
942- fnbuf , keylength , 8 * DH_size (dh ));
943- dh = NULL ;
912+ ereport (isServerStart ? FATAL : LOG ,
913+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
914+ errmsg ("could not load DH parameters file: %s" ,
915+ SSLerrmessage (ERR_get_error ()))));
916+ return NULL ;
944917 }
945918
946919 /* make sure the DH parameters are usable */
947- if (dh != NULL )
920+ if (DH_check ( dh , & codes ) == 0 )
948921 {
949- if (DH_check (dh , & codes ) == 0 )
950- {
951- elog (LOG , "DH_check error (%s): %s" , fnbuf ,
952- SSLerrmessage (ERR_get_error ()));
953- return NULL ;
954- }
955- if (codes & DH_CHECK_P_NOT_PRIME )
956- {
957- elog (LOG , "DH error (%s): p is not prime" , fnbuf );
958- return NULL ;
959- }
960- if ((codes & DH_NOT_SUITABLE_GENERATOR ) &&
961- (codes & DH_CHECK_P_NOT_SAFE_PRIME ))
962- {
963- elog (LOG ,
964- "DH error (%s): neither suitable generator or safe prime" ,
965- fnbuf );
966- return NULL ;
967- }
922+ ereport (isServerStart ? FATAL : LOG ,
923+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
924+ errmsg ("invalid DH parameters: %s" ,
925+ SSLerrmessage (ERR_get_error ()))));
926+ return NULL ;
927+ }
928+ if (codes & DH_CHECK_P_NOT_PRIME )
929+ {
930+ ereport (isServerStart ? FATAL : LOG ,
931+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
932+ errmsg ("invalid DH parameters: p is not prime" )));
933+ return NULL ;
934+ }
935+ if ((codes & DH_NOT_SUITABLE_GENERATOR ) &&
936+ (codes & DH_CHECK_P_NOT_SAFE_PRIME ))
937+ {
938+ ereport (isServerStart ? FATAL : LOG ,
939+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
940+ errmsg ("invalid DH parameters: neither suitable generator or safe prime" )));
941+ return NULL ;
968942 }
969943
970944 return dh ;
@@ -995,102 +969,6 @@ load_dh_buffer(const char *buffer, size_t len)
995969 return dh ;
996970}
997971
998- /*
999- * Generate DH parameters.
1000- *
1001- * Last resort if we can't load precomputed nor hardcoded
1002- * parameters.
1003- */
1004- static DH *
1005- generate_dh_parameters (int prime_len , int generator )
1006- {
1007- DH * dh ;
1008-
1009- if ((dh = DH_new ()) == NULL )
1010- return NULL ;
1011-
1012- if (DH_generate_parameters_ex (dh , prime_len , generator , NULL ))
1013- return dh ;
1014-
1015- DH_free (dh );
1016- return NULL ;
1017- }
1018-
1019- /*
1020- * Generate an ephemeral DH key. Because this can take a long
1021- * time to compute, we can use precomputed parameters of the
1022- * common key sizes.
1023- *
1024- * Since few sites will bother to precompute these parameter
1025- * files, we also provide a fallback to the parameters provided
1026- * by the OpenSSL project.
1027- *
1028- * These values can be static (once loaded or computed) since
1029- * the OpenSSL library can efficiently generate random keys from
1030- * the information provided.
1031- */
1032- static DH *
1033- tmp_dh_cb (SSL * s , int is_export , int keylength )
1034- {
1035- DH * r = NULL ;
1036- static DH * dh = NULL ;
1037- static DH * dh512 = NULL ;
1038- static DH * dh1024 = NULL ;
1039- static DH * dh2048 = NULL ;
1040- static DH * dh4096 = NULL ;
1041-
1042- switch (keylength )
1043- {
1044- case 512 :
1045- if (dh512 == NULL )
1046- dh512 = load_dh_file (keylength );
1047- if (dh512 == NULL )
1048- dh512 = load_dh_buffer (file_dh512 , sizeof file_dh512 );
1049- r = dh512 ;
1050- break ;
1051-
1052- case 1024 :
1053- if (dh1024 == NULL )
1054- dh1024 = load_dh_file (keylength );
1055- if (dh1024 == NULL )
1056- dh1024 = load_dh_buffer (file_dh1024 , sizeof file_dh1024 );
1057- r = dh1024 ;
1058- break ;
1059-
1060- case 2048 :
1061- if (dh2048 == NULL )
1062- dh2048 = load_dh_file (keylength );
1063- if (dh2048 == NULL )
1064- dh2048 = load_dh_buffer (file_dh2048 , sizeof file_dh2048 );
1065- r = dh2048 ;
1066- break ;
1067-
1068- case 4096 :
1069- if (dh4096 == NULL )
1070- dh4096 = load_dh_file (keylength );
1071- if (dh4096 == NULL )
1072- dh4096 = load_dh_buffer (file_dh4096 , sizeof file_dh4096 );
1073- r = dh4096 ;
1074- break ;
1075-
1076- default :
1077- if (dh == NULL )
1078- dh = load_dh_file (keylength );
1079- r = dh ;
1080- }
1081-
1082- /* this may take a long time, but it may be necessary... */
1083- if (r == NULL || 8 * DH_size (r ) < keylength )
1084- {
1085- ereport (DEBUG2 ,
1086- (errmsg_internal ("DH: generating parameters (%d bits)" ,
1087- keylength )));
1088- r = generate_dh_parameters (keylength , DH_GENERATOR_2 );
1089- }
1090-
1091- return r ;
1092- }
1093-
1094972/*
1095973 * Passphrase collection callback
1096974 *
@@ -1172,6 +1050,54 @@ info_cb(const SSL *ssl, int type, int args)
11721050 }
11731051}
11741052
1053+ /*
1054+ * Set DH parameters for generating ephemeral DH keys. The
1055+ * DH parameters can take a long time to compute, so they must be
1056+ * precomputed.
1057+ *
1058+ * Since few sites will bother to create a parameter file, we also
1059+ * also provide a fallback to the parameters provided by the
1060+ * OpenSSL project.
1061+ *
1062+ * These values can be static (once loaded or computed) since the
1063+ * OpenSSL library can efficiently generate random keys from the
1064+ * information provided.
1065+ */
1066+ static bool
1067+ initialize_dh (SSL_CTX * context , bool isServerStart )
1068+ {
1069+ DH * dh = NULL ;
1070+
1071+ SSL_CTX_set_options (context , SSL_OP_SINGLE_DH_USE );
1072+
1073+ if (ssl_dh_params_file [0 ])
1074+ dh = load_dh_file (ssl_dh_params_file , isServerStart );
1075+ if (!dh )
1076+ dh = load_dh_buffer (file_dh2048 , sizeof file_dh2048 );
1077+ if (!dh )
1078+ {
1079+ ereport (isServerStart ? FATAL : LOG ,
1080+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
1081+ (errmsg ("DH: could not load DH parameters" ))));
1082+ return false;
1083+ }
1084+
1085+ if (SSL_CTX_set_tmp_dh (context , dh ) != 1 )
1086+ {
1087+ ereport (isServerStart ? FATAL : LOG ,
1088+ (errcode (ERRCODE_CONFIG_FILE_ERROR ),
1089+ (errmsg ("DH: could not set DH parameters: %s" ,
1090+ SSLerrmessage (ERR_get_error ())))));
1091+ return false;
1092+ }
1093+ return true;
1094+ }
1095+
1096+ /*
1097+ * Set ECDH parameters for generating ephemeral Elliptic Curve DH
1098+ * keys. This is much simpler than the DH parameters, as we just
1099+ * need to provide the name of the curve to OpenSSL.
1100+ */
11751101static bool
11761102initialize_ecdh (SSL_CTX * context , bool isServerStart )
11771103{
0 commit comments