Dave Page wrote:
> Dave Page wrote:
>> I did stumble across this text on a mailing list in response to someone
>> with a similar problem in some JNI code. I know little of the OpenSSL
>> API, but perhaps it rings bells with you before I spend my evening
>> trying to figure it out?
> 
> OK, I think I've figured out a fix. Working up a patch now...

Patch attached.

It appears to work fine except that if the client certificate is
missing, instead of:

could not open certificate file "C:\Documents and
Settings\Dave\Application Data/postgresql/postgresql.crt": No such file
or directory

I get:

Error connecting to the server: SSL SYSCALL error: Operation would block
(0x00002733/10035)

for reasons that are not clear to me. Any ideas?

Regards, Dave
Index: src/interfaces/libpq/fe-secure.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/interfaces/libpq/fe-secure.c,v
retrieving revision 1.94
diff -c -r1.94 fe-secure.c
*** src/interfaces/libpq/fe-secure.c	16 Feb 2007 17:07:00 -0000	1.94
--- src/interfaces/libpq/fe-secure.c	28 Sep 2007 20:15:17 -0000
***************
*** 111,116 ****
--- 111,119 ----
  
  #ifdef USE_SSL
  #include <openssl/ssl.h>
+ #ifdef WIN32
+ #include <openssl/bio.h>
+ #endif
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
  #include <openssl/conf.h> 
  #endif
***************
*** 567,572 ****
--- 570,581 ----
   *	This callback is only called when the server wants a
   *	client cert.
   *
+  *  Note: On Windows we use OpenSSL's BIO functions to
+  *  handle I/O to avoid issues passing FILE pointers to 
+  *  incompatible runtimes. We don't use them on other
+  *  platforms because we couldn't then stat the keys to
+  *  check for changes during execution.
+  *
   *	Must return 1 on success, 0 on no data or error.
   */
  static int
***************
*** 579,585 ****
--- 588,598 ----
  	struct stat buf2;
  #endif
  	char		fnbuf[MAXPGPATH];
+ #ifndef WIN32
  	FILE	   *fp;
+ #else
+ 	BIO		   *bio;
+ #endif
  	PGconn	   *conn = (PGconn *) SSL_get_app_data(ssl);
  	char		sebuf[256];
  
***************
*** 592,605 ****
--- 605,626 ----
  
  	/* read the user certificate */
  	snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
+ #ifndef WIN32
  	if ((fp = fopen(fnbuf, "r")) == NULL)
+ #else
+ 	if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
+ #endif
  	{
  		printfPQExpBuffer(&conn->errorMessage,
  			   libpq_gettext("could not open certificate file \"%s\": %s\n"),
  						  fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
  		return 0;
  	}
+ #ifndef WIN32
  	if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
+ #else
+ 	if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL)
+ #endif
  	{
  		char	   *err = SSLerrmessage();
  
***************
*** 607,616 ****
--- 628,645 ----
  			   libpq_gettext("could not read certificate file \"%s\": %s\n"),
  						  fnbuf, err);
  		SSLerrfree(err);
+ #ifndef WIN32
  		fclose(fp);
+ #else
+ 		BIO_free(bio);
+ #endif
  		return 0;
  	}
+ #ifndef WIN32
  	fclose(fp);
+ #else
+ 	BIO_free(bio);
+ #endif
  
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
  	if (getenv("PGSSLKEY"))
***************
*** 641,647 ****
  			SSLerrfree(err);
  			free(engine_str);
  			return 0;
! 		}	
  
  		*pkey = ENGINE_load_private_key(engine_ptr, engine_colon + 1,
  										NULL, NULL);
--- 670,676 ----
  			SSLerrfree(err);
  			free(engine_str);
  			return 0;
! 		}
  
  		*pkey = ENGINE_load_private_key(engine_ptr, engine_colon + 1,
  										NULL, NULL);
***************
*** 655,661 ****
  			SSLerrfree(err);
  			free(engine_str);
  			return 0;
! 		}		
  		free(engine_str);
  	}
  	else
--- 684,690 ----
  			SSLerrfree(err);
  			free(engine_str);
  			return 0;
! 		}
  		free(engine_str);
  	}
  	else
***************
*** 679,686 ****
  							fnbuf);
  			return 0;
  		}
! #endif
  		if ((fp = fopen(fnbuf, "r")) == NULL)
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  				libpq_gettext("could not open private key file \"%s\": %s\n"),
--- 708,718 ----
  							fnbuf);
  			return 0;
  		}
! 
  		if ((fp = fopen(fnbuf, "r")) == NULL)
+ #else
+ 		if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
+ #endif
  		{
  			printfPQExpBuffer(&conn->errorMessage,
  				libpq_gettext("could not open private key file \"%s\": %s\n"),
***************
*** 695,702 ****
  							libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
  			return 0;
  		}
! #endif
  		if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
  		{
  			char	   *err = SSLerrmessage();
  
--- 727,737 ----
  							libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
  			return 0;
  		}
! 
  		if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
+ #else
+ 		if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL)
+ #endif
  		{
  			char	   *err = SSLerrmessage();
  
***************
*** 704,713 ****
--- 739,756 ----
  				libpq_gettext("could not read private key file \"%s\": %s\n"),
  							fnbuf, err);
  			SSLerrfree(err);
+ #ifndef WIN32
  			fclose(fp);
+ #else
+ 			BIO_free(bio);
+ #endif
  			return 0;
  		}
+ #ifndef WIN32
  		fclose(fp);
+ #else
+ 		BIO_free(bio);
+ #endif
  	}
  
  	/* verify that the cert and key go together */
---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
       subscribe-nomail command to [EMAIL PROTECTED] so that your
       message can get through to the mailing list cleanly

Reply via email to