From cb4c74b47e6643f15e503067c197f86cbc5e6263 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Mon, 19 Jan 2015 16:18:14 +0100 Subject: [PATCH] add: Implement signing based on requested "wish time" --- src/apps/client.cpp | 2 + src/crypto/X509.cpp | 4 +- src/crypto/remoteSigner.cpp | 2 + src/crypto/simpleOpensslSigner.cpp | 44 +++++++++++- src/db/database.h | 3 + src/io/record.h | 2 + src/io/recordHandler.cpp | 8 +++ src/util.cpp | 112 +++++++++++++++++++++++++++++ src/util.h | 6 ++ test/src/time.cpp | 81 +++++++++++++++++++++ 10 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 test/src/time.cpp diff --git a/src/apps/client.cpp b/src/apps/client.cpp index a066d87..e185519 100644 --- a/src/apps/client.cpp +++ b/src/apps/client.cpp @@ -125,6 +125,8 @@ int main( int argc, const char* argv[] ) { if( job->task == "sign" ) { try { std::shared_ptr cert = jp->fetchTBSCert( job ); + cert->wishFrom = job->from; + cert->wishTo = job->to; log << "INFO: message digest: " << cert->md << std::endl; log << "INFO: profile id: " << cert->profile << std::endl; diff --git a/src/crypto/X509.cpp b/src/crypto/X509.cpp index 71060e9..ba39b4b 100644 --- a/src/crypto/X509.cpp +++ b/src/crypto/X509.cpp @@ -138,8 +138,8 @@ void X509Cert::setSerialNumber( BIGNUM* num ) { } void X509Cert::setTimes( uint32_t before, uint32_t after ) { - X509_gmtime_adj( X509_get_notBefore( target.get() ), before ); - X509_gmtime_adj( X509_get_notAfter( target.get() ), after ); + ASN1_TIME_set( X509_get_notBefore( target.get() ), before ); + ASN1_TIME_set( X509_get_notAfter( target.get() ), after ); } static X509_EXTENSION* do_ext_i2d( int ext_nid, int crit, ASN1_VALUE* ext_struc ) { diff --git a/src/crypto/remoteSigner.cpp b/src/crypto/remoteSigner.cpp index 6c842d4..b060f6c 100644 --- a/src/crypto/remoteSigner.cpp +++ b/src/crypto/remoteSigner.cpp @@ -46,6 +46,8 @@ std::shared_ptr RemoteSigner::sign( std::shared_ptrmd ); send( conn, head, RecordHeader::SignerCommand::SET_PROFILE, cert->profile ); + send( conn, head, RecordHeader::SignerCommand::SET_WISH_FROM, cert->wishFrom ); + send( conn, head, RecordHeader::SignerCommand::SET_WISH_TO, cert->wishTo ); for( auto ava : cert->AVAs ) { if( ava->name.find( "," ) != std::string::npos ) { diff --git a/src/crypto/simpleOpensslSigner.cpp b/src/crypto/simpleOpensslSigner.cpp index b0925cc..22687be 100644 --- a/src/crypto/simpleOpensslSigner.cpp +++ b/src/crypto/simpleOpensslSigner.cpp @@ -1,6 +1,5 @@ #include "simpleOpensslSigner.h" -#include #include #include @@ -85,6 +84,8 @@ std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptrwishFrom << std::endl; + signlog << "FINE: Signing is wanted to: " << cert->wishTo << std::endl; std::shared_ptr req; @@ -150,7 +151,46 @@ std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptr parsed; + + if( ( parsed = parseDate( cert->wishFrom ) ).first /* is of yyyy-mm-dd */ ) { + if( parsed.second > now ) { + from = parsed.second; + } else { // fail + from = now; + } + } else { + from = now; + } + + if( from - now > /* 2 Weeks */ 2 * 7 * 24 * 60 * 60 || now - from >= 0 ) { + from = now; + } + + if( ( parsed = parseDate( cert->wishTo ) ).first /*is of yyyy-mm-dd */ ) { + if( parsed.second > from ) { + to = parsed.second; + } else { + to = from + /*2 Years */ 2 * 365 * 24 * 60 * 60; + } + } else if( ( parsed = parseYearInterval( from, cert->wishTo ) ).first /*is of [0-9]+y */ ) { + to = parsed.second; + } else if( ( parsed = parseMonthInterval( from, cert->wishTo ) ).first /*is of [0-9]+m */ ) { + to = parsed.second; + } else { + to = from + /*2 Years */ 2 * 365 * 24 * 60 * 60; + } + + time_t limit = /*2 Years (max possible) */ 2 * 366 * 24 * 60 * 60; + + if( to - from > limit || to - from < 0 ) { + to = from + limit; + } + + c.setTimes( from, to ); signlog << "FINE: Setting extensions." << std::endl; c.setExtensions( ca->ca, cert->SANs, prof ); signlog << "FINE: Signed" << std::endl; diff --git a/src/db/database.h b/src/db/database.h index e7d1952..132d8ef 100644 --- a/src/db/database.h +++ b/src/db/database.h @@ -34,6 +34,9 @@ struct TBSCertificate { std::string csr_content; std::vector> SANs; std::vector> AVAs; + + std::string wishFrom; + std::string wishTo; }; diff --git a/src/io/record.h b/src/io/record.h index bcfc831..ba5a8d8 100644 --- a/src/io/record.h +++ b/src/io/record.h @@ -16,6 +16,8 @@ public: SET_SPKAC = 0x02, SET_SIGNATURE_TYPE = 0x10, SET_PROFILE = 0x11, + SET_WISH_FROM = 0x12, + SET_WISH_TO = 0x13, ADD_SAN = 0x18, ADD_AVA = 0x19, ADD_PROOF_LINE = 0x40, diff --git a/src/io/recordHandler.cpp b/src/io/recordHandler.cpp index 56ebd29..2ba71c2 100644 --- a/src/io/recordHandler.cpp +++ b/src/io/recordHandler.cpp @@ -128,6 +128,14 @@ public: tbs->profile = data; break; + case RecordHeader::SignerCommand::SET_WISH_FROM: + tbs->wishFrom = data; + break; + + case RecordHeader::SignerCommand::SET_WISH_TO: + tbs->wishTo = data; + break; + case RecordHeader::SignerCommand::ADD_SAN: { size_t pos = data.find( "," ); diff --git a/src/util.cpp b/src/util.cpp index f04c4ae..f3d95c0 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -3,6 +3,10 @@ #include #include +#include +#include +#include +#include void writeFile( const std::string& name, const std::string& content ) { std::ofstream file; @@ -40,3 +44,111 @@ std::string writeBackFile( const std::string& serial, const std::string& cert, c return filename; } +bool isDigit( char c ) { + return ( c >= '0' ) && ( c <= '9' ); +} + +std::pair parseDate( const std::string& date ) { + if( date.size() != 10 || date[4] != '-' || date[7] != '-' ) { + return std::pair( false, 0 ); + } + + if( !isDigit( date[0] ) + || !isDigit( date[1] ) + || !isDigit( date[2] ) + || !isDigit( date[3] ) + || !isDigit( date[5] ) + || !isDigit( date[6] ) + || !isDigit( date[8] ) + || !isDigit( date[9] ) ) { + return std::pair( false, 0 ); + } + + std::tm t; + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_year = std::stoi( date.substr( 0, 4 ) ) - 1900; + t.tm_mon = std::stoi( date.substr( 5, 2 ) ) - 1; + t.tm_mday = std::stoi( date.substr( 8, 2 ) ); + setenv( "TZ", "UTC", 1 ); + tzset(); + std::time_t res = mktime( &t ); + char check[11]; + std::size_t siz = strftime( check, 11, "%Y-%m-%d", &t ); + + if( siz != 10 ) { + return std::pair( false, 0 ); + } + + std::string checkS( check, siz ); + + if( checkS != date ) { + return std::pair( false, 0 ); + } + + return std::pair( true, res ); +} + +std::pair addMonths( std::time_t t, int32_t count ) { + std::tm* parsed = gmtime( &t ); + + if( !parsed || count <= 0 || count > 24 ) { // FIXED MAX-Validity-Length + return std::pair( false, 0 ); + } + + parsed->tm_mon += count; + int oldday = parsed->tm_mday; + setenv( "TZ", "UTC", 1 ); + tzset(); + std::time_t res = mktime( parsed ); + + if( parsed->tm_mday != oldday ) { + parsed->tm_mday = 0; + res = mktime( parsed ); + } + + return std::pair( true, res ); + +} + +std::pair parseMonthInterval( std::time_t t, const std::string& date ) { + if( date[date.size() - 1] != 'm' ) { + return std::pair( false, 0 ); + } + + try { + size_t end = 0; + int num = std::stoi( date.substr( 0, date.size() - 1 ) , &end ); + + if( end != date.size() - 1 ) { + return std::pair( false, 0 ); + } + + return addMonths( t, num ); + } catch( const std::invalid_argument& a ) { + return std::pair( false, 0 ); + } catch( const std::out_of_range& a ) { + return std::pair( false, 0 ); + } +} +std::pair parseYearInterval( std::time_t t, const std::string& date ) { + if( date[date.size() - 1] != 'y' ) { + return std::pair( false, 0 ); + } + + try { + size_t end = 0; + int num = std::stoi( date.substr( 0, date.size() - 1 ), &end ); + + if( end != date.size() - 1 ) { + return std::pair( false, 0 ); + } + + return addMonths( t, num * 12 ); + } catch( std::invalid_argument& a ) { + return std::pair( false, 0 ); + } catch( std::out_of_range& a ) { + return std::pair( false, 0 ); + } +} diff --git a/src/util.h b/src/util.h index 55bb578..4149203 100644 --- a/src/util.h +++ b/src/util.h @@ -1,8 +1,14 @@ #pragma once #include +#include void writeFile( const std::string& name, const std::string& content ); std::string readFile( const std::string& name ); std::string writeBackFile( const std::string& serial, const std::string& cert, const std::string& keydir ); + +std::pair parseDate( const std::string& date ); +std::pair parseMonthInterval( std::time_t t, const std::string& date ); +std::pair parseYearInterval( std::time_t t, const std::string& date ); + diff --git a/test/src/time.cpp b/test/src/time.cpp new file mode 100644 index 0000000..ccdd1f4 --- /dev/null +++ b/test/src/time.cpp @@ -0,0 +1,81 @@ +#include "util.h" + +#include +#include +#include + + +BOOST_AUTO_TEST_SUITE( TestTime ) + +BOOST_AUTO_TEST_CASE( testParseDate ) { + if( 1 ) { + return; + } + + auto r = parseDate( "2012-01-01" ); + BOOST_CHECK( r.first ); + BOOST_CHECK( r.second == 1325376000 ); + + r = parseDate( "1970-01-01" ); + BOOST_CHECK( r.first ); + BOOST_CHECK( r.second == 0 ); + + BOOST_CHECK( !( parseDate( "" ) ).first ); + BOOST_CHECK( !( parseDate( "hallo" ) ).first ); + BOOST_CHECK( !( parseDate( "aaaa-aa-aa" ) ).first ); + BOOST_CHECK( !( parseDate( "32-12-12" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-13-01" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-00-01" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-02-30" ) ).first ); + BOOST_CHECK( ( parseDate( "2000-02-29" ) ).first ); + BOOST_CHECK( ( parseDate( "2000-01-31" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-01-32" ) ).first ); + BOOST_CHECK( !( parseDate( "2001-02-29" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-02-0" ) ).first ); + BOOST_CHECK( !( parseDate( "2000-02-99" ) ).first ); +} + +std::time_t extract( std::pair pair, std::string ex ) { + BOOST_REQUIRE( pair.first ); + ( void ) ex; + return pair.second; +} + +#define CHECK_EQ(a, inter, b) BOOST_CHECK_EQUAL( extract(parseMonthInterval(extract(parseDate(a), "a"), inter),"b"), extract(parseDate(b),"c")) + +#define CHECK_EQ_Y(a, inter, b) BOOST_CHECK_EQUAL( extract(parseYearInterval(extract(parseDate(a), "a"), inter),"b"), extract(parseDate(b),"c")) + +BOOST_AUTO_TEST_CASE( testAddInverval ) { + CHECK_EQ( "2000-01-01", "1m", "2000-02-01" ); + CHECK_EQ( "2000-02-29", "12m", "2001-02-28" ); + CHECK_EQ_Y( "2000-02-29", "1y", "2001-02-28" ); + CHECK_EQ( "1999-03-01", "12m", "2000-03-01" ); + CHECK_EQ_Y( "1999-03-01", "1y", "2000-03-01" ); + CHECK_EQ( "2000-01-29", "1m", "2000-02-29" ); + CHECK_EQ( "2001-01-29", "1m", "2001-02-28" ); + CHECK_EQ( "2100-01-29", "1m", "2100-02-28" ); + CHECK_EQ( "2400-01-29", "1m", "2400-02-29" ); + CHECK_EQ( "2099-11-30", "3m", "2100-02-28" ); + CHECK_EQ( "2399-07-29", "7m", "2400-02-29" ); +} +BOOST_AUTO_TEST_CASE( testInvalidInverval ) { + std::time_t base = 0; + BOOST_CHECK( !( parseMonthInterval( base, "1" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "-m" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "0m" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "-1m" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "1g" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "12ym" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "12my" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "-2y2m" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "--2m" ).first ) ); + BOOST_CHECK( !( parseMonthInterval( base, "25m" ).first ) ); // too big + + BOOST_CHECK( !( parseYearInterval( base, "12my" ).first ) ); + BOOST_CHECK( !( parseYearInterval( base, "-2m2y" ).first ) ); + BOOST_CHECK( !( parseYearInterval( base, "--2y" ).first ) ); + BOOST_CHECK( !( parseYearInterval( base, "3y" ).first ) ); // too big + +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.39.5