]> WPIA git - cassiopeia.git/blob - src/io/recordHandler.cpp
upd: various logging updates
[cassiopeia.git] / src / io / recordHandler.cpp
1 #include "io/recordHandler.h"
2
3 #include <iostream>
4 #include <sstream>
5 #include <fstream>
6 #include <ctime>
7 #include <unordered_map>
8
9 #include <openssl/ssl.h>
10
11 #include "util.h"
12 #include "io/record.h"
13 #include "io/opensslBIO.h"
14 #include "io/slipBio.h"
15
16 #include "db/database.h"
17 #include "crypto/remoteSigner.h"
18 #include "crypto/sslUtil.h"
19 #include "crypto/simpleOpensslSigner.h"
20
21 #include "log/logger.hpp"
22
23 extern std::vector<Profile> profiles;
24 extern std::unordered_map<std::string, std::shared_ptr<CAConfig>> CAs;
25
26 class RecordHandlerSession {
27 public:
28     uint32_t sessid;
29     uint32_t lastCommandCount;
30
31     std::shared_ptr<TBSCertificate> tbs;
32     std::shared_ptr<SignedCertificate> result;
33
34     std::shared_ptr<SSL> ssl;
35
36     std::shared_ptr<OpensslBIOWrapper> io;
37     DefaultRecordHandler* parent;
38     std::shared_ptr<Signer> signer;
39
40     std::shared_ptr<std::ofstream> logFile;
41     //std::stringstream sessionlog;
42     std::vector<std::string> serials;
43     logger::logger_set logger;
44
45
46     RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
47         sessid( 0 ),
48         lastCommandCount( 0 ),
49         tbs( new TBSCertificate() ),
50         logFile(openLogfile( std::string( "logs/log_" ) + std::to_string( [](){
51                         time_t c_time;
52                         if( time( &c_time ) == -1 ) {
53                             throw "Error while fetching time?";
54                         }
55                         return c_time;
56                         }() ) )),
57         logger( {
58                 logger::log_target(std::cout, logger::level::note),
59                     //logger::log_target(sessionlog, logger::level::note),
60                     logger::log_target(*logFile, logger::level::note)
61                }, logger::auto_register::on) {
62         this->parent = parent;
63         this->signer = signer;
64
65         ssl = std::shared_ptr<SSL>( SSL_new( ctx.get() ), SSL_free );
66         std::shared_ptr<BIO> bio(
67             BIO_new( BIO_f_ssl() ),
68             [output]( BIO * p ) {
69                 BIO_free( p );
70             } );
71         SSL_set_accept_state( ssl.get() );
72         SSL_set_bio( ssl.get(), output.get(), output.get() );
73         BIO_set_ssl( bio.get(), ssl.get(), BIO_NOCLOSE );
74         io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
75     }
76
77     void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
78         RecordHeader rh;
79         rh.command = ( uint16_t ) res;
80         rh.flags = 0;
81         rh.command_count = 0; // TODO i++
82         rh.totalLength = payload.size();
83         sendCommand( rh, payload, io );
84     }
85
86     void work() {
87         std::vector<char> buffer( 2048, 0 );
88         int res = io->read( buffer.data(), buffer.capacity() );
89
90         if( res <= 0 ) {
91             logger::error( "Stream error, resetting SSL" );
92             parent->reset();
93             return;
94         }
95
96         std::string content( buffer.data(), res );
97
98         try {
99             RecordHeader head;
100             std::string payload = parseCommand( head, content );
101             execute( head, payload );
102         } catch( const char* msg ) {
103             logger::error( "ERROR: ", msg );
104             parent->reset();
105             return;
106         }
107     }
108
109     void execute( RecordHeader& head, std::string data ) {
110         if( head.totalLength != head.payloadLength || head.offset != 0 ) {
111             throw "Error, chunking not supported yet";
112         }
113
114         switch( ( RecordHeader::SignerCommand ) head.command ) {
115         case RecordHeader::SignerCommand::SET_CSR:
116             tbs->csr_content = data;
117             tbs->csr_type = "CSR";
118             logger::note( "INFO: CSR read:\n", tbs->csr_content );
119             break;
120
121         case RecordHeader::SignerCommand::SET_SPKAC:
122             tbs->csr_content = data;
123             tbs->csr_type = "SPKAC";
124             logger::note( "INFO: SPKAC read:\n", tbs->csr_content );
125             break;
126
127         case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
128             tbs->md = data;
129             break;
130
131         case RecordHeader::SignerCommand::SET_PROFILE:
132             // TODO
133             tbs->profile = data;
134             break;
135
136         case RecordHeader::SignerCommand::SET_WISH_FROM:
137             tbs->wishFrom = data;
138             break;
139
140         case RecordHeader::SignerCommand::SET_WISH_TO:
141             tbs->wishTo = data;
142             break;
143
144         case RecordHeader::SignerCommand::ADD_SAN:
145             {
146                 size_t pos = data.find( "," );
147
148                 if( pos == std::string::npos ) {
149                     // error
150                 } else {
151                     std::shared_ptr<SAN> san( new SAN() );
152                     san->type = data.substr( 0, pos );
153                     san->content = data.substr( pos + 1 );
154                     tbs->SANs.push_back( san );
155                 }
156             }
157             break;
158
159         case RecordHeader::SignerCommand::ADD_AVA:
160             {
161                 size_t pos = data.find( "," );
162
163                 if( pos == std::string::npos ) {
164                     // error
165                 } else {
166                     std::shared_ptr<AVA> ava( new AVA() );
167                     ava->name = data.substr( 0, pos );
168                     ava->value = data.substr( pos + 1 );
169                     tbs->AVAs.push_back( ava );
170                 }
171             }
172             break;
173
174         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
175             break;
176
177         case RecordHeader::SignerCommand::SIGN:
178             result = signer->sign( tbs );
179             logger::note( "INFO: signlog:\n", result->log );
180             logger::note( "INFO: res:\n", result->certificate );
181             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
182             break;
183
184         case RecordHeader::SignerCommand::LOG_SAVED:
185             if( result ) {
186                 respondCommand( RecordHeader::SignerResult::SIGNING_CA, result->ca_name );
187                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
188             }
189
190             if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
191                 logger::warn( "ERROR: SSL shutdown failed." );
192             }
193
194             parent->reset(); // Connection ended
195
196             break;
197
198         case RecordHeader::SignerCommand::ADD_SERIAL:
199             serials.push_back( data );
200             break;
201
202         case RecordHeader::SignerCommand::REVOKE:
203             {
204                 logger::note("Revoking: ", data);
205                 std::string ca = data;
206                 auto reqCA = CAs.at( ca );
207                 logger::note( "CA found in recordHandler" );
208                 std::shared_ptr<CRL> crl;
209                 std::string date;
210                 std::tie<std::shared_ptr<CRL>, std::string>( crl, date ) = signer->revoke( reqCA, serials );
211
212                 respondCommand( RecordHeader::SignerResult::REVOKED, date + crl->getSignature() );
213             }
214             break;
215
216         case RecordHeader::SignerCommand::GET_FULL_CRL:
217             {
218                 logger::note("Requesting full CRL: ", data);
219                 auto ca = CAs.at( data );
220                 CRL c( ca->path + "/ca.crl" );
221                 respondCommand( RecordHeader::SignerResult::FULL_CRL, c.toString() );
222
223                 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
224                     logger::error( "ERROR: SSL shutdown failed." );
225                 }
226
227                 parent->reset(); // Connection ended
228             }
229             break;
230
231         default:
232             throw "Unimplemented";
233         }
234     }
235 };
236
237 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
238     bio( bio ), ctx( generateSSLContext( true ) ), signer( signer ), currentSession() {
239 }
240
241 void DefaultRecordHandler::reset() {
242     currentSession = std::shared_ptr<RecordHandlerSession>();
243 }
244
245 void DefaultRecordHandler::handle() {
246     if( !currentSession ) {
247         logger::note( "New session allocated." );
248         currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
249     }
250
251     currentSession->work();
252 }