]> WPIA git - cassiopeia.git/commitdiff
add: signing of OCSP certificates
authorFelix Dörre <felix@dogcraft.de>
Sat, 8 Apr 2017 20:26:03 +0000 (22:26 +0200)
committerFelix Dörre <felix@dogcraft.de>
Mon, 1 May 2017 15:51:52 +0000 (15:51 +0000)
Change-Id: If9298ce309986604d53e82f9b3bc16536dfc70f0

docs/Protocol.md
src/apps/client.cpp
src/config.cpp
src/crypto/remoteSigner.cpp
src/crypto/simpleOpensslSigner.cpp
src/db/database.h
src/io/record.h
src/io/recordHandler.cpp

index 590658c2204ff861a8239d5a710100f0c88a2d12..5379a0756dfc0f880ac0e50cfd1ffdaf854cf91f 100644 (file)
@@ -44,6 +44,8 @@ Record Types/Commands
   Sets the desired starting date.
 (0x13) wishTo
   Sets the desired ending date (or validity-period).
+(0x14) ocspTargetCA
+  Used instead of (0x11) when signing OCSP certs. The payload is an exact time-CA name (e.g. orga_2017_1).
 (0x18) addSAN
   Adds a given SAN (Subject alternative name) to the certificate.
   (DNS,<dnsname> or email,<email address>)
index 92a2369f471465e273cbeebce0119092f0ffff92..63ff0cab5359aa1188c2f87c7c8d0dd48379f37c 100644 (file)
@@ -17,6 +17,8 @@
 #include "io/slipBio.h"
 #include "config.h"
 #include <internal/bio.h>
+#include <dirent.h>
+#include <crypto/X509.h>
 
 #ifdef NO_DAEMON
 #define DAEMON false
@@ -52,6 +54,88 @@ void checkCRLs( std::shared_ptr<Signer> sign ) {
     }
 }
 
