Thread: OpenSSL Applink

OpenSSL Applink

From
Dave Page
Date:
On Windows the OpenSSL guys have included code with 0.9.8 and above to
allow OpenSSL to work correctly regardless of the MSVC runtime libraries
that have been used with the host application. This has become noticable
with the MSVC++ build in which any client apps that connect using libpq
with a client certificate will bail out with an error such as:

C:\pgsql-8.3>bin\psql -p 5433 postgres
OPENSSL_Uplink(00314010,05): no OPENSSL_Applink

The server doesn't seem to be affected, but the attached patch fixes the
problem for the client apps. Unfortunately it must be included in the
app itself, and not libpq.

I'm not sure what the OpenSSL guys were thinking here - apps like
pgAdmin which previously didn't use OpenSSL directly now need the source
code to build. I've also seen reports on the -odbc list that psqlODBC is
similarly affected, though how on earth we're meant to get the AppLink
code into apps such as MS Access or Crystal Reports is beyond me.

Regards, Dave
Index: bin/pg_dump/pg_dump.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.472
diff -u -r1.472 pg_dump.c
--- bin/pg_dump/pg_dump.c    3 Sep 2007 00:39:19 -0000    1.472
+++ bin/pg_dump/pg_dump.c    28 Sep 2007 14:09:59 -0000
@@ -197,6 +197,18 @@
 static void check_sql_result(PGresult *res, PGconn *conn, const char *query,
                  ExecStatusType expected);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char **argv)
