From a14002d5a4531462c0ae6631323dd038e8d9990e Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Mon, 5 Jan 2015 03:57:19 +0100 Subject: [PATCH] upd: Better configuration, respecting profiles --- src/X509.cpp | 7 +- src/X509.h | 3 +- src/apps/client.cpp | 15 +---- src/apps/signer.cpp | 13 ++-- src/config.cpp | 124 +++++++++++++++++++++--------------- src/mysql.cpp | 13 +++- src/simpleOpensslSigner.cpp | 37 ++++++----- src/simpleOpensslSigner.h | 5 +- src/sslUtil.cpp | 6 ++ src/sslUtil.h | 19 ++++-- src/util.cpp | 25 +++++++- src/util.h | 6 +- 12 files changed, 172 insertions(+), 101 deletions(-) diff --git a/src/X509.cpp b/src/X509.cpp index d5f8bc5..71060e9 100644 --- a/src/X509.cpp +++ b/src/X509.cpp @@ -175,12 +175,13 @@ merr: throw "memerr"; } -void X509Cert::setExtensions( std::shared_ptr caCert, std::vector>& sans ) { +void X509Cert::setExtensions( std::shared_ptr caCert, std::vector>& sans, Profile& prof ) { add_ext( caCert, target, NID_basic_constraints, "critical,CA:FALSE" ); add_ext( caCert, target, NID_subject_key_identifier, "hash" ); add_ext( caCert, target, NID_authority_key_identifier, "keyid,issuer:always" ); - add_ext( caCert, target, NID_key_usage, "critical,nonRepudiation,digitalSignature,keyEncipherment" ); - add_ext( caCert, target, NID_ext_key_usage, "clientAuth, serverAuth" ); + std::string ku = std::string( "critical," ) + prof.ku; + add_ext( caCert, target, NID_key_usage, ku.c_str() ); + add_ext( caCert, target, NID_ext_key_usage, prof.eku.c_str() ); add_ext( caCert, target, NID_info_access, "OCSP;URI:http://ocsp.cacert.org" ); add_ext( caCert, target, NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" ); diff --git a/src/X509.h b/src/X509.h index 5f1b76f..79aabc1 100644 --- a/src/X509.h +++ b/src/X509.h @@ -6,6 +6,7 @@ #include #include "database.h" +#include "sslUtil.h" class X509Req { private: @@ -31,7 +32,7 @@ public: void setIssuerNameFrom( std::shared_ptr ca ); void setPubkeyFrom( std::shared_ptr r ); void setSerialNumber( BIGNUM* num ); - void setExtensions( std::shared_ptr caCert, std::vector>& sans ); + void setExtensions( std::shared_ptr caCert, std::vector>& sans, Profile& prof ); void setTimes( uint32_t before, uint32_t after ); std::shared_ptr sign( std::shared_ptr caKey, std::string signAlg ); }; diff --git a/src/apps/client.cpp b/src/apps/client.cpp index 6e21d6e..6613c94 100644 --- a/src/apps/client.cpp +++ b/src/apps/client.cpp @@ -26,19 +26,6 @@ extern std::vector profiles; extern std::string sqlHost, sqlUser, sqlPass, sqlDB; extern std::string serialPath; -std::string writeBackFile( uint32_t serial, std::string cert ) { - std::string filename = keyDir; - mkdir( filename.c_str(), 0755 ); - filename += "/crt"; - mkdir( filename.c_str(), 0755 ); - filename += "/" + std::to_string( serial / 1000 ); - mkdir( filename.c_str(), 0755 ); - filename += "/" + std::to_string( serial ) + ".crt"; - writeFile( filename, cert ); - std::cout << "wrote to " << filename << std::endl; - return filename; -} - int main( int argc, const char* argv[] ) { ( void ) argc; ( void ) argv; @@ -130,7 +117,7 @@ int main( int argc, const char* argv[] ) { log << "FINE: CERTIFICATE LOG: " << res->log << std::endl; log << "FINE: CERTIFICATE:" << std::endl << res->certificate << std::endl; - std::string fn = writeBackFile( atoi( job->target.c_str() ), res->certificate ); + std::string fn = writeBackFile( job->target.c_str(), res->certificate, keyDir ); res->crt_name = fn; jp->writeBack( job, res ); log << "FINE: signing done." << std::endl; diff --git a/src/apps/signer.cpp b/src/apps/signer.cpp index 44f05d6..6dddf02 100644 --- a/src/apps/signer.cpp +++ b/src/apps/signer.cpp @@ -20,7 +20,6 @@ #endif extern std::string serialPath; -extern std::vector profiles; int main( int argc, const char* argv[] ) { ( void ) argc; @@ -49,14 +48,16 @@ int main( int argc, const char* argv[] ) { std::shared_ptr slip1( BIO_new( toBio() ), BIO_free ); ( ( SlipBIO* )slip1->ptr )->setTarget( std::shared_ptr( new OpensslBIOWrapper( conn ) ) ); - try { - DefaultRecordHandler* dh = new DefaultRecordHandler( std::shared_ptr( new SimpleOpensslSigner( profiles[5] ) ), slip1 ); + DefaultRecordHandler* dh = new DefaultRecordHandler( std::shared_ptr( new SimpleOpensslSigner( ) ), slip1 ); - while( true ) { + while( true ) { + try { dh->handle(); + //} catch( const std::exception &ch ) { + //std::cout << "Real exception: " << typeid(ch).name() << ", " << ch.what() << std::endl; + } catch( char const* ch ) { + std::cout << "Exception: " << ch << std::endl; } - } catch( char const* ch ) { - std::cout << "Exception: " << ch << std::endl; } return -1; diff --git a/src/config.cpp b/src/config.cpp index 5556e93..f11edb1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,21 +1,24 @@ #include #include #include +#include +#include #include "sslUtil.h" std::string keyDir; -std::vector profiles; +std::unordered_map profiles; std::string sqlHost, sqlUser, sqlPass, sqlDB; std::string serialPath; -int parseConfig( std::string path ) { +std::shared_ptr> parseConf( std::string path ) { + std::shared_ptr> map( new std::unordered_map() ); std::ifstream config; config.open( path ); if( !config.is_open() ) { - std::cerr << "config missing" << std::endl; - return 1; + std::cout << "Where is " << path << "?" << std::endl; + throw "Config missing"; } std::string line1; @@ -34,58 +37,80 @@ int parseConfig( std::string path ) { std::string key = line1.substr( 0, splitter ); std::string value = line1.substr( splitter + 1 ); + map->emplace( key, value ); + } + + config.close(); + + return map; +} + +int parseConfig( std::string path ) { + + auto masterConf = parseConf( path ); - if( key == "key.directory" ) { - keyDir = value; + keyDir = masterConf->at( "key.directory" ); + sqlHost = masterConf->at( "sql.host" ); + sqlUser = masterConf->at( "sql.user" ); + sqlPass = masterConf->at( "sql.password" ); + sqlDB = masterConf->at( "sql.database" ); + serialPath = masterConf->at( "serialPath" ); + + std::shared_ptr>> CAs( new std::unordered_map>() ); + + DIR* dp; + struct dirent* ep; + dp = opendir( "profiles" ); + + if( dp == NULL ) { + std::cerr << "Profiles not found " << std::endl; + return -1; + } + + while( ( ep = readdir( dp ) ) ) { + if( ep->d_name[0] == '.' ) { continue; - } else if( key == "sql.host" ) { - sqlHost = value; - } else if( key == "sql.user" ) { - sqlUser = value; - } else if( key == "sql.password" ) { - sqlPass = value; - } else if( key == "sql.database" ) { - sqlDB = value; - } else if( key == "serialPath" ) { - serialPath = value; - } else if( key.compare( 0, 8, "profile." ) == 0 ) { - int numE = key.find( ".", 9 ); - - if( numE == 0 ) { - std::cout << "invalid line: " << line1 << std::endl; - continue; - } - - unsigned int i = atoi( key.substr( 8, numE - 8 ).c_str() ); - std::string rest = key.substr( numE + 1 ); - - if( i + 1 > profiles.size() ) { - profiles.resize( i + 1 ); - } - - if( rest == "key" ) { - profiles[i].key = value; - } else if( rest == "cert" ) { - profiles[i].cert = value; - } else if( rest == "ku" ) { - profiles[i].ku = value; - } else if( rest == "eku" ) { - profiles[i].eku = value; - } else { - std::cout << "invalid line: " << line1 << std::endl; - continue; - } } - } - for( auto& prof : profiles ) { - if( prof.cert != "" && prof.key != "" ) { - std::cout << "Loading profile... " << std::endl; - prof.ca = loadX509FromFile( prof.cert ); - prof.caKey = loadPkeyFromFile( prof.key ); + std::string profileName( ep->d_name ); + + int splitter = profileName.find( "-" ); + + if( splitter == -1 ) { + std::cerr << "Ignoring malformed profile: " << profileName << std::endl; + continue; } + + std::string id = profileName.substr( 0, splitter ); + + if( profileName.substr( profileName.size() - 4 ) != ".cfg" ) { + std::cerr << "Ignoring malformed profile: " << profileName << std::endl; + continue; + } + + auto map = parseConf( std::string( "profiles/" ) + profileName ); + + profileName = profileName.substr( 0, profileName.size() - 4 ); + + Profile prof; + prof.id = std::stoi( id ); + prof.eku = map->at( "eku" ); + prof.ku = map->at( "ku" ); + + if( CAs->find( map->at( "ca" ) ) == CAs->end() ) { + std::shared_ptr ca( new CAConfig( "ca/" + map->at( "ca" ) ) ); + CAs->emplace( map->at( "ca" ), ca ); + } + + prof.ca = CAs->at( map->at( "ca" ) ); + + profiles.emplace( profileName, prof ); + std::cout << "Profile: " << profileName << " up and running." << std::endl; } + ( void ) closedir( dp ); + + std::cout << profiles.size() << " profiles loaded." << std::endl; if( keyDir == "" ) { @@ -93,6 +118,5 @@ int parseConfig( std::string path ) { return -1; } - config.close(); return 0; } diff --git a/src/mysql.cpp b/src/mysql.cpp index 15478ac..973e9d0 100644 --- a/src/mysql.cpp +++ b/src/mysql.cpp @@ -199,7 +199,7 @@ void MySQLJobProvider::failJob( std::shared_ptr job ) { std::shared_ptr MySQLJobProvider::fetchTBSCert( std::shared_ptr job ) { std::shared_ptr cert = std::shared_ptr( new TBSCertificate() ); - std::string q = "SELECT md, profile, csr_name, csr_type FROM certs WHERE id='" + this->escape_string( job->target ) + "'"; + std::string q = "SELECT md, profile, csr_name, csr_type, keyname FROM certs INNER JOIN profiles ON profiles.id = certs.profile WHERE certs.id='" + this->escape_string( job->target ) + "'"; int err = 0; @@ -223,8 +223,17 @@ std::shared_ptr MySQLJobProvider::fetchTBSCert( std::shared_ptr< return std::shared_ptr(); } + std::string profileName = std::string( row[4], row[4] + l[4] ); + cert->md = std::string( row[0], row[0] + l[0] ); - cert->profile = std::string( row[1], row[1] + l[1] ); + std::string profileId = std::string( row[1], row[1] + l[1] ); + + while( profileId.size() < 4 ) { + profileId = "0" + profileId; + } + + cert->profile = profileId + "-" + profileName; + cert->csr = std::string( row[2], row[2] + l[2] ); cert->csr_type = std::string( row[3], row[3] + l[3] ); diff --git a/src/simpleOpensslSigner.cpp b/src/simpleOpensslSigner.cpp index 83c5609..ab87057 100644 --- a/src/simpleOpensslSigner.cpp +++ b/src/simpleOpensslSigner.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -14,18 +15,19 @@ #include "util.h" #include "sslUtil.h" -extern std::vector profiles; +extern std::unordered_map profiles; std::shared_ptr SimpleOpensslSigner::lib_ref = ssl_lib_ref; -SimpleOpensslSigner::SimpleOpensslSigner( Profile& prof ) : prof( prof ) { +SimpleOpensslSigner::SimpleOpensslSigner() { } SimpleOpensslSigner::~SimpleOpensslSigner() { } -std::shared_ptr SimpleOpensslSigner::nextSerial( uint16_t profile ) { - std::string res = readFile( "serial" ); +std::pair, std::string> SimpleOpensslSigner::nextSerial( Profile& prof ) { + uint16_t profile = prof.id; + std::string res = readFile( prof.ca->path + "/serial" ); BIGNUM* bn = 0; @@ -61,19 +63,26 @@ std::shared_ptr SimpleOpensslSigner::nextSerial( uint16_t profile ) { []( char* ref ) { OPENSSL_free( ref ); } ); - writeFile( "serial", serStr.get() ); + writeFile( prof.ca->path + "/serial", serStr.get() ); - return std::shared_ptr( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free ); + return std::pair, std::string>( std::shared_ptr( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free ), std::string( serStr.get() ) ); } std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptr cert ) { std::stringstream signlog; + signlog << "FINE: profile is " << cert->profile << std::endl; + + Profile& prof = profiles.at( cert->profile ); + if( !prof.ca ) { throw "CA-key not found"; } signlog << "FINE: CA-key is correctly loaded." << std::endl; + signlog << "FINE: Profile id is: " << prof.id << std::endl; + signlog << "FINE: ku is: " << prof.ku << std::endl; + signlog << "FINE: eku is: " << prof.eku << std::endl; std::shared_ptr req; @@ -132,22 +141,20 @@ std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptrca ); c.setPubkeyFrom( req ); - long int profile = strtol( cert->profile.c_str(), 0, 10 ); - - if( profile > 0xFFFF || profile < 0 || ( profile == 0 && cert->profile != "0" ) ) { - throw "invalid profile id"; - } - std::shared_ptr ser = nextSerial( profile ); + std::shared_ptr ser; + std::string num; + std::tie( ser, num ) = nextSerial( prof ); c.setSerialNumber( ser.get() ); c.setTimes( 0, 60 * 60 * 24 * 10 ); signlog << "FINE: Setting extensions." << std::endl; - c.setExtensions( prof.ca, cert->SANs ); + c.setExtensions( prof.ca->ca, cert->SANs, prof ); signlog << "FINE: Signed" << std::endl; - std::shared_ptr output = c.sign( prof.caKey, cert->md ); + std::shared_ptr output = c.sign( prof.ca->caKey, cert->md ); signlog << "FINE: all went well" << std::endl; + signlog << "FINE: crt went to: " << writeBackFile( num, output->certificate, prof.ca->path ) << std::endl; output->log = signlog.str(); return output; } diff --git a/src/simpleOpensslSigner.h b/src/simpleOpensslSigner.h index e1c912b..944f3d8 100644 --- a/src/simpleOpensslSigner.h +++ b/src/simpleOpensslSigner.h @@ -9,10 +9,9 @@ class SimpleOpensslSigner : public Signer { private: static std::shared_ptr lib_ref; - Profile& prof; - std::shared_ptr nextSerial( uint16_t profile ); + std::pair, std::string> nextSerial( Profile& prof ); public: - SimpleOpensslSigner( Profile& prof ); + SimpleOpensslSigner(); ~SimpleOpensslSigner(); std::shared_ptr sign( std::shared_ptr cert ); }; diff --git a/src/sslUtil.cpp b/src/sslUtil.cpp index 414bf3a..c7944f2 100644 --- a/src/sslUtil.cpp +++ b/src/sslUtil.cpp @@ -172,3 +172,9 @@ std::shared_ptr openSerial( const std::string name ) { std::shared_ptr b( BIO_new_fd( fileno( f ), 0 ), BIO_free ); return b; } + +CAConfig::CAConfig( std::string path ) { + this->path = path; + ca = loadX509FromFile( path + "/ca.crt" ); + caKey = loadPkeyFromFile( path + "/ca.key" ); +} diff --git a/src/sslUtil.h b/src/sslUtil.h index 2bffc14..3fb54e3 100644 --- a/src/sslUtil.h +++ b/src/sslUtil.h @@ -2,15 +2,26 @@ #include #include #include +#include + +class CAConfig { +public: + std::string path; + + std::shared_ptr ca; + std::shared_ptr caKey; + CAConfig( std::string path ); + +}; + struct Profile { - std::string cert; - std::string key; + uint16_t id; + std::string eku; std::string ku; - std::shared_ptr ca; - std::shared_ptr caKey; + std::shared_ptr ca; }; extern std::shared_ptr ssl_lib_ref; diff --git a/src/util.cpp b/src/util.cpp index 13443af..36f2261 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -1,8 +1,10 @@ #include "util.h" +#include + #include -void writeFile( const std::string& name, const std::string& content ) { +void writeFile( std::string name, std::string content ) { std::ofstream file; file.open( name ); @@ -17,3 +19,24 @@ std::string readFile( const std::string& name ) { return res; } + +std::string writeBackFile( std::string serial, std::string cert, std::string keydir ) { + std::string filename = keydir; + mkdir( filename.c_str(), 0755 ); + filename += "/crt"; + mkdir( filename.c_str(), 0755 ); + std::string first; + + if( serial.length() < 3 ) { + first = "0"; + } else { + first = serial.substr( 0, serial.length() - 3 ); + } + + filename += "/" + first; + mkdir( filename.c_str(), 0755 ); + filename += "/" + serial + ".crt"; + writeFile( filename, cert ); + + return filename; +} diff --git a/src/util.h b/src/util.h index 94ca64f..367d245 100644 --- a/src/util.h +++ b/src/util.h @@ -2,5 +2,7 @@ #include -void writeFile( const std::string& name, const std::string& content ); -std::string readFile( const std::string& name ); +void writeFile( std::string name, std::string content ); +std::string readFile( std::string name ); + +std::string writeBackFile( std::string serial, std::string cert, std::string keydir ); -- 2.39.2