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 intmy_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)
316285gotoerror ;
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 */
321289SSL_CTX_set_options (context ,
322290SSL_OP_SINGLE_DH_USE |
323291SSL_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+ gotoerror ;
326296if (!initialize_ecdh (context ,isServerStart ))
327297gotoerror ;
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{
923893FILE * fp ;
924- char fnbuf [MAXPGPATH ];
925894DH * dh = NULL ;
926895int 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 )));
931904return NULL ;
905+ }
932906
933- /*flock(fileno(fp), LOCK_SH); */
934907dh = 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
970944return dh ;
@@ -995,102 +969,6 @@ load_dh_buffer(const char *buffer, size_t len)
995969return 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{