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