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