]> WPIA git - cassiopeia.git/blob - src/simpleOpensslSigner.cpp
3ef4b5eecad6e1f47ad9e13b286dede467552457
[cassiopeia.git] / src / simpleOpensslSigner.cpp
1 #include "simpleOpensslSigner.h"
2
3 #include <iostream>
4
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>
11
12 std::shared_ptr<int> SimpleOpensslSigner::lib_ref(
13     new int( SSL_library_init() ),
14     []( int* ref ) {
15         ( void ) ref;
16     } );
17
18 std::shared_ptr<X509> loadX509FromFile( std::string filename ) {
19     FILE* f = fopen( filename.c_str(), "r" );
20
21     if( !f ) {
22         return std::shared_ptr<X509>();
23     }
24
25     X509* key = PEM_read_X509( f, NULL, NULL, 0 );
26     fclose( f );
27
28     if( !key ) {
29         return std::shared_ptr<X509>();
30     }
31
32     return std::shared_ptr<X509>(
33         key,
34         []( X509 * ref ) {
35             X509_free( ref );
36         } );
37 }
38
39 std::shared_ptr<EVP_PKEY> loadPkeyFromFile( std::string filename ) {
40     FILE* f = fopen( filename.c_str(), "r" );
41
42     if( !f ) {
43         return std::shared_ptr<EVP_PKEY>();
44     }
45
46     EVP_PKEY* key = PEM_read_PrivateKey( f, NULL, NULL, 0 );
47     fclose( f );
48
49     if( !key ) {
50         return std::shared_ptr<EVP_PKEY>();
51     }
52
53     return std::shared_ptr<EVP_PKEY>(
54         key,
55         []( EVP_PKEY * ref ) {
56             EVP_PKEY_free( ref );
57         } );
58 }
59
60 std::shared_ptr<X509> SimpleOpensslSigner::caCert = loadX509FromFile( "assured.crt" );
61
62 std::shared_ptr<EVP_PKEY> SimpleOpensslSigner::caKey = loadPkeyFromFile( "assured.key" );
63
64 int add_ext( std::shared_ptr<X509> issuer, X509* subj, int nid, const char* value ) {
65     X509_EXTENSION* ex;
66     X509V3_CTX ctx;
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
72      */
73     X509V3_set_ctx( &ctx, issuer.get(), subj, NULL, NULL, 0 );
74     ex = X509V3_EXT_conf_nid( NULL, &ctx, nid, const_cast<char*>( value ) );
75
76     if( !ex ) {
77         return 0;
78     }
79
80     X509_add_ext( subj, ex, -1 );
81     X509_EXTENSION_free( ex );
82     return 1;
83 }
84
85 void SimpleOpensslSigner::sign( std::shared_ptr<TBSCertificate> cert ) {
86     if( !caKey ) {
87         throw "CA-key not found";
88     }
89
90     std::shared_ptr<BIO> in = std::shared_ptr<BIO>(
91         BIO_new_mem_buf( const_cast<char*>( cert->csr_content.c_str() ), -1 ),
92         []( BIO * ref ) {
93             BIO_free( ref );
94         } );
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 ) {
98             if( ref ) {
99                 X509_REQ_free( ref );
100             }
101         } );
102
103     if( !req ) {
104         throw "Error parsing CSR";
105     }
106
107     EVP_PKEY* pktmp = X509_REQ_get_pubkey( req.get() );
108
109     if( !pktmp ) {
110         throw "Error extracting pubkey";
111     }
112
113     EVP_PKEY_free( pktmp );
114
115     int i = X509_REQ_verify( req.get(), pktmp );
116
117     if( i < 0 ) {
118         throw "Signature problems ... ";
119     } else if( i == 0 ) {
120         throw "Signature did not match";
121     } else {
122         std::cerr << "Signature ok" << std::endl;
123     }
124
125     // Construct the Certificate
126
127     std::shared_ptr<X509> ret = std::shared_ptr<X509>( X509_new(), X509_free );
128
129     if( !ret ) {
130         throw "Creating X509 failed.";
131     }
132
133     X509_CINF* ci = ret->cert_info;
134
135     if( !X509_set_version( ret.get(), 2 ) ) {
136         throw "Setting X509-version to 3 failed";
137     }
138
139     if( !X509_set_issuer_name( ret.get(), X509_get_subject_name( caCert.get() ) ) ) {
140         throw "Error setting Issuer name";
141     }
142
143     // Serial and Pubkey
144     ASN1_INTEGER_set( ci->serialNumber, 4711 );
145     pktmp = X509_REQ_get_pubkey( req.get() );
146
147     if( !X509_set_pubkey( ret.get(), pktmp ) ) {
148         EVP_PKEY_free( pktmp );
149         throw "Setting public key failed.";
150     } else {
151         EVP_PKEY_free( pktmp );
152     }
153
154     // Dates
155     X509_gmtime_adj( X509_get_notBefore( ret.get() ), 0 );
156     X509_gmtime_adj( X509_get_notAfter( ret.get() ), ( long )60 * 60 * 24 * 10 );
157
158     // Extensions
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" );
166
167     if( !X509_sign( ret.get(), caKey.get(), EVP_sha512() ) ) {
168         throw "Signing failed.";
169     }
170
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() );
174     BUF_MEM* buf;
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;
178 }