+bool pathExists( const std::string& name ) {
+    struct stat buffer;
+    return stat( name.c_str(), &buffer ) == 0;
+}
+
+void checkOCSP( std::shared_ptr<Signer> sign ) {
+    std::unique_ptr<DIR, std::function<void( DIR * )>> dp( opendir( "ca" ), []( DIR * d ) {
+        closedir( d );
+    } );
+
+    // When opendir fails and returns 0 the unique_ptr will be considered unintialized and will not call closedir.
+    // Even if closedir would be called, according to POSIX it MAY handle nullptr properly (for glibc it does).
+    if( !dp ) {
+        logger::error( "CA directory not found" );
+        return;
+    }
+
+    struct dirent *ep;
+
+    while( ( ep = readdir( dp.get() ) ) ) {
+        if( ep->d_name[0] == '.' ) {
+            continue;
+        }
+
+        std::string profileName( ep->d_name );
+        std::string csr = "ca/" + profileName + "/ocsp.csr";
+
+        if( ! pathExists( csr ) ) {
+            continue;
+        }
+
+        std::string crtName = "ca/" + profileName + "/ocsp.crt";
+
+        if( pathExists( crtName ) ) {
+            continue;
+        }
+
+        logger::notef( "Discovered OCSP CSR that needs action: %s", csr );
+        std::string req = readFile( csr );
+        std::shared_ptr<X509Req> parsed = X509Req::parseCSR( req );
+
+        if( parsed->verify() <= 0 ) {
+            logger::errorf( "Invalid CSR for %s", profileName );
+            continue;
+        }
+
+        auto cert = std::make_shared<TBSCertificate>();
+        cert->ocspCA = profileName;
+        cert->wishFrom = "now";
+        cert->wishTo = "1y";
+        cert->md = "sha512";
+
+        logger::note( "INFO: Message Digest: ", cert->md );
+
+        for( auto& SAN : cert->SANs ) {
+            logger::notef( "INFO: SAN %s: %s", SAN->type, SAN->content );
+        }
+
+        for( auto& AVA : cert->AVAs ) {
+            logger::notef( "INFO: AVA %s: %s", AVA->name, AVA->value );
+        }
+
+        cert->csr_content = req;
+        cert->csr_type = "CSR";
+        auto nAVA = std::make_shared<AVA>();
+        nAVA->name = "CN";
+        nAVA->value = "OCSP Responder";
+        cert->AVAs.push_back( nAVA );
+
+        std::shared_ptr<SignedCertificate> res = sign->sign( cert );
+
+        if( !res ) {
+            logger::error( "OCSP Cert signing failed." );
+            continue;
+        }
+
+        writeFile( crtName, res->certificate );
+        logger::notef( "Cert log: %s", res->log );
+    }
+}
+
+
 int main( int argc, const char *argv[] ) {
     bool once = false;
     bool resetOnly = false;
@@ -114,6 +198,8 @@ int main( int argc, const char *argv[] ) {
                 lastCRLCheck = current;
             }
 
+            checkOCSP( sign );
+
             std::shared_ptr<Job> job;
 
             try {
index d078179cee5c8c47c6e0aba45bbe62987f9a9a60..a58cc82878acabf16190dcc212bb27e2a617b8f3 100644 (file)
@@ -93,16 +93,20 @@ int parseProfiles() {
         prof.ku = map->at( "ku" );
         prof.maxValidity = std::stoi( map->at( "days" ) ) * /* DAYS */24 * 60 * 60;
 
-        std::string cas = map->at( "ca" );
 
         DIR *dir;
         struct dirent *ent;
 
-        if( ( dir = opendir( "ca" ) ) != NULL ) {
+        if( profileName == "0100-ocsp" ) {
+            //This profile does not have a specific CA. The concrete CA has to be set in each request.
+        } else if( ( dir = opendir( "ca" ) ) != NULL ) {
+            std::string cas = map->at( "ca" );
+            std::string toFind = cas + "_";
+
             while( ( ent = readdir( dir ) ) != NULL ) {
                 std::string caName = std::string( ent->d_name );
 
-                if( caName.find( cas ) != 0 ) {
+                if( caName.find( toFind ) != 0 ) {
                     continue;
                 }
 
index 64ccebf36166b0db30bcf8ef639199f623fa4d3d..c06af91bc3a48700300c6cd89fdb774d1e1289cb 100644 (file)
@@ -44,7 +44,13 @@ 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 );
+
+    if( !cert->ocspCA.empty() ) {
+        send( conn, head, RecordHeader::SignerCommand::SET_OCSP_TARGET_CA, cert->ocspCA );
+    } else {
+        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 );
 
index 6cf10d060a6039e785095ea652ea5ba280ba46db..a6d037188fbbf915336db93e305c9a0d71dc165b 100644 (file)
@@ -18,6 +18,7 @@
 #include "sslUtil.h"
 
 extern std::unordered_map<std::string, Profile> profiles;
+extern std::unordered_map<std::string, std::shared_ptr<CAConfig>> CAs;
 
 std::shared_ptr<int> SimpleOpensslSigner::lib_ref = ssl_lib_ref;
 
@@ -74,12 +75,28 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
     std::stringstream signlog;
     logger::logger_set log_set_sign( {logger::log_target( signlog, logger::level::debug )}, logger::auto_register::on );
 
-    logger::note( "FINE: Profile name is: ", cert->profile );
+    std::shared_ptr<CAConfig> ca;
+    Profile *prof;
 
-    Profile& prof = profiles.at( cert->profile );
-    logger::note( "FINE: Profile ID is: ", prof.id );
+    if( cert->ocspCA != "" ) {
+        auto caIterator = CAs.find( cert->ocspCA );
 
-    std::shared_ptr<CAConfig> ca = prof.getCA();
+        if( caIterator == CAs.end() ) {
+            logger::error( "ERROR: Signing CA specified in request for an OCSP cert could not be loaded." );
+            throw std::runtime_error( "CA-key for OCSP cert not found" );
+        }
+
+        ca = caIterator->second;
+        logger::note( "Trying to fetch OCSP-profile" );
+        prof = &profiles.at( "0100-ocsp" );
+        logger::note( "Done with it" );
+    } else {
+        logger::note( "FINE: Profile name is: ", cert->profile );
+
+        prof = &profiles.at( cert->profile );
+        logger::note( "FINE: Profile ID is: ", prof->id );
+        ca = prof->getCA();
+    }
 
     if( !ca ) {
         logger::error( "ERROR: Signing CA specified in profile could not be loaded." );
@@ -92,8 +109,8 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
 
     logger::note( "FINE: Key for Signing CA is correctly loaded." );
 
-    logger::note( "INFO: Baseline Key Usage is: ", prof.ku );
-    logger::note( "INFO: Extended Key Usage is: ", prof.eku );
+    logger::note( "INFO: Baseline Key Usage is: ", prof->ku );
+    logger::note( "INFO: Extended Key Usage is: ", prof->eku );
 
     logger::note( "FINE: Signing is wanted by: ", cert->wishFrom );
     logger::note( "FINE: Signing is wanted for: ", cert->wishTo );
@@ -207,7 +224,7 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
             to = from + /*2 Years */ 2 * 365 * 24 * 60 * 60;
         }
 
-        time_t limit = prof.maxValidity;
+        time_t limit = prof->maxValidity;
 
         if( ( to - from > limit ) || ( to - from < 0 ) ) {
             to = from + limit;
@@ -232,13 +249,13 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
     }
 
     logger::note( "INFO: Setting extensions:" );
-    c.setExtensions( ca->ca, cert->SANs, prof, ca->crlURL, ca->crtURL );
+    c.setExtensions( ca->ca, cert->SANs, *prof, ca->crlURL, ca->crtURL );
     logger::note( "FINE: Setting extensions successful." );
 
     logger::note( "INFO: Generating next Serial Number ..." );
     std::shared_ptr<BIGNUM> ser;
     std::string num;
-    std::tie( ser, num ) = nextSerial( prof, ca );
+    std::tie( ser, num ) = nextSerial( *prof, ca );
     c.setSerialNumber( ser.get() );
     logger::note( "FINE: Certificate Serial Number set to: ", num );
 
index 31687b13ce43242e68ab14babba87ae25e2908f6..fb3b093a341b0ae2fb10669ef8f935c90da5d92f 100644 (file)
@@ -38,6 +38,8 @@ struct TBSCertificate {
 
     std::string wishFrom;
     std::string wishTo;
+
+    std::string ocspCA;
 };
 
 struct SignedCertificate {
index 5b9c440d64fd7877965f73548c9e4e81a56dfb37..6c2df6590683d8f480fb286c95a715de90a63251 100644 (file)
@@ -19,6 +19,7 @@ public:
         SET_PROFILE = 0x11,
         SET_WISH_FROM = 0x12,
         SET_WISH_TO = 0x13,
+        SET_OCSP_TARGET_CA = 0x14,
         ADD_SAN = 0x18,
         ADD_AVA = 0x19,
         ADD_PROOF_LINE = 0x40,
index 7b48c6e4685e0b70eb6aeba0b93b2e1b0a2c8cd0..11639c281a57f2b4880369b753ad2efb91f3a752 100644 (file)
@@ -112,6 +112,10 @@ public:
             tbs->wishTo = data;
             break;
 
+        case RecordHeader::SignerCommand::SET_OCSP_TARGET_CA:
+            tbs->ocspCA = data;
+            break;
+
         case RecordHeader::SignerCommand::ADD_SAN: {
             size_t pos = data.find( "," );