Index: bin/pg_dump/pg_dumpall.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v
retrieving revision 1.92
diff -u -r1.92 pg_dumpall.c
--- bin/pg_dump/pg_dumpall.c    8 Jul 2007 19:07:38 -0000    1.92
+++ bin/pg_dump/pg_dumpall.c    28 Sep 2007 14:09:59 -0000
@@ -71,6 +71,19 @@
 static FILE    *OPF;
 static char    *filename = NULL;

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif
+
 int
 main(int argc, char *argv[])
 {
Index: bin/pg_dump/pg_restore.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v
retrieving revision 1.84
diff -u -r1.84 pg_restore.c
--- bin/pg_dump/pg_restore.c    14 Oct 2006 23:07:22 -0000    1.84
+++ bin/pg_dump/pg_restore.c    28 Sep 2007 14:09:59 -0000
@@ -64,6 +64,19 @@

 typedef struct option optType;

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif
+
 int
 main(int argc, char **argv)
 {
Index: bin/psql/startup.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/psql/startup.c,v
retrieving revision 1.141
diff -u -r1.141 startup.c
--- bin/psql/startup.c    8 Jul 2007 19:07:38 -0000    1.141
+++ bin/psql/startup.c    28 Sep 2007 14:07:02 -0000
@@ -95,6 +95,18 @@
 #endif

 /*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif
+
+/*
  *
  * main
  *
Index: bin/scripts/clusterdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/clusterdb.c,v
retrieving revision 1.18
diff -u -r1.18 clusterdb.c
--- bin/scripts/clusterdb.c    4 Jun 2007 10:02:40 -0000    1.18
+++ bin/scripts/clusterdb.c    28 Sep 2007 14:11:03 -0000
@@ -24,6 +24,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/createdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createdb.c,v
retrieving revision 1.23
diff -u -r1.23 createdb.c
--- bin/scripts/createdb.c    4 Jun 2007 10:02:40 -0000    1.23
+++ bin/scripts/createdb.c    28 Sep 2007 14:11:03 -0000
@@ -19,6 +19,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/createlang.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createlang.c,v
retrieving revision 1.26
diff -u -r1.26 createlang.c
--- bin/scripts/createlang.c    10 Aug 2007 00:39:31 -0000    1.26
+++ bin/scripts/createlang.c    28 Sep 2007 14:11:03 -0000
@@ -16,6 +16,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/createuser.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/createuser.c,v
retrieving revision 1.36
diff -u -r1.36 createuser.c
--- bin/scripts/createuser.c    4 Jun 2007 10:02:40 -0000    1.36
+++ bin/scripts/createuser.c    28 Sep 2007 14:11:03 -0000
@@ -24,6 +24,19 @@
     TRI_YES
 };

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif
+
 int
 main(int argc, char *argv[])
 {
Index: bin/scripts/dropdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/dropdb.c,v
retrieving revision 1.20
diff -u -r1.20 dropdb.c
--- bin/scripts/dropdb.c    4 Jun 2007 10:02:40 -0000    1.20
+++ bin/scripts/dropdb.c    28 Sep 2007 14:11:03 -0000
@@ -17,6 +17,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/droplang.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/droplang.c,v
retrieving revision 1.23
diff -u -r1.23 droplang.c
--- bin/scripts/droplang.c    10 Aug 2007 00:39:31 -0000    1.23
+++ bin/scripts/droplang.c    28 Sep 2007 14:11:03 -0000
@@ -19,6 +19,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/dropuser.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/dropuser.c,v
retrieving revision 1.21
diff -u -r1.21 dropuser.c
--- bin/scripts/dropuser.c    4 Jun 2007 10:02:40 -0000    1.21
+++ bin/scripts/dropuser.c    28 Sep 2007 14:11:03 -0000
@@ -17,6 +17,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])
Index: bin/scripts/reindexdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/reindexdb.c,v
retrieving revision 1.11
diff -u -r1.11 reindexdb.c
--- bin/scripts/reindexdb.c    4 Jun 2007 10:02:40 -0000    1.11
+++ bin/scripts/reindexdb.c    28 Sep 2007 14:11:03 -0000
@@ -29,6 +29,19 @@
                         const char *progname, bool echo);
 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif
+
 int
 main(int argc, char *argv[])
 {
Index: bin/scripts/vacuumdb.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/bin/scripts/vacuumdb.c,v
retrieving revision 1.18
diff -u -r1.18 vacuumdb.c
--- bin/scripts/vacuumdb.c    4 Jun 2007 10:02:40 -0000    1.18
+++ bin/scripts/vacuumdb.c    28 Sep 2007 14:11:03 -0000
@@ -26,6 +26,18 @@

 static void help(const char *progname);

+/*
+ * We need to include OpenSSL's applink code with OpenSSL 0.9.8+ on Windows
+ * It needs to be included in every .exe so we include it here.
+ */
+#ifdef WIN32
+#ifdef USE_SSL
+#include <openssl/opensslv.h>
+#if (OPENSSL_VERSION_NUMBER >= 0x00908000L)
+#include <openssl/applink.c>
+#endif
+#endif
+#endif

 int
 main(int argc, char *argv[])

Re: OpenSSL Applink

From
Tom Lane
Date:
Dave Page <dpage@postgresql.org> writes:
> The server doesn't seem to be affected, but the attached patch fixes the
> problem for the client apps. Unfortunately it must be included in the
> app itself, and not libpq.

This is pretty much in the category of "they've got to be kidding".
I recommend sitting on the prior version until upstream fixes their
mistake.

            regards, tom lane

Re: OpenSSL Applink

From
Andrew Dunstan
Date:

Tom Lane wrote:
> Dave Page <dpage@postgresql.org> writes:
>
>> The server doesn't seem to be affected, but the attached patch fixes the
>> problem for the client apps. Unfortunately it must be included in the
>> app itself, and not libpq.
>>
>
> This is pretty much in the category of "they've got to be kidding".
> I recommend sitting on the prior version until upstream fixes their
> mistake.
>
>
>

That was my reaction.

cheers

andrew

Re: OpenSSL Applink

From
Dave Page
Date:
Tom Lane wrote:
> Dave Page <dpage@postgresql.org> writes:
>> The server doesn't seem to be affected, but the attached patch fixes the
>> problem for the client apps. Unfortunately it must be included in the
>> app itself, and not libpq.
>
> This is pretty much in the category of "they've got to be kidding".

Agreed. Unless I've completely missed the point this does seem *really*
dumb.

> I recommend sitting on the prior version until upstream fixes their
> mistake.

Unfortunately from what I've seen it doesn't look like thats on their
agenda... and this has been around in release versions now since July  2005.

I believe we just didn't notice it until now because the older Mingw
builds use the MSVC 6.0 runtimes which just happened to be compatible
with the OpenSSL binary builds (we're now using 8.0), in addition to
which there are relatively few people using client-side certs I'd wager.

/D


Re: OpenSSL Applink

From
Andrew Dunstan
Date:

Dave Page wrote:
>
> I believe we just didn't notice it until now because the older Mingw
> builds use the MSVC 6.0 runtimes which just happened to be compatible
> with the OpenSSL binary builds (we're now using 8.0), in addition to
> which there are relatively few people using client-side certs I'd wager.
>
>

So SSL works without this wart if you don't have a client cert?

cheers

andrew

Re: OpenSSL Applink

From
Dave Page
Date:
Andrew Dunstan wrote:
>
>
> Dave Page wrote:
>>
>> I believe we just didn't notice it until now because the older Mingw
>> builds use the MSVC 6.0 runtimes which just happened to be compatible
>> with the OpenSSL binary builds (we're now using 8.0), in addition to
>> which there are relatively few people using client-side certs I'd wager.
>>
>>
>
> So SSL works without this wart if you don't have a client cert?

Yep.

/D

Re: OpenSSL Applink

From
Andrew Dunstan
Date:

Dave Page wrote:
> Andrew Dunstan wrote:
>>
>>
>> Dave Page wrote:
>>>
>>> I believe we just didn't notice it until now because the older Mingw
>>> builds use the MSVC 6.0 runtimes which just happened to be
>>> compatible with the OpenSSL binary builds (we're now using 8.0), in
>>> addition to which there are relatively few people using client-side
>>> certs I'd wager.
>>>
>>>
>>
>> So SSL works without this wart if you don't have a client cert?
>
> Yep.
>
>

Then I think I'd rather disable use of client certs for the offending
openssl versions in libpq, or let the apps die and refer the customers
to the openssl people to lobby them for a sane solution.

cheers

andrew



Re: OpenSSL Applink

From
Dave Page
Date:
Andrew Dunstan wrote:
> Then I think I'd rather disable use of client certs for the offending
> openssl versions in libpq, or let the apps die and refer the customers
> to the openssl people to lobby them for a sane solution.

If this were 8.0 I'd agree, but thats not a nice solution for those
already using client certs (such as the pgAdmin user who brought this to
my attention).

:-(

/D

Re: OpenSSL Applink

From
Heikki Linnakangas
Date:
Dave Page wrote:
> Andrew Dunstan wrote:
>> Dave Page wrote:
>>> I believe we just didn't notice it until now because the older Mingw
>>> builds use the MSVC 6.0 runtimes which just happened to be compatible
>>> with the OpenSSL binary builds (we're now using 8.0), in addition to
>>> which there are relatively few people using client-side certs I'd wager.
>>
>> So SSL works without this wart if you don't have a client cert?
>
> Yep.

According to the OpenSSL FAQ, the purpose of the applink is to allow
mixing release and debug versions or multi-threaded and
non-multithreaded versions of libraries:

http://www.openssl.org/support/faq.html#PROG2

How come we only bump into the crash with client certs?

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: OpenSSL Applink

From
Dave Page
Date:
Heikki Linnakangas wrote:
> Dave Page wrote:
>> Andrew Dunstan wrote:
>>> Dave Page wrote:
>>>> I believe we just didn't notice it until now because the older Mingw
>>>> builds use the MSVC 6.0 runtimes which just happened to be compatible
>>>> with the OpenSSL binary builds (we're now using 8.0), in addition to
>>>> which there are relatively few people using client-side certs I'd wager.
>>> So SSL works without this wart if you don't have a client cert?
>> Yep.
>
> According to the OpenSSL FAQ, the purpose of the applink is to allow
> mixing release and debug versions or multi-threaded and
> non-multithreaded versions of libraries:
>
> http://www.openssl.org/support/faq.html#PROG2

Yeah - which in itself is a pita because with their 'workaround' we now
need to ensure we use a debug libpq with a debug pgadmin whereas
previously mixing 'n' matching wasn't an issue.

> How come we only bump into the crash with client certs?
>

I assume it uses fopen() or one of the other functions it does a
GetProcAddress() on in that situation.

/D

Re: OpenSSL Applink

From
Tom Lane
Date:
Dave Page <dpage@postgresql.org> writes:
> Andrew Dunstan wrote:
>> Then I think I'd rather disable use of client certs for the offending
>> openssl versions in libpq, or let the apps die and refer the customers
>> to the openssl people to lobby them for a sane solution.

> If this were 8.0 I'd agree, but thats not a nice solution for those
> already using client certs (such as the pgAdmin user who brought this to
> my attention).

Doesn't really matter.  Even if we were willing to hack our own client
apps like that (which I'm not), we can *not* transfer such a requirement
onto every libpq-using application.  It's just not acceptable.

            regards, tom lane

Re: OpenSSL Applink

From
Dave Page
Date:
Tom Lane wrote:
> Dave Page <dpage@postgresql.org> writes:
>> Andrew Dunstan wrote:
>>> Then I think I'd rather disable use of client certs for the offending
>>> openssl versions in libpq, or let the apps die and refer the customers
>>> to the openssl people to lobby them for a sane solution.
>
>> If this were 8.0 I'd agree, but thats not a nice solution for those
>> already using client certs (such as the pgAdmin user who brought this to
>> my attention).
>
> Doesn't really matter.  Even if we were willing to hack our own client
> apps like that (which I'm not), we can *not* transfer such a requirement
> onto every libpq-using application.  It's just not acceptable.

*We're* not transfering any requirement. I've fixed pgAdmin for example
without any need to touch any Postgres code. If you don't want to
include the fix (which I can quite understand) it'll just mean that the
PG utilities won't work with client certs.

/D

Re: OpenSSL Applink

From
"Marko Kreen"
Date:
On 9/28/07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Dave Page <dpage@postgresql.org> writes:
> > Andrew Dunstan wrote:
> >> Then I think I'd rather disable use of client certs for the offending
> >> openssl versions in libpq, or let the apps die and refer the customers
> >> to the openssl people to lobby them for a sane solution.
>
> > If this were 8.0 I'd agree, but thats not a nice solution for those
> > already using client certs (such as the pgAdmin user who brought this to
> > my attention).
>
> Doesn't really matter.  Even if we were willing to hack our own client
> apps like that (which I'm not), we can *not* transfer such a requirement
> onto every libpq-using application.  It's just not acceptable.

Is it possible to use GNUTLS on Windows?

--
marko

Re: OpenSSL Applink

From
Dave Page
Date:
Marko Kreen wrote:
> On 9/28/07, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Dave Page <dpage@postgresql.org> writes:
>>> Andrew Dunstan wrote:
>>>> Then I think I'd rather disable use of client certs for the offending
>>>> openssl versions in libpq, or let the apps die and refer the customers
>>>> to the openssl people to lobby them for a sane solution.
>>> If this were 8.0 I'd agree, but thats not a nice solution for those
>>> already using client certs (such as the pgAdmin user who brought this to
>>> my attention).
>> Doesn't really matter.  Even if we were willing to hack our own client
>> apps like that (which I'm not), we can *not* transfer such a requirement
>> onto every libpq-using application.  It's just not acceptable.
>
> Is it possible to use GNUTLS on Windows?
>

No, I don't think so. I didn't think we accepted Martijn's(?) patch for
it anyway?

Regards, Dave

Re: OpenSSL Applink

From
Andrew Dunstan
Date:

Dave Page wrote:
>>
>> Is it possible to use GNUTLS on Windows?
>>
>
> No, I don't think so. I didn't think we accepted Martijn's(?) patch
> for it anyway?
>
>

This mess might make that worth revisiting, if it can be used on
Windows. See http://josefsson.org/gnutls4win/

cheers

andrew

Re: OpenSSL Applink

From
Tom Lane
Date:
Dave Page <dpage@postgresql.org> writes:
> Tom Lane wrote:
>> Doesn't really matter.  Even if we were willing to hack our own client
>> apps like that (which I'm not), we can *not* transfer such a requirement
>> onto every libpq-using application.  It's just not acceptable.

> *We're* not transfering any requirement. I've fixed pgAdmin for example
> without any need to touch any Postgres code.

Well, yeah, we are, as evidenced by the fact that you had to do
something to pgAdmin.  Every other application that uses libpq would
also be facing source code changes to make it work.

Is there really no way to solve this within libpq?

            regards, tom lane

Re: OpenSSL Applink

From
Dave Page
Date:
Tom Lane wrote:
> Dave Page <dpage@postgresql.org> writes:
>> Tom Lane wrote:
>>> Doesn't really matter.  Even if we were willing to hack our own client
>>> apps like that (which I'm not), we can *not* transfer such a requirement
>>> onto every libpq-using application.  It's just not acceptable.
>
>> *We're* not transfering any requirement. I've fixed pgAdmin for example
>> without any need to touch any Postgres code.
>
> Well, yeah, we are, as evidenced by the fact that you had to do
> something to pgAdmin.  Every other application that uses libpq would
> also be facing source code changes to make it work.

Yes, but it's not us requiring it (except in as much as we provide some
level of SSL support) but the OpenSSL crew.

> Is there really no way to solve this within libpq?

Including the applink code in libpq was the first think I tried but it
doesn't work (apparently because there is no way to ensure that any
random module containing it isn't unloaded before it's needed which
sorta makes sense).

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?

-----
But for new and evolving code [I suppose JNI would be rather
new and evolving] applink should not be preferable option, as there is a
way around it, namely avoid passing FILE* to BIO, but instead let BIO
open files for you, i.e. avoid BIO_new_fp and stick to BIO_new_filename.
Note that applink is engaged purely on demand and it doesn't have to be
present in application if application doesn't pass FILE* to BIO.
-----

/D

Re: OpenSSL Applink

From
Dave Page
Date:
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...

/D

Re: OpenSSL Applink

From
Dave Page
Date:
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 */

Re: OpenSSL Applink

From
Magnus Hagander
Date:
Dave Page wrote:
> 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.

(sorry, been offline for the day)

Is there any reason not to just do this on *all* platforms, and get rid
of all the #ifdefs?

The new code actually seems cleaner to me than what we did before,
really... Since it lets OpenSSL do all the work for it.


> 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?

I wonder if it might be related to our socket/signal emulation stuff.
I'd be interested to see what happens with the same code on Unix, but
sorry, don't have time to test myself - will be offline again tomorrow :-(

//Magnus


Re: OpenSSL Applink

From
Dave Page
Date:
Magnus Hagander wrote:
> Dave Page wrote:
>> 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.
>
> (sorry, been offline for the day)
>
> Is there any reason not to just do this on *all* platforms, and get rid
> of all the #ifdefs?

Yes, (see the comment in the code). We stat the private key on *nix to
ensure it hasn't changed underneath us which can't be done using the BIO
functions... though I wonder if we can get the FILE pointer from BIO and
do it that way. Should be as safe on *nix as what we currently do.

> I wonder if it might be related to our socket/signal emulation stuff.
> I'd be interested to see what happens with the same code on Unix, but
> sorry, don't have time to test myself - will be offline again tomorrow :-(

NP.

/D

Re: OpenSSL Applink

From
Magnus Hagander
Date:
Dave Page wrote:
> Magnus Hagander wrote:
>> Dave Page wrote:
>>> 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.
>> (sorry, been offline for the day)
>>
>> Is there any reason not to just do this on *all* platforms, and get rid
>> of all the #ifdefs?
>
> Yes, (see the comment in the code). We stat the private key on *nix to
> ensure it hasn't changed underneath us which can't be done using the BIO
> functions... though I wonder if we can get the FILE pointer from BIO and
> do it that way. Should be as safe on *nix as what we currently do.

Hrrm. Obviously, I need to go sleep now. Sorry about that.

But it'd be nice to get rid of all those #ifdef blocks..

//Magnus

Re: OpenSSL Applink

From
Dave Page
Date:
Magnus Hagander wrote:
> Hrrm. Obviously, I need to go sleep now. Sorry about that.
>
> But it'd be nice to get rid of all those #ifdef blocks..

See the attached revision. This is untested as I don't have a linux box
to hand, but I believe it's right.

/D

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 21:13:18 -0000
***************
*** 111,116 ****
--- 111,117 ----

  #ifdef USE_SSL
  #include <openssl/ssl.h>
+ #include <openssl/bio.h>
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
  #include <openssl/conf.h>
  #endif
***************
*** 579,586 ****
      struct stat buf2;
  #endif
      char        fnbuf[MAXPGPATH];
!     FILE       *fp;
!     PGconn       *conn = (PGconn *) SSL_get_app_data(ssl);
      char        sebuf[256];

      if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
--- 580,588 ----
      struct stat buf2;
  #endif
      char        fnbuf[MAXPGPATH];
!     FILE        *fp;
!     BIO            *bio;
!     PGconn        *conn = (PGconn *) SSL_get_app_data(ssl);
      char        sebuf[256];

      if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
***************
*** 592,605 ****

      /* read the user certificate */
      snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
!     if ((fp = fopen(fnbuf, "r")) == NULL)
      {
          printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("could not open certificate file \"%s\": %s\n"),
                            fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
          return 0;
      }
!     if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
      {
          char       *err = SSLerrmessage();

--- 594,608 ----

      /* read the user certificate */
      snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
!     if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
      {
          printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("could not open certificate file \"%s\": %s\n"),
                            fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
          return 0;
      }
!
!     if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL)
      {
          char       *err = SSLerrmessage();

***************
*** 607,616 ****
                 libpq_gettext("could not read certificate file \"%s\": %s\n"),
                            fnbuf, err);
          SSLerrfree(err);
!         fclose(fp);
          return 0;
      }
!     fclose(fp);

  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
      if (getenv("PGSSLKEY"))
--- 610,620 ----
                 libpq_gettext("could not read certificate file \"%s\": %s\n"),
                            fnbuf, err);
          SSLerrfree(err);
!         BIO_free(bio);
          return 0;
      }
!
!     BIO_free(bio);

  #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);
--- 645,651 ----
              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
--- 659,665 ----
              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"),
--- 683,690 ----
                              fnbuf);
              return 0;
          }
!
!         if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
          {
              printfPQExpBuffer(&conn->errorMessage,
                  libpq_gettext("could not open private key file \"%s\": %s\n"),
***************
*** 688,693 ****
--- 692,698 ----
              return 0;
          }
  #ifndef WIN32
+         BIO_get_fp(bio, &fp);
          if (fstat(fileno(fp), &buf2) == -1 ||
              buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
          {
***************
*** 696,702 ****
              return 0;
          }
  #endif
!         if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
          {
              char       *err = SSLerrmessage();

--- 701,708 ----
              return 0;
          }
  #endif
!
!         if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL)
          {
              char       *err = SSLerrmessage();

***************
*** 704,713 ****
                  libpq_gettext("could not read private key file \"%s\": %s\n"),
                              fnbuf, err);
              SSLerrfree(err);
!             fclose(fp);
              return 0;
          }
!         fclose(fp);
      }

      /* verify that the cert and key go together */
--- 710,721 ----
                  libpq_gettext("could not read private key file \"%s\": %s\n"),
                              fnbuf, err);
              SSLerrfree(err);
!
!             BIO_free(bio);
              return 0;
          }
!
!         BIO_free(bio);
      }

      /* verify that the cert and key go together */

Re: OpenSSL Applink

From
Dave Page
Date:
Dave Page wrote:
> Magnus Hagander wrote:
>> Hrrm. Obviously, I need to go sleep now. Sorry about that.
>>
>> But it'd be nice to get rid of all those #ifdef blocks..
>
> See the attached revision. This is untested as I don't have a linux box
> to hand, but I believe it's right.

Ignore that - I managed to break it :-(. Here's a corrected version.

/D
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 21:33:46 -0000
***************
*** 111,116 ****
--- 111,117 ----

  #ifdef USE_SSL
  #include <openssl/ssl.h>
+ #include <openssl/bio.h>
  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
  #include <openssl/conf.h>
  #endif
***************
*** 579,586 ****
      struct stat buf2;
  #endif
      char        fnbuf[MAXPGPATH];
!     FILE       *fp;
!     PGconn       *conn = (PGconn *) SSL_get_app_data(ssl);
      char        sebuf[256];

      if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
--- 580,588 ----
      struct stat buf2;
  #endif
      char        fnbuf[MAXPGPATH];
!     FILE        *fp;
!     BIO            *bio;
!     PGconn        *conn = (PGconn *) SSL_get_app_data(ssl);
      char        sebuf[256];

      if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
***************
*** 592,605 ****

      /* read the user certificate */
      snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
!     if ((fp = fopen(fnbuf, "r")) == NULL)
      {
          printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("could not open certificate file \"%s\": %s\n"),
                            fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
          return 0;
      }
!     if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
      {
          char       *err = SSLerrmessage();

--- 594,608 ----

      /* read the user certificate */
      snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
!     if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
      {
          printfPQExpBuffer(&conn->errorMessage,
                 libpq_gettext("could not open certificate file \"%s\": %s\n"),
                            fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
          return 0;
      }
!
!     if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL)
      {
          char       *err = SSLerrmessage();

***************
*** 607,616 ****
                 libpq_gettext("could not read certificate file \"%s\": %s\n"),
                            fnbuf, err);
          SSLerrfree(err);
!         fclose(fp);
          return 0;
      }
!     fclose(fp);

  #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
      if (getenv("PGSSLKEY"))
--- 610,620 ----
                 libpq_gettext("could not read certificate file \"%s\": %s\n"),
                            fnbuf, err);
          SSLerrfree(err);
!         BIO_free(bio);
          return 0;
      }
!
!     BIO_free(bio);

  #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);
--- 645,651 ----
              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
--- 659,665 ----
              SSLerrfree(err);
              free(engine_str);
              return 0;
!         }
          free(engine_str);
      }
      else
***************
*** 680,686 ****
              return 0;
          }
  #endif
