]> WPIA git - cassiopeia.git/commitdiff
add: Adding CRL generation
authorFelix Dörre <felix@dogcraft.de>
Wed, 7 Jan 2015 00:01:40 +0000 (01:01 +0100)
committerBenny Baumann <BenBE@geshi.org>
Sat, 24 Jan 2015 17:33:29 +0000 (18:33 +0100)
Currently this only supports complete transfers of the CRL

13 files changed:
src/config.cpp
src/config.h
src/crypto/CRL.cpp [new file with mode: 0644]
src/crypto/CRL.h [new file with mode: 0644]
src/crypto/remoteSigner.cpp
src/crypto/remoteSigner.h
src/crypto/signer.h
src/crypto/simpleOpensslSigner.cpp
src/crypto/simpleOpensslSigner.h
src/io/recordHandler.cpp
test/.gitignore
test/genTestData.sh
test/src/CRL.cpp [new file with mode: 0644]

index a518db568863ba5a5d6f775269bc717e8104a2ff..b746bad11a88049338853537be38250c1297bb6a 100644 (file)
@@ -46,17 +46,7 @@ std::shared_ptr<std::unordered_map<std::string, std::string>> 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<std::string, std::shared_ptr<CAConfig>>();
 
     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;
 }
index a4ce78932e8444de3f36a26f6547c2bb9b49b673..cac138b136eaba5bef6fd7fa510dd7c802522699 100644 (file)
@@ -3,3 +3,4 @@
 #include <string>
 
 int parseConfig( std::string path );
+void parseProfiles();
diff --git a/src/crypto/CRL.cpp b/src/crypto/CRL.cpp
new file mode 100644 (file)
index 0000000..dd32670
--- /dev/null
@@ -0,0 +1,124 @@
+#include "CRL.h"
+
+#include <openssl/ssl.h>
+
+CRL::CRL( std::string path ) {
+    std::shared_ptr<BIO> bio( BIO_new_file( path.c_str(), "r" ), free );
+    crl = std::shared_ptr<X509_CRL>( PEM_read_bio_X509_CRL( bio.get(), 0, NULL, 0 ), X509_CRL_free );
+
+    if( !crl ) {
+        crl = std::shared_ptr<X509_CRL>( 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<BIGNUM> serBNP( serBN, BN_free );
+    std::shared_ptr<ASN1_INTEGER> ser( BN_to_ASN1_INTEGER( serBN, NULL ), ASN1_INTEGER_free );
+
+    if( !ser ) {
+        throw "BN Malloc fail";
+    }
+
+    std::shared_ptr<ASN1_TIME> 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<CAConfig> ca ) {
+    // Updating necessary CRL props
+    std::shared_ptr<ASN1_TIME> 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<CAConfig> ca ) {
+    std::shared_ptr<EVP_PKEY> 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<BIO> 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 (file)
index 0000000..4e3deb7
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <string>
+#include <memory>
+
+#include "crypto/sslUtil.h"
+
+class CRL {
+private:
+    std::shared_ptr<X509_CRL> 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<CAConfig> ca );
+
+    bool verify( std::shared_ptr<CAConfig> ca );
+
+    std::string getSignature();
+    void setSignature( std::string signature );
+
+    std::string toString();
+};
index a6ea5780c4c5d8ca5a55c1cd656edef766ef9e26..f04f6d3b732297e53425666a299cb8d8f4f75cb6 100644 (file)
@@ -1,4 +1,5 @@
 #include "remoteSigner.h"
+#include "util.h"
 
 #include <iostream>
 
@@ -139,7 +140,7 @@ std::shared_ptr<SignedCertificate> RemoteSigner::sign( std::shared_ptr<TBSCertif
     return result;
 }
 
-std::shared_ptr<X509_CRL> RemoteSigner::revoke( std::shared_ptr<CAConfig> ca, std::string serial ) {
+std::shared_ptr<CRL> RemoteSigner::revoke( std::shared_ptr<CAConfig> ca, std::string serial ) {
     ( void )BIO_reset( target.get() );
 
     std::shared_ptr<SSL> ssl( SSL_new( ctx.get() ), SSL_free );
@@ -161,7 +162,7 @@ std::shared_ptr<X509_CRL> RemoteSigner::revoke( std::shared_ptr<CAConfig> ca, st
 
     if( length <= 0 ) {
         std::cout << "Error, no response data" << std::endl;
-        return std::shared_ptr<X509_CRL>();
+        return std::shared_ptr<CRL>();
     }
 
     payload = parseCommand( head, std::string( buffer.data(), length ), log );
@@ -175,11 +176,13 @@ std::shared_ptr<X509_CRL> RemoteSigner::revoke( std::shared_ptr<CAConfig> 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<X509_CRL>();
+    return std::shared_ptr<CRL>();
 }
 
 void RemoteSigner::setLog( std::shared_ptr<std::ostream> target ) {
index 09331bbacd9cff5567fce1ef7d8b3b9be298d0a7..1be28ed66ee94c83054c4dab7aa47abb7d4eb97d 100644 (file)
@@ -20,7 +20,7 @@ public:
     RemoteSigner( std::shared_ptr<BIO> target, std::shared_ptr<SSL_CTX> ctx );
     ~RemoteSigner();
     std::shared_ptr<SignedCertificate> sign( std::shared_ptr<TBSCertificate> cert );
-    std::shared_ptr<X509_CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial );
+    std::shared_ptr<CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial );
 
     void setLog( std::shared_ptr<std::ostream> target );
 };
index d9ab74ee3c15a271201d048a62637c9635efb4a7..44b2546a905d77cc23b0eea82f20d778220b1117 100644 (file)
@@ -4,9 +4,10 @@
 
 #include "db/database.h"
 #include "crypto/sslUtil.h"
+#include "crypto/CRL.h"
 
 class Signer {
 public:
     virtual std::shared_ptr<SignedCertificate> sign( std::shared_ptr<TBSCertificate> cert ) = 0;
-    virtual std::shared_ptr<X509_CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial ) = 0;
+    virtual std::shared_ptr<CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial ) = 0;
 };
index cd02a969d6553c2441f8889a55f645af089b7606..8eb97d579bc997785cb1abd9804273cc5e2d4138 100644 (file)
@@ -63,6 +63,7 @@ std::pair<std::shared_ptr<BIGNUM>, std::string> SimpleOpensslSigner::nextSerial(
         []( char* ref ) {
             OPENSSL_free( ref );
         } );
+
     writeFile( prof.ca->path + "/serial", serStr.get() );
 
     return std::pair<std::shared_ptr<BIGNUM>, std::string>( std::shared_ptr<BIGNUM>( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free ), std::string( serStr.get() ) );
@@ -159,67 +160,12 @@ std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TB
     return output;
 }
 
