]> WPIA git - cassiopeia.git/blobdiff - src/simpleOpensslSigner.cpp
add: simple, signer-side record handling
[cassiopeia.git] / src / simpleOpensslSigner.cpp
index 3ef4b5eecad6e1f47ad9e13b286dede467552457..0096d5ec0457f67ca4f42058fbb8778124753254 100644 (file)
@@ -9,10 +9,18 @@
 #include <openssl/engine.h>
 #include <openssl/x509v3.h>
 
+#include "X509.h"
+#include "util.h"
+
+extern std::vector<Profile> profiles;
+
 std::shared_ptr<int> SimpleOpensslSigner::lib_ref(
     new int( SSL_library_init() ),
     []( int* ref ) {
-        ( void ) ref;
+        delete ref;
+
+        EVP_cleanup();
+        CRYPTO_cleanup_all_ex_data();
     } );
 
 std::shared_ptr<X509> loadX509FromFile( std::string filename ) {
@@ -57,62 +65,72 @@ std::shared_ptr<EVP_PKEY> loadPkeyFromFile( std::string filename ) {
         } );
 }
 
-std::shared_ptr<X509> SimpleOpensslSigner::caCert = loadX509FromFile( "assured.crt" );
+SimpleOpensslSigner::SimpleOpensslSigner() {
+    caCert = loadX509FromFile( profiles[0].cert );
+    caKey = loadPkeyFromFile( profiles[0].key );
+}
+
+SimpleOpensslSigner::~SimpleOpensslSigner() {
+}
+
+std::shared_ptr<BIGNUM> SimpleOpensslSigner::nextSerial( uint16_t profile ) {
+    std::string res = readFile( "serial" );
 
-std::shared_ptr<EVP_PKEY> SimpleOpensslSigner::caKey = loadPkeyFromFile( "assured.key" );
+    BIGNUM* bn = 0;
 
-int add_ext( std::shared_ptr<X509> issuer, X509* subj, int nid, const char* value ) {
-    X509_EXTENSION* ex;
-    X509V3_CTX ctx;
-    /* This sets the 'context' of the extensions. */
-    /* No configuration database */
-    X509V3_set_ctx_nodb( &ctx );
-    /* Issuer and subject certs: both the target since it is self signed,
-     * no request and no CRL
-     */
-    X509V3_set_ctx( &ctx, issuer.get(), subj, NULL, NULL, 0 );
-    ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast<char*>( value ) );
+    if( res == "" ) {
+        bn = BN_new();
 
-    if( !ex ) {
-        return 0;
+        if( !bn ) {
+            throw "Initing serial failed";
+        }
+    } else {
+        if( !BN_hex2bn( &bn, res.c_str() + 1 ) ) {
+            throw "Parsing serial failed.";
+        }
     }
 
-    X509_add_ext( subj, ex, -1 );
-    X509_EXTENSION_free( ex );
-    return 1;
-}
+    std::shared_ptr<BIGNUM> serial = std::shared_ptr<BIGNUM>( bn, BN_free );
 
-void SimpleOpensslSigner::sign( std::shared_ptr<TBSCertificate> cert ) {
-    if( !caKey ) {
-        throw "CA-key not found";
+    std::shared_ptr<unsigned char> data = std::shared_ptr<unsigned char>( ( unsigned char* ) malloc( BN_num_bytes( serial.get() ) + 20 ), free );
+    int len = BN_bn2bin( serial.get(), data.get() );
+
+    data.get()[len] = 0x0;
+    data.get()[len + 1] = 0x0; // signer id
+
+    data.get()[len + 2] = profile >> 8;
+    data.get()[len + 3] = profile & 0xFF; // profile id
+
+    if( !RAND_bytes( data.get() + len + 4, 16 ) || !BN_add_word( serial.get(), 1 ) ) {
+        throw "Big number math failed while calcing serials.";
     }
 
-    std::shared_ptr<BIO> in = std::shared_ptr<BIO>(
-        BIO_new_mem_buf( const_cast<char*>( cert->csr_content.c_str() ), -1 ),
-        []( BIO * ref ) {
-            BIO_free( ref );
-        } );
-    std::shared_ptr<X509_REQ> req = std::shared_ptr<X509_REQ>(
-        PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL ),
-        []( X509_REQ * ref ) {
-            if( ref ) {
-                X509_REQ_free( ref );
-            }
+    std::shared_ptr<char> serStr = std::shared_ptr<char>(
+        BN_bn2hex( serial.get() ),
+        []( char* ref ) {
+            OPENSSL_free( ref );
         } );
+    writeFile( "serial", serStr.get() );
+
+    return std::shared_ptr<BIGNUM>( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free );
+}
 
-    if( !req ) {
-        throw "Error parsing CSR";
+std::shared_ptr<SignedCertificate> SimpleOpensslSigner::sign( std::shared_ptr<TBSCertificate> cert ) {
+    if( !caKey ) {
+        throw "CA-key not found";
     }
 
-    EVP_PKEY* pktmp = X509_REQ_get_pubkey( req.get() );
+    std::shared_ptr<X509Req> req;
 
-    if( !pktmp ) {
-        throw "Error extracting pubkey";
+    if( cert->csr_type == "SPKAC" ) {
+        req = X509Req::parseSPKAC( cert->csr_content );
+    } else if( cert->csr_type == "CSR" ) {
+        req = X509Req::parseCSR( cert->csr_content );
+    } else {
+        throw "Error, unknown REQ rype " + ( cert->csr_type );
     }
 
-    EVP_PKEY_free( pktmp );
-
-    int i = X509_REQ_verify( req.get(), pktmp );
+    int i = req->verify();
 
     if( i < 0 ) {
         throw "Signature problems ... ";
@@ -123,56 +141,54 @@ void SimpleOpensslSigner::sign( std::shared_ptr<TBSCertificate> cert ) {
     }
 
     // Construct the Certificate
-
-    std::shared_ptr<X509> ret = std::shared_ptr<X509>( X509_new(), X509_free );
+    X509Cert c = X509Cert();
+    std::shared_ptr<X509> retsh = std::shared_ptr<X509>( X509_new(), X509_free );
+    X509* ret = retsh.get();
 
     if( !ret ) {
         throw "Creating X509 failed.";
     }
 
-    X509_CINF* ci = ret->cert_info;
+    X509_NAME* subjectP = X509_NAME_new();
 
-    if( !X509_set_version( ret.get(), 2 ) ) {
-        throw "Setting X509-version to 3 failed";
+    if( !subjectP ) {
+        throw "malloc failure";
     }
 
-    if( !X509_set_issuer_name( ret.get(), X509_get_subject_name( caCert.get() ) ) ) {
-        throw "Error setting Issuer name";
+    for( std::shared_ptr<AVA> a : cert->AVAs ) {
+        if( a->name == "CN" ) {
+            c.addRDN( NID_commonName, a->value );
+        } else if( a->name == "EMAIL" ) {
+            c.addRDN( NID_pkcs9_emailAddress, a->value );
+        } else if( a->name == "C" ) {
+            c.addRDN( NID_countryName, a->value );
+        } else if( a->name == "L" ) {
+            c.addRDN( NID_localityName, a->value );
+        } else if( a->name == "ST" ) {
+            c.addRDN( NID_stateOrProvinceName, a->value );
+        } else if( a->name == "O" ) {
+            c.addRDN( NID_organizationName, a->value );
+        } else if( a->name == "OU" ) {
+            c.addRDN( NID_organizationalUnitName, a->value );
+        } else {
+            throw "unknown AVA-type";
+        }
     }
 
-    // Serial and Pubkey
-    ASN1_INTEGER_set( ci->serialNumber, 4711 );
-    pktmp = X509_REQ_get_pubkey( req.get() );
+    c.setIssuerNameFrom( caCert );
+    c.setPubkeyFrom( req );
+    long int profile = strtol( cert->profile.c_str(), 0, 10 );
 
-    if( !X509_set_pubkey( ret.get(), pktmp ) ) {
-        EVP_PKEY_free( pktmp );
-        throw "Setting public key failed.";
-    } else {
-        EVP_PKEY_free( pktmp );
+    if( profile > 0xFFFF || profile < 0 || ( profile == 0 && cert->profile != "0" ) ) {
+        throw "invalid profile id";
     }
 
-    // Dates
-    X509_gmtime_adj( X509_get_notBefore( ret.get() ), 0 );
-    X509_gmtime_adj( X509_get_notAfter( ret.get() ), ( long )60 * 60 * 24 * 10 );
-
-    // Extensions
-    add_ext( caCert, ret.get(), NID_basic_constraints, "critical,CA:FALSE" );
-    add_ext( caCert, ret.get(), NID_subject_key_identifier, "hash" );
-    add_ext( caCert, ret.get(), NID_authority_key_identifier, "keyid,issuer:always" );
-    add_ext( caCert, ret.get(), NID_key_usage, "critical,nonRepudiation,digitalSignature,keyEncipherment" );
-    add_ext( caCert, ret.get(), NID_ext_key_usage, "clientAuth, serverAut" );
-    add_ext( caCert, ret.get(), NID_info_access, "OCSP;URI:http://ocsp.cacert.org" );
-    add_ext( caCert, ret.get(), NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" );
-
-    if( !X509_sign( ret.get(), caKey.get(), EVP_sha512() ) ) {
-        throw "Signing failed.";
-    }
+    std::shared_ptr<BIGNUM> ser = nextSerial( profile );
+    c.setSerialNumber( ser.get() );
+    c.setTimes( 0, 60 * 60 * 24 * 10 );
+    c.setExtensions( caCert, cert->SANs );
+
+    std::shared_ptr<SignedCertificate> output = c.sign( caKey, cert->md );
 
-    X509_print_fp( stdout, ret.get() );
-    std::shared_ptr<BIO> mem = std::shared_ptr<BIO>( BIO_new( BIO_s_mem() ), BIO_free );
-    PEM_write_bio_X509( mem.get(), ret.get() );
-    BUF_MEM* buf;
-    BIO_get_mem_ptr( mem.get(), &buf );
-    std::string output( buf->data, buf->data + buf->length );
-    std::cout << "Certificate:" << std::endl << output << std::endl;
+    return output;
 }