!         if ((fp = fopen(fnbuf, "r")) == NULL)
          {
              printfPQExpBuffer(&conn->errorMessage,
                  libpq_gettext("could not open private key file \"%s\": %s\n"),
--- 684,691 ----
              return 0;
          }
  #endif
!
!         if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
          {
              printfPQExpBuffer(&conn->errorMessage,
                  libpq_gettext("could not open private key file \"%s\": %s\n"),
***************
*** 688,693 ****
--- 693,699 ----
              return 0;
          }
  #ifndef WIN32
+         BIO_get_fp(bio, &fp);
          if (fstat(fileno(fp), &buf2) == -1 ||
              buf.st_dev != buf2.st_dev || buf.st_ino != buf2.st_ino)
          {
***************
*** 696,702 ****
              return 0;
          }
  #endif
!         if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
          {
              char       *err = SSLerrmessage();

--- 702,709 ----
              return 0;
          }
  #endif
!
!         if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL)
          {
              char       *err = SSLerrmessage();

***************
*** 704,713 ****
                  libpq_gettext("could not read private key file \"%s\": %s\n"),
                              fnbuf, err);
              SSLerrfree(err);
!             fclose(fp);
              return 0;
          }
!         fclose(fp);
      }

      /* verify that the cert and key go together */
--- 711,722 ----
                  libpq_gettext("could not read private key file \"%s\": %s\n"),
                              fnbuf, err);
              SSLerrfree(err);
