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;
}
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 ) {
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 ) {
#include "simpleOpensslSigner.h"
-#include <iostream>
#include <sstream>
#include <unordered_map>
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;
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;
std::string csr_content;
std::vector<std::shared_ptr<SAN>> SANs;
std::vector<std::shared_ptr<AVA>> AVAs;
+
+ std::string wishFrom;
+ std::string wishTo;
};
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,
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( "," );
#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;
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 );
+ }
+}
#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 );
+
--- /dev/null
+#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()