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