!
!             BIO_free(bio);
              return 0;
          }
!
!         BIO_free(bio);
      }

      /* verify that the cert and key go together */

Re: OpenSSL Applink

From
Tom Lane
Date:
Dave Page <dpage@postgresql.org> writes:
> Magnus Hagander wrote:
>> Is there any reason not to just do this on *all* platforms, and get rid
>> of all the #ifdefs?

> Yes, (see the comment in the code). We stat the private key on *nix to
> ensure it hasn't changed underneath us which can't be done using the BIO
> functions... though I wonder if we can get the FILE pointer from BIO and
> do it that way. Should be as safe on *nix as what we currently do.

Perhaps you could still open the file yourself, and use BIO_new_fp()
instead of BIO_new_file()?  I'm not getting responses from openssl.org
at the moment, but here's another copy of the relevant man page:

http://developer.apple.com/documentation/Darwin/Reference/Manpages/man3/BIO_s_file.3ssl.html

I concur with Magnus that it'll be better if there's not two code paths
here.  It's not entirely clear whether BIO_new_fp() would avoid the
problematic calls, but it doesn't look like it'd be hard to try.

            regards, tom lane

Re: OpenSSL Applink

From
"Dave Page"
Date:

> ------- Original Message -------
> From: Tom Lane <tgl@sss.pgh.pa.us>
> To: Dave Page <dpage@postgresql.org>
> Sent: 29/09/07, 01:28:09
> Subject: Re: [PATCHES] OpenSSL Applink
>
> I concur with Magnus that it'll be better if there's not two code paths
> here.  It's not entirely clear whether BIO_new_fp() would avoid the
> problematic calls, but it doesn't look like it'd be hard to try.

