]> WPIA git - cassiopeia.git/blob - src/recordHandler.cpp
add: Plug things together so we can have TBSCertificates from the database
[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 "sslUtil.h"
20 #include "slipBio.h"
21
22 class RecordHandlerSession {
23 public:
24     uint32_t sessid;
25     uint32_t lastCommandCount;
26
27     std::shared_ptr<TBSCertificate> tbs;
28     std::shared_ptr<SignedCertificate> result;
29
30     SSL* ssl;
31
32     std::shared_ptr<OpensslBIOWrapper> io;
33     DefaultRecordHandler* parent;
34     std::shared_ptr<Signer> signer;
35
36     RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
37         tbs( new TBSCertificate() ) {
38         this->parent = parent;
39         this->signer = signer;
40
41         ssl = SSL_new( ctx.get() );
42         std::shared_ptr<BIO> bio(
43             BIO_new( BIO_f_ssl() ),
44             [output]( BIO * p ) {
45                 BIO_free( p );
46             } );
47         SSL_set_accept_state( ssl );
48         SSL_set_bio( ssl, output.get(), output.get() );
49         BIO_set_ssl( bio.get(), ssl, BIO_NOCLOSE );
50         io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
51     }
52
53     void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
54         RecordHeader rh;
55         rh.command = ( uint16_t ) res;
56         rh.flags = 0;
57         rh.command_count = 0; // TODO i++
58         rh.totalLength = payload.size();
59         sendCommand( rh, payload, io );
60     }
61
62     void work() {
63         std::cout << "done" << std::endl;
64         std::vector<char> buffer( 2048, 0 );
65         std::cout << "reading" << std::endl;
66         int res = io->read( buffer.data(), buffer.capacity() );
67         std::cout << "read" << std::endl;
68
69         if( res <= 0 ) {
70             parent->reset();
71             return;
72         }
73
74         std::string content( buffer.data(), res );
75
76         try {
77             RecordHeader head;
78             std::string payload = parseCommand( head, content );
79             execute( head, payload );
80         } catch( const char* msg ) {
81             std::cout << msg << std::endl;
82             parent->reset();
83             return;
84         }
85     }
86
87     void execute( RecordHeader& head, std::string data ) {
88         if( head.totalLength != head.payloadLength || head.offset != 0 ) {
89             throw "Error, chunking not supported yet";
90         }
91
92         switch( ( RecordHeader::SignerCommand ) head.command ) {
93         case RecordHeader::SignerCommand::SET_CSR: // setCSR
94             tbs->csr_content = data;
95             tbs->csr_type = "CSR";
96             std::cout << "CSR read" << std::endl;
97             break;
98
99         case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
100             tbs->md = data;
101             break;
102
103         case RecordHeader::SignerCommand::SET_PROFILE:
104             // TODO
105             tbs->profile = data;
106             break;
107
108         case RecordHeader::SignerCommand::ADD_SAN: {
109             size_t pos = data.find( "," );
110
111             if( pos == std::string::npos ) {
112             } else {
113                 std::shared_ptr<SAN> san( new SAN() );
114                 san->type = data.substr( 0, pos );
115                 san->content = data.substr( pos + 1 );
116                 tbs->SANs.push_back( san );
117             }
118         }
119         break;
120
121         case RecordHeader::SignerCommand::ADD_AVA: {
122             size_t pos = data.find( "," );
123
124             if( pos == std::string::npos ) {
125                 // error
126             } else {
127                 std::shared_ptr<AVA> ava( new AVA() );
128                 ava->name = data.substr( 0, pos );
129                 ava->value = data.substr( pos + 1 );
130                 tbs->AVAs.push_back( ava );
131             }
132         }
133         break;
134
135         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
136             break;
137
138         case RecordHeader::SignerCommand::SIGN:
139             result = signer->sign( tbs );
140             std::cout << "res: " << result->certificate << std::endl;
141             result->log = "I am a dummy log.\nI signed that thing ;-) \n";
142             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
143             break;
144
145         case RecordHeader::SignerCommand::LOG_SAVED:
146             if( result ) {
147                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
148             }
149
150             break;
151
152         default:
153             throw "Unimplemented";
154         }
155     }
156 };
157
158 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
159     currentSession() {
160
161     this->signer = signer;
162
163     ctx = generateSSLContext( true );
164
165     this->bio = bio;
166 }
167
168 void DefaultRecordHandler::reset() {
169     currentSession = std::shared_ptr<RecordHandlerSession>();
170 }
171
172 void DefaultRecordHandler::handle() {
173     if( !currentSession ) {
174         std::cout << "session allocated" << std::endl;
175         currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
176     }
177
178     std::cout << "really allocated: " << currentSession << ";" << std::endl;
179     currentSession->work();
180 }
181
182 int handlermain( int argc, const char* argv[] ) {
183     ( void ) argc;
184     ( void ) argv;
185
186     std::shared_ptr<OpensslBIOWrapper> bio( new OpensslBIOWrapper( std::shared_ptr<BIO>( BIO_new_fd( 0, 0 ), BIO_free ) ) );
187     std::string data =
188         "-----BEGIN CERTIFICATE REQUEST-----\n"
189         "MIIBSzCBtQIBADAMMQowCAYDVQQDDAFhMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
190         "iQKBgQDerBEpIShJlx3zzl4AOS1NcwEg4iAWknQeTtI8B5dnk+l5HkOdTxqeehZn\n"
191         "iZnuIuYXA+JWmoECg/w69+N5zw2BabelgK3cSvRqycwPEU/gceGJZTaBfkkN0hBk\n"
192         "rpXDiLSlox5oeR150MrsHvVc+W2e+0jW1tuhz4QLzn8/uI/toQIDAQABoAAwDQYJ\n"
193         "KoZIhvcNAQELBQADgYEATQU5VrgQAkvpCvIwRUyjj9YAa9E014tNY0jMcBdv95fy\n"
194         "/f49zIcVtUJuZuEwY6uDZQqfAm+8CLNpOCICH/Qw7YOe+s/Yw7a8rk5VqLtgxR4M\n"
195         "z6DUeVL0zYFoLUxIje9yDU3pWmPvyVaBPdo0DguZwFMfiWwzhkUDeQgyeaiMvQA=\n"
196         "-----END CERTIFICATE REQUEST-----";
197
198     RecordHeader head;
199     head.flags = 0;
200     head.sessid = 13;
201
202     //---
203
204     std::shared_ptr<int> ssl_lib = ssl_lib_ref;
205
206     if( argc >= 2 ) {
207         std::shared_ptr<BIO> b = openSerial( "/dev/ttyUSB0" );
208         std::shared_ptr<BIO> slip1( BIO_new( toBio<SlipBIO>() ), BIO_free );
209         ( ( SlipBIO* )slip1->ptr )->setTarget( std::shared_ptr<OpensslBIO>( new OpensslBIOWrapper( b ) ) );
210         std::shared_ptr<RemoteSigner> sign( new RemoteSigner( slip1, generateSSLContext( false ) ) );
211
212         std::shared_ptr<TBSCertificate> cert( new TBSCertificate() );
213         cert->csr_type = "csr";
214         cert->csr_content = data;
215         cert->md = "sha256";
216         cert->profile = "1";
217         std::shared_ptr<AVA> ava( new AVA() );
218         ava->name = "CN";
219         ava->value = "Dummy user certificates";
220         cert->AVAs.push_back( ava );
221         std::shared_ptr<SAN> san( new SAN() );
222         san->type = "DNS";
223         san->content = "n42.example.com";
224         cert->SANs.push_back( san );
225
226         auto res = sign->sign( cert );
227         std::cout << "log: " << res->log << std::endl;
228         std::cout << "cert things: " << res->certificate << std::endl;
229         return 0;
230     }
231
232     std::shared_ptr<BIO> conn = openSerial( "/dev/ttyS0" );
233     std::shared_ptr<BIO> slip1( BIO_new( toBio<SlipBIO>() ), BIO_free );
234
235     ( ( SlipBIO* )slip1->ptr )->setTarget( std::shared_ptr<OpensslBIO>( new OpensslBIOWrapper( conn ) ) );
236
237     try {
238         DefaultRecordHandler* dh = new DefaultRecordHandler( std::shared_ptr<Signer>( new SimpleOpensslSigner() ), slip1 );
239
240         while( true ) {
241             dh->handle();
242         }
243     } catch( char const* ch ) {
244         std::cout << "Exception: " << ch << std::endl;
245     }
246
247     return 0;
248 }