]> WPIA git - cassiopeia.git/blob - src/io/record.cpp
add: signing of OCSP certificates
[cassiopeia.git] / src / io / record.cpp
1 #include "record.h"
2
3 #include <iomanip>
4 #include <iostream>
5 #include <memory>
6 #include <sstream>
7
8 #include "io/bios.h"
9 #include "io/opensslBIO.h"
10 #include "log/logger.hpp"
11
12 std::string toHexAndChecksum( const std::string& src ) {
13     char checksum = 0;
14     std::stringstream ss;
15     ss << ':' << std::hex << std::setfill( '0' ) << std::uppercase;
16
17     for( auto c : src ) {
18         ss << std::setw( 2 ) << ( ( ( uint32_t ) c ) & 0xFF );
19         checksum += c;
20     }
21
22     ss << std::setw( 2 ) << ( ( ( uint32_t )( ~checksum ) ) & 0xFF );
23     ss << '\n';
24     return ss.str();
25 }
26
27 void sendCommand( RecordHeader& head, const std::string& data, std::shared_ptr<OpensslBIO> bio ) {
28     std::stringstream ss;
29     ss << data.size();
30     logger::debugf( "Record payload length: %s", ss.str() );
31     size_t pos = 0;
32     head.offset = 0;
33     head.totalLength = data.size();
34
35     do {
36         size_t toTransfer = std::min( static_cast<size_t>( 0xF000 ), data.size() - pos );
37         head.payloadLength = toTransfer;
38
39         std::string s;
40         s += head.packToString();
41         s += data.substr( pos, toTransfer );
42
43         std::string res = toHexAndChecksum( s );
44
45         logger::debug( "FINE: RECORD output: ", res );
46
47         bio->write( res.data(), res.size() );
48
49         pos += toTransfer;
50         head.offset += 1;
51     } while( pos < data.size() );
52 }
53
54 int32_t fromHexDigit( char c ) {
55     int32_t res = -1;
56
57     if( c >= '0' && c <= '9' ) {
58         res = c - '0';
59     }
60
61     if( c >= 'A' && c <= 'F' ) {
62         res = c - 'A' + 10;
63     }
64
65     return res;
66 }
67
68 std::string parseCommand( RecordHeader& head, const std::string& input ) {
69     logger::debug( "FINE: RECORD input: ", input );
70
71     int32_t dlen = ( input.size() - 2 ) / 2;
72     char checksum = 0;
73     bool error = false;
74
75     std::string str( std::max( dlen, RECORD_HEADER_SIZE ), 0 );
76
77     for( int i = 0; i < dlen; i++ ) {
78         int32_t digit;
79         int32_t accum;
80         digit = fromHexDigit( input[i * 2 + 1] );
81         error |= digit == -1;
82         accum = digit;
83         accum <<= 4;
84         digit = fromHexDigit( input[i * 2 + 2] );
85         error |= digit == -1;
86         accum += digit;
87         str[i] = accum;
88         checksum += str[i];
89     }
90
91     head.unpackFromString( str.substr( 0, RECORD_HEADER_SIZE ) );
92     uint32_t len = head.payloadLength;
93     uint32_t expectedTotalLength = ( RECORD_HEADER_SIZE + len + 1 /*checksum*/ ) * 2 + 2;
94     std::string data = str.substr( RECORD_HEADER_SIZE, str.size() - RECORD_HEADER_SIZE );
95
96     if( expectedTotalLength != input.size() ) {
97         std::stringstream ss;
98         ss << "Expected: " << expectedTotalLength << ", Got: " << input.size();
99         logger::error( ss.str() );
100         throw std::length_error( "Error, invalid length" );
101     }
102
103     if( checksum != -1 || error || dlen < RECORD_HEADER_SIZE ) {
104         throw std::runtime_error( "Error, invalid checksum" );
105     }
106
107     data.pop_back();
108
109     return data;
110 }
111 std::string parseCommandChunked( RecordHeader& head, std::shared_ptr<OpensslBIOWrapper> io ) {
112     logger::note( "reading" );
113     std::string payload = parseCommand( head, io->readLine() );
114     std::string all( head.totalLength, ' ' );
115     auto target = all.begin();
116     size_t pos = 0;
117     RecordHeader head2;
118
119     while( true ) {
120         pos += head.payloadLength;
121         target = std::copy( payload.begin(), payload.end(), target );
122
123         if( pos >= head.totalLength ) {
124             break;
125         }
126
127         logger::note( "chunk digested, reading next one" );
128
129         payload = parseCommand( head2, io->readLine() );
130
131         if( !head2.isFollowupOf( head ) ) {
132             throw std::runtime_error( "Error, header of follow up chunk was malformed" );
133         }
134
135         head = head2;
136     }
137
138     return all;
139 }