The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 

I believe the problem is sharing FILE*'s between differing runtime versions used by openssl and the app. Coding it with
BIO_new_filemakes it less tempting for future changes to start mucking about with FILE*'s on Windows. 

Note that I've been away from my *nix boxes so I haven't tested the patch except on Windows yet.

/D

Re: OpenSSL Applink

From
Tom Lane
Date:
"Dave Page" <dpage@postgresql.org> writes:
>> From: Tom Lane <tgl@sss.pgh.pa.us>
>> ... It's not entirely clear whether BIO_new_fp() would avoid the
>> problematic calls, but it doesn't look like it'd be hard to try.

> The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 

Did you manage to get rid of the bogus-error-message problem that
afflicted the first version of the patch?  If so, this way is fine.
If not, keeping control of file-opening in our own hands might be
a way to dodge that.

            regards, tom lane

Re: OpenSSL Applink

From
Dave Page
Date:
Tom Lane wrote:
> "Dave Page" <dpage@postgresql.org> writes:
>>> From: Tom Lane <tgl@sss.pgh.pa.us>
>>> ... It's not entirely clear whether BIO_new_fp() would avoid the
>>> problematic calls, but it doesn't look like it'd be hard to try.
>
>> The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 
>
> Did you manage to get rid of the bogus-error-message problem that
> afflicted the first version of the patch?  If so, this way is fine.

