]> WPIA git - cassiopeia.git/blob - src/recordHandler.cpp
add: simple, signer-side record handling
[cassiopeia.git] / src / recordHandler.cpp
1 #include "recordHandler.h"
2
3 #include <iostream>
4
5 #include <openssl/ssl.h>
6
7 #include "database.h"
8 #include "record.h"
9 #include "opensslBIO.h"
10
11 class RecordHandlerSession {
12 public:
13     uint32_t sessid;
14     uint32_t lastCommandCount;
15
16     std::shared_ptr<TBSCertificate> tbs;
17     std::shared_ptr<SignedCertificate> result;
18
19     SSL* ssl;
20
21     std::shared_ptr<OpensslBIOWrapper> io;
22     DefaultRecordHandler* parent;
23     std::shared_ptr<Signer> signer;
24
25     RecordHandlerSession( DefaultRecordHandler* parent, std::shared_ptr<Signer> signer, std::shared_ptr<SSL_CTX> ctx, BIO* output ) :
26         tbs( new TBSCertificate() ) {
27         this->parent = parent;
28         this->signer = signer;
29
30         ssl = SSL_new( ctx.get() );
31         BIO* bio = BIO_new( BIO_f_ssl() );
32         SSL_set_accept_state( ssl );
33         SSL_set_bio( ssl, output, output );
34         BIO_set_ssl( bio, ssl, BIO_NOCLOSE );
35         io = std::shared_ptr<OpensslBIOWrapper>( new OpensslBIOWrapper( bio ) );
36     }
37
38     void respondCommand( RecordHeader::SignerResult res, std::string payload ) {
39         RecordHeader rh;
40         rh.command = ( uint16_t ) res;
41         rh.flags = 0;
42         rh.command_count = 0; // TODO i++
43         rh.totalLength = payload.size();
44         sendCommand( rh, payload, io );
45     }
46
47     void work() {
48         std::vector<char> buffer( 2048, 0 );
49         int res = io->read( buffer.data(), buffer.capacity() );
50
51         if( res <= 0 ) {
52             parent->reset();
53             return;
54         }
55
56         std::string content( buffer.data(), res );
57
58         try {
59             RecordHeader head;
60             std::string payload = parseCommand( head, content );
61             execute( head, payload );
62         } catch( const char* msg ) {
63             std::cout << msg << std::endl;
64             parent->reset();
65             return;
66         }
67     }
68
69     void execute( RecordHeader& head, std::string data ) {
70         if( head.totalLength != head.payloadLength || head.offset != 0 ) {
71             throw "Error, chunking not supported yet";
72         }
73
74         switch( ( RecordHeader::SignerCommand ) head.command ) {
75         case RecordHeader::SignerCommand::SET_CSR: // setCSR
76             tbs->csr_content = data;
77             tbs->csr_type = "CSR";
78             std::cout << "CSR read" << std::endl;
79             break;
80
81         case RecordHeader::SignerCommand::SET_SIGNATURE_TYPE:
82             tbs->md = "sha256"; // TODO use content ;-)
83             break;
84
85         case RecordHeader::SignerCommand::SET_PROFILE:
86             // TODO
87             tbs->profile = data;
88             break;
89
90         case RecordHeader::SignerCommand::ADD_SAN: {
91             size_t pos = data.find( "," );
92
93             if( pos == std::string::npos ) {
94             } else {
95                 std::shared_ptr<SAN> san( new SAN() );
96                 san->type = data.substr( 0, pos );
97                 san->content = data.substr( pos + 1 );
98                 tbs->SANs.push_back( san );
99             }
100         }
101         break;
102
103         case RecordHeader::SignerCommand::ADD_AVA: {
104             size_t pos = data.find( "," );
105
106             if( pos == std::string::npos ) {
107                 // error
108             } else {
109                 std::shared_ptr<AVA> ava( new AVA() );
110                 ava->name = data.substr( 0, pos );
111                 ava->value = data.substr( pos + 1 );
112                 tbs->AVAs.push_back( ava );
113             }
114         }
115         break;
116
117         case RecordHeader::SignerCommand::ADD_PROOF_LINE:
118             break;
119
120         case RecordHeader::SignerCommand::SIGN:
121             result = signer->sign( tbs );
122             std::cout << "res: " << result->certificate << std::endl;
123             result->log = "I am a dummy log.\nI signed that thing ;-) \n";
124             respondCommand( RecordHeader::SignerResult::SAVE_LOG, result->log );
125             break;
126
127         case RecordHeader::SignerCommand::LOG_SAVED:
128             if( result ) {
129                 respondCommand( RecordHeader::SignerResult::CERTIFICATE, result->certificate );
130             }
131
132             break;
133
134         default:
135             throw "Unimplemented";
136         }
137     }
138 };
139
140 DefaultRecordHandler::DefaultRecordHandler( std::shared_ptr<Signer> signer, BIO* bio ) :
141     currentSession() {
142
143     this->signer = signer;
144
145     ctx = std::shared_ptr<SSL_CTX>( SSL_CTX_new( TLSv1_method() ), SSL_CTX_free );
146     SSL_CTX_use_certificate_file( ctx.get(), "testdata/server.crt", SSL_FILETYPE_PEM );
147     SSL_CTX_use_PrivateKey_file( ctx.get(), "testdata/server.key", SSL_FILETYPE_PEM );
148
149     this->bio = bio;
150 }
151
152 void DefaultRecordHandler::reset() {
153     currentSession = std::shared_ptr<RecordHandlerSession>();
154 }
155
156 void DefaultRecordHandler::handle() {
157     if( !currentSession ) {
158         currentSession = std::shared_ptr<RecordHandlerSession>( new RecordHandlerSession( this, signer, ctx, bio ) );
159     }
160
161     currentSession->work();
162 }