1111 *
1212 *
1313 * IDENTIFICATION
14- * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.94 2007/02/16 17:07:00 tgl Exp $
14+ * $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.95 2007/10/01 20:30:06 mha Exp $
1515 *
1616 * NOTES
1717 * [ Most of these notes are wrong/obsolete, but perhaps not all ]
111111
112112#ifdef USE_SSL
113113#include <openssl/ssl.h>
114+ #include <openssl/bio.h>
114115#if (SSLEAY_VERSION_NUMBER >=0x00907000L )
115116#include <openssl/conf.h>
116117#endif
@@ -567,6 +568,10 @@ verify_peer(PGconn *conn)
567568 *This callback is only called when the server wants a
568569 *client cert.
569570 *
571+ *Since BIO functions can set OpenSSL error codes, we must
572+ *reset the OpenSSL error stack on *every* exit from this
573+ *function once we've started using BIO.
574+ *
570575 *Must return 1 on success, 0 on no data or error.
571576 */
572577static int
@@ -579,8 +584,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
579584struct stat buf2 ;
580585#endif
581586char fnbuf [MAXPGPATH ];
582- FILE * fp ;
583- PGconn * conn = (PGconn * )SSL_get_app_data (ssl );
587+ FILE * fp ;
588+ BIO * bio ;
589+ PGconn * conn = (PGconn * )SSL_get_app_data (ssl );
584590char sebuf [256 ];
585591
586592if (!pqGetHomeDirectory (homedir ,sizeof (homedir )))
@@ -590,27 +596,34 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
590596return 0 ;
591597}
592598
599+ /* save OpenSSL error stack */
600+ ERR_set_mark ();
601+
593602/* read the user certificate */
594603snprintf (fnbuf ,sizeof (fnbuf ),"%s/%s" ,homedir ,USER_CERT_FILE );
595- if ((fp = fopen (fnbuf ,"r" ))== NULL )
604+ if ((bio = BIO_new_file (fnbuf ,"r" ))== NULL )
596605{
597606printfPQExpBuffer (& conn -> errorMessage ,
598607libpq_gettext ("could not open certificate file \"%s\": %s\n" ),
599608fnbuf ,pqStrerror (errno ,sebuf ,sizeof (sebuf )));
609+ ERR_pop_to_mark ();
600610return 0 ;
601611}
602- if (PEM_read_X509 (fp ,x509 ,NULL ,NULL )== NULL )
612+
613+ if (PEM_read_bio_X509 (bio ,x509 ,NULL ,NULL )== NULL )
603614{
604615char * err = SSLerrmessage ();
605616
606617printfPQExpBuffer (& conn -> errorMessage ,
607618libpq_gettext ("could not read certificate file \"%s\": %s\n" ),
608619fnbuf ,err );
609620SSLerrfree (err );
610- fclose (fp );
621+ BIO_free (bio );
622+ ERR_pop_to_mark ();
611623return 0 ;
612624}
613- fclose (fp );
625+
626+ BIO_free (bio );
614627
615628#if (SSLEAY_VERSION_NUMBER >=0x00907000L )&& !defined(OPENSSL_NO_ENGINE )
616629if (getenv ("PGSSLKEY" ))
@@ -625,6 +638,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
625638{
626639printfPQExpBuffer (& conn -> errorMessage ,
627640libpq_gettext ("invalid value of PGSSLKEY environment variable\n" ));
641+ ERR_pop_to_mark ();
628642return 0 ;
629643}
630644
@@ -640,8 +654,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
640654engine_str ,err );
641655SSLerrfree (err );
642656free (engine_str );
657+ ERR_pop_to_mark ();
643658return 0 ;
644- }
659+ }
645660
646661* pkey = ENGINE_load_private_key (engine_ptr ,engine_colon + 1 ,
647662NULL ,NULL );
@@ -654,8 +669,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
654669engine_colon + 1 ,engine_str ,err );
655670SSLerrfree (err );
656671free (engine_str );
672+ ERR_pop_to_mark ();
657673return 0 ;
658- }
674+ }
659675free (engine_str );
660676}
661677else
@@ -668,6 +684,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
668684printfPQExpBuffer (& conn -> errorMessage ,
669685libpq_gettext ("certificate present, but not private key file \"%s\"\n" ),
670686fnbuf );
687+ ERR_pop_to_mark ();
671688return 0 ;
672689}
673690#ifndef WIN32
@@ -677,37 +694,46 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
677694printfPQExpBuffer (& conn -> errorMessage ,
678695libpq_gettext ("private key file \"%s\" has wrong permissions\n" ),
679696fnbuf );
697+ ERR_pop_to_mark ();
680698return 0 ;
681699}
682700#endif
683- if ((fp = fopen (fnbuf ,"r" ))== NULL )
701+
702+ if ((bio = BIO_new_file (fnbuf ,"r" ))== NULL )
684703{
685704printfPQExpBuffer (& conn -> errorMessage ,
686705libpq_gettext ("could not open private key file \"%s\": %s\n" ),
687706fnbuf ,pqStrerror (errno ,sebuf ,sizeof (sebuf )));
707+ ERR_pop_to_mark ();
688708return 0 ;
689709}
690710#ifndef WIN32
711+ BIO_get_fp (bio ,& fp );
691712if (fstat (fileno (fp ),& buf2 )== -1 ||
692713buf .st_dev != buf2 .st_dev || buf .st_ino != buf2 .st_ino )
693714{
694715printfPQExpBuffer (& conn -> errorMessage ,
695716libpq_gettext ("private key file \"%s\" changed during execution\n" ),fnbuf );
717+ ERR_pop_to_mark ();
696718return 0 ;
697719}
698720#endif
699- if (PEM_read_PrivateKey (fp ,pkey ,NULL ,NULL )== NULL )
721+
722+ if (PEM_read_bio_PrivateKey (bio ,pkey ,NULL ,NULL )== NULL )
700723{
701724char * err = SSLerrmessage ();
702725
703726printfPQExpBuffer (& conn -> errorMessage ,
704727libpq_gettext ("could not read private key file \"%s\": %s\n" ),
705728fnbuf ,err );
706729SSLerrfree (err );
707- fclose (fp );
730+
731+ BIO_free (bio );
732+ ERR_pop_to_mark ();
708733return 0 ;
709734}
710- fclose (fp );
735+
736+ BIO_free (bio );
711737}
712738
713739/* verify that the cert and key go together */
@@ -719,9 +745,12 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
719745libpq_gettext ("certificate does not match private key file \"%s\": %s\n" ),
720746fnbuf ,err );
721747SSLerrfree (err );
748+ ERR_pop_to_mark ();
722749return 0 ;
723750}
724751
752+ ERR_pop_to_mark ();
753+
725754return 1 ;
726755}
727756