1 #include "simpleOpensslSigner.h"
5 #include <openssl/ssl.h>
6 #include <openssl/err.h>
7 #include <openssl/bio.h>
8 #include <openssl/bn.h>
9 #include <openssl/engine.h>
10 #include <openssl/x509v3.h>
12 std::shared_ptr<int> SimpleOpensslSigner::lib_ref(
13 new int( SSL_library_init() ),
18 std::shared_ptr<X509> loadX509FromFile( std::string filename ) {
19 FILE* f = fopen( filename.c_str(), "r" );
22 return std::shared_ptr<X509>();
25 X509* key = PEM_read_X509( f, NULL, NULL, 0 );
29 return std::shared_ptr<X509>();
32 return std::shared_ptr<X509>(
39 std::shared_ptr<EVP_PKEY> loadPkeyFromFile( std::string filename ) {
40 FILE* f = fopen( filename.c_str(), "r" );
43 return std::shared_ptr<EVP_PKEY>();
46 EVP_PKEY* key = PEM_read_PrivateKey( f, NULL, NULL, 0 );
50 return std::shared_ptr<EVP_PKEY>();
53 return std::shared_ptr<EVP_PKEY>(
55 []( EVP_PKEY * ref ) {
60 std::shared_ptr<X509> SimpleOpensslSigner::caCert = loadX509FromFile( "assured.crt" );
62 std::shared_ptr<EVP_PKEY> SimpleOpensslSigner::caKey = loadPkeyFromFile( "assured.key" );
64 int add_ext( std::shared_ptr<X509> issuer, X509* subj, int nid, const char* value ) {
67 /* This sets the 'context' of the extensions. */
68 /* No configuration database */
69 X509V3_set_ctx_nodb( &ctx );
70 /* Issuer and subject certs: both the target since it is self signed,
71 * no request and no CRL
73 X509V3_set_ctx( &ctx, issuer.get(), subj, NULL, NULL, 0 );
74 ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast<char*>( value ) );
80 X509_add_ext( subj, ex, -1 );
81 X509_EXTENSION_free( ex );
85 void SimpleOpensslSigner::sign( std::shared_ptr<TBSCertificate> cert ) {
87 throw "CA-key not found";
90 std::shared_ptr<BIO> in = std::shared_ptr<BIO>(
91 BIO_new_mem_buf( const_cast<char*>( cert->csr_content.c_str() ), -1 ),
95 std::shared_ptr<X509_REQ> req = std::shared_ptr<X509_REQ>(
96 PEM_read_bio_X509_REQ( in.get(), NULL, NULL, NULL ),
97 []( X509_REQ * ref ) {
104 throw "Error parsing CSR";
107 EVP_PKEY* pktmp = X509_REQ_get_pubkey( req.get() );
110 throw "Error extracting pubkey";
113 EVP_PKEY_free( pktmp );
115 int i = X509_REQ_verify( req.get(), pktmp );
118 throw "Signature problems ... ";
119 } else if( i == 0 ) {
120 throw "Signature did not match";
122 std::cerr << "Signature ok" << std::endl;
125 // Construct the Certificate
127 std::shared_ptr<X509> ret = std::shared_ptr<X509>( X509_new(), X509_free );
130 throw "Creating X509 failed.";
133 X509_CINF* ci = ret->cert_info;
135 if( !X509_set_version( ret.get(), 2 ) ) {
136 throw "Setting X509-version to 3 failed";
139 if( !X509_set_issuer_name( ret.get(), X509_get_subject_name( caCert.get() ) ) ) {
140 throw "Error setting Issuer name";
144 ASN1_INTEGER_set( ci->serialNumber, 4711 );
145 pktmp = X509_REQ_get_pubkey( req.get() );
147 if( !X509_set_pubkey( ret.get(), pktmp ) ) {
148 EVP_PKEY_free( pktmp );
149 throw "Setting public key failed.";
151 EVP_PKEY_free( pktmp );
155 X509_gmtime_adj( X509_get_notBefore( ret.get() ), 0 );
156 X509_gmtime_adj( X509_get_notAfter( ret.get() ), ( long )60 * 60 * 24 * 10 );
159 add_ext( caCert, ret.get(), NID_basic_constraints, "critical,CA:FALSE" );
160 add_ext( caCert, ret.get(), NID_subject_key_identifier, "hash" );
161 add_ext( caCert, ret.get(), NID_authority_key_identifier, "keyid,issuer:always" );
162 add_ext( caCert, ret.get(), NID_key_usage, "critical,nonRepudiation,digitalSignature,keyEncipherment" );
163 add_ext( caCert, ret.get(), NID_ext_key_usage, "clientAuth, serverAut" );
164 add_ext( caCert, ret.get(), NID_info_access, "OCSP;URI:http://ocsp.cacert.org" );
165 add_ext( caCert, ret.get(), NID_crl_distribution_points, "URI:http://crl.cacert.org/class3-revoke.crl" );
167 if( !X509_sign( ret.get(), caKey.get(), EVP_sha512() ) ) {
168 throw "Signing failed.";
171 X509_print_fp( stdout, ret.get() );
172 std::shared_ptr<BIO> mem = std::shared_ptr<BIO>( BIO_new( BIO_s_mem() ), BIO_free );
173 PEM_write_bio_X509( mem.get(), ret.get() );
175 BIO_get_mem_ptr( mem.get(), &buf );
176 std::string output( buf->data, buf->data + buf->length );
177 std::cout << "Certificate:" << std::endl << output << std::endl;