Browse Source

make QP encoding also a template. Use it in bodyparser.cc

afl-fuzzing
Roker 3 years ago
parent
commit
25dc154b27
4 changed files with 129 additions and 53 deletions
  1. +18
    -0
      src/bodyparser.cc
  2. +13
    -53
      src/quoted_printable.cc
  3. +5
    -0
      src/quoted_printable.hh
  4. +93
    -0
      src/quoted_printable.hxx

+ 18
- 0
src/bodyparser.cc View File

@ -2,6 +2,7 @@
#include "pEpMIME_internal.hh"
#include "rules.hh"
#include "base64.hxx"
#include "quoted_printable.hxx"
#include <pEp/pEp_string.h>
#include <boost/spirit/include/qi.hpp>
@ -59,6 +60,23 @@ char* base64_decode(const BodyLines& bl, size_t& output_size)
return out_string;
}
char* qp_decode(const BodyLines& bl, size_t& output_size)
{
size_t out_size = 0;
for(const auto& line : bl)
{
out_size += line.size();
}
char* out_string = new_string(nullptr, out_size);
char* out_begin = out_string;
char* out_end = out_string + out_size;
qp::decode_iter( BodyIterator{bl}, BodyIterator{}, out_begin, out_end);
output_size = out_begin - out_string;
return out_string;
}
// Tokens from RFC 2045


+ 13
- 53
src/quoted_printable.cc View File

@ -1,4 +1,4 @@
#include "quoted_printable.hh"
#include "quoted_printable.hxx"
#include <stdint.h>
#include <stdexcept>
@ -7,8 +7,6 @@ namespace pEpMIME
namespace qp
{
#define __ (-1) // invalid char -> exception!
const int8_t values[256] = {
// 1 2 3 4 5 6 7 8 9 A B C D E F
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 0x00 .. 0x0F
@ -29,67 +27,29 @@ namespace qp
__, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // 0xF0 .. 0xFF
};
unsigned from_hex(char high, char low)
{
const int h2 = values[(unsigned char)high];
const int l2 = values[(unsigned char)low];
if(h2<0 || l2<0)
{
throw std::runtime_error(std::string("Illegal Hex sequence \"=") + high + low + "\" in QP-encoded string!");
}
return h2*16u + l2;
}
// decodes "quoted printable"-encoded 'input', throw if illegal character found in string
std::string decode(const std::string& input)
try
{
std::string ret;
ret.reserve( input.size() );
const char* c = input.data();
const char* const end = c + input.size();
while(c < end)
{
const char ch = *c;
if(ch=='=')
{
++c;
if(c+1>=end)
{
throw std::runtime_error("Unexpected end of qp-encoded string!");
}
if(*c == '\r') // soft line break
{
if(*++c == '\n') // CRLF sequence completed
{
++c;
continue; // Soft Line Break: just absorb and go on.
}else{
throw std::runtime_error("Illegal sequence of Soft Line Break");
}
}
const char high = *c;
++c;
const char low = *c;
ret += char(from_hex(high, low));
}else{
ret += ch;
}
++c;
}
auto out = std::back_inserter(ret);
decode_iter(input.begin(), input.end(), out, infinity_end);
return ret;
}
catch(const UnexpectedEnd& ue)
{
throw std::runtime_error("Unexpected end of qp-encoded string \"" + input + "\"");
}
catch(const IllegalHexSequence& ihs)
{
throw std::runtime_error( std::string("Illegal hex sequence “=") + ihs.high + ihs.low + "” in qp-encoded string \"" + input + "\"");
}
// decodes "quoted printable"-encoded header line, throw if illegal character found in string
// means: no "soft line breaks", but special handling of underscores.
// TODO: use decode_iter<> here, too? Humm, don't know...
std::string decode_header(const std::string& input)
{
std::string ret;


+ 5
- 0
src/quoted_printable.hh View File

@ -14,6 +14,11 @@ std::string decode(const std::string& input);
// Encodes into "quoted printable" encoding, with optional line breaks
std::string encode(const std::string& input, int line_length=-1, const std::string& delimiter = "\r\n");
///////////////////////////////////////
// Low-level interface, necessary to use base64-encoding also from C
template<class InIter, class OutIter, class OutIter2>
void decode_iter(InIter begin, InIter end, OutIter& out, OutIter2 out_end);
// For RFC-2047-compliant header fields "quoted printable" differs a bit:
// Decodes "quoted printable"-encoded 'input', throw std::runtime_error if an illegal character found in string


+ 93
- 0
src/quoted_printable.hxx View File

@ -0,0 +1,93 @@
#include "quoted_printable.hh"
#include <stdint.h>
#include <stdexcept>
namespace pEpMIME
{
namespace qp
{
struct UnexpectedEnd {};
struct IllegalHexSequence
{
IllegalHexSequence(char h, char l) : high(h), low(l) {}
char high, low;
};
constexpr const int8_t __ = -1; // invalid char -> exception!
extern const int8_t values[256];
inline
unsigned from_hex(char high, char low)
{
const int h2 = values[(unsigned char)high];
const int l2 = values[(unsigned char)low];
if(h2<0 || l2<0)
{
throw IllegalHexSequence{high,low};
}
return h2*16u + l2;
}
// use with potentially "infinite" output containers, e.g. together with back_insert_iterator<>
struct InfinityIterator {};
static InfinityIterator infinity_end{};
template<class OutIter>
inline
bool operator==(OutIter out, InfinityIterator ii)
{
return false;
}
template<class InIter, class OutIter, class OutIter2>
void decode_iter(InIter begin, InIter end, OutIter& out, OutIter2 out_end)
{
InIter c = begin;
while(c != end)
{
const char ch = *c;
if(ch=='=')
{
++c;
if(c==end) throw UnexpectedEnd{};
if(*c == '\r') // soft line break
{
++c;
if(c==end) throw UnexpectedEnd{};
if(*c == '\n') // CRLF sequence completed
{
++c;
continue; // Soft Line Break: just absorb and go on.
}else{
throw IllegalHexSequence{'\r', *c};
}
}
const char high = *c;
++c;
if(c==end) throw std::runtime_error("Unexpected end of qp-encoded string!");
const char low = *c;
if(out == out_end) throw std::runtime_error("Output buffer too small.");
*out = char(from_hex(high, low));
++out;
}else{
if(out == out_end) throw std::runtime_error("Output buffer too small.");
*out = ch;
++out;
}
++c;
}
}
} // end of namespace pEpMIME::qp
} // end of namespace pEpMIME

Loading…
Cancel
Save