/* * TLS Data Reader * (C) 2010-2011,2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ #ifndef BOTAN_TLS_READER_H__ #define BOTAN_TLS_READER_H__ #include #include #include #include #include #include namespace Botan { namespace TLS { /** * Helper class for decoding TLS protocol messages */ class TLS_Data_Reader { public: TLS_Data_Reader(const char* type, const std::vector& buf_in) : m_typename(type), m_buf(buf_in), m_offset(0) {} void assert_done() const { if(has_remaining()) throw decode_error("Extra bytes at end of message"); } size_t read_so_far() const { return m_offset; } size_t remaining_bytes() const { return m_buf.size() - m_offset; } bool has_remaining() const { return (remaining_bytes() > 0); } std::vector get_remaining() { return std::vector(m_buf.begin() + m_offset, m_buf.end()); } void discard_next(size_t bytes) { assert_at_least(bytes); m_offset += bytes; } u16bit get_u32bit() { assert_at_least(4); u16bit result = make_u32bit(m_buf[m_offset ], m_buf[m_offset+1], m_buf[m_offset+2], m_buf[m_offset+3]); m_offset += 4; return result; } u16bit get_u16bit() { assert_at_least(2); u16bit result = make_u16bit(m_buf[m_offset], m_buf[m_offset+1]); m_offset += 2; return result; } byte get_byte() { assert_at_least(1); byte result = m_buf[m_offset]; m_offset += 1; return result; } template Container get_elem(size_t num_elems) { assert_at_least(num_elems * sizeof(T)); Container result(num_elems); for(size_t i = 0; i != num_elems; ++i) result[i] = load_be(&m_buf[m_offset], i); m_offset += num_elems * sizeof(T); return result; } template std::vector get_range(size_t len_bytes, size_t min_elems, size_t max_elems) { const size_t num_elems = get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); return get_elem >(num_elems); } template std::vector get_range_vector(size_t len_bytes, size_t min_elems, size_t max_elems) { const size_t num_elems = get_num_elems(len_bytes, sizeof(T), min_elems, max_elems); return get_elem >(num_elems); } std::string get_string(size_t len_bytes, size_t min_bytes, size_t max_bytes) { std::vector v = get_range_vector(len_bytes, min_bytes, max_bytes); return std::string(reinterpret_cast(v.data()), v.size()); } template std::vector get_fixed(size_t size) { return get_elem >(size); } private: size_t get_length_field(size_t len_bytes) { assert_at_least(len_bytes); if(len_bytes == 1) return get_byte(); else if(len_bytes == 2) return get_u16bit(); throw decode_error("Bad length size"); } size_t get_num_elems(size_t len_bytes, size_t T_size, size_t min_elems, size_t max_elems) { const size_t byte_length = get_length_field(len_bytes); if(byte_length % T_size != 0) throw decode_error("Size isn't multiple of T"); const size_t num_elems = byte_length / T_size; if(num_elems < min_elems || num_elems > max_elems) throw decode_error("Length field outside parameters"); return num_elems; } void assert_at_least(size_t n) const { if(m_buf.size() - m_offset < n) throw decode_error("Expected " + std::to_string(n) + " bytes remaining, only " + std::to_string(m_buf.size()-m_offset) + " left"); } Decoding_Error decode_error(const std::string& why) const { return Decoding_Error("Invalid " + std::string(m_typename) + ": " + why); } const char* m_typename; const std::vector& m_buf; size_t m_offset; }; /** * Helper function for encoding length-tagged vectors */ template void append_tls_length_value(std::vector& buf, const T* vals, size_t vals_size, size_t tag_size) { const size_t T_size = sizeof(T); const size_t val_bytes = T_size * vals_size; if(tag_size != 1 && tag_size != 2) throw Invalid_Argument("append_tls_length_value: invalid tag size"); if((tag_size == 1 && val_bytes > 255) || (tag_size == 2 && val_bytes > 65535)) throw Invalid_Argument("append_tls_length_value: value too large"); for(size_t i = 0; i != tag_size; ++i) buf.push_back(get_byte(sizeof(val_bytes)-tag_size+i, val_bytes)); for(size_t i = 0; i != vals_size; ++i) for(size_t j = 0; j != T_size; ++j) buf.push_back(get_byte(j, vals[i])); } template void append_tls_length_value(std::vector& buf, const std::vector& vals, size_t tag_size) { append_tls_length_value(buf, vals.data(), vals.size(), tag_size); } template void append_tls_length_value(std::vector& buf, const std::string& str, size_t tag_size) { append_tls_length_value(buf, reinterpret_cast(str.data()), str.size(), tag_size); } } } #endif