No, thats still an issue.

> If not, keeping control of file-opening in our own hands might be
> a way to dodge that.

That doesn't work because we still end up passing FILE pointers between
potentially differing runtime builds/versions) which OpenSSL then
detects and bleats about including OPENSSL_Applink().

/D

Re: OpenSSL Applink

From
Magnus Hagander
Date:
On Sat, Sep 29, 2007 at 09:01:16PM +0100, Dave Page wrote:
> Tom Lane wrote:
> > "Dave Page" <dpage@postgresql.org> writes:
> >>> From: Tom Lane <tgl@sss.pgh.pa.us>
> >>> ... It's not entirely clear whether BIO_new_fp() would avoid the
> >>> problematic calls, but it doesn't look like it'd be hard to try.
> >
> >> The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 
> >
> > Did you manage to get rid of the bogus-error-message problem that
> > afflicted the first version of the patch?  If so, this way is fine.
>
> No, thats still an issue.

A guess on this - probably the BIO stuff overwrites some internal OpenSSL
"errno" value, causing the wrong error to be passed up. Most likely, it's
not save to call BIO functions from inside the callback. My bet is that
it'll actually break without this patch, if you stick something that's
invalid in there. It's just taht we picked up the "does not exist" error
without calling BIO functions.

A quick peek at the OpenSSL sources seems to confirm this.

I think we want to either attempt to load the client certificate before we
connect (and before it's requested) and just queue up the error to show it
in only if it's requested, or we want to try some magic around
ERR_set_mark()/ERR_pop_to_mark() to clear out any BIO errors before we hand
control back.

I'll see if I can put together a poc patch - need to reproduce the problem
first :-)

//Magnus

Re: OpenSSL Applink

From
Magnus Hagander
Date:
On Mon, Oct 01, 2007 at 02:37:44PM +0200, Magnus Hagander wrote:
> On Sat, Sep 29, 2007 at 09:01:16PM +0100, Dave Page wrote:
> > Tom Lane wrote:
> > > "Dave Page" <dpage@postgresql.org> writes:
> > >>> From: Tom Lane <tgl@sss.pgh.pa.us>
> > >>> ... It's not entirely clear whether BIO_new_fp() would avoid the
> > >>> problematic calls, but it doesn't look like it'd be hard to try.
> > >
> > >> The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 
> > >
> > > Did you manage to get rid of the bogus-error-message problem that
> > > afflicted the first version of the patch?  If so, this way is fine.
> >
> > No, thats still an issue.
>
> A guess on this - probably the BIO stuff overwrites some internal OpenSSL
> "errno" value, causing the wrong error to be passed up. Most likely, it's
> not save to call BIO functions from inside the callback. My bet is that
> it'll actually break without this patch, if you stick something that's
> invalid in there. It's just taht we picked up the "does not exist" error
> without calling BIO functions.
>
> A quick peek at the OpenSSL sources seems to confirm this.
>
> I think we want to either attempt to load the client certificate before we
> connect (and before it's requested) and just queue up the error to show it
> in only if it's requested, or we want to try some magic around
> ERR_set_mark()/ERR_pop_to_mark() to clear out any BIO errors before we hand
> control back.
>
> I'll see if I can put together a poc patch - need to reproduce the problem
> first :-)

