Use BIO functions to avoid passing FILE * pointers to OpenSSL functions.

This fixes potential crashes on old versions of OpenSSL and the requirement on
"Applink" in new versions when building with MSVC and using different
runtimes.

Dave Page with fixes from me.
This commit is contained in:
Magnus Hagander 2007-10-01 20:30:06 +00:00
parent c2862e3cad
commit ec4b6a81f6
1 changed files with 42 additions and 13 deletions

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.94 2007/02/16 17:07:00 tgl Exp $
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.95 2007/10/01 20:30:06 mha Exp $
*
* NOTES
* [ Most of these notes are wrong/obsolete, but perhaps not all ]
@ -111,6 +111,7 @@
#ifdef USE_SSL
#include <openssl/ssl.h>
#include <openssl/bio.h>
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L)
#include <openssl/conf.h>
#endif
@ -567,6 +568,10 @@ verify_peer(PGconn *conn)
* This callback is only called when the server wants a
* client cert.
*
* Since BIO functions can set OpenSSL error codes, we must
* reset the OpenSSL error stack on *every* exit from this
* function once we've started using BIO.
*
* Must return 1 on success, 0 on no data or error.
*/
static int
@ -579,8 +584,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
struct stat buf2;
#endif
char fnbuf[MAXPGPATH];
FILE *fp;
PGconn *conn = (PGconn *) SSL_get_app_data(ssl);
FILE *fp;
BIO *bio;
PGconn *conn = (PGconn *) SSL_get_app_data(ssl);
char sebuf[256];
if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
@ -590,16 +596,21 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
return 0;
}
/* save OpenSSL error stack */
ERR_set_mark();
/* read the user certificate */
snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);
if ((fp = fopen(fnbuf, "r")) == NULL)
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)));
ERR_pop_to_mark();
return 0;
}
if (PEM_read_X509(fp, x509, NULL, NULL) == NULL)
if (PEM_read_bio_X509(bio, x509, NULL, NULL) == NULL)
{
char *err = SSLerrmessage();
@ -607,10 +618,12 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
libpq_gettext("could not read certificate file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
fclose(fp);
BIO_free(bio);
ERR_pop_to_mark();
return 0;
}
fclose(fp);
BIO_free(bio);
#if (SSLEAY_VERSION_NUMBER >= 0x00907000L) && !defined(OPENSSL_NO_ENGINE)
if (getenv("PGSSLKEY"))
@ -625,6 +638,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("invalid value of PGSSLKEY environment variable\n"));
ERR_pop_to_mark();
return 0;
}
@ -640,8 +654,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
engine_str, err);
SSLerrfree(err);
free(engine_str);
ERR_pop_to_mark();
return 0;
}
}
*pkey = ENGINE_load_private_key(engine_ptr, engine_colon + 1,
NULL, NULL);
@ -654,8 +669,9 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
engine_colon + 1, engine_str, err);
SSLerrfree(err);
free(engine_str);
ERR_pop_to_mark();
return 0;
}
}
free(engine_str);
}
else
@ -668,6 +684,7 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("certificate present, but not private key file \"%s\"\n"),
fnbuf);
ERR_pop_to_mark();
return 0;
}
#ifndef WIN32
@ -677,26 +694,32 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" has wrong permissions\n"),
fnbuf);
ERR_pop_to_mark();
return 0;
}
#endif
if ((fp = fopen(fnbuf, "r")) == NULL)
if ((bio = BIO_new_file(fnbuf, "r")) == NULL)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not open private key file \"%s\": %s\n"),
fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));
ERR_pop_to_mark();
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)
{
printfPQExpBuffer(&conn->errorMessage,
libpq_gettext("private key file \"%s\" changed during execution\n"), fnbuf);
ERR_pop_to_mark();
return 0;
}
#endif
if (PEM_read_PrivateKey(fp, pkey, NULL, NULL) == NULL)
if (PEM_read_bio_PrivateKey(bio, pkey, NULL, NULL) == NULL)
{
char *err = SSLerrmessage();
@ -704,10 +727,13 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
libpq_gettext("could not read private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
fclose(fp);
BIO_free(bio);
ERR_pop_to_mark();
return 0;
}
fclose(fp);
BIO_free(bio);
}
/* verify that the cert and key go together */
@ -719,9 +745,12 @@ client_cert_cb(SSL *ssl, X509 **x509, EVP_PKEY **pkey)
libpq_gettext("certificate does not match private key file \"%s\": %s\n"),
fnbuf, err);
SSLerrfree(err);
ERR_pop_to_mark();
return 0;
}
ERR_pop_to_mark();
return 1;
}