]> WPIA git - cassiopeia.git/blob - src/recordHandler.cpp
add: Enable SPKAC
[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
14 #include <openssl/ssl.h>
15
16 #include "database.h"
17 #include "record.h"
18 #include "opensslBIO.h"
19 #include "remoteSigner.h"
20 #include "simpleOpensslSigner.h"
21 #include "sslUtil.h"
22 #include "slipBio.h"
23
24 extern std::vector<Profile> profiles;
25
26 class RecordHandlerSession {
27 public:
28     uint32_t sessid;
29     uint32_t lastCommandCount;
30
31     std::shared_ptr<TBSCertificate> tbs;
32     std::shared_ptr<SignedCertificate> result;
33
34     std::shared_ptr<SSL> ssl;
35
36     std::shared_ptr<OpensslBIOWrapper> io;
37     DefaultRecordHandler* parent;
38     std::shared_ptr<Signer> signer;
39
40     std::shared_ptr<std::ofstream> log;
41
42     RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, std::shared_ptr<BIO> output ) :
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:" << std::endl << tbs->csr_content;
116             break;
117
118         case RecordHeader::SignerCommand::SET_SPKAC:
119             tbs->csr_content = data;
120             tbs->csr_type = "SPKAC";
121             ( *log ) << "INFO: SPKAC read:" << std::endl << tbs->csr_content;
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::ADD_SAN: {
134             size_t pos = data.find( "," );
135
136             if( pos == std::string::npos ) {
137             } else {
138                 std::shared_ptr<SAN> san( new SAN() );
139                 san->type = data.substr( 0, pos );
140                 san->content = data.substr( pos + 1 );
141                 tbs->SANs.push_back( san );
142             }
143         }
144         break;
145
146         case RecordHeader::SignerCommand::ADD_AVA: {
147             size_t pos = data.find( "," );
148
149             if( pos == std::string::npos ) {
150                 // error
151             } else {
152                 std::shared_ptr<AVA> ava( new AVA() );
153                 ava->name = data.substr( 0, pos );
154                 ava->value = data.substr( pos + 1 );
155                 tbs->AVAs.push_back( ava );
156             }
157         }
158         break;
159
160         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
161             break;
162
163         case RecordHeader::SignerCommand::SIGN:
164             result = signer->sign( tbs );
165             ( *log ) << "INFO: signlog: " << result->log << std::endl;
166             ( *log ) << "INFO: res: " << result->certificate << std::endl;
167             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
168             break;
169
170         case RecordHeader::SignerCommand::LOG_SAVED:
171             if( result ) {
172                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
173             }
174
175             if( !SSL_shutdown( ssl.get() ) && !SSL_shutdown( ssl.get() ) ) {
176                 ( *log ) << "ERROR: SSL close failed" << std::endl;
177             }
178
179             break;
180
181         default:
182             throw "Unimplemented";
183         }
184     }
185 };
186
187 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, std::shared_ptr<BIO> bio ) :
188     currentSession() {
189
190     this->signer = signer;
191
192     ctx = generateSSLContext( true );
193
194     this->bio = bio;
195 }
196
197 void DefaultRecordHandler::reset() {
198     currentSession = std::shared_ptr<RecordHandlerSession>();
199 }
200
201 void DefaultRecordHandler::handle() {
202     if( !currentSession ) {
203         std::cout << "session allocated" << std::endl;
204         currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
205     }
206
207     currentSession->work();
208 }