]> WPIA git - cassiopeia.git/commitdiff
add: Implement signing based on requested "wish time"
authorFelix Dörre <felix@dogcraft.de>
Mon, 19 Jan 2015 15:18:14 +0000 (16:18 +0100)
committerBenny Baumann <BenBE@geshi.org>
Mon, 9 Feb 2015 19:04:10 +0000 (20:04 +0100)
src/apps/client.cpp
src/crypto/X509.cpp
src/crypto/remoteSigner.cpp
src/crypto/simpleOpensslSigner.cpp
src/db/database.h
src/io/record.h
src/io/recordHandler.cpp
src/util.cpp
src/util.h
test/src/time.cpp [new file with mode: 0644]

index a066d87589b38a0c4222287b7371c71b9c791219..e1855190673870e998e3aeb78ff5ed405a0e9302 100644 (file)
@@ -125,6 +125,8 @@ int main( int argc, const char* argv[] ) {
         if( job->task == "sign" ) {
             try {
                 std::shared_ptr<TBSCertificate> 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;
 
index 71060e99ebb143f73af05eb444fdd03851346438..ba39b4bcef68287bd15ef8ce5247c44b853f6ccd 100644 (file)
@@ -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 ) {
index 6c842d4a6fd08b5db87689427a7b86537f310fcb..b060f6cca116f25a4516357147f9f10612e6f512 100644 (file)
@@ -46,6 +46,8 @@ std::shared_ptr<SignedCertificate> RemoteSigner::sign( std::shared_ptr<TBSCertif
 
     send( conn, head, RecordHeader::SignerCommand::SET_SIGNATURE_TYPE, cert->md );
     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 ) {
index b0925ccdeea5c757f65f653480c040c36d4bd4b9..22687be3c518579a3b9fbd1531726bb51acefc6c 100644 (file)
@@ -1,6 +1,5 @@
 #include "simpleOpensslSigner.h"
 
-#include <iostream>
 #include <sstream>
 #include <unordered_map>
 
@@ -85,6 +84,8 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
     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;
+    signlog << "FINE: Signing is wanted from: " << cert->wishFrom << std::endl;
+    signlog << "FINE: Signing is wanted to: " << cert->wishTo << std::endl;
 
     std::shared_ptr<X509Req> req;
 
@@ -150,7 +151,46 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
     std::string num;
     std::tie( ser, num ) = nextSerial( prof, ca );
     c.setSerialNumber( ser.get() );
-    c.setTimes( 0, 60 * 60 * 24 * 10 );
+
+    std::time_t from, to;
+    std::time_t now = time( 0 );
+    std::pair<bool, std::time_t> 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;
index e7d195229158ec44379ab14c82fc1c0ccc47926d..132d8ef22b1b521760c6015701a369648a9962c9 100644 (file)
@@ -34,6 +34,9 @@ struct TBSCertificate {
     std::string csr_content;
     std::vector<std::shared_ptr<SAN>> SANs;
     std::vector<std::shared_ptr<AVA>> AVAs;
+
+    std::string wishFrom;
+    std::string wishTo;
 };
 
 
index bcfc831c7b2206cd3a8faf81a8febf943d997048..ba5a8d8be7d6f789557d91fe8f0bd813af1b592b 100644 (file)
@@ -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,
index 56ebd29c30af6d6506f7e2b61aa985f12892e411..2ba71c2675b821080fc39617523d6bd0096b4bc0 100644 (file)
@@ -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( "," );
 
index f04c4ae036bd9833a971c3d64993f2310296deb8..f3d95c0ad522f3933ab1e7e57bf94d445a28d715 100644 (file)
@@ -3,6 +3,10 @@
 #include <sys/stat.h>
 
 #include <fstream>
+#include <iostream>
+#include <sstream>
+#include <time.h>
+#include <stdexcept>
 
 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<bool, time_t> parseDate( const std::string& date ) {
+    if( date.size() != 10 || date[4] != '-' || date[7] != '-' ) {
+        return std::pair<bool, time_t>( 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<bool, time_t>( 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<bool, time_t>( false, 0 );
+    }
+
+    std::string checkS( check, siz );
+
+    if( checkS != date ) {
+        return std::pair<bool, time_t>( false, 0 );
+    }
+
+    return std::pair<bool, time_t>( true, res );
+}
+
+std::pair<bool, time_t> 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<bool, time_t>( 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<bool, time_t>( true, res );
+
+}
+
+std::pair<bool, time_t> parseMonthInterval( std::time_t t, const std::string& date ) {
+    if( date[date.size() - 1] != 'm' ) {
+        return  std::pair<bool, time_t>( 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<bool, time_t>( false, 0 );
+        }
+
+        return addMonths( t, num );
+    } catch( const std::invalid_argument& a ) {
+        return std::pair<bool, time_t>( false, 0 );
+    } catch( const std::out_of_range& a ) {
+        return std::pair<bool, time_t>( false, 0 );
+    }
+}
+std::pair<bool, time_t> parseYearInterval( std::time_t t, const std::string& date ) {
+    if( date[date.size() - 1] != 'y' ) {
+        return  std::pair<bool, time_t>( 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<bool, time_t>( false, 0 );
+        }
+
+        return addMonths( t, num * 12 );
+    } catch( std::invalid_argument& a ) {
+        return std::pair<bool, time_t>( false, 0 );
+    } catch( std::out_of_range& a ) {
+        return std::pair<bool, time_t>( false, 0 );
+    }
+}
index 55bb57876fa59b05b5cc9caa36c998e9b1a3956a..41492031f6310e5861dce31883313820e4f3760a 100644 (file)
@@ -1,8 +1,14 @@
 #pragma once
 
 #include <string>
+#include <ctime>
 
 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<bool, std::time_t> parseDate( const std::string& date );
+std::pair<bool, std::time_t> parseMonthInterval( std::time_t t, const std::string& date );
+std::pair<bool, std::time_t> 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 (file)
index 0000000..ccdd1f4
--- /dev/null
@@ -0,0 +1,81 @@
+#include "util.h"
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+#include <openssl/err.h>
+
+
+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<bool, std::time_t> 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()