Just a quick followup - this is also reproducible on Unix:

mha@builder:~/inst-pg/head/bin$ PGSSLMODE=require ./psql -h localhost
postgres
psql: SSL SYSCALL error: Resource temporarily unavailable


//Magnus

Re: OpenSSL Applink

From
Magnus Hagander
Date:
On Mon, Oct 01, 2007 at 03:16:13PM +0200, Magnus Hagander wrote:
> On Mon, Oct 01, 2007 at 02:37:44PM +0200, Magnus Hagander wrote:
> > On Sat, Sep 29, 2007 at 09:01:16PM +0100, Dave Page wrote:
> > > Tom Lane wrote:
> > > > "Dave Page" <dpage@postgresql.org> writes:
> > > >>> From: Tom Lane <tgl@sss.pgh.pa.us>
> > > >>> ... It's not entirely clear whether BIO_new_fp() would avoid the
> > > >>> problematic calls, but it doesn't look like it'd be hard to try.
> > > >
> > > >> The last version of the patch I posted uses BIO_new_file() in all cases, and (from memory) BIO_get_fp() in the
non-win32case to get a FILE* to pass to fstat. 
> > > >
> > > > Did you manage to get rid of the bogus-error-message problem that
> > > > afflicted the first version of the patch?  If so, this way is fine.
> > >
> > > No, thats still an issue.
> >
> > A guess on this - probably the BIO stuff overwrites some internal OpenSSL
> > "errno" value, causing the wrong error to be passed up. Most likely, it's
> > not save to call BIO functions from inside the callback. My bet is that
> > it'll actually break without this patch, if you stick something that's
> > invalid in there. It's just taht we picked up the "does not exist" error
> > without calling BIO functions.
> >
> > A quick peek at the OpenSSL sources seems to confirm this.
> >
> > I think we want to either attempt to load the client certificate before we
> > connect (and before it's requested) and just queue up the error to show it
> > in only if it's requested, or we want to try some magic around
> > ERR_set_mark()/ERR_pop_to_mark() to clear out any BIO errors before we hand
> > control back.
> >
> > I'll see if I can put together a poc patch - need to reproduce the problem
> > first :-)

Yes, that was the problem. Attached patch fixes the problem for me on
Windows and Linux using the error mark functionality. It seems a lot
cleaner than the other option.

Dave - can you test this one? Assuming that works, I'll go ahead and apply
it.

I also think we have the same problem in the current code, just not for
fopen(). We trap fopen() without anything happening inside OpenSSL, but if
we get an error in the OpenSSL functions we call, something similar would
likely happen.

Should we backpatch all the stuff, or just the error push/pop thing?

//Magnus

Attachment

Re: OpenSSL Applink

From
Dave Page
Date:
Magnus Hagander wrote:
> Yes, that was the problem. Attached patch fixes the problem for me on
> Windows and Linux using the error mark functionality. It seems a lot
> cleaner than the other option.
 >
> Dave - can you test this one? Assuming that works, I'll go ahead and apply
> it.

Yep, looks good here. Thanks.

> I also think we have the same problem in the current code, just not for
> fopen(). We trap fopen() without anything happening inside OpenSSL, but if
> we get an error in the OpenSSL functions we call, something similar would
> likely happen.
>
> Should we backpatch all the stuff, or just the error push/pop thing?

All of it. Anyone building just libpq/psql using the old MSVC makefiles
will probably see the applink problem if they try to use client certs.

/D


Re: OpenSSL Applink

From
Tom Lane
Date:
Dave Page <dpage@postgresql.org> writes:
> Magnus Hagander wrote:
>> Should we backpatch all the stuff, or just the error push/pop thing?

> All of it. Anyone building just libpq/psql using the old MSVC makefiles
> will probably see the applink problem if they try to use client certs.

I'd vote for backpatching, but only as far as 8.2, seeing that we're
abandoning the older branches on Windows.

            regards, tom lane

Re: OpenSSL Applink

From
Magnus Hagander
Date:
On Mon, Oct 01, 2007 at 10:51:01AM -0400, Tom Lane wrote:
> Dave Page <dpage@postgresql.org> writes:
> > Magnus Hagander wrote:
> >> Should we backpatch all the stuff, or just the error push/pop thing?
>
> > All of it. Anyone building just libpq/psql using the old MSVC makefiles
> > will probably see the applink problem if they try to use client certs.
>
> I'd vote for backpatching, but only as far as 8.2, seeing that we're
> abandoning the older branches on Windows.

Should we backpatch a version of it to previous versions that does just the
error stack manipulation, or just ignore on the grounds that nobody has
reported the problem there (it's there, but it's a lot more narrow - I know
it's there, but I havent' been able to provoket it due to not knowing
enough about setting up certificate chains and such)

//Magnus

Re: OpenSSL Applink

From
Tom Lane
Date:
Magnus Hagander <magnus@hagander.net> writes:
> On Mon, Oct 01, 2007 at 10:51:01AM -0400, Tom Lane wrote:
>> I'd vote for backpatching, but only as far as 8.2, seeing that we're
>> abandoning the older branches on Windows.

