Settings of SSL context for PGserver and for libpq

Поиск
Список
Период
Сортировка
От Dmitrij K
Тема Settings of SSL context for PGserver and for libpq
Дата
Msg-id DUB116-W11959D17D7B0131C5AF6E62C1620@phx.gbl
обсуждение исходный текст
Список 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 space
extern 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 certs
uint8_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 lib
void _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 lib
void _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 module
SSL_CTX *ctx; // the context


ctx = NULL;

// trying to get path to module import ssl context from config file
if ( ( 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);

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Josh Berkus
Дата:
Сообщение: Re: Proposal/design feedback needed: WITHIN GROUP (sql standard ordered set aggregate functions)
Следующее
От: Alvaro Herrera
Дата:
Сообщение: Re: ALTER SYSTEM SET command to change postgresql.conf parameters (RE: Proposal for Allow postgresql.conf values to be changed via SQL [review])