1 #include "io/recordHandler.h"
6 #include <unordered_map>
8 #include <openssl/ssl.h>
11 #include "io/record.h"
12 #include "io/opensslBIO.h"
13 #include "io/slipBio.h"
15 #include "db/database.h"
16 #include "crypto/remoteSigner.h"
17 #include "crypto/sslUtil.h"
19 #include "crypto/simpleOpensslSigner.h"
21 extern std::vector<Profile> profiles;
22 extern std::unordered_map<std::string, std::shared_ptr<CAConfig>> CAs;
24 class RecordHandlerSession {
27 uint32_t lastCommandCount;
29 std::shared_ptr<TBSCertificate> tbs;
30 std::shared_ptr<SignedCertificate> result;
32 std::shared_ptr<SSL> ssl;
34 std::shared_ptr<OpensslBIOWrapper> io;
35 DefaultRecordHandler* parent;
36 std::shared_ptr<Signer> signer;
38 std::shared_ptr<std::ofstream> log;
39 std::vector<std::string> serials;
41 RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
43 lastCommandCount( 0 ),
44 tbs( new TBSCertificate() ) {
45 this->parent = parent;
46 this->signer = signer;
49 if( time( &c_time ) == -1 ) {
50 throw "Error while fetching time?";
53 log = openLogfile( std::string( "logs/log_" ) + std::to_string( c_time ) );
55 ssl = std::shared_ptr<SSL>( SSL_new( ctx.get() ), SSL_free );
56 std::shared_ptr<BIO> bio(
57 BIO_new( BIO_f_ssl() ),
61 SSL_set_accept_state( ssl.get() );
62 SSL_set_bio( ssl.get(), output.get(), output.get() );
63 BIO_set_ssl( bio.get(), ssl.get(), BIO_NOCLOSE );
64 io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
67 void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
69 rh.command = ( uint16_t ) res;
71 rh.command_count = 0; // TODO i++
72 rh.totalLength = payload.size();
73 sendCommand( rh, payload, io, log );
77 std::vector<char> buffer( 2048, 0 );
78 int res = io->read( buffer.data(), buffer.capacity() );
81 ( *log ) << "Stream error, resetting SSL" << std::endl;
86 std::string content( buffer.data(), res );
90 std::string payload = parseCommand( head, content, log );
91 execute( head, payload );
92 } catch( const char* msg ) {
94 ( *log ) << "ERROR: " << msg << std::endl;
102 void execute( RecordHeader& head, std::string data ) {
103 if( head.totalLength != head.payloadLength || head.offset != 0 ) {
104 throw "Error, chunking not supported yet";
107 switch( ( RecordHeader::SignerCommand ) head.command ) {
108 case RecordHeader::SignerCommand::SET_CSR:
109 tbs->csr_content = data;
110 tbs->csr_type = "CSR";
111 ( *log ) << "INFO: CSR read: " << tbs->csr_content << std::endl;
114 case RecordHeader::SignerCommand::SET_SPKAC:
115 tbs->csr_content = data;
116 tbs->csr_type = "SPKAC";
117 ( *log ) << "INFO: SPKAC read: " << tbs->csr_content << std::endl;
120 case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
124 case RecordHeader::SignerCommand::SET_PROFILE:
129 case RecordHeader::SignerCommand::SET_WISH_FROM:
130 tbs->wishFrom = data;
133 case RecordHeader::SignerCommand::SET_WISH_TO:
137 case RecordHeader::SignerCommand::ADD_SAN: {
138 size_t pos = data.find( "," );
140 if( pos == std::string::npos ) {
143 std::shared_ptr<SAN> san( new SAN() );
144 san->type = data.substr( 0, pos );
145 san->content = data.substr( pos + 1 );
146 tbs->SANs.push_back( san );
151 case RecordHeader::SignerCommand::ADD_AVA: {
152 size_t pos = data.find( "," );
154 if( pos == std::string::npos ) {
157 std::shared_ptr<AVA> ava( new AVA() );
158 ava->name = data.substr( 0, pos );
159 ava->value = data.substr( pos + 1 );
160 tbs->AVAs.push_back( ava );
165 case RecordHeader::SignerCommand::ADD_PROOF_LINE:
168 case RecordHeader::SignerCommand::SIGN:
169 result = signer->sign( tbs );
170 ( *log ) << "INFO: signlog: " << result->log << std::endl;
171 ( *log ) << "INFO: res: " << result->certificate << std::endl;
172 respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
175 case RecordHeader::SignerCommand::LOG_SAVED:
177 respondCommand( RecordHeader::SignerResult::SIGNING_CA, result->ca_name );
178 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
181 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
182 ( *log ) << "ERROR: SSL close failed" << std::endl;
184 parent->reset(); // Connection ended
188 case RecordHeader::SignerCommand::ADD_SERIAL:
189 serials.push_back( data );
192 case RecordHeader::SignerCommand::REVOKE: {
193 std::string ca = data;
194 auto reqCA = CAs.at( ca );
195 ( *log ) << "CA found" << std::endl;
196 std::shared_ptr<CRL> crl;
198 std::tie<std::shared_ptr<CRL>, std::string>( crl, date ) = signer->revoke( reqCA, serials );
200 respondCommand( RecordHeader::SignerResult::REVOKED, date + crl->getSignature() );
205 case RecordHeader::SignerCommand::GET_FULL_CRL: {
206 auto ca = CAs.at( data );
207 CRL c( ca->path + "/ca.crl" );
208 respondCommand( RecordHeader::SignerResult::FULL_CRL, c.toString() );
210 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
211 ( *log ) << "ERROR: SSL close failed" << std::endl;
213 parent->reset(); // Connection ended
218 throw "Unimplemented";
223 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio )
224 : bio( bio ), ctx( generateSSLContext( true ) ), signer( signer ), currentSession() {
227 void DefaultRecordHandler::reset() {
228 currentSession = std::shared_ptr<RecordHandlerSession>();
231 void DefaultRecordHandler::handle() {
232 if( !currentSession ) {
233 std::cout << "session allocated" << std::endl;
234 currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
237 currentSession->work();