Dear Developers.
Could you do things written in this message ?
/// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/* Target
auditorium of this doc are: developers the Postgresql, developers apps c/c++,
paranoiacs . A hosting(dedicted/virtual) is not safe place for storing the
private key/cert. Here is presented a concept secured way to initialize context
SSL for PGserver. This doc has three parts: 1) module, that will load
dynamically by the PGserver for initializing the context SSL, and import this
into the PGserver address space. 2) some server actions (checking cert & pkey),
and adding new variable into `pg_config'. 3) and some recomendations for adding
new procs into API libpq. PS: this way is not panacea, but is protecting from
fools. PSS: sorry for my english. Thanks for your attention. -- The best
regards.*/
/// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* 1) Part first: Module side: module is a shared library written on `C' - for
get symbol `PGimportSSLCTX' by `dlsym' from the PGserver.*/
// [SOURCEFILE=pg_import_sslctx.c]// for compile it by GCC: gcc -shared -fPIC
-c pg_import_sslctx.c && ld -shared -export-dynamic pg_import_sslctx.o -o
libpg_import_sslctx.so -ldl -lc
#include <stdint.h>#include <sys/types.h>#include <openssl/ssl.h>#include
<openssl/x509.h>
// function for export SSL_CTX into the PGserver address spaceextern int
PGimportSSLCTX ( SSL_CTX **pp_ctx );
void *h_ssl; // handle of `libssl'
// cert and private key in a encrypted form (simulation)uint8_t pkey [] = {'s',
'u', 'p', 'e', 'r', ' ', 'e', 'n', 'c', 'r', 'y', 'p', 't', 'e', 'd', ' ', 'k',
'e', 'y', 0};uint8_t cert [] = {'s', 'u', 'p', 'e', 'r', ' ', 'e', 'n', 'c',
'r', 'y', 'p', 't', 'e', 'd', ' ', 'c', 'e', 'r', 't', 0};
// blank proc decrypting the cert/pkey (simulation)void decrypt (uint8_t *data)
{ return ; }
// simulation of trusted certsuint8_t trusted_cert1 [] = {0, 5, 7, 12, 76, 4,
9};uint8_t trusted_cert2 [] = {89, 5, 4, 12, 56, 11, 0};
// NOTE : for windows, you can use the `dlfcn-win32' , or you can use code
below:#ifdef _WIN32#include <windows.h>#define RTLD_LAZY
0x00001#define RTLD_NOW 0x00002#define RTLD_BINDING_MASK
0x3#define RTLD_NOLOAD 0x00004#define RTLD_GLOBAL 0x00100#define
RTLD_LOCAL 0#define RTLD_NODELETE 0x01000
inline void* dlopen ( const char *f, int m ){ HMODULE *hdll; DWORD flags;
flags = LOAD_WITH_ALTERED_SEARCH_PATH; if( (m & RTLD_LAZY) ){ flags |=
DONT_RESOLVE_DLL_REFERENCES; } if(f == NULL){ hdll = (HMODULE *)
GetModuleHandle ( NULL ); } else { hdll = (HMODULE *) LoadLibraryEx ( f, NULL,
flags ); } return (void *) hdll;}
inline int dlclose ( void* h ) { if ( !FreeLibrary ((HMODULE)h) ){ return -1; }
return 0;}
inline void* dlsym ( void* h, const char *name ) { return (void *)
GetProcAddress ( (HMODULE)h, name );}
#else
#include <dlfcn.h> #include <sys/mman.h>
#endif
// this procedure will be called after loading the shared libvoid _init () {
#if defined (_WIN32) // I don't know how to off swapping on Windows, sorry
:(... const char *filedll = "libssl.dll"; #else mlockall ( MCL_CURRENT ); //
swap off const char *filedll = "libssl.so"; // `libssl.so' is link to
`libssl.so.1.0.0' usually #endif // We are trying load `libssl' h_ssl = dlopen
( filedll, RTLD_NOW | RTLD_NOLOAD ); if ( !h_ssl ) { h_ssl = dlopen ( filedll,
RTLD_NOW | RTLD_LOCAL ); }}
// this procedure will be called before unloading the shared libvoid _fini () {
if ( h_ssl ) { dlclose ( h_ssl ); } // unload `libssl' #ifndef _WIN32
munlockall (); #endif}
// pointers to procedures SSL, imported form shared `libssl'const SSL_METHOD*
(*p_TLSv1_server_method)(void);SSL_CTX* (*p_SSL_CTX_new)(const
SSL_METHOD*);void (*p_SSL_CTX_free)(SSL_CTX*);int
(*p_SSL_CTX_use_PrivateKey)(SSL_CTX*,EVP_PKEY*);int
(*p_SSL_CTX_use_certificate)(SSL_CTX*,X509*);void
(*p_SSL_CTX_set_verify)(SSL_CTX*,int ,int(*)(int,X509_STORE_CTX*));long
(*p_SSL_CTX_ctrl)(SSL_CTX*,int,long,void*);
// realisation:int PGimportSSLCTX ( SSL_CTX **pp_ctx ) { int ret; SSL_CTX *ctx;
const SSL_METHOD *meth; ret = 0; if ( !h_ssl ) { goto end; } // libssl was
not loaded if ( !( p_TLSv1_server_method = dlsym ( h_ssl,
"TLSv1_server_method" ) ) ) { goto end; } // fails get symbol if ( !( meth =
p_TLSv1_server_method () ) ) { goto end; } // fails get TLSv1_server_method if
( !( p_SSL_CTX_new = dlsym ( h_ssl, "SSL_CTX_new" ) ) ) { goto end; } // fails
get symbol if ( !( ctx = p_SSL_CTX_new ( meth) ) ) { goto end; } // fails
create new context // decrypt ours the private key and the cert decrypt ( pkey
); decrypt ( cert ); if ( !( p_SSL_CTX_use_PrivateKey = dlsym ( h_ssl,
"SSL_CTX_use_PrivateKey" ) ) ) { goto end; } // fails get symbol if ( !(
p_SSL_CTX_use_certificate = dlsym ( h_ssl, "SSL_CTX_use_certificate" ) ) ) {
goto end; } // fails get symbol // maybe we need do `d2i_PrivateKey' before
setup pkey/cert into the context ? .. if ( p_SSL_CTX_use_PrivateKey ( ctx,
(EVP_PKEY*) pkey ) <= 0 ) { goto end; } // fails set the private key into the
context if ( p_SSL_CTX_use_certificate ( ctx, (X509*) cert ) <= 0 ) { goto end;
} // fails set the cert into the context if ( !( p_SSL_CTX_set_verify = dlsym
( h_ssl, "SSL_CTX_set_verify" ) ) ) { goto end; } // fails get symbol // set up
rules of verifyng p_SSL_CTX_set_verify ( ctx, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL ); if ( !( p_SSL_CTX_ctrl = dlsym (
h_ssl, "SSL_CTX_ctrl" ) ) ) { goto end; } // fails get symbol // making our own
trusted chain of certs: p_SSL_CTX_ctrl ( ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
(char *)trusted_cert1 ); p_SSL_CTX_ctrl ( ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0,
(char *)trusted_cert2 ); // set up options to the context p_SSL_CTX_ctrl (
ctx, SSL_CTRL_OPTIONS, SSL_OP_NO_SSLv2 |
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION, NULL ); // set up modes to the
context p_SSL_CTX_ctrl ( ctx, SSL_CTRL_MODE, SSL_MODE_ENABLE_PARTIAL_WRITE |
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY, NULL ); ret =
1; end: if ( ret ) { *pp_ctx = ctx; } else if ( ctx ){ if ( ( p_SSL_CTX_free
= dlsym ( h_ssl, "SSL_CTX_free" ) ) ) { p_SSL_CTX_free ( ctx ); } } return
ret;}
// [/SOURCEFILE]
/// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/* 2) Part second: Server side: [CONFIGFILE]
PG_IMPORT_SSLCTX="/usr/lib/postgresql/libpg_import_sslctx.so" [/CONFIGFILE] */
// NOTE : imported from a module the SSL context MUST BE freed by server side
!!!
// a some place in the PGserver source code ...
const char *path2mod; // path to a moduleSSL_CTX *ctx; // the context
ctx = NULL;
// trying to get path to module import ssl context from config fileif ( (
path2mod = get_PG_IMPORT_SSLCTX_from_ConfigFile() ) ) { // we have a path to
module, needs to load it int ret; void *h_mod; // handle of
`libpg_import_sslctx.so' int (*p_PGimportSSLCTX) ( SSL_CTX ** ); // pointer to
`PGimportSSLCTX' proc ret = 0; if ( !( h_mod = dlopen (path2mod, RTLD_NOW |
RTLD_LOCAL) ) ) { goto end; } // can't load the module if ( !( p_PGimportSSLCTX
= dlsym (h_mod, "PGimportSSLCTX") ) ) { goto end; } // can't get the symbol of
importing the SSL context if ( !p_PGimportSSLCTX ( &ctx ) ) { goto end; } //
can't get the SSL context for accepting SSL/TLS connections if (
SSL_CTX_check_private_key(ctx) <= 0 ) { goto end; } // private key and cert are
not match ! fails ! // and other actions, that needed for starting accepting
SSL/TLS connections ... ret = 1; end: if ( h_mod ) { dlclose ( h_mod ); } //
unload the module if ( !ret && ctx ) { SSL_CTX_free ( ctx ); ctx = NULL; } //
fails, needs to free the context }
/// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++/* 3) Part
third: client side (libpq):*/
// will be very good thing to add into libpq API something like:extern PGconn
*PQconnectStart(const char *conninfo, SSL_CTX *ctx);extern PGconn
*PQconnectdb(const char *conninfo, SSL_CTX *ctx);