]> WPIA git - cassiopeia.git/blob - src/recordHandler.cpp
add: Enable (peer)-verification
[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
12 #include <openssl/ssl.h>
13
14 #include "database.h"
15 #include "record.h"
16 #include "opensslBIO.h"
17 #include "remoteSigner.h"
18 #include "simpleOpensslSigner.h"
19 #include "slipBio.h"
20
21 int gencb( int a, int b, BN_GENCB* g ) {
22     ( void ) a;
23     ( void ) b;
24     ( void ) g;
25
26     std::cout << ( a == 0 ? "." : "+" ) << std::flush;
27
28     return 1;
29 }
30
31 static int verify_callback( int preverify_ok, X509_STORE_CTX* ctx ) {
32     if( !preverify_ok ) {
33         std::cout << "Verification failed: " << preverify_ok << " because " << X509_STORE_CTX_get_error( ctx ) << std::endl;
34     }
35
36     return preverify_ok;
37 }
38
39 static std::shared_ptr<DH> dh_param;
40
41 std::shared_ptr<SSL_CTX> generateSSLContext( bool server ) {
42     std::shared_ptr<SSL_CTX> ctx = std::shared_ptr<SSL_CTX>(
43         SSL_CTX_new( TLSv1_2_method() ),
44         []( SSL_CTX * p ) {
45             SSL_CTX_free( p );
46         } );
47
48     if( !SSL_CTX_set_cipher_list( ctx.get(), "HIGH:+CAMELLIA256:!eNull:!aNULL:!ADH:!MD5:-RSA+AES+SHA1:!RC4:!DES:!3DES:!SEED:!EXP:!AES128:!CAMELLIA128" ) ) {
49         throw "Cannot set cipher list. Your source is broken.";
50     }
51
52     SSL_CTX_set_verify( ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback );
53     SSL_CTX_use_certificate_file( ctx.get(), server ? "keys/signer_server.crt" : "keys/signer_client.crt", SSL_FILETYPE_PEM );
54     SSL_CTX_use_PrivateKey_file( ctx.get(), server ? "keys/signer_server.key" : "keys/signer_client.key", SSL_FILETYPE_PEM );
55     SSL_CTX_load_verify_locations( ctx.get(), "keys/env.crt", 0 );
56
57     if( server ) {
58         STACK_OF( X509_NAME ) *names = SSL_load_client_CA_file( "keys/env.crt" );
59
60         if( names ) {
61             SSL_CTX_set_client_CA_list( ctx.get(), names );
62         } else {
63             // error
64         }
65
66         if( !dh_param ) {
67             FILE* paramfile = fopen( "dh_param.pem", "r" );
68
69             if( paramfile ) {
70                 dh_param = std::shared_ptr<DH>( PEM_read_DHparams( paramfile, NULL, NULL, NULL ), DH_free );
71                 fclose( paramfile );
72             } else {
73                 dh_param = std::shared_ptr<DH>( DH_new(), DH_free );
74                 std::cout << "Generating DH params" << std::endl;
75                 BN_GENCB cb;
76                 cb.ver = 2;
77                 cb.arg = 0;
78                 cb.cb.cb_2 = gencb;
79
80                 if( !DH_generate_parameters_ex( dh_param.get(), 2048, 5, &cb ) ) {
81                     throw "DH generation failed";
82                 }
83
84                 std::cout << std::endl;
85                 paramfile = fopen( "dh_param.pem", "w" );
86
87                 if( paramfile ) {
88                     PEM_write_DHparams( paramfile, dh_param.get() );
89                     fclose( paramfile );
90                 }
91             }
92         }
93
94         if( !SSL_CTX_set_tmp_dh( ctx.get(), dh_param.get() ) ) {
95             throw "Cannot set tmp dh.";
96         }
97     }
98
99     return ctx;
100 }
101
102 class RecordHandlerSession {
103 public:
104     uint32_t sessid;
105     uint32_t lastCommandCount;
106
107     std::shared_ptr<TBSCertificate> tbs;
108     std::shared_ptr<SignedCertificate> result;
109
110     SSL* ssl;
111
112     std::shared_ptr<OpensslBIOWrapper> io;
113     DefaultRecordHandler* parent;
114     std::shared_ptr<Signer> signer;
115
116     RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
117         tbs( new TBSCertificate() ) {
118         this->parent = parent;
119         this->signer = signer;
120
121         ssl = SSL_new( ctx.get() );
122         std::shared_ptr<BIO> bio( BIO_new( BIO_f_ssl() ), [output]( BIO * p ) {
123             BIO_free( p );
124         } );
125         SSL_set_accept_state( ssl );
126         SSL_set_bio( ssl, output.get(), output.get() );
127         BIO_set_ssl( bio.get(), ssl, BIO_NOCLOSE );
128         io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
129     }
130
131     void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
132         RecordHeader rh;
133         rh.command = ( uint16_t ) res;
134         rh.flags = 0;
135         rh.command_count = 0; // TODO i++
136         rh.totalLength = payload.size();
137         sendCommand( rh, payload, io );
138     }
139
140     void work() {
141         std::cout << "done" << std::endl;
142         std::vector<char> buffer( 2048, 0 );
143         std::cout << "reading" << std::endl;
144         int res = io->read( buffer.data(), buffer.capacity() );
145         std::cout << "read" << std::endl;
146
147         if( res <= 0 ) {
148             parent->reset();
149             return;
150         }
151
152         std::string content( buffer.data(), res );
153
154         try {
155             RecordHeader head;
156             std::string payload = parseCommand( head, content );
157             execute( head, payload );
158         } catch( const char* msg ) {
159             std::cout << msg << std::endl;
160             parent->reset();
161             return;
162         }
163     }
164
165     void execute( RecordHeader& head, std::string data ) {
166         if( head.totalLength != head.payloadLength || head.offset != 0 ) {
167             throw "Error, chunking not supported yet";
168         }
169
170         switch( ( RecordHeader::SignerCommand ) head.command ) {
171         case RecordHeader::SignerCommand::SET_CSR: // setCSR
172             tbs->csr_content = data;
173             tbs->csr_type = "CSR";
174             std::cout << "CSR read" << std::endl;
175             break;
176
177         case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
178             tbs->md = data;
179             break;
180
181         case RecordHeader::SignerCommand::SET_PROFILE:
182             // TODO
183             tbs->profile = data;
184             break;
185
186         case RecordHeader::SignerCommand::ADD_SAN: {
187             size_t pos = data.find( "," );
188
189             if( pos == std::string::npos ) {
190             } else {
191                 std::shared_ptr<SAN> san( new SAN() );
192                 san->type = data.substr( 0, pos );
193                 san->content = data.substr( pos + 1 );
194                 tbs->SANs.push_back( san );
195             }
196         }
197         break;
198
199         case RecordHeader::SignerCommand::ADD_AVA: {
200             size_t pos = data.find( "," );
201
202             if( pos == std::string::npos ) {
203                 // error
204             } else {
205                 std::shared_ptr<AVA> ava( new AVA() );
206                 ava->name = data.substr( 0, pos );
207                 ava->value = data.substr( pos + 1 );
208                 tbs->AVAs.push_back( ava );
209             }
210         }
211         break;
212
213         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
214             break;
215
216         case RecordHeader::SignerCommand::SIGN:
217             result = signer->sign( tbs );
218             std::cout << "res: " << result->certificate << std::endl;
219             result->log = "I am a dummy log.\nI signed that thing ;-) \n";
220             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
221             break;
222
223         case RecordHeader::SignerCommand::LOG_SAVED:
224             if( result ) {
225                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
226             }
227
228             break;
229
230         default:
231             throw "Unimplemented";
232         }
233     }
234 };
235
236 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
237     currentSession() {
238
239     this->signer = signer;
240
241     ctx = generateSSLContext( true );
242
243     this->bio = bio;
244 }
245
246 void DefaultRecordHandler::reset() {
247     currentSession = std::shared_ptr<RecordHandlerSession>();
248 }
249
250 void DefaultRecordHandler::handle() {
251     if( !currentSession ) {
252         std::cout << "session allocated" << std::endl;
253         currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
254     }
255
256     std::cout << "really allocated: " << currentSession << ";" << std::endl;
257     currentSession->work();
258 }
259
260 void setupSerial( FILE* f ) {
261     struct termios attr;
262
263     if( tcgetattr( fileno( f ), &attr ) ) {
264         throw "failed to get attrs";
265     }
266
267     attr.c_iflag &= ~( IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON );
268     attr.c_oflag &= ~OPOST;
269     attr.c_lflag &= ~( ECHO | ECHONL | ICANON | ISIG | IEXTEN );
270     attr.c_cflag &= ~( CSIZE | PARENB );
271     attr.c_cflag |= CS8;
272
273     cfsetispeed( &attr, B115200 );
274     cfsetospeed( &attr, B115200 );
275
276     if( tcsetattr( fileno( f ), TCSANOW, &attr ) ) {
277         throw "failed to get attrs";
278     }
279 }
280
281 int handlermain( int argc, const char* argv[] ) {
282     ( void ) argc;
283     ( void ) argv;
284
285     std::shared_ptr<OpensslBIOWrapper> bio( new OpensslBIOWrapper( std::shared_ptr<BIO>( BIO_new_fd( 0, 0 ), BIO_free ) ) );
286     std::string data =
287         "-----BEGIN CERTIFICATE REQUEST-----\n"
288         "MIIBSzCBtQIBADAMMQowCAYDVQQDDAFhMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
289         "iQKBgQDerBEpIShJlx3zzl4AOS1NcwEg4iAWknQeTtI8B5dnk+l5HkOdTxqeehZn\n"
290         "iZnuIuYXA+JWmoECg/w69+N5zw2BabelgK3cSvRqycwPEU/gceGJZTaBfkkN0hBk\n"
291         "rpXDiLSlox5oeR150MrsHvVc+W2e+0jW1tuhz4QLzn8/uI/toQIDAQABoAAwDQYJ\n"
292         "KoZIhvcNAQELBQADgYEATQU5VrgQAkvpCvIwRUyjj9YAa9E014tNY0jMcBdv95fy\n"
293         "/f49zIcVtUJuZuEwY6uDZQqfAm+8CLNpOCICH/Qw7YOe+s/Yw7a8rk5VqLtgxR4M\n"
294         "z6DUeVL0zYFoLUxIje9yDU3pWmPvyVaBPdo0DguZwFMfiWwzhkUDeQgyeaiMvQA=\n"
295         "-----END CERTIFICATE REQUEST-----";
296
297     RecordHeader head;
298     head.flags = 0;
299     head.sessid = 13;
300
301     //---
302
303     SSL_library_init();
304
305     if( argc >= 2 ) {
306         FILE* f = fopen( "/dev/ttyUSB0", "r+" );
307
308         if( !f ) {
309             std::cout << "Opening /dev/ttyUSB0 bio failed" << std::endl;
310             return -1;
311         }
312
313         setupSerial( f );
314
315         std::shared_ptr<BIO> b( BIO_new_fd( fileno( f ), 0 ), BIO_free );
316         std::shared_ptr<BIO> slip1( BIO_new( toBio<SlipBIO>() ), BIO_free );
317         ( ( SlipBIO* )slip1->ptr )->setTarget( std::shared_ptr<OpensslBIO>( new OpensslBIOWrapper( b ) ) );
318         std::cout << "Initing tlsv1_2" << std::endl;
319         std::shared_ptr<SSL_CTX> ctx = generateSSLContext( false );
320         std::shared_ptr<RemoteSigner> sign( new RemoteSigner( slip1, ctx ) );
321         std::shared_ptr<TBSCertificate> cert( new TBSCertificate() );
322         cert->csr_type = "csr";
323         cert->csr_content = data;
324         cert->md = "sha256";
325         cert->profile = "1";
326         std::shared_ptr<AVA> ava( new AVA() );
327         ava->name = "CN";
328         ava->value = "Dummy user certificates";
329         cert->AVAs.push_back( ava );
330         std::shared_ptr<SAN> san( new SAN() );
331         san->type = "DNS";
332         san->content = "n42.example.com";
333         cert->SANs.push_back( san );
334
335         auto res = sign->sign( cert );
336         std::cout << "log: " << res->log << std::endl;
337         std::cout << "cert things: " << res->certificate << std::endl;
338         return 0;
339     }
340
341     FILE* f = fopen( "/dev/ttyS0", "r+" );
342
343     if( !f ) {
344         std::cout << "Opening /dev/ttyS0 bio failed" << std::endl;
345         return -1;
346     }
347
348     setupSerial( f );
349
350     std::shared_ptr<BIO> conn( BIO_new_fd( fileno( f ), 0 ), BIO_free );
351     std::shared_ptr<BIO> slip1( BIO_new( toBio<SlipBIO>() ), BIO_free );
352
353     ( ( SlipBIO* )slip1->ptr )->setTarget( std::shared_ptr<OpensslBIO>( new OpensslBIOWrapper( conn ) ) );
354
355     try {
356         DefaultRecordHandler* dh = new DefaultRecordHandler( std::shared_ptr<Signer>( new SimpleOpensslSigner() ), slip1 );
357
358         while( true ) {
359             dh->handle();
360         }
361     } catch( char const* ch ) {
362         std::cout << "Exception: " << ch << std::endl;
363     }
364
365     return 0;
366 }