]> WPIA git - cassiopeia.git/blob - src/io/recordHandler.cpp
change to postgres with libpqxx
[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 = 0;
29     uint32_t lastCommandCount = 0;
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::unique_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         tbs( std::make_shared<TBSCertificate>() ),
48         logFile(openLogfile( "logs/log_" + timestamp() ) ),
49         logger{ std::cout, *logFile } {
50         this->parent = parent;
51         this->signer = signer;
52
53         ssl = std::shared_ptr<SSL>( SSL_new( ctx.get() ), SSL_free );
54         std::shared_ptr<BIO> bio(
55             BIO_new( BIO_f_ssl() ),
56             [output]( BIO * p ) {
57                 BIO_free( p );
58             } );
59         SSL_set_accept_state( ssl.get() );
60         SSL_set_bio( ssl.get(), output.get(), output.get() );
61         BIO_set_ssl( bio.get(), ssl.get(), BIO_NOCLOSE );
62         io = std::make_shared<OpensslBIOWrapper>( bio );
63     }
64
65     void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
66         RecordHeader rh;
67         rh.command = static_cast<uint16_t>( res );
68         rh.flags = 0;
69         rh.command_count = 0; // TODO i++
70         rh.totalLength = payload.size();
71         sendCommand( rh, payload, io );
72     }
73
74     void work() {
75         std::vector<char> buffer( 2048 );
76         int res = io->read( buffer.data(), buffer.size() );
77
78         if( res <= 0 ) {
79             logger::error( "Stream error, resetting SSL" );
80             parent->reset();
81             return;
82         }
83
84         std::string content( buffer.data(), res );
85
86         try {
87             RecordHeader head;
88             std::string payload = parseCommand( head, content );
89             execute( head, payload );
90         } catch( const char* msg ) {
91             logger::error( "ERROR: ", msg );
92             parent->reset();
93             return;
94         }
95     }
96
97     void execute( RecordHeader& head, std::string data ) {
98         if( head.totalLength != head.payloadLength || head.offset != 0 ) {
99             throw "Error, chunking not supported yet";
100         }
101
102         switch( static_cast<RecordHeader::SignerCommand>( head.command )) {
103         case RecordHeader::SignerCommand::SET_CSR:
104             tbs->csr_content = data;
105             tbs->csr_type = "CSR";
106             logger::note( "INFO: CSR read:\n", tbs->csr_content );
107             break;
108
109         case RecordHeader::SignerCommand::SET_SPKAC:
110             tbs->csr_content = data;
111             tbs->csr_type = "SPKAC";
112             logger::note( "INFO: SPKAC read:\n", tbs->csr_content );
113             break;
114
115         case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
116             tbs->md = data;
117             break;
118
119         case RecordHeader::SignerCommand::SET_PROFILE:
120             // TODO
121             tbs->profile = data;
122             break;
123
124         case RecordHeader::SignerCommand::SET_WISH_FROM:
125             tbs->wishFrom = data;
126             break;
127
128         case RecordHeader::SignerCommand::SET_WISH_TO:
129             tbs->wishTo = data;
130             break;
131
132         case RecordHeader::SignerCommand::ADD_SAN:
133             {
134                 size_t pos = data.find( "," );
135
136                 if( pos == std::string::npos ) {
137                     // error
138                 } else {
139                     auto san = std::make_shared<SAN>();
140                     san->type = data.substr( 0, pos );
141                     san->content = data.substr( pos + 1 );
142                     tbs->SANs.push_back( san );
143                 }
144             }
145             break;
146
147         case RecordHeader::SignerCommand::ADD_AVA:
148             {
149                 size_t pos = data.find( "," );
150
151                 if( pos == std::string::npos ) {
152                     // error
153                 } else {
154                     auto ava = std::make_shared<AVA>();
155                     ava->name = data.substr( 0, pos );
156                     ava->value = data.substr( pos + 1 );
157                     tbs->AVAs.push_back( ava );
158                 }
159             }
160             break;
161
162         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
163             break;
164
165         case RecordHeader::SignerCommand::SIGN:
166             result = signer->sign( tbs );
167             logger::note( "INFO: signlog:\n", result->log );
168             logger::note( "INFO: res:\n", result->certificate );
169             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
170             break;
171
172         case RecordHeader::SignerCommand::LOG_SAVED:
173             if( result ) {
174                 respondCommand( RecordHeader::SignerResult::SIGNING_CA, result->ca_name );
175                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
176             }
177
178             logger::note( "Shutting down SSL" );
179             if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
180                 logger::warn( "ERROR: SSL shutdown failed." );
181             }
182             io->ctrl( BIO_CTRL_FLUSH, 0, NULL );
183             logger::note( "Shutted down SSL" );
184
185             parent->reset(); // Connection ended
186
187             break;
188
189         case RecordHeader::SignerCommand::ADD_SERIAL:
190             serials.push_back( data );
191             break;
192
193         case RecordHeader::SignerCommand::REVOKE:
194             {
195                 logger::note("Revoking: ", data);
196                 std::string ca = data;
197                 auto reqCA = CAs.at( ca );
198                 logger::note( "CA found in recordHandler" );
199                 std::shared_ptr<CRL> crl;
200                 std::string date;
201                 std::tie( crl, date ) = signer->revoke( reqCA, serials );
202
203                 respondCommand( RecordHeader::SignerResult::REVOKED, date + crl->getSignature() );
204             }
205             break;
206
207         case RecordHeader::SignerCommand::GET_FULL_CRL:
208             {
209                 logger::note("Requesting full CRL: ", data);
210                 auto ca = CAs.at( data );
211                 CRL c( ca->path + "/ca.crl" );
212                 respondCommand( RecordHeader::SignerResult::FULL_CRL, c.toString() );
213                 
214                 logger::note( "Shutting down SSL" );
215                 if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
216                     logger::error( "ERROR: SSL shutdown failed." );
217                 }
218                 io->ctrl( BIO_CTRL_FLUSH, 0, NULL );
219                 logger::note( "Shutted down SSL" );
220
221                 parent->reset(); // Connection ended
222             }
223             break;
224
225         default:
226             throw "Unimplemented";
227         }
228     }
229 };
230
231 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
232     bio( bio ), ctx( generateSSLContext( true ) ), signer( signer ), currentSession() {
233 }
234
235 void DefaultRecordHandler::reset() {
236     currentSession = std::shared_ptr<RecordHandlerSession>();
237 }
238
239 void DefaultRecordHandler::handle() {
240     if( !currentSession ) {
241         (void) BIO_reset( bio.get() );
242         logger::note( "New session allocated." );
243         currentSession = std::make_shared<RecordHandlerSession>( this, signer, ctx, bio );
244     }
245
246     currentSession->work();
247 }