From: Felix Dörre Date: Sun, 2 Nov 2014 00:01:47 +0000 (+0100) Subject: chg: Split off X509-related API X-Git-Url: https://code.wpia.club/?a=commitdiff_plain;ds=sidebyside;h=cdd9db03550f3aa151f44a2cf2a31db9388df9dd;p=cassiopeia.git chg: Split off X509-related API --- diff --git a/src/X509.cpp b/src/X509.cpp new file mode 100644 index 0000000..2e441b2 --- /dev/null +++ b/src/X509.cpp @@ -0,0 +1,120 @@ +#include "X509.h" + +#include +#include +#include + +X509Req::X509Req( X509_REQ* csr ) { + req = std::shared_ptr( csr, X509_REQ_free ); + EVP_PKEY* pkt = X509_REQ_get_pubkey( req.get() ); + + if( !pkt ) { + throw "Error extracting public key"; + } + + pk = std::shared_ptr( pkt, EVP_PKEY_free ); +} + +int X509Req::verify() { + return X509_REQ_verify( req.get(), pk.get() ); +} + +std::shared_ptr X509Req::getPkey() { + return pk; +} + +std::shared_ptr X509Req::parse( std::string filename ) { + std::shared_ptr in = std::shared_ptr( BIO_new_mem_buf( const_cast( filename.c_str() ), -1 ), BIO_free ); + X509_REQ* req = PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL ); + + if( !req ) { + throw "Error parsing CSR"; + } + + return std::shared_ptr( new X509Req( req ) ); +} + +int add_ext( std::shared_ptr issuer, std::shared_ptr 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.get(), NULL, NULL, 0 ); + ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast( value ) ); + + if( !ex ) { + return 0; + } + + X509_add_ext( subj.get(), ex, -1 ); + X509_EXTENSION_free( ex ); + + return 1; +} + +X509Cert::X509Cert() { + X509* c = X509_new(); + + if( !c ) { + throw "malloc failed"; + } + + target = std::shared_ptr( c, X509_free ); + + if( !X509_set_version( c, 2 ) ) { + throw "Setting X509-version to 3 failed"; + } +} + +void X509Cert::setIssuerNameFrom( std::shared_ptr caCert ) { + if( !X509_set_issuer_name( target.get(), X509_get_subject_name( caCert.get() ) ) ) { + throw "Error setting Issuer name"; + } +} + +void X509Cert::setPubkeyFrom( std::shared_ptr req ) { + std::shared_ptr pktmp = req->getPkey(); + + if( !X509_set_pubkey( target.get(), pktmp.get() ) ) { + throw "Setting public key failed."; + } +} + +void X509Cert::setSerialNumber( int num ) { + ASN1_INTEGER_set( target.get()->cert_info->serialNumber, num ); +} + +void X509Cert::setTimes( long before, long after ) { + X509_gmtime_adj( X509_get_notBefore( target.get() ), before ); + X509_gmtime_adj( X509_get_notAfter( target.get() ), after ); +} + +void X509Cert::setExtensions( std::shared_ptr caCert ) { + add_ext( caCert, target, NID_basic_constraints, "critical,CA:FALSE" ); + add_ext( caCert, target, NID_subject_key_identifier, "hash" ); + add_ext( caCert, target, NID_authority_key_identifier, "keyid,issuer:always" ); + add_ext( caCert, target, NID_key_usage, "critical,nonRepudiation,digitalSignature,keyEncipherment" ); + add_ext( caCert, target, NID_ext_key_usage, "clientAuth, serverAuth" ); + add_ext( caCert, target, NID_info_access, "OCSP;URI:http://ocsp.cacert.org" ); + add_ext( caCert, target, NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" ); +} + +std::string X509Cert::sign( std::shared_ptr caKey ) { + if( !X509_sign( target.get(), caKey.get(), EVP_sha512() ) ) { + throw "Signing failed."; + } + + X509_print_fp( stdout, target.get() ); + std::shared_ptr mem = std::shared_ptr( BIO_new( BIO_s_mem() ), BIO_free ); + PEM_write_bio_X509( mem.get(), target.get() ); + BUF_MEM* buf; + BIO_get_mem_ptr( mem.get(), &buf ); + std::string output( buf->data, buf->data + buf->length ); + return output; +} diff --git a/src/X509.h b/src/X509.h new file mode 100644 index 0000000..a9d60e6 --- /dev/null +++ b/src/X509.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +class X509Req { +private: + std::shared_ptr pk; + std::shared_ptr req; + X509Req( X509_REQ* csr ); +public: + static std::shared_ptr parse( std::string filename ); + int verify(); + std::shared_ptr getPkey(); +}; + +class X509Cert { +private: + std::shared_ptr target; +public: + X509Cert(); + void setIssuerNameFrom( std::shared_ptr ca ); + void setPubkeyFrom( std::shared_ptr r ); + void setSerialNumber( int num ); + void setExtensions( std::shared_ptr caCert ); + void setTimes( long before, long after ); + std::string sign( std::shared_ptr caKey ); +}; + diff --git a/src/main.cpp b/src/main.cpp index b57d343..e03c361 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -40,11 +40,15 @@ int main( int argc, const char* argv[] ) { } if( job->task == "sign" ) { - std::shared_ptr cert = jp->fetchTBSCert( job ); - std::cout << "Found a CSR at '" << cert->csr << "' signing" << std::endl; - std::ifstream t( cert->csr ); - cert->csr_content = std::string( std::istreambuf_iterator( t ), std::istreambuf_iterator() ); - sign->sign( cert ); + try { + std::shared_ptr cert = jp->fetchTBSCert( job ); + std::cout << "Found a CSR at '" << cert->csr << "' signing" << std::endl; + std::ifstream t( cert->csr ); + cert->csr_content = std::string( std::istreambuf_iterator( t ), std::istreambuf_iterator() ); + sign->sign( cert ); + } catch( const char* c ) { + std::cerr << c << std::endl; + } } if( !jp->finishJob( job ) ) { diff --git a/src/simpleOpensslSigner.cpp b/src/simpleOpensslSigner.cpp index 3ef4b5e..89151a6 100644 --- a/src/simpleOpensslSigner.cpp +++ b/src/simpleOpensslSigner.cpp @@ -9,6 +9,8 @@ #include #include +#include "X509.h" + std::shared_ptr SimpleOpensslSigner::lib_ref( new int( SSL_library_init() ), []( int* ref ) { @@ -61,58 +63,14 @@ std::shared_ptr SimpleOpensslSigner::caCert = loadX509FromFile( "assured.c std::shared_ptr SimpleOpensslSigner::caKey = loadPkeyFromFile( "assured.key" ); -int add_ext( std::shared_ptr 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( value ) ); - - if( !ex ) { - return 0; - } - - X509_add_ext( subj, ex, -1 ); - X509_EXTENSION_free( ex ); - return 1; -} - void SimpleOpensslSigner::sign( std::shared_ptr cert ) { if( !caKey ) { throw "CA-key not found"; } - std::shared_ptr in = std::shared_ptr( - BIO_new_mem_buf( const_cast( cert->csr_content.c_str() ), -1 ), - []( BIO * ref ) { - BIO_free( ref ); - } ); - std::shared_ptr req = std::shared_ptr( - PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL ), - []( X509_REQ * ref ) { - if( ref ) { - X509_REQ_free( ref ); - } - } ); - - if( !req ) { - throw "Error parsing CSR"; - } - - EVP_PKEY* pktmp = X509_REQ_get_pubkey( req.get() ); - - if( !pktmp ) { - throw "Error extracting pubkey"; - } + std::shared_ptr req = X509Req::parse( cert->csr_content ); - EVP_PKEY_free( pktmp ); - - int i = X509_REQ_verify( req.get(), pktmp ); + int i = req->verify(); if( i < 0 ) { throw "Signature problems ... "; @@ -123,56 +81,21 @@ void SimpleOpensslSigner::sign( std::shared_ptr cert ) { } // Construct the Certificate - - std::shared_ptr ret = std::shared_ptr( X509_new(), X509_free ); + 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_CINF* ci = ret->cert_info; - - if( !X509_set_version( ret.get(), 2 ) ) { - throw "Setting X509-version to 3 failed"; - } - - if( !X509_set_issuer_name( ret.get(), X509_get_subject_name( caCert.get() ) ) ) { - throw "Error setting Issuer name"; - } + c.setIssuerNameFrom( caCert ); + c.setPubkeyFrom( req ); + c.setSerialNumber( 4711 ); + c.setTimes( 0, 1000 * 60 * 60 * 24 * 10 ); + c.setExtensions( caCert ); - // Serial and Pubkey - ASN1_INTEGER_set( ci->serialNumber, 4711 ); - pktmp = X509_REQ_get_pubkey( req.get() ); - - if( !X509_set_pubkey( ret.get(), pktmp ) ) { - EVP_PKEY_free( pktmp ); - throw "Setting public key failed."; - } else { - EVP_PKEY_free( pktmp ); - } - - // 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::string output = c.sign( caKey ); - X509_print_fp( stdout, ret.get() ); - std::shared_ptr mem = std::shared_ptr( 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; }