9 #include "crypto/CRL.h"
10 #include "log/logger.hpp"
13 std::shared_ptr<int> ssl_lib_ref(
14 new int( SSL_library_init() ),
19 CRYPTO_cleanup_all_ex_data();
23 std::shared_ptr<X509> loadX509FromFile( const std::string& filename ) {
24 std::shared_ptr<FILE> f( fopen( filename.c_str(), "r" ), fclose );
27 return std::shared_ptr<X509>();
30 X509 *key = PEM_read_X509( f.get(), NULL, NULL, 0 );
33 return std::shared_ptr<X509>();
36 auto freeX509 = []( X509 * ref ) {
39 return std::shared_ptr<X509>( key, freeX509 );
42 std::shared_ptr<EVP_PKEY> loadPkeyFromFile( const std::string& filename ) {
43 auto freeFile = []( FILE * ptr ) {
48 std::shared_ptr<FILE> f( fopen( filename.c_str(), "r" ), freeFile );
51 return std::shared_ptr<EVP_PKEY>();
54 EVP_PKEY *key = PEM_read_PrivateKey( f.get(), NULL, NULL, 0 );
57 return std::shared_ptr<EVP_PKEY>();
60 auto freeKey = []( EVP_PKEY * ref ) {
63 return std::shared_ptr<EVP_PKEY>( key, freeKey );
66 int gencb( int a, int b, BN_GENCB *g ) {
71 std::cout << ( a == 0 ? "." : "+" ) << std::flush;
76 static int verify_callback( int preverify_ok, X509_STORE_CTX *ctx ) {
78 //auto cert = X509_STORE_CTX_get_current_cert(ctx);
79 //BIO *o = BIO_new_fp(stdout,BIO_NOCLOSE);
80 //X509_print_ex(o, cert, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
83 logger::errorf( "Verification failed: %s because %s", preverify_ok, X509_STORE_CTX_get_error( ctx ) );
89 static std::shared_ptr<DH> dh_param;
91 std::shared_ptr<SSL_CTX> generateSSLContext( bool server ) {
92 auto freeSSL = []( SSL_CTX * p ) {
95 std::shared_ptr<SSL_CTX> ctx = std::shared_ptr<SSL_CTX>( SSL_CTX_new( TLS_method() ), freeSSL );
97 if( !SSL_CTX_set_cipher_list( ctx.get(), "HIGH:+CAMELLIA256:!eNull:!aNULL:!ADH:!MD5:-RSA+AES+SHA1:!RC4:!DES:!3DES:!SEED:!EXP:!AES128:!CAMELLIA128" ) ) {
98 throw std::runtime_error( "Cannot set cipher list. Your source is broken." );
101 SSL_CTX_set_verify( ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback );
102 SSL_CTX_use_certificate_file( ctx.get(), server ? "keys/signer_server.crt" : "keys/signer_client.crt", SSL_FILETYPE_PEM );
103 SSL_CTX_use_PrivateKey_file( ctx.get(), server ? "keys/signer_server.key" : "keys/signer_client.key", SSL_FILETYPE_PEM );
105 if( 1 != SSL_CTX_load_verify_locations( ctx.get(), "keys/ca.crt", 0 ) ) {
106 throw std::runtime_error( "Cannot load CA store for certificate validation." );
110 STACK_OF( X509_NAME ) *names = SSL_load_client_CA_file( "keys/env.crt" );
113 SSL_CTX_set_client_CA_list( ctx.get(), names );
119 std::shared_ptr<FILE> paramfile( fopen( "dh_param.pem", "r" ), fclose );
122 dh_param = std::shared_ptr<DH>( PEM_read_DHparams( paramfile.get(), NULL, NULL, NULL ), DH_free );
124 dh_param = std::shared_ptr<DH>( DH_new(), DH_free );
125 logger::note( "Generating DH params" );
126 BN_GENCB *cb = BN_GENCB_new();
127 BN_GENCB_set( cb, gencb, NULL );
129 if( !DH_generate_parameters_ex( dh_param.get(), 2048, 5, cb ) ) {
130 throw std::runtime_error( "DH generation failed" );
135 std::cout << std::endl;
136 paramfile = std::shared_ptr<FILE>( fopen( "dh_param.pem", "w" ), fclose );
139 PEM_write_DHparams( paramfile.get(), dh_param.get() );
144 if( !SSL_CTX_set_tmp_dh( ctx.get(), dh_param.get() ) ) {
145 throw std::runtime_error( "Cannot set tmp dh." );
152 void setupSerial( std::shared_ptr<FILE> f ) {
155 if( tcgetattr( fileno( f.get() ), &attr ) ) {
156 throw std::runtime_error( "failed to get attrs" );
159 attr.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON );
160 attr.c_oflag &= ~OPOST;
161 attr.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
162 attr.c_cflag &= ~( CSIZE | PARENB );
165 cfsetispeed( &attr, B115200 );
166 cfsetospeed( &attr, B115200 );
168 if( tcsetattr( fileno( f.get() ), TCSANOW, &attr ) ) {
169 throw std::runtime_error( "failed to get attrs" );
173 std::shared_ptr<BIO> openSerial( const std::string& name ) {
174 std::shared_ptr<FILE> f( fopen( name.c_str(), "r+" ), fclose );
177 logger::error( "Opening serial device failed." );
178 return std::shared_ptr<BIO>();
182 auto freeBIO = [f]( BIO * b ) {
185 return std::shared_ptr<BIO>( BIO_new_fd( fileno( f.get() ), 0 ), freeBIO );
188 extern std::string crlPrefix;
189 extern std::string crtPrefix;
191 CAConfig::CAConfig( const std::string& name ) : path( "ca/" + name ), name( name ) {
192 ca = loadX509FromFile( path + "/ca.crt" );
195 throw new std::invalid_argument( "ca name: " + name + " contains unreadable certificate." );
198 caKey = loadPkeyFromFile( path + "/ca.key" );
200 ASN1_TIME *tm = X509_get_notBefore( ca.get() ); // tm MUST NOT be free'd; duplicate for owning copy.
201 notBefore = std::shared_ptr<ASN1_TIME>( ASN1_STRING_dup( tm ), ASN1_TIME_free );
203 std::size_t pos = name.find( "_" );
205 if( pos == std::string::npos ) {
206 throw new std::invalid_argument( "ca name: " + name + " is malformed." );
209 std::size_t pos2 = name.find( "_", pos + 1 );
211 if( pos2 == std::string::npos ) {
212 throw new std::invalid_argument( "ca name: " + name + " is malformed." );
215 crlURL = crlPrefix + "/g2/" + name.substr( pos + 1, pos2 - pos - 1 ) + "/" + name.substr( 0, pos ) + "-" + name.substr( pos2 + 1 ) + ".crl";
216 crtURL = crtPrefix + "/g2/" + name.substr( pos + 1, pos2 - pos - 1 ) + "/" + name.substr( 0, pos ) + "-" + name.substr( pos2 + 1 ) + ".crt";
219 std::string timeToString( std::shared_ptr<ASN1_TIME> time ) {
220 std::shared_ptr<ASN1_GENERALIZEDTIME> gtime( ASN1_TIME_to_generalizedtime( time.get(), 0 ), ASN1_GENERALIZEDTIME_free );
221 std::string strdate( ( char * ) ASN1_STRING_get0_data( gtime.get() ), ASN1_STRING_length( gtime.get() ) );
223 logger::notef( "openssl formatted me a date: %s", strdate );
225 if( strdate[strdate.size() - 1] != 'Z' ) {
226 throw std::runtime_error( "Got invalid date?" );
229 return strdate.substr( 0, strdate.size() - 1 );
232 void extractTimes( std::shared_ptr<X509> target, std::shared_ptr<SignedCertificate> cert ) {
233 cert->before = timeToString( std::shared_ptr<ASN1_TIME>( X509_get_notBefore( target.get() ), [target]( auto p ) {
236 cert->after = timeToString( std::shared_ptr<ASN1_TIME>( X509_get_notAfter( target.get() ), [target]( auto p ) {
241 bool CAConfig::crlNeedsResign() {
242 auto crl = std::make_shared<CRL>( path + "/ca.crl" );
243 return crl->needsResign();