From ab317a7803ad0ff688ab8fb452d13d8bdd09fd60 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Wed, 7 Jan 2015 01:01:40 +0100 Subject: [PATCH] add: Adding CRL generation Currently this only supports complete transfers of the CRL --- src/config.cpp | 30 ++++--- src/config.h | 1 + src/crypto/CRL.cpp | 124 +++++++++++++++++++++++++++++ src/crypto/CRL.h | 34 ++++++++ src/crypto/remoteSigner.cpp | 9 ++- src/crypto/remoteSigner.h | 2 +- src/crypto/signer.h | 3 +- src/crypto/simpleOpensslSigner.cpp | 64 ++------------- src/crypto/simpleOpensslSigner.h | 3 +- src/io/recordHandler.cpp | 11 +-- test/.gitignore | 1 + test/genTestData.sh | 11 +++ test/src/CRL.cpp | 43 ++++++++++ 13 files changed, 251 insertions(+), 85 deletions(-) create mode 100644 src/crypto/CRL.cpp create mode 100644 src/crypto/CRL.h create mode 100644 test/src/CRL.cpp diff --git a/src/config.cpp b/src/config.cpp index a518db5..b746bad 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -46,17 +46,7 @@ std::shared_ptr> parseConf( std::st return map; } -int parseConfig( std::string path ) { - - auto masterConf = parseConf( path ); - - 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" ); - +int parseProfiles() { CAs = std::unordered_map>(); DIR* dp; @@ -114,10 +104,28 @@ int parseConfig( std::string path ) { std::cout << profiles.size() << " profiles loaded." << std::endl; + return 0; +} + +int parseConfig( std::string path ) { + + auto masterConf = parseConf( path ); + + 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" ); + if( keyDir == "" ) { std::cerr << "Missing config property key.directory" << std::endl; return -1; } + if( parseProfiles() != 0 ) { + return -1; + } + return 0; } diff --git a/src/config.h b/src/config.h index a4ce789..cac138b 100644 --- a/src/config.h +++ b/src/config.h @@ -3,3 +3,4 @@ #include int parseConfig( std::string path ); +void parseProfiles(); diff --git a/src/crypto/CRL.cpp b/src/crypto/CRL.cpp new file mode 100644 index 0000000..dd32670 --- /dev/null +++ b/src/crypto/CRL.cpp @@ -0,0 +1,124 @@ +#include "CRL.h" + +#include + +CRL::CRL( std::string path ) { + std::shared_ptr bio( BIO_new_file( path.c_str(), "r" ), free ); + crl = std::shared_ptr( PEM_read_bio_X509_CRL( bio.get(), 0, NULL, 0 ), X509_CRL_free ); + + if( !crl ) { + crl = std::shared_ptr( X509_CRL_new(), X509_CRL_free ); + } +} + +std::string CRL::revoke( std::string serial, std::string time ) { + BIGNUM* serBN = 0; + + if( ! BN_hex2bn( &serBN, serial.c_str() ) ) { + throw "hex2bn malloc fail"; + } + + std::shared_ptr serBNP( serBN, BN_free ); + std::shared_ptr ser( BN_to_ASN1_INTEGER( serBN, NULL ), ASN1_INTEGER_free ); + + if( !ser ) { + throw "BN Malloc fail"; + } + + std::shared_ptr tmptm( ASN1_TIME_new(), ASN1_TIME_free ); + + if( !tmptm ) { + throw "ASN1-Time Malloc fail"; + } + + X509_gmtime_adj( tmptm.get(), 0 ); + + X509_REVOKED* rev = X509_REVOKED_new(); + X509_REVOKED_set_serialNumber( rev, ser.get() ); + + if( time != "" ) { + const unsigned char* data = ( unsigned char* )( time.data() ); + d2i_ASN1_UTCTIME( &rev->revocationDate, &data, time.size() ); + } else { + X509_REVOKED_set_revocationDate( rev, tmptm.get() ); + } + + X509_CRL_add0_revoked( crl.get(), rev ); + + int len = i2d_ASN1_UTCTIME( tmptm.get(), NULL ); + unsigned char* buffer = ( unsigned char* ) OPENSSL_malloc( len ); + unsigned char* pos = buffer; + i2d_ASN1_UTCTIME( tmptm.get(), &pos ); + std::string rettime = std::string( ( char* ) buffer, len ); + OPENSSL_free( buffer ); + return rettime; +} + +void CRL::sign( std::shared_ptr ca ) { + // Updating necessary CRL props + std::shared_ptr tmptm( ASN1_TIME_new(), ASN1_TIME_free ); + + if( !tmptm ) { + throw "ASN1-Time Malloc fail"; + } + + X509_gmtime_adj( tmptm.get(), 0 ); + + if( !X509_CRL_set_issuer_name( crl.get(), X509_get_subject_name( ca->ca.get() ) ) ) { + throw "Setting issuer failed"; + } + + X509_CRL_set_lastUpdate( crl.get(), tmptm.get() ); + + if( !X509_time_adj_ex( tmptm.get(), 1, 10, NULL ) ) { + throw "Updating time failed"; + } + + X509_CRL_set_nextUpdate( crl.get(), tmptm.get() ); + + // Sorting and signing + X509_CRL_sort( crl.get() ); + X509_CRL_sign( crl.get(), ca->caKey.get(), EVP_sha256() ); +} + +bool CRL::verify( std::shared_ptr ca ) { + std::shared_ptr pk( X509_get_pubkey( ca->ca.get() ), EVP_PKEY_free ); + return X509_CRL_verify( crl.get(), pk.get() ) > 0; +} + +std::string CRL::toString() { + // Write out the new CRL + std::shared_ptr mem( BIO_new( BIO_s_mem() ), BIO_free ); + PEM_write_bio_X509_CRL( mem.get(), crl.get() ); + BUF_MEM* bptr; + BIO_get_mem_ptr( mem.get(), &bptr ); + std::string newCRL( bptr->data, bptr->length ); + return newCRL; +} + +std::string CRL::getSignature() { + int len = i2d_X509_ALGOR( crl->sig_alg, NULL ); + len += i2d_ASN1_BIT_STRING( crl->signature, NULL ); + len += i2d_ASN1_UTCTIME( crl->crl->lastUpdate, NULL ); + len += i2d_ASN1_UTCTIME( crl->crl->nextUpdate, NULL ); + + unsigned char* buffer = ( unsigned char* ) OPENSSL_malloc( len ); + unsigned char* pos = buffer; + i2d_X509_ALGOR( crl->sig_alg, &pos ); + i2d_ASN1_BIT_STRING( crl->signature, &pos ); + i2d_ASN1_UTCTIME( crl->crl->lastUpdate, &pos ); + i2d_ASN1_UTCTIME( crl->crl->nextUpdate, &pos ); + std::string res = std::string( ( char* ) buffer, len ); + OPENSSL_free( buffer ); + + return res; +} + +void CRL::setSignature( std::string signature ) { + const unsigned char* data = ( unsigned char* )( signature.data() ); + const unsigned char* buffer = data; + d2i_X509_ALGOR( &crl->sig_alg, &buffer, signature.size() ); + d2i_ASN1_BIT_STRING( &crl->signature, &buffer, signature.size() + buffer - data ); + d2i_ASN1_UTCTIME( &crl->crl->lastUpdate, &buffer, signature.size() + buffer - data ); + d2i_ASN1_UTCTIME( &crl->crl->nextUpdate, &buffer, signature.size() + buffer - data ); +} diff --git a/src/crypto/CRL.h b/src/crypto/CRL.h new file mode 100644 index 0000000..4e3deb7 --- /dev/null +++ b/src/crypto/CRL.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "crypto/sslUtil.h" + +class CRL { +private: + std::shared_ptr crl; +public: + CRL( std::string path ); + + /** + * Adds the serial to this serial. + * @param serial the serial to remove (as hex string) + * @param time the "revokation time" (der-encoded) + * @returns DER-encoded UTCTIME of the revoked time + */ + std::string revoke( std::string serial, std::string time ); + + /** + * Signs this CRL. + * @param ca the CA to sign with + */ + void sign( std::shared_ptr ca ); + + bool verify( std::shared_ptr ca ); + + std::string getSignature(); + void setSignature( std::string signature ); + + std::string toString(); +}; diff --git a/src/crypto/remoteSigner.cpp b/src/crypto/remoteSigner.cpp index a6ea578..f04f6d3 100644 --- a/src/crypto/remoteSigner.cpp +++ b/src/crypto/remoteSigner.cpp @@ -1,4 +1,5 @@ #include "remoteSigner.h" +#include "util.h" #include @@ -139,7 +140,7 @@ std::shared_ptr RemoteSigner::sign( std::shared_ptr RemoteSigner::revoke( std::shared_ptr ca, std::string serial ) { +std::shared_ptr RemoteSigner::revoke( std::shared_ptr ca, std::string serial ) { ( void )BIO_reset( target.get() ); std::shared_ptr ssl( SSL_new( ctx.get() ), SSL_free ); @@ -161,7 +162,7 @@ std::shared_ptr RemoteSigner::revoke( std::shared_ptr ca, st if( length <= 0 ) { std::cout << "Error, no response data" << std::endl; - return std::shared_ptr(); + return std::shared_ptr(); } payload = parseCommand( head, std::string( buffer.data(), length ), log ); @@ -175,11 +176,13 @@ std::shared_ptr RemoteSigner::revoke( std::shared_ptr ca, st throw "Invalid response command."; } + writeFile( ca->path + "/ca.crl", payload ); + if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) { // need to close the connection twice std::cout << "SSL shutdown failed" << std::endl; } - return std::shared_ptr(); + return std::shared_ptr(); } void RemoteSigner::setLog( std::shared_ptr target ) { diff --git a/src/crypto/remoteSigner.h b/src/crypto/remoteSigner.h index 09331bb..1be28ed 100644 --- a/src/crypto/remoteSigner.h +++ b/src/crypto/remoteSigner.h @@ -20,7 +20,7 @@ public: RemoteSigner( std::shared_ptr target, std::shared_ptr ctx ); ~RemoteSigner(); std::shared_ptr sign( std::shared_ptr cert ); - std::shared_ptr revoke( std::shared_ptr ca, std::string serial ); + std::shared_ptr revoke( std::shared_ptr ca, std::string serial ); void setLog( std::shared_ptr target ); }; diff --git a/src/crypto/signer.h b/src/crypto/signer.h index d9ab74e..44b2546 100644 --- a/src/crypto/signer.h +++ b/src/crypto/signer.h @@ -4,9 +4,10 @@ #include "db/database.h" #include "crypto/sslUtil.h" +#include "crypto/CRL.h" class Signer { public: virtual std::shared_ptr sign( std::shared_ptr cert ) = 0; - virtual std::shared_ptr revoke( std::shared_ptr ca, std::string serial ) = 0; + virtual std::shared_ptr revoke( std::shared_ptr ca, std::string serial ) = 0; }; diff --git a/src/crypto/simpleOpensslSigner.cpp b/src/crypto/simpleOpensslSigner.cpp index cd02a96..8eb97d5 100644 --- a/src/crypto/simpleOpensslSigner.cpp +++ b/src/crypto/simpleOpensslSigner.cpp @@ -63,6 +63,7 @@ std::pair, std::string> SimpleOpensslSigner::nextSerial( []( char* ref ) { OPENSSL_free( ref ); } ); + writeFile( prof.ca->path + "/serial", serStr.get() ); return std::pair, std::string>( std::shared_ptr( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free ), std::string( serStr.get() ) ); @@ -159,67 +160,12 @@ std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptr SimpleOpensslSigner::revoke( std::shared_ptr ca, std::string serial ) { +std::shared_ptr SimpleOpensslSigner::revoke( std::shared_ptr ca, std::string serial ) { std::string crlpath = ca->path + "/ca.crl"; - std::shared_ptr bio( BIO_new_file( crlpath.c_str(), "r" ), free ); - std::shared_ptr crl( PEM_read_bio_X509_CRL( bio.get(), 0, NULL, 0 ), X509_CRL_free ); - std::cout << "Starting revocation" << std::endl; - - if( !crl ) { - std::cout << "CRL was not loaded" << std::endl; - crl = std::shared_ptr( X509_CRL_new(), X509_CRL_free ); - } - - BIGNUM* serBN = 0; - - if( ! BN_hex2bn( &serBN, serial.c_str() ) ) { - //error - } - - std::shared_ptr serBNP( serBN, BN_free ); - std::shared_ptr ser( BN_to_ASN1_INTEGER( serBN, NULL ), ASN1_INTEGER_free ); - - if( !ser ) { - // error - } - - std::shared_ptr tmptm( ASN1_TIME_new(), ASN1_TIME_free ); - - if( !tmptm ) { - // error - } - - X509_gmtime_adj( tmptm.get(), 0 ); - - X509_REVOKED* rev = X509_REVOKED_new(); - X509_REVOKED_set_serialNumber( rev, ser.get() ); - X509_REVOKED_set_revocationDate( rev, tmptm.get() ); - - X509_CRL_add0_revoked( crl.get(), rev ); - - if( !X509_CRL_set_issuer_name( crl.get(), X509_get_subject_name( ca->ca.get() ) ) ) { - // error - } - - X509_CRL_set_lastUpdate( crl.get(), tmptm.get() ); - - if( !X509_time_adj_ex( tmptm.get(), 1, 10, NULL ) ) { - // error - } - - X509_CRL_set_nextUpdate( crl.get(), tmptm.get() ); - - - std::cout << "Signing" << std::endl; - X509_CRL_sort( crl.get() ); - X509_CRL_sign( crl.get(), ca->caKey.get(), EVP_sha256() ); - - std::cout << "writing bio" << std::endl; - std::shared_ptr bioOut( BIO_new_file( crlpath.c_str(), "w" ), BIO_free ); - PEM_write_bio_X509_CRL( bioOut.get(), crl.get() ); - std::cout << "finished crl" << std::endl; + std::shared_ptr crl( new CRL( crlpath ) ); + crl->revoke( serial, "" ); + crl->sign( ca ); return crl; } diff --git a/src/crypto/simpleOpensslSigner.h b/src/crypto/simpleOpensslSigner.h index 11e95dd..a6af01a 100644 --- a/src/crypto/simpleOpensslSigner.h +++ b/src/crypto/simpleOpensslSigner.h @@ -5,6 +5,7 @@ #include "db/database.h" #include "crypto/sslUtil.h" #include "crypto/signer.h" +#include "crypto/CRL.h" class SimpleOpensslSigner : public Signer { private: @@ -14,5 +15,5 @@ public: SimpleOpensslSigner(); ~SimpleOpensslSigner(); std::shared_ptr sign( std::shared_ptr cert ); - std::shared_ptr revoke( std::shared_ptr ca, std::string serial ); + std::shared_ptr revoke( std::shared_ptr ca, std::string serial ); }; diff --git a/src/io/recordHandler.cpp b/src/io/recordHandler.cpp index 93990b0..abac9a5 100644 --- a/src/io/recordHandler.cpp +++ b/src/io/recordHandler.cpp @@ -201,16 +201,9 @@ public: auto reqCA = CAs.at( ca ); ( *log ) << "CA found" << std::endl; - std::shared_ptr crl = signer->revoke( reqCA, serial ); + std::shared_ptr crl = signer->revoke( reqCA, serial ); - std::shared_ptr mem( BIO_new( BIO_s_mem() ), BIO_free ); - - PEM_write_bio_X509_CRL( mem.get(), crl.get() ); - BUF_MEM* bptr; - BIO_get_mem_ptr( mem.get(), &bptr ); - - std::string newCRL( bptr->data, bptr->length ); - respondCommand( RecordHeader::SignerResult::REVOKED, newCRL ); + respondCommand( RecordHeader::SignerResult::REVOKED, crl->toString() ); if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) { ( *log ) << "ERROR: SSL close failed" << std::endl; diff --git a/test/.gitignore b/test/.gitignore index ace1063..d96a486 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -1 +1,2 @@ /testdata +/profiles diff --git a/test/genTestData.sh b/test/genTestData.sh index 87bbae6..08c732b 100755 --- a/test/genTestData.sh +++ b/test/genTestData.sh @@ -19,3 +19,14 @@ done openssl req -new -newkey rsa:2048 -nodes -subj "/CN=cn" -keyout testdata/server.key -out testdata/server.csr 2> /dev/null openssl x509 -in testdata/server.csr -signkey testdata/server.key -req -out testdata/server.crt 2> /dev/null + +mkdir profiles +cat > profiles/0001-type1.cfg < + +#include +#include + +extern std::unordered_map> CAs; + +BOOST_AUTO_TEST_SUITE( TestCRL ) +BOOST_AUTO_TEST_CASE( SeperateSignature ) { + parseProfiles(); + std::shared_ptr ca = CAs.at( "unassured" ); + + CRL c( "" ); + c.setSignature( c.getSignature() ); + c.sign( ca ); + std::string oldsig = c.getSignature(); + BOOST_CHECK( c.verify( ca ) ); + std::string date = c.revoke( "1234", "" ); + BOOST_CHECK( !c.verify( ca ) ); + c.sign( ca ); + BOOST_CHECK( c.verify( ca ) ); + std::string newsig = c.getSignature(); + c.setSignature( oldsig ); + BOOST_CHECK( !c.verify( ca ) ); + c.setSignature( newsig ); + BOOST_CHECK( c.verify( ca ) ); + + CRL c2( "" ); + c2.sign( ca ); + + std::string date2 = c2.revoke( "1234", date ); + BOOST_CHECK_EQUAL( date, date2 ); + c2.setSignature( newsig ); + BOOST_CHECK( c2.verify( ca ) ); + + BOOST_CHECK_EQUAL( c.toString(), c2.toString() ); + +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.39.2