-
-std::shared_ptr<X509_CRL> SimpleOpensslSigner::revoke( std::shared_ptr<CAConfig> ca, std::string serial ) {
+std::shared_ptr<CRL> SimpleOpensslSigner::revoke( std::shared_ptr<CAConfig> ca, std::string serial ) {
     std::string crlpath = ca->path + "/ca.crl";
 
-    std::shared_ptr<BIO> bio( BIO_new_file( crlpath.c_str(), "r" ), free );
-    std::shared_ptr<X509_CRL> 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>( X509_CRL_new(), X509_CRL_free );
-    }
-
-    BIGNUM* serBN = 0;
-
-    if( ! BN_hex2bn( &serBN, serial.c_str() ) ) {
-        //error
-    }
-
-    std::shared_ptr<BIGNUM> serBNP( serBN, BN_free );
-    std::shared_ptr<ASN1_INTEGER> ser( BN_to_ASN1_INTEGER( serBN, NULL ), ASN1_INTEGER_free );
-
-    if( !ser ) {
-        // error
-    }
-
-    std::shared_ptr<ASN1_TIME> 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<BIO> 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> crl( new CRL( crlpath ) );
+    crl->revoke( serial, "" );
+    crl->sign( ca );
 
     return crl;
 }
index 11e95dd7807c68d4926060686302fefe8d10ca14..a6af01a7155414941d6662b7f4eb7243a4d5247c 100644 (file)
@@ -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<SignedCertificate> sign( std::shared_ptr<TBSCertificate> cert );
-    std::shared_ptr<X509_CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial );
+    std::shared_ptr<CRL> revoke( std::shared_ptr<CAConfig> ca, std::string serial );
 };
index 93990b0c1d6f447d2696140c97f7f09bb7bc019b..abac9a53b7ec8034f29424f0af7969c749e8110d 100644 (file)
@@ -201,16 +201,9 @@ public:
 
             auto reqCA = CAs.at( ca );
             ( *log ) << "CA found" << std::endl;
-            std::shared_ptr<X509_CRL> crl = signer->revoke( reqCA, serial );
+            std::shared_ptr<CRL> crl = signer->revoke( reqCA, serial );
 
-            std::shared_ptr<BIO> 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;
index ace1063ab026afd4eca6e8cf32336a7b4c3e3382..d96a4864c73d8738dfb2e8a4c970a0615b4f5148 100644 (file)
@@ -1 +1,2 @@
 /testdata
+/profiles
index 87bbae6e02f3364245bbfa8e83692fe3c59818f6..08c732ba1501c3ba4410cd640da6e7eada402659 100755 (executable)
@@ -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 <<EOF
+ca=unassured
+eku=
+ku=
+EOF
+
+mkdir -p ca/unassured
+cp testdata/server.key ca/unassured/ca.key
+cp testdata/server.crt ca/unassured/ca.crt
diff --git a/test/src/CRL.cpp b/test/src/CRL.cpp
new file mode 100644 (file)
index 0000000..c3c999b
--- /dev/null
@@ -0,0 +1,43 @@
+#include "crypto/CRL.h"
+#include "config.h"
+
+#include <boost/test/unit_test.hpp>
+
+#include <iostream>
+#include <unordered_map>
+
+extern std::unordered_map<std::string, std::shared_ptr<CAConfig>> CAs;
+
+BOOST_AUTO_TEST_SUITE( TestCRL )
+BOOST_AUTO_TEST_CASE( SeperateSignature ) {
+    parseProfiles();
+    std::shared_ptr<CAConfig> 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()