From: Daniel Gustafsson =0A= Date: Tue, 4 Oct 2016 14:41:39 +0200=0A= Subject: [PATCH 1/3] WIP: Add support for macOS Secure Transport SSL librar= y=0A= =0A= This is a work in progress trying to add full support for Secure=0A= Transport to the front- and backend. Currently only the frontend=0A= is worked on in an attempt to start small (or rather, somewhere).=0A= ---=0A= configure.in | 14 +=0A= src/Makefile.global.in | 1 +=0A= src/include/pg_config.h.in | 3 +=0A= src/include/pg_config_manual.h | 2 +-=0A= src/interfaces/libpq/Makefile | 5 +=0A= src/interfaces/libpq/fe-connect.c | 4 +=0A= src/interfaces/libpq/fe-secure-securetransport.c | 1589 ++++++++++++++++++= ++++=0A= src/interfaces/libpq/libpq-int.h | 17 +=0A= 8 files changed, 1634 insertions(+), 1 deletion(-)=0A= create mode 100644 src/interfaces/libpq/fe-secure-securetransport.c=0A= =0A= diff --git a/configure.in b/configure.in=0A= index 9850d99..7506bfb 100644=0A= --- a/configure.in=0A= +++ b/configure.in=0A= @@ -713,6 +713,15 @@ AC_MSG_RESULT([$with_openssl])=0A= AC_SUBST(with_openssl)=0A= =20=0A= #=0A= +# macOS Secure Transport=0A= +#=0A= +AC_MSG_CHECKING([whether to build with macOS Secure Transport support])=0A= +PGAC_ARG_BOOL(with, securetransport, no, [build with macOS Secure Transpor= t support],=0A= + [AC_DEFINE([USE_SECURETRANSPORT], 1, [Define to build with macOS Secu= re Transport support. (--with-securetransport)])])=0A= +AC_MSG_RESULT([$with_securetransport])=0A= +AC_SUBST(with_securetransport)=0A= +=0A= +#=0A= # SELinux=0A= #=0A= AC_MSG_CHECKING([whether to build with SELinux support])=0A= @@ -1283,6 +1292,11 @@ if test "$with_openssl" =3D yes ; then=0A= AC_CHECK_HEADER(openssl/err.h, [], [AC_MSG_ERROR([header file is required for OpenSSL])])=0A= fi=0A= =20=0A= +if test "$with_securetransport" =3D yes ; then=0A= + AC_CHECK_HEADER(Security/Security.h, [], [AC_MSG_ERROR([header file is required for Secure Transport])])=0A= + AC_CHECK_HEADER(CoreFoundation/CoreFoundation.h, [], [AC_MSG_ERROR([head= er file is required for Secure Transport]= )])=0A= +fi=0A= +=0A= if test "$with_pam" =3D yes ; then=0A= AC_CHECK_HEADERS(security/pam_appl.h, [],=0A= [AC_CHECK_HEADERS(pam/pam_appl.h, [],=0A= diff --git a/src/Makefile.global.in b/src/Makefile.global.in=0A= index c211a2d..54a4651 100644=0A= --- a/src/Makefile.global.in=0A= +++ b/src/Makefile.global.in=0A= @@ -183,6 +183,7 @@ with_perl =3D @with_perl@=0A= with_python =3D @with_python@=0A= with_tcl =3D @with_tcl@=0A= with_openssl =3D @with_openssl@=0A= +with_securetransport =3D @with_securetransport@=0A= with_selinux =3D @with_selinux@=0A= with_systemd =3D @with_systemd@=0A= with_libxml =3D @with_libxml@=0A= diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in=0A= index 7dbfa90..cf4df0d 100644=0A= --- a/src/include/pg_config.h.in=0A= +++ b/src/include/pg_config.h.in=0A= @@ -842,6 +842,9 @@=0A= /* Define to build with OpenSSL support. (--with-openssl) */=0A= #undef USE_OPENSSL=0A= =20=0A= +/* Define to build with Apple Secure Transport support. (--with-securetran= sport) */=0A= +#undef USE_SECURETRANSPORT=0A= +=0A= /* Define to 1 to build with PAM support. (--with-pam) */=0A= #undef USE_PAM=0A= =20=0A= diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.= h=0A= index a2b2b61..357ebbb 100644=0A= --- a/src/include/pg_config_manual.h=0A= +++ b/src/include/pg_config_manual.h=0A= @@ -152,7 +152,7 @@=0A= * implementation. (Currently, only OpenSSL is supported, but we might ad= d=0A= * more implementations in the future.)=0A= */=0A= -#ifdef USE_OPENSSL=0A= +#if defined(USE_OPENSSL) || defined(USE_SECURETRANSPORT)=0A= #define USE_SSL=0A= #endif=0A= =20=0A= diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile= =0A= index b1789eb..b8aed5a 100644=0A= --- a/src/interfaces/libpq/Makefile=0A= +++ b/src/interfaces/libpq/Makefile=0A= @@ -48,6 +48,11 @@ ifeq ($(with_openssl),yes)=0A= OBJS +=3D fe-secure-openssl.o=0A= endif=0A= =20=0A= +ifeq ($(with_securetransport), yes)=0A= +OBJS +=3D fe-secure-securetransport.o=0A= +override CFLAGS +=3D -framework Security -framework CoreFoundation -fconst= ant-cfstrings=0A= +endif=0A= +=0A= ifeq ($(PORTNAME), cygwin)=0A= override shlib =3D cyg$(NAME)$(DLSUFFIX)=0A= endif=0A= diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-co= nnect.c=0A= index f3a9e5a..e141786 100644=0A= --- a/src/interfaces/libpq/fe-connect.c=0A= +++ b/src/interfaces/libpq/fe-connect.c=0A= @@ -254,6 +254,10 @@ static const internalPQconninfoOption PQconninfoOption= s[] =3D {=0A= "SSL-Mode", "", 12, /* sizeof("verify-full") =3D=3D 12 */=0A= offsetof(struct pg_conn, sslmode)},=0A= =20=0A= + /*=0A= + * SSL Compression is only available in OpenSSL enabled builds making thi= s=0A= + * option a no op when using other SSL libraries.=0A= + */=0A= {"sslcompression", "PGSSLCOMPRESSION", "1", NULL,=0A= "SSL-Compression", "", 1,=0A= offsetof(struct pg_conn, sslcompression)},=0A= diff --git a/src/interfaces/libpq/fe-secure-securetransport.c b/src/interfa= ces/libpq/fe-secure-securetransport.c=0A= new file mode 100644=0A= index 0000000..1b3772e=0A= --- /dev/null=0A= +++ b/src/interfaces/libpq/fe-secure-securetransport.c=0A= @@ -0,0 +1,1589 @@=0A= +/*------------------------------------------------------------------------= -=0A= + *=0A= + * fe-secure-securetransport.c=0A= + * Secure Transport support=0A= + *=0A= + *=0A= + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group= =0A= + * Portions Copyright (c) 1994, Regents of the University of California=0A= + *=0A= + *=0A= + * IDENTIFICATION=0A= + * src/interfaces/libpq/fe-secure-securetransport.c=0A= + *=0A= + * NOTES=0A= + * Unlike the OpenSSL support there is no shared state between connectio= ns=0A= + * so there is no special handling for ENABLE_THREAD_SAFETY.=0A= + *=0A= + * TODO:=0A= + * - CRL support=0A= + * - CRL is handled by the Keychain and there is no (obvious) way to=0A= + * inject x509 CRL records programatically. Perhaps creating a temp=0A= + * keychain for the connection and see if we can manipulate that?=0A= + * - Load certificate/key from keychain=0A= + * - Currently the certificate/key are expected to be files on disk=0A= + * but with a good prefix like keychain:foo we can load directly=0A= + * from the keychain the user wants.=0A= + * - Supprt pkcs12 certificates=0A= + * - Remove use of private API=0A= + * - Remove use of deprecated functions=0A= + * - pgcrypto=0A= + *=0A= + *------------------------------------------------------------------------= -=0A= + */=0A= +=0A= +#include "postgres_fe.h"=0A= +=0A= +#include =0A= +#include =0A= +#include =0A= +=0A= +#include "libpq-fe.h"=0A= +#include "fe-auth.h"=0A= +#include "libpq-int.h"=0A= +=0A= +#include =0A= +#include =0A= +#include =0A= +#include =0A= +#ifdef HAVE_NETINET_TCP_H=0A= +#include =0A= +#endif=0A= +#include =0A= +=0A= +#include =0A= +=0A= +#include =0A= +#include =0A= +#include =0A= +=0A= +/*=0A= + * The number of required key/value pairs in the dictionary used for query= ing=0A= + * the Keychain: Class, Return Reference, MatchLimit, MatchPolicy=0A= + */=0A= +#define KEYCHAIN_SEARCH_SIZE 4=0A= +=0A= +/*=0A= + * Private API call used in the Webkit code for creating an identity from = a=0A= + * certificate with a key. While stable and used in many open source proje= cts=0A= + * it should be replaced with a published API call since private APIs aren= 't=0A= + * subject to the same deprecation rules. Could potentially be replaced by= =0A= + * using SecIdentityCreateWithCertificate() ?=0A= + */=0A= +extern SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator,=0A= + SecCertificateRef certificate,=0A= + SecKeyRef privateKey);=0A= +=0A= +static char *SSLerrmessage(OSStatus errcode);=0A= +static void SSLerrfree(char *err_buf);=0A= +static int SSLsessionstate(PGconn *conn, char *msg, size_t len);=0A= +static const char * SSLciphername(SSLCipherSuite cipher);=0A= +=0A= +static OSStatus SSLSocketRead(SSLConnectionRef conn, void *data,=0A= + size_t *len);=0A= +static OSStatus SSLSocketWrite(SSLConnectionRef conn, const void *data,=0A= + size_t *len);=0A= +static OSStatus SSLOpenClient(PGconn *conn);=0A= +static OSStatus SSLLoadCertificate(PGconn *conn, CFArrayRef *cert_array,= =0A= + CFArrayRef *key_array,=0A= + CFArrayRef *rootcert_array);=0A= +=0A= +static OSStatus import_certificate(const char *path, int size,=0A= + SecExternalFormat format, char *passphrase,=0A= + CFArrayRef *certificate);=0A= +static OSStatus import_pem(const char *path, int size, char *passphrase,= =0A= + CFArrayRef *cert_arr);=0A= +static OSStatus import_pkcs12(const char *path, int size, char *passphrase= ,=0A= + CFArrayRef *cert_arr);=0A= +=0A= +/* ------------------------------------------------------------ */=0A= +/* Public interface */=0A= +/* ------------------------------------------------------------ */=0A= +=0A= +/*=0A= + * Exported function to allow application to tell us it's already=0A= + * initialized Secure Transport and/or libcrypto.=0A= + */=0A= +void=0A= +pgtls_init_library(bool do_ssl, int do_crypto)=0A= +{=0A= +#ifndef __darwin__=0A= + /*=0A= + * Secure Transport is only available on Darwin platforms so autoconf=0A= + * should protect us from ever reaching here=0A= + */=0A= + Assert(false);=0A= +#endif=0A= +}=0A= +=0A= +/*=0A= + * Begin or continue negotiating a secure session.=0A= + */=0A= +PostgresPollingStatusType=0A= +pgtls_open_client(PGconn *conn)=0A= +{=0A= + OSStatus open_status;=0A= +=0A= + CFArrayRef certificate;=0A= + CFArrayRef key;=0A= + CFArrayRef rootcert;=0A= +=0A= + /*=0A= + * If the SSL context hasn't been set up then initiate it, else continue= =0A= + * with handshake=0A= + */=0A= + if (conn->ssl =3D=3D NULL)=0A= + {=0A= + conn->ssl_key_bits =3D 0;=0A= + conn->ssl_buffered =3D 0;=0A= + /*=0A= + * Create the SSL context using the new API introduced in 10.8 since=0A= + * the SSLNewContext() API call was deprecated in 10.9. The standard=0A= + * allocator is used since we are client side.=0A= + */=0A= + conn->ssl =3D SSLCreateContext(NULL /* allocator */,=0A= + kSSLClientSide, kSSLStreamType);=0A= + if (!conn->ssl)=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not create SSL context\n"));=0A= + return PGRES_POLLING_FAILED;=0A= + }=0A= + /*=0A= + * SSLSetProtocolVersionEnabled() is marked as deprecated as of 10.9=0A= + * but the alternative SSLSetSessionConfig() is as of 10.11 not yet=0A= + * documented with the kSSLSessionConfig_xxx constants belonging to=0A= + * the 10.12 SDK. Rely on the deprecation for now until the dust has=0A= + * properly settled around this.=0A= + */=0A= + SSLSetProtocolVersionEnabled(conn->ssl, kTLSProtocol12, true);=0A= +=0A= + open_status =3D SSLSetConnection(conn->ssl, conn);=0A= + if (open_status !=3D noErr)=0A= + goto error;=0A= +=0A= + /*=0A= + * Set the low level functions for reading and writing off a socket=0A= + */=0A= + open_status =3D SSLSetIOFuncs(conn->ssl, SSLSocketRead, SSLSocketWrite);= =0A= + if (open_status !=3D noErr)=0A= + goto error;=0A= +=0A= + /*=0A= + * Load client certificate, private key, and trusted CA certs. The=0A= + * conn->errorMessage will be populated by the certificate loading=0A= + * so we can return without altering it.=0A= + */=0A= + if (SSLLoadCertificate(conn, &certificate, &key, &rootcert) !=3D noErr)= =0A= + {=0A= + pgtls_close(conn);=0A= + return PGRES_POLLING_FAILED;=0A= + }=0A= +=0A= + conn->st_rootcert =3D CFRetain(rootcert);=0A= +=0A= + /*=0A= + * If we are asked to verify the peer hostname, set it as a requirement= =0A= + * on the connection. This must be set before calling SSLHandshake().=0A= + */=0A= + if (strcmp(conn->sslmode, "verify-full") =3D=3D 0)=0A= + {=0A= + /* If we are asked to verify a hostname we dont have, error out */=0A= + if (!conn->pghost)=0A= + {=0A= + pgtls_close(conn);=0A= + return PGRES_POLLING_FAILED;=0A= + }=0A= +=0A= + SSLSetPeerDomainName(conn->ssl, conn->pghost, strlen(conn->pghost));=0A= + }=0A= + }=0A= +=0A= + /*=0A= + * Perform handshake=0A= + */=0A= + open_status =3D SSLOpenClient(conn);=0A= + if (open_status =3D=3D noErr)=0A= + {=0A= + conn->ssl_in_use =3D true;=0A= + return PGRES_POLLING_OK;=0A= + }=0A= +=0A= +error:=0A= + if (open_status !=3D noErr)=0A= + {=0A= + char *err_msg =3D SSLerrmessage(open_status);=0A= + if (conn->errorMessage.len > 0)=0A= + appendPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext(", ssl error: %s\n"), err_msg);=0A= + else=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not establish SSL connection: %s\n"),=0A= + err_msg);=0A= + SSLerrfree(err_msg);=0A= +=0A= + pgtls_close(conn);=0A= + }=0A= +=0A= + return PGRES_POLLING_FAILED;=0A= +}=0A= +=0A= +/*=0A= + * SSLOpenClient=0A= + * Validates remote certificate and performs handshake.=0A= + *=0A= + * If the user has supplied a root certificate we add that to the chain he= re=0A= + * before initiating validation. The caller is responsible for invoking er= ror=0A= + * logging in the case of errors returned.=0A= + */=0A= +static OSStatus=0A= +SSLOpenClient(PGconn *conn)=0A= +{=0A= + OSStatus status;=0A= + SecTrustRef trust =3D NULL;=0A= + SecTrustResultType trust_eval =3D 0;=0A= + bool trusted =3D false;=0A= + bool only_anchor =3D true;=0A= +=0A= + SSLSetSessionOption(conn->ssl, kSSLSessionOptionBreakOnServerAuth, true);= =0A= +=0A= + /*=0A= + * TODO: Is there a better way to repeatedly call SSLHandshake until we g= et=0A= + * another response than an errSSLWouldBlock?=0A= + */=0A= + do=0A= + {=0A= + status =3D SSLHandshake(conn->ssl);=0A= + /* busy-wait loop */=0A= + }=0A= + while (status =3D=3D errSSLWouldBlock || status =3D=3D -1);=0A= +=0A= + if (status !=3D errSSLServerAuthCompleted)=0A= + return status;=0A= +=0A= + /*=0A= + * Get peer server certificate and validate it. SSLCopyPeerTrust() is not= =0A= + * supposed to return a NULL trust on noErr but have been reported to do= =0A= + * in the past so add a belts-and-suspenders check=0A= + */=0A= + status =3D SSLCopyPeerTrust(conn->ssl, &trust);=0A= + if (status !=3D noErr || trust =3D=3D NULL)=0A= + return status;=0A= +=0A= + /*=0A= + * If we have our own root certificate configured then add it to the chai= n=0A= + * of trust and specify that it should be trusted.=0A= + */=0A= + if (conn->st_rootcert)=0A= + {=0A= + status =3D SecTrustSetAnchorCertificates(trust, conn->st_rootcert);=0A= + if (status !=3D noErr)=0A= + return status;=0A= +=0A= + /* We have a trusted local root cert, trust more than anchor */=0A= + only_anchor =3D false;=0A= + }=0A= +=0A= + status =3D SecTrustSetAnchorCertificatesOnly(trust, only_anchor);=0A= + if (status !=3D noErr)=0A= + return status;=0A= +=0A= + status =3D SecTrustEvaluate(trust, &trust_eval);=0A= + if (status =3D=3D errSecSuccess)=0A= + {=0A= + switch (trust_eval)=0A= + {=0A= + /*=0A= + * If 'Unspecified' then an anchor certificate was reached without=0A= + * encountering any explicit user trust. If 'Proceed' then the user=0A= + * has chosen to explicitly trust a certificate in the chain by=0A= + * clicking "Trust" in the Keychain app.=0A= + */=0A= + case kSecTrustResultUnspecified:=0A= + case kSecTrustResultProceed:=0A= + trusted =3D true;=0A= + break;=0A= +=0A= + /*=0A= + * 'Confirm' indicates that an interactive confirmation from the=0A= + * user is requested. This result code was deprecated in 10.9=0A= + * however so treat it as a Deny to avoid having to invoke UI=0A= + * elements from the Keychain.=0A= + */=0A= + case kSecTrustResultConfirm:=0A= + /*=0A= + * 'RecoverableTrustFailure' indicates that the certificate was=0A= + * rejected but might be trusted with minor changes to the eval=0A= + * context (ignoring expired certificate etc). TODO: Opening up to=0A= + * changing the eval context here seems dangerous but we can do=0A= + * better logging of the error by invoking SecTrustGetTrustResult()=0A= + * to get info on exactly what failed; call and extract relevant=0A= + * information to the logstring.=0A= + */=0A= + case kSecTrustResultRecoverableTrustFailure:=0A= + /*=0A= + * The below results are all cases where the certificate should be=0A= + * rejected without further questioning.=0A= + */=0A= + case kSecTrustResultDeny:=0A= + case kSecTrustResultFatalTrustFailure:=0A= + case kSecTrustResultOtherError:=0A= + default:=0A= + trusted =3D false;=0A= + break;=0A= + }=0A= + }=0A= +=0A= + /*=0A= + * TODO: return a better error code than SSLInternalError=0A= + */=0A= + if (!trusted)=0A= + return errSecInternalError;=0A= +=0A= + /*=0A= + * If we reach here the documentation states we need to run the Handshake= =0A= + * again after validating the trust */=0A= + return SSLOpenClient(conn);=0A= +}=0A= +=0A= +/*=0A= + * Is there unread data waiting in the SSL read buffer?=0A= + */=0A= +bool=0A= +pgtls_read_pending(PGconn *conn)=0A= +{=0A= + OSStatus read_status;=0A= + size_t len =3D 0;=0A= +=0A= + read_status =3D SSLGetBufferedReadSize(conn->ssl, &len);=0A= +=0A= + /*=0A= + * Should we get an error back then we assume that subsequent read=0A= + * operations will fail as well.=0A= + */=0A= + return (read_status =3D=3D noErr && len > 0);=0A= +}=0A= +=0A= +/*=0A= + * pgtls_read=0A= + * Read data from a secure connection.=0A= + *=0A= + * On failure, this function is responsible for putting a suitable message= =0A= + * into conn->errorMessage. The caller must still inspect errno, but only= =0A= + * to determine whether to continue/retry after error.=0A= + */=0A= +ssize_t=0A= +pgtls_read(PGconn *conn, void *ptr, size_t len)=0A= +{=0A= + OSStatus read_status;=0A= + size_t n =3D 0;=0A= + ssize_t ret =3D 0;=0A= + int read_errno =3D 0;=0A= + char sess_msg[25];=0A= +=0A= + /*=0A= + * Double-check that we have a connection which is in the correct state= =0A= + * for reading before attempting to pull any data off the wire.=0A= + */=0A= + if (SSLsessionstate(conn, sess_msg, sizeof(sess_msg)) =3D=3D -1)=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("SSL connection is: %s\n"), sess_msg);=0A= + read_errno =3D ECONNRESET;=0A= + return -1;=0A= + }=0A= +=0A= + read_status =3D SSLRead(conn->ssl, ptr, len, &n);=0A= + ret =3D (ssize_t) n;=0A= +=0A= + switch (read_status)=0A= + {=0A= + case noErr:=0A= + break;=0A= + case -1:=0A= + case errSSLWouldBlock:=0A= + /* If we did perform a read then skip EAGAIN */=0A= + if (n =3D=3D 0)=0A= + read_errno =3D EINTR;=0A= + break;=0A= +=0A= + /*=0A= + * Clean disconnections=0A= + */=0A= + case errSSLClosedNoNotify:=0A= + /* fall through */=0A= + case errSSLClosedGraceful:=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("SSL connection has been closed unexpectedly\n"));=0A= + read_errno =3D ECONNRESET;=0A= + ret =3D -1;=0A= + break;=0A= +=0A= + default:=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("unrecognized SSL error %d\n"), read_status);=0A= + read_errno =3D ECONNRESET;=0A= + ret =3D -1;=0A= + break;=0A= + }=0A= +=0A= + SOCK_ERRNO_SET(read_errno);=0A= + return ret;=0A= +}=0A= +=0A= +/*=0A= + * Write data to a secure connection.=0A= + *=0A= + * On failure, this function is responsible for putting a suitable message= =0A= + * into conn->errorMessage. The caller must still inspect errno, but only= =0A= + * to determine whether to continue/retry after error.=0A= + */=0A= +ssize_t=0A= +pgtls_write(PGconn *conn, const void *ptr, size_t len)=0A= +{=0A= + OSStatus write_status;=0A= + size_t n =3D 0;=0A= + ssize_t ret =3D 0;=0A= + int write_errno =3D 0;=0A= + char sess_msg[25];=0A= +=0A= + /*=0A= + * Double-check that we have a connection which is in the correct state= =0A= + * for writing before attempting to push any data on to the wire or the= =0A= + * local SSL buffer.=0A= + */=0A= + if (SSLsessionstate(conn, sess_msg, sizeof(sess_msg)) =3D=3D -1)=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("SSL connection is: %s\n"), sess_msg);=0A= + write_errno =3D ECONNRESET;=0A= + return -1;=0A= + }=0A= +=0A= + if (conn->ssl_buffered > 0)=0A= + {=0A= + write_status =3D SSLWrite(conn->ssl, NULL, 0, &n);=0A= +=0A= + if (write_status =3D=3D noErr)=0A= + {=0A= + ret =3D conn->ssl_buffered;=0A= + conn->ssl_buffered =3D 0;=0A= + }=0A= + else if (write_status =3D=3D errSSLWouldBlock || write_status =3D=3D -1)= =0A= + {=0A= + ret =3D 0;=0A= + write_errno =3D EINTR;=0A= + }=0A= + else=0A= + {=0A= + /* TODO: pull error message string, on read too */=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("unrecognized SSL error: %d\n"), write_status);=0A= + ret =3D -1;=0A= + write_errno =3D ECONNRESET;=0A= + }=0A= + }=0A= + else=0A= + {=0A= + write_status =3D SSLWrite(conn->ssl, ptr, len, &n);=0A= + ret =3D n;=0A= +=0A= + switch (write_status)=0A= + {=0A= + case noErr:=0A= + break;=0A= +=0A= + case -1:=0A= + case errSSLWouldBlock:=0A= + conn->ssl_buffered =3D len;=0A= + ret =3D 0;=0A= +#ifdef EAGAIN=0A= + write_errno =3D EAGAIN;=0A= +#else=0A= + write_errno =3D EINTR;=0A= +#endif=0A= + break;=0A= +=0A= + /*=0A= + * Clean disconnections=0A= + */=0A= + case errSSLClosedNoNotify:=0A= + /* fall through */=0A= + case errSSLClosedGraceful:=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("SSL connection has been closed unexpectedly\n"));=0A= + write_errno =3D ECONNRESET;=0A= + ret =3D -1;=0A= + break;=0A= +=0A= + default:=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("unrecognized SSL error %d\n"), write_status);=0A= + write_errno =3D ECONNRESET;=0A= + ret =3D -1;=0A= + break;=0A= + }=0A= + }=0A= +=0A= + SOCK_ERRNO_SET(write_errno);=0A= + return ret;=0A= +}=0A= +=0A= +/*=0A= + * Initialize SSL system, in particular creating the SSL_context object=0A= + * that will be shared by all SSL-using connections in this process.=0A= + *=0A= + * In threadsafe mode, this includes setting up libcrypto callback functio= ns=0A= + * to do thread locking.=0A= + *=0A= + * If the caller has told us (through PQinitOpenSSL) that he's taking care= =0A= + * of libcrypto, we expect that callbacks are already set, and won't try t= o=0A= + * override it.=0A= + *=0A= + * The conn parameter is only used to be able to pass back an error=0A= + * message - no connection-local setup is made here.=0A= + *=0A= + * Returns 0 if OK, -1 on failure (with a message in conn->errorMessage).= =0A= + */=0A= +int=0A= +pgtls_init(PGconn *conn)=0A= +{=0A= + conn->ssl_buffered =3D 0;=0A= + conn->ssl_in_use =3D false;=0A= +=0A= + return 0;=0A= +}=0A= +=0A= +/*=0A= + * pgtls_close=0A= + * Close SSL connection.=0A= + *=0A= + * This function must cope with connections in all states of disrepair sin= ce=0A= + * it will be called from pgtls_open_client to clean up any potentially us= ed=0A= + * resources in case it breaks halfway.=0A= + */=0A= +void=0A= +pgtls_close(PGconn *conn)=0A= +{=0A= + if (!conn->ssl)=0A= + return;=0A= +=0A= + CFRelease(conn->st_rootcert);=0A= +=0A= + SSLClose(conn->ssl);=0A= + CFRelease(conn->ssl);=0A= +=0A= + /* TODO: Release any certificates loaded */=0A= +=0A= + conn->ssl =3D NULL;=0A= + conn->ssl_in_use =3D false;=0A= +}=0A= +=0A= +=0A= +=0A= +/*=0A= + * The amount of read bytes is returned in the len variable=0A= + */=0A= +static OSStatus=0A= +SSLSocketRead(SSLConnectionRef conn, void *data, size_t *len)=0A= +{=0A= + OSStatus status =3D noErr;=0A= + int res;=0A= +=0A= + res =3D pqsecure_raw_read((PGconn *) conn, data, *len);=0A= +=0A= + if (res < 0)=0A= + {=0A= + /* TODO: Handle more error cases? */=0A= + switch (SOCK_ERRNO)=0A= + {=0A= + case ENOENT:=0A= + status =3D errSSLClosedGraceful;=0A= + break;=0A= +=0A= +#ifdef EAGAIN=0A= + case EAGAIN:=0A= +#endif=0A= +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK !=3D EAGAIN)= )=0A= + case EWOULDBLOCK:=0A= +#endif=0A= + case EINTR:=0A= + status =3D errSSLWouldBlock;=0A= + break;=0A= + }=0A= + }=0A= +=0A= + *len =3D res;=0A= +=0A= + return status;=0A= +}=0A= +=0A= +static OSStatus=0A= +SSLSocketWrite(SSLConnectionRef conn, const void *data, size_t *len)=0A= +{=0A= + OSStatus status =3D noErr;=0A= + int res;=0A= +=0A= + res =3D pqsecure_raw_write((PGconn *) conn, data, *len);=0A= +=0A= + if (res < 0)=0A= + {=0A= + /* TODO: Handle more error cases? */=0A= + switch (SOCK_ERRNO)=0A= + {=0A= +#ifdef EAGAIN=0A= + case EAGAIN:=0A= +#endif=0A= +#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK !=3D EAGAIN)= )=0A= + case EWOULDBLOCK:=0A= +#endif=0A= + case EINTR:=0A= + status =3D errSSLWouldBlock;=0A= + break;=0A= +=0A= + default:=0A= + break;=0A= + }=0A= + }=0A= +=0A= + *len =3D res;=0A= +=0A= + return status;=0A= +}=0A= +=0A= +static OSStatus=0A= +import_pem(const char *path, int size, char *passphrase, CFArrayRef *cert_= arr)=0A= +{=0A= + return import_certificate(path, size, kSecFormatPEMSequence, passphrase, = cert_arr);=0A= +}=0A= +=0A= +static OSStatus=0A= +import_pkcs12(const char *path, int size, char *passphrase, CFArrayRef *ce= rt_arr)=0A= +{=0A= + return import_certificate(path, size, kSecFormatPKCS12, passphrase, cert_= arr);=0A= +}=0A= +=0A= +/*=0A= + * import_certificate_keychain=0A= + *=0A= + * Queries the local keychain for a certificate with the passed identity.= =0A= + */=0A= +static OSStatus=0A= +import_certificate_keychain(const char *identity, SecIdentityRef *certific= ate)=0A= +{=0A= + OSStatus status =3D errSecItemNotFound;=0A= + CFTypeRef key[KEYCHAIN_SEARCH_SIZE];=0A= + CFTypeRef val[KEYCHAIN_SEARCH_SIZE];=0A= + CFDictionaryRef identity_search;=0A= + CFStringRef identity_ref;=0A= +=0A= + identity_ref =3D CFStringCreateWithCString(NULL /* allocator */,=0A= + identity, kCFStringEncodingUTF8);=0A= + key[0] =3D kSecClass;=0A= + val[0] =3D kSecClassIdentity;=0A= + key[1] =3D kSecReturnRef;=0A= + val[1] =3D kCFBooleanTrue;=0A= + key[2] =3D kSecMatchLimit;=0A= + val[2] =3D kSecMatchLimitOne;=0A= + key[3] =3D kSecMatchPolicy;=0A= + val[3] =3D SecPolicyCreateSSL(false, identity_ref);=0A= +=0A= + identity_search =3D CFDictionaryCreate(NULL /* allocator */,=0A= + (const void **) key,=0A= + (const void **) val,=0A= + KEYCHAIN_SEARCH_SIZE,=0A= + &kCFCopyStringDictionaryKeyCallBacks,=0A= + &kCFTypeDictionaryValueCallBacks);=0A= +=0A= + status =3D SecItemCopyMatching(identity_search, (CFTypeRef *) certificate= );=0A= +=0A= + CFRelease(identity_search);=0A= + CFRelease(val[3]);=0A= + CFRelease(identity_ref);=0A= +=0A= + return status;=0A= +}=0A= +=0A= +static OSStatus=0A= +import_certificate(const char *path, int size, SecExternalFormat format,= =0A= + char *passphrase, CFArrayRef *certificate)=0A= +{=0A= + OSStatus status;=0A= + CFDataRef data_ref;=0A= + CFStringRef file_type;=0A= + SecExternalItemType item_type;=0A= + SecItemImportExportKeyParameters params;=0A= +=0A= + FILE *fp;=0A= + UInt8 *certdata;=0A= +=0A= + Assert(path && strlen(path) > 0);=0A= +=0A= + fp =3D fopen(path, "r");=0A= + if (!fp)=0A= + return errSecInternalError;=0A= +=0A= + certdata =3D malloc(size);=0A= + if (!certdata)=0A= + {=0A= + fclose(fp);=0A= + return errSecAllocate;=0A= + }=0A= +=0A= + /* TODO: should we use fopen()/fread() here or other fs abstractions */= =0A= + if (fread(certdata, 1, size, fp) !=3D size)=0A= + {=0A= + fclose(fp);=0A= + return errSecInternalError;=0A= + }=0A= + fclose(fp);=0A= +=0A= + data_ref =3D CFDataCreate(NULL /* allocator */, certdata, size);=0A= +=0A= + memset(¶ms, 0, sizeof(SecItemImportExportKeyParameters));=0A= + params.version =3D SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;=0A= + /* Set OS default access control on the imported key */=0A= + params.flags =3D kSecKeyNoAccessControl;=0A= + if (passphrase)=0A= + params.passphrase =3D CFStringCreateWithCString(NULL, passphrase,=0A= + kCFStringEncodingUTF8);=0A= +=0A= + /*=0A= + * Provide a synthetic file ending for the certificate file to aid the=0A= + * parsing of the certificate, the default name of ".crt" isn't terribly= =0A= + * helpful for figuring out the type=0A= + */=0A= + if (format =3D=3D kSecFormatPKCS12)=0A= + file_type =3D CFSTR(".pkcs12");=0A= + else=0A= + file_type =3D CFSTR(".pem");=0A= +=0A= + item_type =3D kSecItemTypeCertificate;=0A= +=0A= + status =3D SecItemImport(data_ref, file_type, &format, &item_type,=0A= + 0 /* flags */, ¶ms, NULL /* keychain */,=0A= + certificate);=0A= +=0A= + if (status !=3D errSecSuccess)=0A= + return status;=0A= +=0A= + return status;=0A= +}=0A= +=0A= +/*=0A= + * Since failures can come from multiple places, the PGconn errorMessage i= s=0A= + * populated here even for SSL library errors.=0A= + */=0A= +static OSStatus=0A= +SSLLoadCertificate(PGconn *conn, CFArrayRef *cert_array, CFArrayRef *key_a= rray,=0A= + CFArrayRef *rootcert_array)=0A= +{=0A= + OSStatus status;=0A= + struct stat buf;=0A= + char homedir[MAXPGPATH];=0A= + char fnbuf[MAXPGPATH];=0A= + char sebuf[256];=0A= + bool have_homedir;=0A= + bool have_cert;=0A= + char *ssl_err_msg;=0A= + CFMutableArrayRef cert_copy;=0A= + SecIdentityRef identity;=0A= + SecCertificateRef cert_ref;=0A= + SecKeyRef key_ref;=0A= +=0A= + /*=0A= + * We'll need the home directory if any of the relevant parameters are=0A= + * defaulted. If pqGetHomeDirectory fails, act as though none of the=0A= + * files could be found.=0A= + */=0A= + if (!(conn->sslcert && strlen(conn->sslcert) > 0) ||=0A= + !(conn->sslkey && strlen(conn->sslkey) > 0) ||=0A= + !(conn->sslrootcert && strlen(conn->sslrootcert) > 0) ||=0A= + !(conn->sslcrl && strlen(conn->sslcrl) > 0))=0A= + have_homedir =3D pqGetHomeDirectory(homedir, sizeof(homedir));=0A= + else /* won't need it */=0A= + have_homedir =3D false;=0A= +=0A= + /* Read the client certificate file */=0A= + if (conn->sslcert && strlen(conn->sslcert) > 0)=0A= + strlcpy(fnbuf, conn->sslcert, sizeof(fnbuf));=0A= + else if (have_homedir)=0A= + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_CERT_FILE);=0A= + else=0A= + fnbuf[0] =3D '\0';=0A= +=0A= + if (fnbuf[0] =3D=3D '\0')=0A= + {=0A= + /* no home directory, proceed without a client cert */=0A= + have_cert =3D false;=0A= + }=0A= + else if (stat(fnbuf, &buf) !=3D 0)=0A= + {=0A= + /*=0A= + * If file is not present, just go on without a client cert; server=0A= + * might or might not accept the connection. Any other error,=0A= + * however, is grounds for complaint.=0A= + */=0A= + if (errno !=3D ENOENT && errno !=3D ENOTDIR)=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not open certificate file \"%s\": %s\n"),=0A= + fnbuf, pqStrerror(errno, sebuf, sizeof(sebuf)));=0A= + return errSecInternalError;=0A= + }=0A= + have_cert =3D false;=0A= + }=0A= + else=0A= + {=0A= + status =3D import_pem(fnbuf, buf.st_size, NULL, cert_array);=0A= + if (status !=3D noErr)=0A= + {=0A= + ssl_err_msg =3D SSLerrmessage(status);=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not load certificate file \"%s\": (%d) %s\n"),= =0A= + fnbuf, status, ssl_err_msg);=0A= + SSLerrfree(ssl_err_msg);=0A= + return status;=0A= + }=0A= +=0A= + have_cert =3D true;=0A= + }=0A= +=0A= + if (have_cert)=0A= + {=0A= + if (conn->sslkey && strlen(conn->sslkey) > 0)=0A= + strlcpy(fnbuf, conn->sslkey, sizeof(fnbuf));=0A= + else if (have_homedir)=0A= + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, USER_KEY_FILE);=0A= + else=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("certificate present, but private key file not foun= d\n"));=0A= + return errSecInternalError;=0A= + }=0A= +=0A= + if (stat(fnbuf, &buf) !=3D 0)=0A= + {=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("certificate present, but not private key file \"%s= \"\n"),=0A= + fnbuf);=0A= + return errSecInternalError;=0A= + }=0A= +=0A= + status =3D import_pem(fnbuf, buf.st_size, NULL, key_array);=0A= + if (status !=3D noErr)=0A= + {=0A= + ssl_err_msg =3D SSLerrmessage(status);=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not load private key file \"%s\": %s\n"),=0A= + fnbuf, ssl_err_msg);=0A= + SSLerrfree(ssl_err_msg);=0A= + return status;=0A= + }=0A= +=0A= + cert_ref =3D (SecCertificateRef) CFArrayGetValueAtIndex(*cert_array, 0);= =0A= + key_ref =3D (SecKeyRef) CFArrayGetValueAtIndex(*key_array, 0);=0A= +=0A= + identity =3D SecIdentityCreate(NULL /* allocator */, cert_ref, key_ref);= =0A= +=0A= + cert_copy =3D CFArrayCreateMutableCopy(NULL /* allocator */, 0, *cert_ar= ray);=0A= + CFArraySetValueAtIndex(cert_copy, 0, identity);=0A= +=0A= + /* FIXME: CFRelease whats not needed */=0A= +=0A= + status =3D SSLSetCertificate(conn->ssl, cert_copy);=0A= +=0A= + CFRelease(cert_copy);=0A= +=0A= + if (status !=3D noErr)=0A= + {=0A= + ssl_err_msg =3D SSLerrmessage(status);=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not set certificate for connection: (%d) %s\n"),= =0A= + status, ssl_err_msg);=0A= + SSLerrfree(ssl_err_msg);=0A= + return status;=0A= + }=0A= + }=0A= +=0A= + /* Load the root cert */=0A= + if (conn->sslrootcert && strlen(conn->sslrootcert) > 0)=0A= + strlcpy(fnbuf, conn->sslrootcert, sizeof(fnbuf));=0A= + else if (have_homedir)=0A= + snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOT_CERT_FILE);=0A= + else=0A= + fnbuf[0] =3D '\0';=0A= +=0A= + if (fnbuf[0] !=3D '\0')=0A= + {=0A= + if (stat(fnbuf, &buf) !=3D 0)=0A= + {=0A= + /*=0A= + * stat() failed; assume root file doesn't exist. If sslmode is=0A= + * verify-ca or verify-full, this is an error. Otherwise, continue=0A= + * without performing any server cert verification.=0A= + */=0A= + if (conn->sslmode[0] =3D=3D 'v') /* "verify-ca" or "verify-full" */=0A= + {=0A= + /*=0A= + * The only way to reach here with an empty filename is if=0A= + * pqGetHomeDirectory failed. That's a sufficiently unusual case=0A= + * that it seems worth having a specialized error message for it.=0A= + */=0A= + if (fnbuf[0] =3D=3D '\0')=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not get home directory to locate root cert= ificate file\n"=0A= + "Either provide the file or change sslmode to disable server = certificate verification.\n"));=0A= + else=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("root certificate file \"%s\" does not exist\n"=0A= + "Either provide the file or change sslmode to disable server ce= rtificate verification.\n"), fnbuf);=0A= + return errSecInternalError;=0A= + }=0A= + }=0A= + else=0A= + {=0A= + status =3D import_pem(fnbuf, buf.st_size, NULL, rootcert_array);=0A= + if (status !=3D noErr)=0A= + {=0A= + ssl_err_msg =3D SSLerrmessage(status);=0A= + printfPQExpBuffer(&conn->errorMessage,=0A= + libpq_gettext("could not load root certificate file \"%s\": %s\n"),= =0A= + fnbuf, ssl_err_msg);=0A= + SSLerrfree(ssl_err_msg);=0A= + return status;=0A= + }=0A= +=0A= + /* TODO: Load the CRL */=0A= + }=0A= + }=0A= +=0A= + /*=0A= + * Reaching here implies that the certificate and key has been loaded and= =0A= + * verified, now we can safely set the key size used.=0A= + */=0A= + conn->ssl_key_bits =3D SecKeyGetBlockSize(key_ref);=0A= + return noErr;=0A= +}=0A= +=0A= +/* ------------------------------------------------------------ */=0A= +/* SSL information functions */=0A= +/* ------------------------------------------------------------ */=0A= +=0A= +int=0A= +PQsslInUse(PGconn *conn)=0A= +{=0A= + if (!conn)=0A= + return 0;=0A= + return conn->ssl_in_use;=0A= +}=0A= +=0A= +/*=0A= + * Return pointer to the Secure Transport SSL Context object.=0A= + */=0A= +void *=0A= +PQgetssl(PGconn *conn)=0A= +{=0A= + if (!conn)=0A= + return NULL;=0A= + return conn->ssl;=0A= +}=0A= +=0A= +void *=0A= +PQsslStruct(PGconn *conn, const char *struct_name)=0A= +{=0A= + if (!conn)=0A= + return NULL;=0A= + if (strcmp(struct_name, "SecureTransport") =3D=3D 0)=0A= + return conn->ssl;=0A= + return NULL;=0A= +}=0A= +=0A= +const char *const *=0A= +PQsslAttributeNames(PGconn *conn)=0A= +{=0A= + static const char *const result[] =3D {=0A= + "library",=0A= + "key_bits",=0A= + "cipher",=0A= + "protocol",=0A= + NULL=0A= + };=0A= +=0A= + return result;=0A= +}=0A= +=0A= +const char *=0A= +PQsslAttribute(PGconn *conn, const char *attribute_name)=0A= +{=0A= + SSLCipherSuite cipher;=0A= + SSLProtocol protocol;=0A= + OSStatus status;=0A= + const char *attribute =3D NULL;=0A= +=0A= + if (!conn || !conn->ssl)=0A= + return NULL;=0A= +=0A= + if (strcmp(attribute_name, "library") =3D=3D 0)=0A= + attribute =3D "SecureTransport";=0A= + else if (strcmp(attribute_name, "key_bits") =3D=3D 0)=0A= + {=0A= + if (conn->ssl_key_bits > 0)=0A= + {=0A= + static char sslbits_str[10];=0A= + snprintf(sslbits_str, sizeof(sslbits_str), "%d", conn->ssl_key_bits);= =0A= + attribute =3D sslbits_str;=0A= + }=0A= + }=0A= + else if (strcmp(attribute_name, "cipher") =3D=3D 0)=0A= + {=0A= + status =3D SSLGetNegotiatedCipher(conn->ssl, &cipher);=0A= + if (status =3D=3D noErr)=0A= + return SSLciphername(cipher);=0A= + }=0A= + else if (strcmp(attribute_name, "protocol") =3D=3D 0)=0A= + {=0A= + status =3D SSLGetNegotiatedProtocolVersion(conn->ssl, &protocol);=0A= + if (status =3D=3D noErr)=0A= + {=0A= + switch (protocol)=0A= + {=0A= + case kTLSProtocol11:=0A= + attribute =3D "TLSv1.1";=0A= + break;=0A= + case kTLSProtocol12:=0A= + attribute =3D "TLSv1.2";=0A= + break;=0A= + default:=0A= + break;=0A= + }=0A= + }=0A= + }=0A= +=0A= + return attribute;=0A= +}=0A= +=0A= +/* ------------------------------------------------------------ */=0A= +/* Secure Transport Information Functions */=0A= +/* ------------------------------------------------------------ */=0A= +=0A= +/*=0A= + * Obtain reason string for passed SSL errcode=0A= + */=0A= +static char ssl_noerr[] =3D "no SSL error reported";=0A= +static char ssl_nomem[] =3D "out of memory allocating error description";= =0A= +#define SSL_ERR_LEN 128=0A= +=0A= +static char *=0A= +SSLerrmessage(OSStatus errcode)=0A= +{=0A= + char *err_buf;=0A= + const char *tmp;=0A= + CFStringRef err_msg;=0A= +=0A= + if (errcode =3D=3D noErr || errcode =3D=3D errSecSuccess)=0A= + return ssl_noerr;=0A= +=0A= + err_buf =3D malloc(SSL_ERR_LEN);=0A= + if (!err_buf)=0A= + return ssl_nomem;=0A= +=0A= + err_msg =3D SecCopyErrorMessageString(errcode, NULL);=0A= + if (err_msg)=0A= + {=0A= + tmp =3D CFStringGetCStringPtr(err_msg, kCFStringEncodingUTF8);=0A= + strlcpy(err_buf, tmp, SSL_ERR_LEN);=0A= + CFRelease(err_msg);=0A= + }=0A= + else=0A= + snprintf(err_buf, sizeof(err_buf), _("SSL error code %d"), errcode);=0A= +=0A= + return err_buf;=0A= +}=0A= +=0A= +static void=0A= +SSLerrfree(char *err_buf)=0A= +{=0A= + if (err_buf && err_buf !=3D ssl_nomem && err_buf !=3D ssl_noerr)=0A= + free(err_buf);=0A= +}=0A= +=0A= +/*=0A= + * SSLsessionstate=0A= + *=0A= + * Returns 0 if the connection is open and -1 in case the connection is cl= osed=0A= + * or its status unknown. If msg is non-NULL the current state is copied w= ith=0A= + * at most len characters.=0A= + */=0A= +static int=0A= +SSLsessionstate(PGconn *conn, char *msg, size_t len)=0A= +{=0A= + SSLSessionState state =3D -1;=0A= + OSStatus status =3D errSecInternalError;=0A= + const char *status_msg;=0A= +=0A= + /*=0A= + * If conn->ssl isn't defined we will report "Unknown" which it could be= =0A= + * argued being correct or not, but since we don't know if there has ever= =0A= + * been a connection at all it's not more correct to say "Closed" or=0A= + * "Aborted".=0A= + */=0A= + if (conn->ssl)=0A= + status =3D SSLGetSessionState(conn->ssl, &state);=0A= +=0A= + switch (state)=0A= + {=0A= + case kSSLConnected:=0A= + status_msg =3D "Connected";=0A= + status =3D 0;=0A= + break;=0A= + case kSSLHandshake:=0A= + status_msg =3D "Handshake";=0A= + status =3D 0;=0A= + break;=0A= + case kSSLIdle:=0A= + status_msg =3D "Idle";=0A= + status =3D 0;=0A= + break;=0A= + case kSSLClosed:=0A= + status_msg =3D "Closed";=0A= + status =3D -1;=0A= + break;=0A= + case kSSLAborted:=0A= + status_msg =3D "Aborted";=0A= + status =3D -1;=0A= + break;=0A= + default:=0A= + status_msg =3D "Unknown";=0A= + status =3D -1;=0A= + break;=0A= + }=0A= +=0A= + if (msg)=0A= + strlcpy(msg, status_msg, len);=0A= +=0A= + return (status =3D=3D noErr ? 0 : -1);=0A= +}=0A= +=0A= +/*=0A= + * SSLciphername=0A= + *=0A= + * Translate an SSLCipherSuite code into a string literal suitable for pri= nting=0A= + * in log/informational messages to the user. Since this implementation of= the=0A= + * Secure Transport lib doesn't support SSLv2/v3 these ciphernames are omi= tted.=0A= + */=0A= +static const char *=0A= +SSLciphername(SSLCipherSuite cipher)=0A= +{=0A= + switch (cipher)=0A= + {=0A= + case TLS_NULL_WITH_NULL_NULL:=0A= + return "NULL_WITH_NULL_NULL";=0A= + break;=0A= +=0A= + /* TLS addenda using AES, per RFC 3268 */=0A= + case TLS_RSA_WITH_AES_128_CBC_SHA:=0A= + return "RSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_128_CBC_SHA:=0A= + return "DH_DSS_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_128_CBC_SHA:=0A= + return "DH_RSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:=0A= + return "DHE_DSS_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:=0A= + return "DHE_RSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_128_CBC_SHA:=0A= + return "DH_anon_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_RSA_WITH_AES_256_CBC_SHA:=0A= + return "RSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_256_CBC_SHA:=0A= + return "DH_DSS_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_256_CBC_SHA:=0A= + return "DH_RSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:=0A= + return "DHE_DSS_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:=0A= + return "DHE_RSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_256_CBC_SHA:=0A= + return "DH_anon_WITH_AES_256_CBC_SHA";=0A= + break;=0A= +=0A= + /* ECDSA addenda, RFC 4492 */=0A= + case TLS_ECDH_ECDSA_WITH_NULL_SHA:=0A= + return "ECDH_ECDSA_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:=0A= + return "ECDH_ECDSA_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:=0A= + return "ECDH_ECDSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:=0A= + return "ECDH_ECDSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_NULL_SHA:=0A= + return "ECDHE_ECDSA_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:=0A= + return "ECDHE_ECDSA_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:=0A= + return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:=0A= + return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_NULL_SHA:=0A= + return "ECDH_RSA_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_RC4_128_SHA:=0A= + return "ECDH_RSA_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "ECDH_RSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:=0A= + return "ECDH_RSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:=0A= + return "ECDH_RSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_NULL_SHA:=0A= + return "ECDHE_RSA_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_RC4_128_SHA:=0A= + return "ECDHE_RSA_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:=0A= + return "ECDHE_RSA_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:=0A= + return "ECDHE_RSA_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_anon_WITH_NULL_SHA:=0A= + return "ECDH_anon_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_ECDH_anon_WITH_RC4_128_SHA:=0A= + return "ECDH_anon_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:=0A= + return "ECDH_anon_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:=0A= + return "ECDH_anon_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:=0A= + return "ECDH_anon_WITH_AES_256_CBC_SHA";=0A= + break;=0A= +=0A= + /* Server provided RSA certificate for key exchange. */=0A= + case TLS_RSA_WITH_NULL_MD5:=0A= + return "RSA_WITH_NULL_MD5";=0A= + break;=0A= + case TLS_RSA_WITH_NULL_SHA:=0A= + return "RSA_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_RSA_WITH_RC4_128_MD5:=0A= + return "RSA_WITH_RC4_128_MD5";=0A= + break;=0A= + case TLS_RSA_WITH_RC4_128_SHA:=0A= + return "RSA_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_RSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "RSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_RSA_WITH_NULL_SHA256:=0A= + return "RSA_WITH_NULL_SHA256";=0A= + break;=0A= + case TLS_RSA_WITH_AES_128_CBC_SHA256:=0A= + return "RSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_RSA_WITH_AES_256_CBC_SHA256:=0A= + return "RSA_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= +=0A= + /*=0A= + * Server-authenticated (and optionally client-authenticated)=0A= + * Diffie-Hellman.=0A= + */=0A= + case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:=0A= + return "DH_DSS_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "DH_RSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:=0A= + return "DHE_DSS_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:=0A= + return "DHE_RSA_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:=0A= + return "DH_DSS_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:=0A= + return "DH_RSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:=0A= + return "DHE_DSS_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:=0A= + return "DHE_RSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:=0A= + return "DH_DSS_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:=0A= + return "DH_RSA_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:=0A= + return "DHE_DSS_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:=0A= + return "DHE_RSA_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= +=0A= + /* Completely anonymous Diffie-Hellman */=0A= + case TLS_DH_anon_WITH_RC4_128_MD5:=0A= + return "DH_anon_WITH_RC4_128_MD5";=0A= + break;=0A= + case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:=0A= + return "DH_anon_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_128_CBC_SHA256:=0A= + return "DH_anon_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_256_CBC_SHA256:=0A= + return "DH_anon_WITH_AES_256_CBC_SHA256";=0A= + break;=0A= +=0A= + /* Addendum from RFC 4279, TLS PSK */=0A= + case TLS_PSK_WITH_RC4_128_SHA:=0A= + return "PSK_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_PSK_WITH_3DES_EDE_CBC_SHA:=0A= + return "PSK_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_PSK_WITH_AES_128_CBC_SHA:=0A= + return "PSK_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_PSK_WITH_AES_256_CBC_SHA:=0A= + return "PSK_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_RC4_128_SHA:=0A= + return "DHE_PSK_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:=0A= + return "DHE_PSK_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:=0A= + return "DHE_PSK_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:=0A= + return "DHE_PSK_WITH_AES_256_CBC_SHA";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_RC4_128_SHA:=0A= + return "RSA_PSK_WITH_RC4_128_SHA";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:=0A= + return "RSA_PSK_WITH_3DES_EDE_CBC_SHA";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:=0A= + return "RSA_PSK_WITH_AES_128_CBC_SHA";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:=0A= + return "RSA_PSK_WITH_AES_256_CBC_SHA";=0A= + break;=0A= +=0A= + /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */= =0A= + case TLS_PSK_WITH_NULL_SHA:=0A= + return "PSK_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_NULL_SHA:=0A= + return "DHE_PSK_WITH_NULL_SHA";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_NULL_SHA:=0A= + return "RSA_PSK_WITH_NULL_SHA";=0A= + break;=0A= +=0A= + /*=0A= + * Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites=0A= + * for TLS.=0A= + */=0A= + case TLS_RSA_WITH_AES_128_GCM_SHA256:=0A= + return "RSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_RSA_WITH_AES_256_GCM_SHA384:=0A= + return "RSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:=0A= + return "DHE_RSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:=0A= + return "DHE_RSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:=0A= + return "DH_RSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:=0A= + return "DH_RSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:=0A= + return "DHE_DSS_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:=0A= + return "DHE_DSS_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:=0A= + return "DH_DSS_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:=0A= + return "DH_DSS_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_128_GCM_SHA256:=0A= + return "DH_anon_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DH_anon_WITH_AES_256_GCM_SHA384:=0A= + return "DH_anon_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= +=0A= + /* RFC 5487 - PSK with SHA-256/384 and AES GCM */=0A= + case TLS_PSK_WITH_AES_128_GCM_SHA256:=0A= + return "PSK_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_PSK_WITH_AES_256_GCM_SHA384:=0A= + return "PSK_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:=0A= + return "DHE_PSK_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:=0A= + return "DHE_PSK_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:=0A= + return "RSA_PSK_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:=0A= + return "RSA_PSK_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_PSK_WITH_AES_128_CBC_SHA256:=0A= + return "PSK_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_PSK_WITH_AES_256_CBC_SHA384:=0A= + return "PSK_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_PSK_WITH_NULL_SHA256:=0A= + return "PSK_WITH_NULL_SHA256";=0A= + break;=0A= + case TLS_PSK_WITH_NULL_SHA384:=0A= + return "PSK_WITH_NULL_SHA384";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:=0A= + return "DHE_PSK_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:=0A= + return "DHE_PSK_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_NULL_SHA256:=0A= + return "DHE_PSK_WITH_NULL_SHA256";=0A= + break;=0A= + case TLS_DHE_PSK_WITH_NULL_SHA384:=0A= + return "DHE_PSK_WITH_NULL_SHA384";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:=0A= + return "RSA_PSK_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:=0A= + return "RSA_PSK_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_NULL_SHA256:=0A= + return "RSA_PSK_WITH_NULL_SHA256";=0A= + break;=0A= + case TLS_RSA_PSK_WITH_NULL_SHA384:=0A= + return "RSA_PSK_WITH_NULL_SHA384";=0A= + break;=0A= +=0A= + /*=0A= + * Addenda from rfc 5289 Elliptic Curve Cipher Suites with=0A= + * HMAC SHA-256/384.=0A= + */=0A= + case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:=0A= + return "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:=0A= + return "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:=0A= + return "ECDH_ECDSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:=0A= + return "ECDH_ECDSA_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:=0A= + return "ECDHE_RSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:=0A= + return "ECDHE_RSA_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:=0A= + return "ECDH_RSA_WITH_AES_128_CBC_SHA256";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:=0A= + return "ECDH_RSA_WITH_AES_256_CBC_SHA384";=0A= + break;=0A= +=0A= + /*=0A= + * Addenda from rfc 5289 Elliptic Curve Cipher Suites with=0A= + * SHA-256/384 and AES Galois Counter Mode (GCM)=0A= + */=0A= + case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:=0A= + return "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:=0A= + return "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:=0A= + return "ECDH_ECDSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:=0A= + return "ECDH_ECDSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:=0A= + return "ECDHE_RSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:=0A= + return "ECDHE_RSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:=0A= + return "ECDH_RSA_WITH_AES_128_GCM_SHA256";=0A= + break;=0A= + case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:=0A= + return "ECDH_RSA_WITH_AES_256_GCM_SHA384";=0A= + break;=0A= +=0A= + default:=0A= + break;=0A= + }=0A= +=0A= + return NULL;=0A= +}=0A= diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-= int.h=0A= index be6c370..649d22f 100644=0A= --- a/src/interfaces/libpq/libpq-int.h=0A= +++ b/src/interfaces/libpq/libpq-int.h=0A= @@ -82,6 +82,15 @@ typedef struct=0A= #endif=0A= #endif /* USE_OPENSSL */=0A= =20=0A= +#ifdef USE_SECURETRANSPORT=0A= +#define Size pg_Size=0A= +#define uint64 pg_uint64=0A= +#include =0A= +#include =0A= +#undef Size=0A= +#undef uint64=0A= +#endif=0A= +=0A= /*=0A= * POSTGRES backend dependent Constants.=0A= */=0A= @@ -439,6 +448,14 @@ struct pg_conn=0A= * OpenSSL version changes */=0A= #endif=0A= #endif /* USE_OPENSSL */=0A= +=0A= +#ifdef USE_SECURETRANSPORT=0A= + SSLContextRef ssl; /* SSL context reference */=0A= + CFArrayRef st_rootcert;=0A= + ssize_t ssl_buffered;=0A= + int ssl_key_bits;=0A= +#endif /* USE_SECURETRANSPORT */=0A= +=0A= #endif /* USE_SSL */=0A= =20=0A= #ifdef ENABLE_GSS=0A= --=20=0A= 2.6.4 (Apple Git-63)=0A= =0A= --Apple-Mail=_9549589E-0CF6-4351-B71B-F9BC7C5EA4D8 Content-Disposition: attachment; filename=0002-Enable-ssl-tests-to-be-using-a-different-set-of-Post.patch Content-Type: application/octet-stream; name="0002-Enable-ssl-tests-to-be-using-a-different-set-of-Post.patch" Content-Transfer-Encoding: quoted-printable