Tls deser ser

Deserializer for TLS records

include tls_record
object tls_deser = {}
object tls_ser = {}
object tls_ser_server = {}
<<< member
    class `tls_deser`;
    class `tls_ser`;
    class `tls_ser_server`;
>>>
<<< impl
    //https://tools.ietf.org/html/draft-thomson-quic-bit-grease-00
    //https://tools.ietf.org/id/draft-huitema-quic-ts-03.html

    //TODO
define QUOTEME(x) QUOTEME_1(x) define QUOTEME_1(x) #x define QUIC_SER_DESER_HEADER_PATH PANTHER_IVY_BASE_DIR/quic_utils/quic_ser_deser.h include QUOTEME(QUIC_SER_DESER_HEADER_PATH)

    class `tls_deser` : public ivy_binary_deser_128 {
    //class `tls_deser` : public ivy_binary_deser {
        int field_bytes;
        std::vector<unsigned> fence;
        int in_encrypted_extensions;
        bool is_session_ticket;
        bool ticket_nonce_b;
        bool ticket_b;
        bool extensions_b;
        bool early_data_b;
        bool is_server_hello;

    public:

        tls_deser(const std::vector<char> &inp) : ivy_binary_deser_128(inp) {
        //tls_deser(const std::vector<char> &inp) : ivy_binary_deser(inp) {
            field_bytes = 2;
            in_encrypted_extensions = 0;
            is_session_ticket = false;
            ticket_nonce_b = false;
            ticket_b = false;
            extensions_b = false;
            early_data_b = false;
            is_server_hello = false;
        }

        virtual bool more(unsigned bytes) {
            if (fence.size() > 0 && pos + bytes > fence.back()) {
                return false;
        }
            return ivy_binary_deser_128::more(bytes);
            //return ivy_binary_deser::more(bytes);
        }

        virtual void open_field(const std::string &name) {
            std::cerr << "deser-open_field: name : " << name << "\n";
            if(name == "tls.server_hello")
                is_server_hello = true;
            if(name == "tls.client_hello")
                is_server_hello = false;
            if (name == "random_bytes") { //28 bytes tls1.2, 32bytes tls1.3
                fence.push_back(pos+28);
                field_bytes = 1;
            }
            else if (name == "versions") {
                field_bytes = 4;
                int128_t bytes = 0;
                //long long bytes = 0;
                if (in_encrypted_extensions) {
                    getn(bytes,1);
                }
                fence.push_back(pos+bytes);
            }
            else if (tls_field_length_bytes_map.find(name) != tls_field_length_bytes_map.end()) {
                int length_field_bytes = tls_field_length_bytes_map[name];
                int128_t bytes;
                //long long bytes;
                std::cerr << "deser-open_field: length_field_bytes : " << length_field_bytes << "\n";
                getn(bytes,length_field_bytes);
                /*if(is_session_ticket && name == "unknown_message_bytes") {
                    is_session_ticket = false;
                }*/
                /*if(name == "psk_identities")
                    bytes -= 2;*/
                std::cerr << "deser-open_field: flength : " << bytes << "\n";
                if(tls_field_bytes_map.find(name) != tls_field_bytes_map.end()) {
                    //tls_field_bytes_map[name] = bytes;
                    std::cerr << "deser-open_field: tls_field_bytes_map[" << name << "] : " << bytes << "\n";
                } //else if (name == )

                fence.push_back(pos+bytes);

                // if (name == "ticket" && ! ticket_b) {
                //     std::cerr << "deser-open_field: name BITE : " << name << "\n";
                //     // int128_t val;
                //     // getn(val,bytes);
                //     //std::cerr << "deser-open_field: val BITE : " << val << "\n";
                //     //std::cerr << "deser-open_field: pos+bytes BITE : " << pos+bytes << "\n";
                //     const char * session_file = getenv("STFILE2");
                //     FILE *fp;
                //     if(session_file != NULL) {
                //         fp = fopen(session_file,"a");
                //         uint16_t val_trunc = bytes;
                //         fprintf(fp, "%02hhx%02hhx", val_trunc >> 8, val_trunc); //length field
                //         for(int j = 0; j < bytes; j++) {
                //             int128_t val;
                //             getn(val,1);
                //             //std::cerr << "deser-open_field: val BITE : " << val << "\n";
                //             val_trunc = val;
                //             fprintf(fp, "%02x", val_trunc);
                //         }
                //         fclose(fp);
                //         pos -= bytes;
                //     }
                //     ticket_b = true;
                // }
                // if (name == "ticket_nonce" && !ticket_nonce_b) {
                //     std::cerr << "deser-open_field: name BITE : " << name << "\n";
                //     // int128_t val;
                //     // getn(val,bytes);
                //     ////std::cerr << "deser-open_field: val BITE : " << val << "\n";
                //     //std::cerr << "deser-open_field: pos+bytes BITE : " << pos+bytes << "\n";
                //     const char * session_file = getenv("STFILE2");
                //     FILE *fp;
                //     if(session_file != NULL) {
                //         fp = fopen(session_file,"a");
                //         uint16_t val_trunc = bytes;
                //         fprintf(fp, "%02hhx", val_trunc);
                //         for(int j = 0; j < bytes && bytes > 0; j++) {
                //             int128_t val;
                //             getn(val,1);
                //             //std::cerr << "deser-open_field: val BITE : " << val << "\n";
                //             val_trunc = val;
                //             fprintf(fp, "%02x", val_trunc); //length field
                //         }
                //         fclose(fp);
                //         pos -= bytes;
                //     }
                //     ticket_nonce_b = true;
                // }
                // if (name == "extensions" && ticket_b && !extensions_b) {
                //     std::cerr << "deser-open_field: name BITE : " << name << "\n";
                //     // int128_t val;
                //     // getn(val,bytes);
                //     ////std::cerr << "deser-open_field: val BITE : " << val << "\n";
                //     //std::cerr << "deser-open_field: pos+bytes BITE : " << pos+bytes << "\n";
                //     const char * session_file = getenv("STFILE2");
                //     FILE *fp;
                //     if(session_file != NULL) {
                //         fp = fopen(session_file,"a");
                //         uint16_t val_trunc = bytes;
                //         fprintf(fp, "%02hhx%02hhx", val_trunc >> 8, val_trunc);
                //         fclose(fp);
                //     }
                //     extensions_b = true;
                // }
                // if (name == "tls.early_data" && !early_data_b) {
                    //std::cerr << "deser-open_field: name BITE : " << name << "\n";
                    // int128_t val;
                    // getn(val,bytes);
                    ////std::cerr << "deser-open_field: val BITE : " << val << "\n";
                    //std::cerr << "deser-open_field: pos+bytes BITE : " << pos+bytes << "\n";
                    // const char * session_file = getenv("STFILE2");
                    // FILE *fp;
                    // if(session_file != NULL) {
                    //     fp = fopen(session_file,"a");
                    //     uint16_t val_trunc1 = 42;
                    //     fprintf(fp, "%02hhx%02hhx", val_trunc1 >> 8, val_trunc1);
                    //     uint16_t val_trunc = bytes;
                    //     fprintf(fp, "%02hhx%02hhx", val_trunc >> 8, val_trunc);
                    //     for(int j = 0; j < bytes; j++) {
                    //         int128_t val;
                    //         getn(val,1);
                    //         //std::cerr << "deser-open_field: val BITE : " << val << "\n";
                    //         val_trunc = val;
                    //         fprintf(fp, "%02x", val_trunc); //length field
                    //     }
                    //     fclose(fp);
                    //     pos -= bytes;
                    // }
                    //early_data_b = true;
                //}

            }
            else if (fence.size() > 0) {
                unsigned b = fence.back();
                std::cerr << "4) pkt-pos =  " << b << "\n";
                fence.push_back(b);
            }
            if (tls_field_bytes_map.find(name) != tls_field_bytes_map.end()) {
                field_bytes = tls_field_bytes_map[name];
                // if (name == "ticket_lifetime" ||
                //     name == "ticket_age_add") {
                    //std::cerr << "deser-open_field: name BITE : " << name << "\n";
                    //int128_t val;
                    //getn(val,field_bytes);
                    //std::cerr << "deser-open_field: val BITE : " << val << "\n";
                    //std::cerr << "deser-open_field: pos+bytes BITE : " << pos+bytes << "\n";
                    // const char * session_file = getenv("STFILE2");
                    // FILE *fp;
                    // if(session_file != NULL) {
                    //     if (name == "ticket_lifetime")
                    //         fp = fopen(session_file,"w");
                    //     else
                    //         fp = fopen(session_file,"a");
                    //     int32_t val_trunc = val;
                    //     //fprintf(fp, "%04x", val_trunc);
                    //     fprintf(fp, "%02hhx%02hhx%02hhx%02hhx", val_trunc >> 24, val_trunc >> 16, val_trunc >> 8, val_trunc);
                    //     fclose(fp);
                    // }
                    //pos -= field_bytes;
                //}
                std::cerr << "deser-open_field: field_bytes : " << field_bytes << "\n";

            }
            if (name == "tls.encrypted_extensions") {
                in_encrypted_extensions = fence.size();
            }
        }

        virtual void close_field() {
            if (fence.size() == in_encrypted_extensions)
                in_encrypted_extensions = 0;
            if (fence.size() > 0)
                fence.pop_back();
        }

        virtual int open_tag(const std::vector<std::string> &tags) {
            int bytes = 1;
            if (tls_tag_bytes_map.find(tags[0]) != tls_tag_bytes_map.end())   {
                bytes = tls_tag_bytes_map[tags[0]];
            }
            int128_t tag;
            int128_t tag_new;
            uint128_t tag_final; //uint128_t
            //long long tag;
            //long long tag_new;
            //unsigned long long tag_final;
            long long mask;
            getn(tag,bytes);
            std::cerr << "tag v1: " << tag << "\n";
            std::cerr << "bytes v1: " << bytes << "\n";
            u_int tag_int = (u_int) tag;  //TODO change could be dangerous
            int tag_size = (tag_int >> 6) & ((1 << 2) -1);
            if(tag_size == 0) {
                tag_size = 1;
                mask = 0x3ff;
            } else if(tag_size == 1) {
                tag_size = 2;
                mask = 0x3fff;
            } else if(tag_size == 2) {
                tag_size = 4;
                mask = 0x3fffffff;
            } else if(tag_size == 3) {
                tag_size = 8;
                mask = 0x3fffffffffffffff;
            }

            bool is_unknow = false;
            if(tag > 0x0f && tag != 0x002a && tag != 0x0029)
                is_unknow = true;

            //if(tag == 0x00C0)
            //    is_unknow = false;

            std::cerr <<  "is_unknow: " <<  is_unknow << "\n";

            if(tag == 0x002a || tag == 0x0029)
                tag_size = 2;

            std::cerr <<  "Tag size: " <<  tag_size << "\n";
            std::cerr <<  "tags[0]: " <<  tags[0] << "\n";

            int128_t value_size = 0;
            //long long value_size = 0;
            if((tags[0] == "tls.client_hello" || tags[0] == "tls.server_hello") && tag == 4) {
                // new session ticket
                //tls_field_bytes_map["ticket"] = value_size;
                is_session_ticket = true;
            }
            if((((tag_size != bytes || is_unknow || tag == 0x1010 || tag == 0x0f || tag == 0x00 || tag == 0x0d)
                    && tags[0] != "tls.client_hello" && tags[0] != "tls.unknown_extension" //&& tags[0] != "tls.early_data" && tags[0] != "tls.unknown_extension"
                    && tags[0] != "tls.server_hello"))
                || tag ==0x002a || tag == 0x0029) { //|| tag == 0x0d
                tls_tag_bytes_map["unknown_transport_parameter"] = tag_size;
                pos -= bytes;

                bytes = tag_size;
                getn(tag_new,bytes);

                //unsigned long long tag_intt = (uint128_t) tag_new;
                uint128_t tag_intt = (uint128_t) tag_new;
                tag_final = (tag_intt & mask);
                if(tag == 0x0029 || tag == 0x002a) {
                    getn(value_size,2);
                    pos -= 2;
                } else {
                    getn(value_size,1);
                    pos -= 1;
                }

                std::cerr << "tag: " << tag << "\n";
                std::cerr << "value_size: " << value_size << "\n";

                if(tag == 0x0f || tag == 0x00) {
                    tls_field_bytes_map["scid"] = value_size;
                }
                else if(tag == 0x002a) {
                    tls_field_bytes_map["max_early_data_size"] = value_size;
                }
                /*else if(tag == 0x0029) {
                    tls_field_bytes_map["content_psk"] = value_size;
                    //tls_field_bytes_map["tls.pre_shared_key"] = value_size;
                }*/
                else if(tag == 0x0d) {
                    int128_t pcil = value_size - 4 - 2 -16 - 2 - 1 - 16;
                    std::cerr << "pcil: " << pcil << "\n";
                    std::cerr << "pref_add: " << (pcil+4+2+16+2+1+16) << "\n";
                    tls_field_bytes_map["pcid"] = pcil;
                }
                else if(tag == 0x10) { // else if(tag == 0x1010) {
                    tls_field_bytes_map["rcid"] = value_size;
                }
                else if (is_unknow) {
                    tls_field_bytes_map["unknown"] = value_size;
                }
            } else {
                tag_final = tag;
            }

            unsigned long long casted_tag = (unsigned long long)(tag_final & 0xFFFFFFFFFFFFFFFF);
            std::cerr << "value_size: " << value_size << "\n";
            std::cerr << "tag v2: " <<  casted_tag  << "\n";
            if(casted_tag == 4278509082)
                tag_final = -4611686014148878822; //TODO hack
            for (int i = 0; i < tags.size(); i++) {
               // std::cerr << "tags[i]: " << tags[i] << "\n";
               // std::cerr << "tls_tags_map[tags[i]]: " << tls_tags_map[tags[i]] << "\n";
                if (tag_final == tls_tags_map[tags[i]]) {
                    if(is_server_hello && tags[i] == "tls.pre_shared_key_client")
                        continue;
                    else {
                        open_field(tags[i]);
                        return i;
                    }
                }
            }
            for (int i = 0; i < tags.size(); i++) {
                if (-1 == tls_tags_map[tags[i]]) {
                    if(is_server_hello && tags[i] == "tls.pre_shared_key_client")
                        continue;
                    else {
                        pos -= bytes; // leave the unknown tag to parse again
                        open_field(tags[i]);
                        return i;
                    }
                }
            }
            for (int i = 0; i < tags.size(); i++) {
                if (-2 == tls_tags_map[tags[i]]) {
                    if(is_server_hello && tags[i] == "tls.pre_shared_key_client")
                        continue;
                    else {
                        open_field(tags[i]);
                        return i;
                    }
                }
            }
            std::cerr << "error tls_desert 1\n";
            throw deser_err();
        }

        virtual void close_tag() {
            close_field();
        }

        virtual void get(int128_t &res) {
        //virtual void get(long long &res) {
            if (field_bytes == -1) get_var_int(res);
            else getn(res,field_bytes);
        }

        void get_var_int(int128_t &res) {
        //void get_var_int(long long &res) {
            static int lens[4] = {0,1,3,7};
            int128_t lobyte;
            //long long lobyte;
            ivy_binary_deser_128::getn(lobyte,1);
            //ivy_binary_deser::getn(lobyte,1);
            int bytes = lens[(lobyte & 0xc0) >> 6];
            ivy_binary_deser_128::getn(res,bytes);
            //ivy_binary_deser::getn(res,bytes);
            res |= (lobyte & 0x3f) << (bytes << 3);
        }

        virtual bool open_list_elem() {
            if (fence.size() == 0) {  // tricky: see if input contains a full message
                if (!more(4)) {
                    return false;
                }
                unsigned len = (inp[pos+1] << 16) + (inp[pos+2] << 8) + inp[pos];
                return inp.size() >= pos + len + 4;
            }
            return more(1);
        }

        void close_list_elem() {}

        void open_list() {}
        void close_list() {}

        ~tls_deser(){}
    };

    struct `tls_ser` : public ivy_binary_ser_128 {
    //struct `tls_ser` : public ivy_binary_ser {

        int field_bytes;
        std::vector<uint128_t> field_start;
        std::vector<uint128_t> field_length_bytes;
        //std::vector<unsigned long long> field_start;
        //std::vector<unsigned long long> field_length_bytes;
        int in_encrypted_extensions;

        tls_ser() {
            in_encrypted_extensions = 0;
            if(const char* env_p3 = std::getenv("INITIAL_VERSION")) {
                std::cerr << "INITIAL_VERSION " << env_p3 << "\n";
                int iversion = atoi(env_p3);
                std::cerr << "INITIAL_VERSION " << iversion << "\n";
                if(iversion == 1) {
                    tls_tags_map["quic_transport_parameters"] = 0x39;
                } else {
                    tls_tags_map["quic_transport_parameters"] = 0xffa5;
                }
                std::cerr << "tls_tags_map[quic_transport_parameters] " << tls_tags_map["quic_transport_parameters"] << "\n";
            }
        }

        /**
          * Allocate memory for each transport parameters
          */
        virtual void open_field(const std::string &name) {
            int flb = 0;
            std::cerr << "ser-open_field: name 1: " << name << "\n";
            // if(name == "tls.server_hello")
            //     is_server_hello = true;
            if (name == "random_bytes") {
                field_bytes = 1;
            }
            /*else if (name == "content_psk") {
                field_bytes = 2;
            }else if (name == "tls.new_session_ticket") {
                field_bytes = 1;
            }*/ else if (name == "versions") {
                field_bytes = 4;
                if (in_encrypted_extensions) {
                    flb = 1;
                    res.resize(res.size() + flb);
                }
            }
            else if (name != "tls.early_data"  && // && name != "tls.pre_shared_key_client" && name != "identity"
             tls_field_length_bytes_map.find(name) != tls_field_length_bytes_map.end()) {
                flb = tls_field_length_bytes_map[name];
                std::cerr << "ser-open_field: flb : " << flb << "\n";
                res.resize(res.size() + flb);
            }
            std::cerr << "ser-open_field: field_start.push_back(res.size()) : " << res.size() << "\n";
            std::cerr << "ser-open_field: ffield_length_bytes.push_back(flb) : " << flb << "\n";
            field_start.push_back(res.size());
            field_length_bytes.push_back(flb);
            if (tls_field_bytes_map.find(name) != tls_field_bytes_map.end()
                ) { //&& name != "psk_identities"
                field_bytes = tls_field_bytes_map[name];
                std::cerr << "ser-open_field: name_field_bytes 1: " << field_bytes << "\n";
            }   else
                std::cerr << "ser-open_field: name_field_bytes 2: " << field_bytes << "\n";
            if (name == "tls.encrypted_extensions") { // || name == "tls.new_session_ticket"
                in_encrypted_extensions = field_start.size();
                std::cerr << "ser-open_field: name == tls.encrypted_extensions 2: " << in_encrypted_extensions << "\n";
            }
            std::cerr << "ser-open_field: field_bytes: " << field_bytes << "\n";
            std::cerr << "ser-open_field: res.size() : " << res.size() << "\n";
        }
        //TODO [xx]
        virtual void close_field() {
            if (field_start.size() == in_encrypted_extensions)
                in_encrypted_extensions = 0;
            // tricky -- go back and fill in the length bytes after the field is serialized
            int start = field_start.back();
            int end = res.size();
            int flb = field_length_bytes.back();
            std::vector<char> temp;
            temp.swap(res);
            int len = end-start;
            std::cerr << "ser-close_field: start : " << start << "\n";
            std::cerr << "ser-close_field: end : " << end << "\n";
            std::cerr << "ser-close_field: len : " << len << "\n";
            std::cerr << "ser-close_field: flb : " << flb << "\n";
            std::cerr << "-------------------" << "\n";
            setn(len,flb);
            temp.swap(res); //[xx] remove
            std::copy(temp.begin(),temp.end(),res.begin()+start-flb); // [xx] remove
            field_start.pop_back();
            field_length_bytes.pop_back();
        }

        virtual void open_tag(int ivy_tag, const std::string &name) {
            int bytes = 1;
            if (tls_tag_bytes_map.find(name) != tls_tag_bytes_map.end())
                bytes = tls_tag_bytes_map[name];
            int128_t tag = tls_tags_map[name];
            std::cerr << "ser-open_tag: bytes : " << bytes << "\n";
            std::cerr << "ser-open_tag: tag : " << tag << "\n";
            //long long tag = tls_tags_map[name];
            if (tag !=-1) {
                std::cerr << "ser-open_tag: tag != -1: \n";
                setn(tag,bytes); // var int ?
            }
            if(const char* env_p2 = std::getenv("TEST_TYPE")) {
                // because it seralize directly so we dont know the scid/dcid length
                // TODO maybe change and put the value directly in envvar
                std::cerr << "TEST_TYPE " << env_p2 << "\n";
                if(strcmp(env_p2, "client") == 0) {
                    if(const char* env_p3 = std::getenv("TEST_SCIL")) {
                        std::cerr << "TEST_SCIL " << env_p3 << "\n";
                        //tls_field_bytes_map["scid"] = atoi(env_p3);
                    }
                    if(const char* env_p3 = std::getenv("TEST_DCIL")) {
                        std::cerr << "TEST_DCIL " << env_p3 << "\n";
                        tls_field_bytes_map["dcid"] = atoi(env_p3);
                    }
                    if(const char* env_p3 = std::getenv("TEST_PCIL")) {
                        std::cerr << "TEST_PCIL " << env_p3 << "\n";
                        tls_field_bytes_map["pcid"] = atoi(env_p3);
                    }
                }
            }
            open_field(name);
        }

        virtual void close_tag() {
            close_field();
        }

        void set(int128_t inp) {
        //void set(long long inp) {
            if (field_bytes == -1) set_var_int(inp);
            else setn(inp,field_bytes);
        }

        void set_var_int(int128_t res) {
            int128_t val = res & 0x3fffffffffffffff;
        //void set_var_int(long long res) {
        //    long long val = res & 0x3fffffffffffffff;
            int bytecode = res <= 0x3f ? 0 : res <= 0x3fff ? 1 : res <= 0x3fffffff ? 2 : 3;
            int bytes = 1 << bytecode;
            val |= bytecode << ((bytes << 3) - 2);
            setn(val,bytes);
        }

        void open_list(int len) {
        }
    };

    struct `tls_ser_server` : public tls_ser {
        // This version of the serializer uses the server format. The only difference is
        // that the QUIC_extension structure has an extra field "versions".

        tls_ser_server() {
          in_encrypted_extensions = -1;
        }

    };
>>>

<<< init

    tls_make_name_map(tls_field_length_bytes,tls_field_length_bytes_map);
    tls_make_name_map(tls_field_bytes,tls_field_bytes_map);
    tls_make_name_map(tls_tags,tls_tags_map);
    tls_make_name_map(tls_tag_bytes,tls_tag_bytes_map);

>>>