Settings of SSL context for PGserver and for libpq

From: Dmitrij K <kdiman(at)live(dot)ru>
To: "pgsql-hackers(at)postgresql(dot)org" <pgsql-hackers(at)postgresql(dot)org>
Subject: Settings of SSL context for PGserver and for libpq
Date: 2013-07-18 19:49:10
Message-ID: DUB116-W11959D17D7B0131C5AF6E62C1620@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

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

Browse pgsql-hackers by date

  From Date Subject
Next Message Indrajit Roychoudhury 2013-07-18 20:02:29 Re: Fatal error after starting postgres : sys identifiers must be different
Previous Message Stephen Frost 2013-07-18 19:40:24 Re: Improvement of checkpoint IO scheduler for stable transaction responses