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);
                                          

Reply via email to