> Should we backpatch a version of it to previous versions that does just the
> error stack manipulation, or just ignore on the grounds that nobody has
> reported the problem there (it's there, but it's a lot more narrow - I know
> it's there, but I havent' been able to provoket it due to not knowing
> enough about setting up certificate chains and such)

That's only a cosmetic problem (wrong error message), right?  I'd vote
for no backpatch, at least for now --- I'd rather see this change get
through beta testing first.  Anytime you're fooling with interactions
with some other package, the risk of portability issues is high.

            regards, tom lane

Re: OpenSSL Applink

From
Magnus Hagander
Date:
Tom Lane wrote:
> Magnus Hagander <magnus@hagander.net> writes:
>> On Mon, Oct 01, 2007 at 10:51:01AM -0400, Tom Lane wrote:
>>> I'd vote for backpatching, but only as far as 8.2, seeing that we're
>>> abandoning the older branches on Windows.
>
>> Should we backpatch a version of it to previous versions that does just the
>> error stack manipulation, or just ignore on the grounds that nobody has
>> reported the problem there (it's there, but it's a lot more narrow - I know
>> it's there, but I havent' been able to provoket it due to not knowing
>> enough about setting up certificate chains and such)
>
> That's only a cosmetic problem (wrong error message), right?  I'd vote
> for no backpatch, at least for now --- I'd rather see this change get
> through beta testing first.  Anytime you're fooling with interactions
> with some other package, the risk of portability issues is high.

Right.
Applied to HEAD. Will wait for a buildfarm cycle to make sure it doesn't
kill anything else then try to backport to 8.2 (patch didn't apply
cleanly to it)

//Magnus

Re: OpenSSL Applink

From
Heikki Linnakangas
Date:
Magnus Hagander wrote:
> Tom Lane wrote:
>> Magnus Hagander <magnus@hagander.net> writes:
>>> On Mon, Oct 01, 2007 at 10:51:01AM -0400, Tom Lane wrote:
>>>> I'd vote for backpatching, but only as far as 8.2, seeing that we're
>>>> abandoning the older branches on Windows.
>>> Should we backpatch a version of it to previous versions that does just the
>>> error stack manipulation, or just ignore on the grounds that nobody has
>>> reported the problem there (it's there, but it's a lot more narrow - I know
>>> it's there, but I havent' been able to provoket it due to not knowing
>>> enough about setting up certificate chains and such)
>> That's only a cosmetic problem (wrong error message), right?  I'd vote
>> for no backpatch, at least for now --- I'd rather see this change get
>> through beta testing first.  Anytime you're fooling with interactions
>> with some other package, the risk of portability issues is high.
>
> Right.
> Applied to HEAD. Will wait for a buildfarm cycle to make sure it doesn't
> kill anything else then try to backport to 8.2 (patch didn't apply
> cleanly to it)

I guess you guys already found a solution that works, but there's yet
another function, "BIO *BIO_new_mem_buf(void *data, int len)", that we
could use. We could open and read the file all by ourselves into memory,
then call BIO_new_mem_buf and pass that to PEM_read_X509. No need to
pass around file pointers, and we could handle any file I/O errors
ourselves. Presumably certificates are never very big, so reading it all
in memory shouldn't be a problem.

BIO_new_mem_buf was introduced in OpenSSL 0.9.7. What versions do we
support?

--
  Heikki Linnakangas
  EnterpriseDB   http://www.enterprisedb.com

Re: OpenSSL Applink

From
Tom Lane
Date:
Heikki Linnakangas <heikki@enterprisedb.com> writes:
> I guess you guys already found a solution that works, but there's yet
> another function, "BIO *BIO_new_mem_buf(void *data, int len)", that we
> could use. We could open and read the file all by ourselves into memory,
> then call BIO_new_mem_buf and pass that to PEM_read_X509. No need to
> pass around file pointers, and we could handle any file I/O errors
> ourselves. Presumably certificates are never very big, so reading it all
> in memory shouldn't be a problem.

> BIO_new_mem_buf was introduced in OpenSSL 0.9.7. What versions do we
> support?

This seems like a good idea.  To judge from the release history at
http://www.openssl.org/news/
the OpenSSL boys stopped supporting 0.9.6 in 2004, so I figure we
don't have to support it either.  But 0.9.7 is still a live release
branch, so it'd be good if we could play nice with it.

http://www.openssl.org/docs/crypto/BIO_s_mem.html

            regards, tom lane

Re: OpenSSL Applink

From
Magnus Hagander
Date:
Tom Lane wrote:
> Heikki Linnakangas <heikki@enterprisedb.com> writes:
>> I guess you guys already found a solution that works, but there's yet
>> another function, "BIO *BIO_new_mem_buf(void *data, int len)", that we
>> could use. We could open and read the file all by ourselves into memory,
>> then call BIO_new_mem_buf and pass that to PEM_read_X509. No need to
>> pass around file pointers, and we could handle any file I/O errors
>> ourselves. Presumably certificates are never very big, so reading it all
>> in memory shouldn't be a problem.
>
>> BIO_new_mem_buf was introduced in OpenSSL 0.9.7. What versions do we
>> support?
>
> This seems like a good idea.  To judge from the release history at
> http://www.openssl.org/news/
> the OpenSSL boys stopped supporting 0.9.6 in 2004, so I figure we
> don't have to support it either.  But 0.9.7 is still a live release
> branch, so it'd be good if we could play nice with it.
>
> http://www.openssl.org/docs/crypto/BIO_s_mem.html

Not sure it buys us much more than we already have. Sure, we can handle
file I/O. But we still can't handle errors in the parsing of the file.

I think that if we can open the file, then the chance that we fail to
read it is extremely small, compared to the chance that we get a parsing
error.

//Magnus