1 #include "io/recordHandler.h"
6 #include <unordered_map>
8 #include <openssl/ssl.h>
10 #include "io/record.h"
11 #include "io/opensslBIO.h"
12 #include "io/slipBio.h"
14 #include "db/database.h"
15 #include "crypto/remoteSigner.h"
16 #include "crypto/sslUtil.h"
18 #include "crypto/simpleOpensslSigner.h"
20 extern std::vector<Profile> profiles;
21 extern std::unordered_map<std::string, std::shared_ptr<CAConfig>> CAs;
23 class RecordHandlerSession {
26 uint32_t lastCommandCount;
28 std::shared_ptr<TBSCertificate> tbs;
29 std::shared_ptr<SignedCertificate> result;
31 std::shared_ptr<SSL> ssl;
33 std::shared_ptr<OpensslBIOWrapper> io;
34 DefaultRecordHandler* parent;
35 std::shared_ptr<Signer> signer;
37 std::shared_ptr<std::ofstream> log;
39 RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
40 tbs( new TBSCertificate() ) {
41 this->parent = parent;
42 this->signer = signer;
45 if( time( &c_time ) == -1 ) {
46 throw "Error while fetching time?";
49 log = std::shared_ptr<std::ofstream>(
50 new std::ofstream( std::string( "logs/log_" ) + std::to_string( c_time ) ),
51 []( std::ofstream * ptr ) {
56 ssl = std::shared_ptr<SSL>( SSL_new( ctx.get() ), SSL_free );
57 std::shared_ptr<BIO> bio(
58 BIO_new( BIO_f_ssl() ),
62 SSL_set_accept_state( ssl.get() );
63 SSL_set_bio( ssl.get(), output.get(), output.get() );
64 BIO_set_ssl( bio.get(), ssl.get(), BIO_NOCLOSE );
65 io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
68 void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
70 rh.command = ( uint16_t ) res;
72 rh.command_count = 0; // TODO i++
73 rh.totalLength = payload.size();
74 sendCommand( rh, payload, io, log );
78 std::vector<char> buffer( 2048, 0 );
79 int res = io->read( buffer.data(), buffer.capacity() );
82 ( *log ) << "Stream error, resetting SSL" << std::endl;
87 std::string content( buffer.data(), res );
91 std::string payload = parseCommand( head, content, log );
92 execute( head, payload );
93 } catch( const char* msg ) {
95 ( *log ) << "ERROR: " << msg << std::endl;
103 void execute( RecordHeader& head, std::string data ) {
104 if( head.totalLength != head.payloadLength || head.offset != 0 ) {
105 throw "Error, chunking not supported yet";
108 switch( ( RecordHeader::SignerCommand ) head.command ) {
109 case RecordHeader::SignerCommand::SET_CSR:
110 tbs->csr_content = data;
111 tbs->csr_type = "CSR";
112 ( *log ) << "INFO: CSR read:" << std::endl << tbs->csr_content;
115 case RecordHeader::SignerCommand::SET_SPKAC:
116 tbs->csr_content = data;
117 tbs->csr_type = "SPKAC";
118 ( *log ) << "INFO: SPKAC read:" << std::endl << tbs->csr_content;
121 case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
125 case RecordHeader::SignerCommand::SET_PROFILE:
130 case RecordHeader::SignerCommand::ADD_SAN: {
131 size_t pos = data.find( "," );
133 if( pos == std::string::npos ) {
136 std::shared_ptr<SAN> san( new SAN() );
137 san->type = data.substr( 0, pos );
138 san->content = data.substr( pos + 1 );
139 tbs->SANs.push_back( san );
144 case RecordHeader::SignerCommand::ADD_AVA: {
145 size_t pos = data.find( "," );
147 if( pos == std::string::npos ) {
150 std::shared_ptr<AVA> ava( new AVA() );
151 ava->name = data.substr( 0, pos );
152 ava->value = data.substr( pos + 1 );
153 tbs->AVAs.push_back( ava );
158 case RecordHeader::SignerCommand::ADD_PROOF_LINE:
161 case RecordHeader::SignerCommand::SIGN:
162 result = signer->sign( tbs );
163 ( *log ) << "INFO: signlog: " << result->log << std::endl;
164 ( *log ) << "INFO: res: " << result->certificate << std::endl;
165 respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
168 case RecordHeader::SignerCommand::LOG_SAVED:
170 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
173 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
174 ( *log ) << "ERROR: SSL close failed" << std::endl;
179 case RecordHeader::SignerCommand::REVOKE: {
180 ( *log ) << "got revoking command: " << data.size() << std::endl;
181 std::string nullstr( "\0", 1 );
182 size_t t = data.find( nullstr );
184 if( t == std::string::npos ) {
186 ( *log ) << "error while parsing revoking command." << data << std::endl;
190 std::string ca = data.substr( 0, t );
191 std::string serial = data.substr( t + 1 );
192 ( *log ) << "revoking " << ca << "<->" << serial << std::endl;
196 for( auto x : CAs ) {
197 ( *log ) << x.first << ", ";
200 ( *log ) << "]" << std::endl;
202 auto reqCA = CAs.at( ca );
203 ( *log ) << "CA found" << std::endl;
204 std::shared_ptr<CRL> crl;
206 std::tie<std::shared_ptr<CRL>, std::string>( crl, date ) = signer->revoke( reqCA, serial );
208 respondCommand( RecordHeader::SignerResult::REVOKED, date + crl->getSignature() );
213 case RecordHeader::SignerCommand::GET_FULL_CRL: {
214 auto ca = CAs.at( data );
215 CRL c( ca->path + "/ca.crl" );
216 respondCommand( RecordHeader::SignerResult::FULL_CRL, c.toString() );
218 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
219 ( *log ) << "ERROR: SSL close failed" << std::endl;
226 throw "Unimplemented";
231 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
234 this->signer = signer;
236 ctx = generateSSLContext( true );
241 void DefaultRecordHandler::reset() {
242 currentSession = std::shared_ptr<RecordHandlerSession>();
245 void DefaultRecordHandler::handle() {
246 if( !currentSession ) {
247 std::cout << "session allocated" << std::endl;
248 currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
251 currentSession->work();