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