X-Git-Url: https://code.wpia.club/?a=blobdiff_plain;ds=sidebyside;f=src%2FsimpleOpensslSigner.cpp;h=eb7d8b9e720232989b8a60c5b0bfc792a50d2fe0;hb=7a72391242e316a16992e0874a118999486afb87;hp=08471bc2a3f3ec3cb84cdfbea0319f15d950e3aa;hpb=08f8da2e81d783d851e9d0a4bbaded420a665d6f;p=cassiopeia.git diff --git a/src/simpleOpensslSigner.cpp b/src/simpleOpensslSigner.cpp index 08471bc..eb7d8b9 100644 --- a/src/simpleOpensslSigner.cpp +++ b/src/simpleOpensslSigner.cpp @@ -1,46 +1,196 @@ #include "simpleOpensslSigner.h" #include +#include #include #include #include #include #include +#include -void SimpleOpensslSigner::sign( std::shared_ptr cert ) { - std::cout << cert->CN << std::endl; - BIO* in; - in = BIO_new_mem_buf( const_cast( cert->csr_content.c_str() ), -1 ); - X509_REQ* req = PEM_read_bio_X509_REQ( in, NULL, NULL, NULL ); +#include "X509.h" - if( req == NULL ) { - std::cerr << "Error parsing CSR" << std::endl; - return; +extern std::vector profiles; + +std::shared_ptr SimpleOpensslSigner::lib_ref( + new int( SSL_library_init() ), + []( int* ref ) { + delete ref; + + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + } ); + +std::shared_ptr loadX509FromFile( std::string filename ) { + FILE* f = fopen( filename.c_str(), "r" ); + + if( !f ) { + return std::shared_ptr(); + } + + X509* key = PEM_read_X509( f, NULL, NULL, 0 ); + fclose( f ); + + if( !key ) { + return std::shared_ptr(); + } + + return std::shared_ptr( + key, + []( X509 * ref ) { + X509_free( ref ); + } ); +} + +std::shared_ptr loadPkeyFromFile( std::string filename ) { + FILE* f = fopen( filename.c_str(), "r" ); + + if( !f ) { + return std::shared_ptr(); + } + + EVP_PKEY* key = PEM_read_PrivateKey( f, NULL, NULL, 0 ); + fclose( f ); + + if( !key ) { + return std::shared_ptr(); + } + + return std::shared_ptr( + key, + []( EVP_PKEY * ref ) { + EVP_PKEY_free( ref ); + } ); +} + +SimpleOpensslSigner::SimpleOpensslSigner() { + caCert = loadX509FromFile( profiles[0].cert ); + caKey = loadPkeyFromFile( profiles[0].key ); +} + +SimpleOpensslSigner::~SimpleOpensslSigner() { +} + +std::shared_ptr SimpleOpensslSigner::nextSerial( uint16_t profile ) { + std::ifstream serialif( "serial" ); + std::string res; + serialif >> res; + serialif.close(); + + BIGNUM* bn = 0; + + if( res == "" ) { + bn = BN_new(); + + if( !bn ) { + throw "Initing serial failed"; + } + } else { + if( !BN_hex2bn( &bn, res.c_str() + 1 ) ) { + throw "Parsing serial failed."; + } + } + + std::shared_ptr serial = std::shared_ptr( bn, BN_free ); + + std::shared_ptr data = std::shared_ptr( ( 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."; } - EVP_PKEY* pktmp = X509_REQ_get_pubkey( req ); + char* serStr = BN_bn2hex( serial.get() ); + std::ofstream serialf( "serial" ); + serialf << serStr; + serialf.close(); + OPENSSL_free( serStr ); - if( pktmp == NULL ) { - std::cerr << "Error extracting pubkey" << std::endl; - return; + return std::shared_ptr( BN_bin2bn( data.get(), len + 4 + 16 , 0 ), BN_free ); +} + +std::shared_ptr SimpleOpensslSigner::sign( std::shared_ptr cert ) { + if( !caKey ) { + throw "CA-key not found"; + } + + std::shared_ptr req; + + if( cert->csr_type == "SPKAC" ) { + req = X509Req::parseSPKAC( cert->csr_content ); + } else if( cert->csr_type == "CSR" ) { + req = X509Req::parse( cert->csr_content ); + } else { + throw "Error, unknown REQ rype " + ( cert->csr_type ); } - std::cout << req << ";" << pktmp << std::endl; - SSL_library_init(); - int i = X509_REQ_verify( req, pktmp ); - ERR_load_crypto_strings(); - ERR_print_errors_fp( stderr ); - std::cout << ERR_get_error() << std::endl; + int i = req->verify(); if( i < 0 ) { - std::cerr << "Signature problems ... " << i << std::endl; - return; + throw "Signature problems ... "; } else if( i == 0 ) { - std::cerr << "Signature did not match" << std::endl; - return; + throw "Signature did not match"; } else { std::cerr << "Signature ok" << std::endl; } + // Construct the Certificate + X509Cert c = X509Cert(); + std::shared_ptr retsh = std::shared_ptr( X509_new(), X509_free ); + X509* ret = retsh.get(); + + if( !ret ) { + throw "Creating X509 failed."; + } + + X509_NAME* subjectP = X509_NAME_new(); + + if( !subjectP ) { + throw "malloc failure"; + } + + for( std::shared_ptr 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"; + } + } + + c.setIssuerNameFrom( caCert ); + c.setPubkeyFrom( req ); + long int profile = strtol( cert->profile.c_str(), 0, 10 ); + + if( profile > 0xFFFF || profile < 0 || ( profile == 0 && cert->profile != "0" ) ) { + throw "invalid profile id"; + } + + std::shared_ptr ser = nextSerial( profile ); + c.setSerialNumber( ser.get() ); + c.setTimes( 0, 60 * 60 * 24 * 10 ); + c.setExtensions( caCert, cert->SANs ); + + std::shared_ptr output = c.sign( caKey, cert->md ); + + return output; }