2013-03-18 19:02:42 +01:00
/******************************************************************************
* Icinga 2 *
2014-03-19 01:02:29 +01:00
* Copyright ( C ) 2012 - 2014 Icinga Development Team ( http : //www.icinga.org) *
2013-03-18 19:02:42 +01:00
* *
* This program is free software ; you can redistribute it and / or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation ; either version 2 *
* of the License , or ( at your option ) any later version . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the Free Software Foundation *
* Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-05-25 16:23:35 +02:00
# include "base/tlsutility.hpp"
2014-08-04 17:13:42 +02:00
# include "base/convert.hpp"
# include "base/logger_fwd.hpp"
# include "base/context.hpp"
2014-10-16 12:27:09 +02:00
# include "base/application.hpp"
2014-08-04 17:13:42 +02:00
2013-03-18 22:40:40 +01:00
namespace icinga
{
2013-03-18 19:02:42 +01:00
static bool l_SSLInitialized = false ;
2014-04-12 21:22:59 +02:00
static boost : : mutex * l_Mutexes ;
2014-05-11 06:30:50 +02:00
static void OpenSSLLockingCallback ( int mode , int type , const char * , int )
2014-04-12 21:22:59 +02:00
{
if ( mode & CRYPTO_LOCK )
l_Mutexes [ type ] . lock ( ) ;
else
l_Mutexes [ type ] . unlock ( ) ;
}
2013-03-18 19:02:42 +01:00
2014-08-01 14:28:32 +02:00
static unsigned long OpenSSLIDCallback ( void )
{
# ifdef _WIN32
2014-08-07 14:23:20 +02:00
return ( unsigned long ) GetCurrentThreadId ( ) ;
2014-08-01 14:28:32 +02:00
# else /* _WIN32 */
2014-08-04 09:50:30 +02:00
return ( unsigned long ) pthread_self ( ) ;
2014-08-01 14:28:32 +02:00
# endif /* _WIN32 */
}
2013-03-18 19:02:42 +01:00
/**
* Initializes the OpenSSL library .
*/
2014-10-15 18:22:56 +02:00
void InitializeOpenSSL ( void )
2013-03-18 19:02:42 +01:00
{
if ( l_SSLInitialized )
return ;
SSL_library_init ( ) ;
SSL_load_error_strings ( ) ;
2013-09-11 17:12:28 +02:00
SSL_COMP_get_compression_methods ( ) ;
2013-03-18 19:02:42 +01:00
2014-04-12 21:22:59 +02:00
l_Mutexes = new boost : : mutex [ CRYPTO_num_locks ( ) ] ;
CRYPTO_set_locking_callback ( & OpenSSLLockingCallback ) ;
2014-08-01 14:28:32 +02:00
CRYPTO_set_id_callback ( & OpenSSLIDCallback ) ;
2014-04-12 21:22:59 +02:00
2013-03-18 19:02:42 +01:00
l_SSLInitialized = true ;
}
/**
* Initializes an SSL context using the specified certificates .
*
* @ param pubkey The public key .
* @ param privkey The matching private key .
* @ param cakey CA certificate chain file .
* @ returns An SSL context .
*/
shared_ptr < SSL_CTX > MakeSSLContext ( const String & pubkey , const String & privkey , const String & cakey )
{
2014-08-04 17:13:42 +02:00
std : : ostringstream msgbuf ;
2014-08-05 11:30:06 +02:00
char errbuf [ 120 ] ;
2013-03-18 19:02:42 +01:00
InitializeOpenSSL ( ) ;
shared_ptr < SSL_CTX > sslContext = shared_ptr < SSL_CTX > ( SSL_CTX_new ( TLSv1_method ( ) ) , SSL_CTX_free ) ;
2014-08-01 14:28:32 +02:00
SSL_CTX_set_mode ( sslContext . get ( ) , SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER ) ;
2013-03-18 19:02:42 +01:00
if ( ! SSL_CTX_use_certificate_chain_file ( sslContext . get ( ) , pubkey . CStr ( ) ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error with public key file ' " < < pubkey < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SSL_CTX_use_certificate_chain_file " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) )
2013-03-18 19:02:42 +01:00
< < boost : : errinfo_file_name ( pubkey ) ) ;
}
if ( ! SSL_CTX_use_PrivateKey_file ( sslContext . get ( ) , privkey . CStr ( ) , SSL_FILETYPE_PEM ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error with private key file ' " < < privkey < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SSL_CTX_use_PrivateKey_file " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) )
2013-03-18 19:02:42 +01:00
< < boost : : errinfo_file_name ( privkey ) ) ;
}
2013-10-15 21:24:55 +02:00
if ( ! SSL_CTX_check_private_key ( sslContext . get ( ) ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error checking private key ' " < < privkey < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-10-15 21:24:55 +02:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SSL_CTX_check_private_key " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-10-15 21:24:55 +02:00
}
2014-10-16 12:27:09 +02:00
if ( ! cakey . IsEmpty ( ) ) {
if ( ! SSL_CTX_load_verify_locations ( sslContext . get ( ) , cakey . CStr ( ) , NULL ) ) {
msgbuf < < " Error loading and verifying locations in ca key file ' " < < cakey < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SSL_CTX_load_verify_locations " )
< < errinfo_openssl_error ( ERR_peek_error ( ) )
< < boost : : errinfo_file_name ( cakey ) ) ;
}
STACK_OF ( X509_NAME ) * cert_names ;
cert_names = SSL_load_client_CA_file ( cakey . CStr ( ) ) ;
if ( cert_names = = NULL ) {
msgbuf < < " Error loading client ca key file ' " < < cakey < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SSL_load_client_CA_file " )
< < errinfo_openssl_error ( ERR_peek_error ( ) )
< < boost : : errinfo_file_name ( cakey ) ) ;
}
SSL_CTX_set_client_CA_list ( sslContext . get ( ) , cert_names ) ;
2013-03-18 19:02:42 +01:00
}
return sslContext ;
}
2013-11-13 10:30:40 +01:00
/**
* Loads a CRL and appends its certificates to the specified SSL context .
*
* @ param context The SSL context .
* @ param crlPath The path to the CRL file .
*/
void AddCRLToSSLContext ( const shared_ptr < SSL_CTX > & context , const String & crlPath )
{
2014-08-04 17:13:42 +02:00
std : : ostringstream msgbuf ;
2014-08-05 11:30:06 +02:00
char errbuf [ 120 ] ;
2013-11-13 10:30:40 +01:00
X509_STORE * x509_store = SSL_CTX_get_cert_store ( context . get ( ) ) ;
X509_LOOKUP * lookup ;
lookup = X509_STORE_add_lookup ( x509_store , X509_LOOKUP_file ( ) ) ;
if ( ! lookup ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error adding X509 store lookup: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-11-13 10:30:40 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " X509_STORE_add_lookup " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-11-13 10:30:40 +01:00
}
if ( X509_LOOKUP_load_file ( lookup , crlPath . CStr ( ) , X509_FILETYPE_PEM ) ! = 0 ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error loading crl file ' " < < crlPath < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-11-13 10:30:40 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " X509_LOOKUP_load_file " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) )
2013-11-13 10:30:40 +01:00
< < boost : : errinfo_file_name ( crlPath ) ) ;
}
X509_VERIFY_PARAM * param = X509_VERIFY_PARAM_new ( ) ;
X509_VERIFY_PARAM_set_flags ( param , X509_V_FLAG_CRL_CHECK ) ;
2013-11-13 10:36:57 +01:00
X509_STORE_set1_param ( x509_store , param ) ;
2013-11-13 10:30:40 +01:00
X509_VERIFY_PARAM_free ( param ) ;
}
2013-03-18 19:02:42 +01:00
/**
* Retrieves the common name for an X509 certificate .
*
* @ param certificate The X509 certificate .
* @ returns The common name .
*/
String GetCertificateCN ( const shared_ptr < X509 > & certificate )
{
2014-08-04 17:13:42 +02:00
std : : ostringstream msgbuf ;
2014-08-05 11:30:06 +02:00
char errbuf [ 120 ] ;
2013-03-18 19:02:42 +01:00
char buffer [ 256 ] ;
int rc = X509_NAME_get_text_by_NID ( X509_get_subject_name ( certificate . get ( ) ) ,
NID_commonName , buffer , sizeof ( buffer ) ) ;
if ( rc = = - 1 ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error with x509 NAME getting text by NID: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " X509_NAME_get_text_by_NID " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-03-18 19:02:42 +01:00
}
return buffer ;
}
/**
* Retrieves an X509 certificate from the specified file .
*
* @ param pemfile The filename .
* @ returns An X509 certificate .
*/
shared_ptr < X509 > GetX509Certificate ( const String & pemfile )
{
2014-08-04 17:13:42 +02:00
std : : ostringstream msgbuf ;
2014-08-05 11:30:06 +02:00
char errbuf [ 120 ] ;
2013-03-18 19:02:42 +01:00
X509 * cert ;
BIO * fpcert = BIO_new ( BIO_s_file ( ) ) ;
if ( fpcert = = NULL ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error creating new BIO: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " BIO_new " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-03-18 19:02:42 +01:00
}
if ( BIO_read_filename ( fpcert , pemfile . CStr ( ) ) < 0 ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error reading pem file ' " < < pemfile < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " BIO_read_filename " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) )
2013-03-18 19:02:42 +01:00
< < boost : : errinfo_file_name ( pemfile ) ) ;
}
cert = PEM_read_bio_X509_AUX ( fpcert , NULL , NULL , NULL ) ;
if ( cert = = NULL ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error on bio X509 AUX reading pem file ' " < < pemfile < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-03-18 19:02:42 +01:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " PEM_read_bio_X509_AUX " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) )
2013-10-17 15:46:50 +02:00
< < boost : : errinfo_file_name ( pemfile ) ) ;
2013-03-18 19:02:42 +01:00
}
BIO_free ( fpcert ) ;
return shared_ptr < X509 > ( cert , X509_free ) ;
}
2014-10-13 13:58:18 +02:00
int MakeX509CSR ( const String & cn , const String & keyfile , const String & csrfile , const String & certfile , bool ca )
2014-04-18 12:14:21 +02:00
{
2014-08-04 17:13:42 +02:00
InitializeOpenSSL ( ) ;
2014-04-18 12:14:21 +02:00
RSA * rsa = RSA_generate_key ( 4096 , RSA_F4 , NULL , NULL ) ;
2014-10-13 12:34:31 +02:00
Log ( LogInformation , " base " , " Writing private key to ' " + keyfile + " '. " ) ;
2014-10-15 16:01:15 +02:00
BIO * bio = BIO_new_file ( const_cast < char * > ( keyfile . CStr ( ) ) , " w " ) ;
2014-04-18 12:14:21 +02:00
PEM_write_bio_RSAPrivateKey ( bio , rsa , NULL , NULL , 0 , NULL , NULL ) ;
BIO_free ( bio ) ;
2014-10-13 12:34:31 +02:00
# ifndef _WIN32
chmod ( keyfile . CStr ( ) , 0600 ) ;
# endif /* _WIN32 */
2014-04-18 12:14:21 +02:00
EVP_PKEY * key = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( key , rsa ) ;
2014-10-13 12:34:31 +02:00
if ( ! certfile . IsEmpty ( ) ) {
2014-10-15 16:01:15 +02:00
X509_NAME * subject = X509_NAME_new ( ) ;
X509_NAME_add_entry_by_txt ( subject , " CN " , MBSTRING_ASC , ( unsigned char * ) cn . CStr ( ) , - 1 , - 1 , 0 ) ;
2014-10-16 12:27:09 +02:00
shared_ptr < X509 > cert = CreateCert ( key , subject , subject , key , ca ) ;
2014-10-15 16:01:15 +02:00
X509_NAME_free ( subject ) ;
2014-10-13 12:34:31 +02:00
Log ( LogInformation , " base " , " Writing X509 certificate to ' " + certfile + " '. " ) ;
2014-10-15 16:01:15 +02:00
2014-10-13 12:34:31 +02:00
bio = BIO_new ( BIO_s_file ( ) ) ;
BIO_write_filename ( bio , const_cast < char * > ( certfile . CStr ( ) ) ) ;
2014-10-16 12:27:09 +02:00
PEM_write_bio_X509 ( bio , cert . get ( ) ) ;
2014-10-13 12:34:31 +02:00
BIO_free ( bio ) ;
}
2014-04-18 12:14:21 +02:00
2014-10-13 13:43:05 +02:00
if ( ! csrfile . IsEmpty ( ) ) {
2014-10-15 16:01:15 +02:00
X509_REQ * req = X509_REQ_new ( ) ;
if ( ! req )
return 0 ;
2014-10-13 13:43:05 +02:00
X509_REQ_set_version ( req , 0 ) ;
X509_REQ_set_pubkey ( req , key ) ;
X509_NAME * name = X509_REQ_get_subject_name ( req ) ;
X509_NAME_add_entry_by_txt ( name , " CN " , MBSTRING_ASC , ( unsigned char * ) cn . CStr ( ) , - 1 , - 1 , 0 ) ;
X509_REQ_sign ( req , key , EVP_sha1 ( ) ) ;
2014-10-15 18:22:56 +02:00
Log ( LogInformation , " base " , " Writing certificate signing request to ' " + csrfile + " '. " ) ;
2014-10-13 13:43:05 +02:00
bio = BIO_new ( BIO_s_file ( ) ) ;
BIO_write_filename ( bio , const_cast < char * > ( csrfile . CStr ( ) ) ) ;
PEM_write_bio_X509_REQ ( bio , req ) ;
BIO_free ( bio ) ;
X509_REQ_free ( req ) ;
}
2014-04-18 12:14:21 +02:00
EVP_PKEY_free ( key ) ;
return 1 ;
}
2014-10-16 12:27:09 +02:00
shared_ptr < X509 > CreateCert ( EVP_PKEY * pubkey , X509_NAME * subject , X509_NAME * issuer , EVP_PKEY * cakey , bool ca , const String & serialfile )
2014-10-15 16:01:15 +02:00
{
X509 * cert = X509_new ( ) ;
ASN1_INTEGER_set ( X509_get_serialNumber ( cert ) , 1 ) ;
X509_gmtime_adj ( X509_get_notBefore ( cert ) , 0 ) ;
X509_gmtime_adj ( X509_get_notAfter ( cert ) , 365 * 24 * 60 * 60 * 30 ) ;
X509_set_pubkey ( cert , pubkey ) ;
X509_set_subject_name ( cert , subject ) ;
X509_set_issuer_name ( cert , issuer ) ;
if ( ca ) {
X509_EXTENSION * ext ;
X509V3_CTX ctx ;
X509V3_set_ctx_nodb ( & ctx ) ;
X509V3_set_ctx ( & ctx , cert , cert , NULL , NULL , 0 ) ;
ext = X509V3_EXT_conf_nid ( NULL , & ctx , NID_basic_constraints , const_cast < char * > ( " critical,CA:TRUE " ) ) ;
if ( ext )
X509_add_ext ( cert , ext , - 1 ) ;
X509_EXTENSION_free ( ext ) ;
}
X509_sign ( cert , cakey , EVP_sha1 ( ) ) ;
2014-10-16 12:27:09 +02:00
return shared_ptr < X509 > ( cert , X509_free ) ;
}
String GetIcingaCADir ( void )
{
return Application : : GetLocalStateDir ( ) + " /lib/icinga2/ca " ;
}
shared_ptr < X509 > CreateCertIcingaCA ( EVP_PKEY * pubkey , X509_NAME * subject )
{
std : : stringstream msgbuf ;
char errbuf [ 120 ] ;
String cadir = GetIcingaCADir ( ) ;
String cakeyfile = cadir + " /ca.key " ;
RSA * rsa ;
BIO * cakeybio = BIO_new_file ( const_cast < char * > ( cakeyfile . CStr ( ) ) , " r " ) ;
if ( ! cakeybio ) {
msgbuf < < " Could not open CA key file ' " < < cakeyfile < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
return shared_ptr < X509 > ( ) ;
}
rsa = PEM_read_bio_RSAPrivateKey ( cakeybio , NULL , NULL , NULL ) ;
if ( ! rsa ) {
msgbuf < < " Could not read RSA key from CA key file ' " < < cakeyfile < < " ': " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
return shared_ptr < X509 > ( ) ;
}
BIO_free ( cakeybio ) ;
String cacertfile = cadir + " /ca.crt " ;
shared_ptr < X509 > cacert = GetX509Certificate ( cacertfile ) ;
EVP_PKEY * privkey = EVP_PKEY_new ( ) ;
EVP_PKEY_assign_RSA ( privkey , rsa ) ;
return CreateCert ( pubkey , subject , X509_get_subject_name ( cacert . get ( ) ) , privkey , false , cadir + " /serial.txt " ) ;
}
String CertificateToString ( const shared_ptr < X509 > & cert )
{
BIO * mem = BIO_new ( BIO_s_mem ( ) ) ;
PEM_write_bio_X509 ( mem , cert . get ( ) ) ;
char * data ;
long len = BIO_get_mem_data ( mem , & data ) ;
String result = String ( data , data + len ) ;
BIO_free ( mem ) ;
return result ;
}
2014-10-16 13:36:25 +02:00
String PBKDF2_SHA1 ( const String & password , const String & salt , int iterations )
2014-10-16 12:27:09 +02:00
{
2014-10-16 13:36:25 +02:00
unsigned char digest [ SHA_DIGEST_LENGTH ] ;
PKCS5_PBKDF2_HMAC_SHA1 ( password . CStr ( ) , password . GetLength ( ) , reinterpret_cast < const unsigned char * > ( salt . CStr ( ) ) , salt . GetLength ( ) ,
iterations , sizeof ( digest ) , digest ) ;
2014-10-16 12:27:09 +02:00
2014-10-16 13:36:25 +02:00
char output [ SHA_DIGEST_LENGTH * 2 + 1 ] ;
for ( int i = 0 ; i < SHA_DIGEST_LENGTH ; i + + )
2014-10-16 12:27:09 +02:00
sprintf ( output + 2 * i , " %02x " , digest [ i ] ) ;
return output ;
2014-10-15 16:01:15 +02:00
}
2013-09-04 15:47:15 +02:00
String SHA256 ( const String & s )
{
2014-08-04 17:13:42 +02:00
std : : ostringstream msgbuf ;
2014-08-05 11:30:06 +02:00
char errbuf [ 120 ] ;
2013-09-04 15:47:15 +02:00
SHA256_CTX context ;
unsigned char digest [ SHA256_DIGEST_LENGTH ] ;
if ( ! SHA256_Init ( & context ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error on SHA256 Init: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-09-04 15:47:15 +02:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SHA256_Init " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-09-04 15:47:15 +02:00
}
if ( ! SHA256_Update ( & context , ( unsigned char * ) s . CStr ( ) , s . GetLength ( ) ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error on SHA256 Update: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-09-04 15:47:15 +02:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SHA256_Update " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-09-04 15:47:15 +02:00
}
if ( ! SHA256_Final ( digest , & context ) ) {
2014-10-15 18:22:56 +02:00
msgbuf < < " Error on SHA256 Final: " < < ERR_peek_error ( ) < < " , \" " < < ERR_error_string ( ERR_peek_error ( ) , errbuf ) < < " \" " ;
2014-08-04 17:13:42 +02:00
Log ( LogCritical , " SSL " , msgbuf . str ( ) ) ;
2013-09-04 15:47:15 +02:00
BOOST_THROW_EXCEPTION ( openssl_error ( )
< < boost : : errinfo_api_function ( " SHA256_Final " )
2014-10-15 18:22:56 +02:00
< < errinfo_openssl_error ( ERR_peek_error ( ) ) ) ;
2013-09-04 15:47:15 +02:00
}
char output [ SHA256_DIGEST_LENGTH * 2 + 1 ] ;
2014-10-16 12:27:09 +02:00
for ( int i = 0 ; i < 32 ; i + + )
2013-09-04 15:47:15 +02:00
sprintf ( output + 2 * i , " %02x " , digest [ i ] ) ;
return output ;
}
2013-03-18 22:40:40 +01:00
}