# Autogeneration of C++ helper code to sort TLS extensions

## Sorting TLS extensions in fingerprint string
The TLS fingerprint string consists of TLS version, cipher suites and TLS extensions. The TLS extensions in fingerprints are sorted starting from fingerprint format 1 and above. In general the time complexity to sort is O(nlogn). Sorting can be done in linear time if the values to be sorted are known before hand. For tls extension use case, modified version of counting sort is used.

### Algorithm for sorting tls extensions in linear time:

1. Prepare tls_include_list which contains the list of TLS extensions that are part of the fingerprint string.
2. Sort the tls_include_list and use hash table to store the sorted indices of each extension in tls_include_list.
2.	Create an auxiliary array of the size of tls_include_list to store the extension and its count and initialize the count to zero.
3.	For each extension in the input, get the sorted index of the extension by performing hash table lookup. Store the extension in the retrieved index of auxiliary array and increment the count.
4.	Now do the final pass in the auxiliary array to read the count of each element. While the count is positive, print the element and decrement the count to get the sorted tls extensions.

The hash table mentioned above needs rework as when there is modification to the TLS extension include list.

Mercury package provides tls_csv utility which can generate C++ classes and supporting apis required to sort tls extensions based on the above mentioned algorithm. The autogeneration code for tls_csv utility is present under src/tables folder in the mercury repository and source code is present in src/tables/tls_extension_generator.cc.

## How to use tls_csv utility to generate C++ classes

tls_csv utility can be run as below

```
 ./tls_csv outfile=<of> include_extensions=<include_extensions_file> <infile.csv>:<classname> [ <infile.csv>:<classname> ... ]
```
 `outfile` - writes the header file with name <of>

 `include_extensions` - reads the input text file <include_extensions_file>

 `<infile.csv>` - input csv file

 `<classname>` - name of the class name in the output header file <of>



### CSV files containing tls extension type code and name
The tls_csv reads one or more CSV files which contains the mapping between tls extension type code and the name. The Makefile in the src/tables has the changes to download the csv files from the IANA site.

Sample csv file
```
Value,Extension Name,TLS 1.3,DTLS-Only,Recommended,Reference
0,server_name,"CH, EE, CR",N,Y,[RFC6066][RFC9261]
1,max_fragment_length,"CH, EE",N,N,[RFC6066][RFC8449]
2,client_certificate_url,-,N,Y,[RFC6066]
```
The tls_csv utility uses the values from the first two columns - Value and Extension Name.

### Text file with TLS extensions that need to be part of fingerprint string
It also reads a text file which contains the comma separated list of tls extensions that needs to be part of the fingerprint. The extensions values can also contain a range of tls extensions whose format is [start_range-end_range]

Example:

> 0-20,22-34,36-40,43-62,2570

Mercury package has the input text file local_include_extension.txt and is present in the path src/tables/source. This file needs to be edited for any change in the tls extensions include list.

## Compiling tls_csv utility
The Makefile in src/folder has the required changes to compile tls_csv utility.

To compile the changes, do either of the below

> make

This will compile both csv and tls_csv utility


> make tls

This will compile the tls_csv utility only.

## Running tls_csv utility

Let us see how to run the tls_csv file and understand its output
```
./tls_csv outfile=tls_extensions.h verbose=true dir=source include_extensions=local_include_extension.txt tls-extensiontype-values-1.csv:tls_extensions_assign
```
Running the tls_csv will write the header file tls_extensions.h and it will create the class with name tls_extensions_assign.

Let us understand the autogenerated code with a sample output from tls_csv utility.

```
// tls_extensions.h
//
// this file was autogenerated at 2024-02-14T10:17:23Z
// you should edit the source file(s) instead of this one
//
// source files:
//     tls-extensiontype-values-1.csv
//

#ifndef TLS_EXTENSIONS_H
#define TLS_EXTENSIONS_H

#include <unordered_map>

class tls_extensions_assign{
    static std::unordered_map<int32_t, int32_t>& get_mapping_index() {
        static std::unordered_map<int32_t, int32_t> mapping_index = {
        { 0, 0},
        { 1, 1},
        { 2, 2},
        { 3, 3},
        { 4, 4},
        { 5, 5},
        { 6, 6},
        ....
        ....
        { 65037, 65},
        { 65280, 66},
        { 65281, 67},
        { 65283, 68},
        { 65486, 69},
        };
        return mapping_index;
    }

public:
    static constexpr uint16_t include_list_len = 70;

    tls_extensions_assign() {}

    static int32_t get_index(uint16_t type) {
        static const std::unordered_map<int32_t, int32_t> &mapping_index = get_mapping_index();
        auto it = mapping_index.find(type);
        if (it != mapping_index.end()) {
            return(it->second);
        }
        return -1;
    }

    static constexpr uint16_t smallest_private_extn = 65280;

    static constexpr uint16_t smallest_unassigned_extn = 62;

};


#endif // TLS_EXTENSIONS_H
```

Let us look at how the class is created by reading the input files.

#### Step 1
The text file local_include_extension.txt is read and parsed to create a list of tls extensions and sort the list. The sorted list is used to created the unordered map that is present in the output file with type code as the key and its position in the sorted list as the value.

#### Step 2
A static variable include_list_len is initialized with the length of tls extensions include list.

#### Step 3
The input csv file tls-extensiontype-values-1.csv is parsed to find the smallest tls extension in Unassigned and Reserved for Private Use range. These values are used to initialize the two static variables smallest_unassigned_extn and smallest_private_extn in the class.

### Step 4
Add required helper functions to complete the class.

Member function get_index()


`Input Parameter`     - tls extension type code
`Output Parameters`   - Returns the index of the sorted position of the tls extension code in the tls extension include list.
                    - Returns -1 if the extension is not part of the tls extension include list.

## References
Counting Sort - https://www.geeksforgeeks.org/counting-sort/
