0

I wrote a c program that listen to 443 port and receives ssl packets :

#include <errno.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <stdio.h>

 #define MAX_SIZE 10000

struct ssl_header {
  uint8_t type;
  uint16_t   version;
  uint16_t   length;
};

struct handshake {
  struct ssl_header hdr;
  uint8_t type;
  unsigned int length[3]; 
  unsigned int ssl_version[2];
  char random[32];
};

void *message_processing(int sockfd){
    char *buff = calloc(MAX_SIZE + 1, sizeof (char));
    struct handshake *pkt;       
    pkt = calloc (1, sizeof (struct handshake));               

    while (1) {
        int len_of_read_data = read( sockfd, buff, MAX_SIZE);

        if (len_of_read_data > 0) {
          memcpy(pkt, buff, sizeof (struct handshake) );
          FILE* file = fopen("logfile", "a"); 
          fprintf (file, "*********************************\n");
          fprintf (file, "type1 : %u\n", pkt->hdr.type );
          fprintf(file, "version1 : %u\n", pkt->hdr.version);
          fprintf(file, "len1 : %u\n", pkt->hdr.length);
          fprintf(file, "type2 : %u\n", pkt->type);
          fprintf(file, "len2 : %u%u%u\n", pkt->length[0],pkt->length[1], pkt->length[2] );
          fprintf(file, "version2 : %u.%u\n", pkt->ssl_version[0], pkt->ssl_version[1]);
          fprintf(file, "random : %s\n", pkt->random);
          fclose(file);
        }
    }
}

int main () {
    struct sockaddr_in serv_addr;
    int sock_descriptor = socket(AF_INET, SOCK_STREAM, 0);
    int trueval = 1;
    setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEPORT | SO_REUSEADDR, (char *)&trueval, sizeof(trueval));

    bzero((char *) &serv_addr, sizeof (serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = INADDR_ANY;
    serv_addr.sin_port = htons(443);

    bind(sock_descriptor, (struct sockaddr *) &serv_addr, sizeof (serv_addr));
    listen(sock_descriptor, 50);

    while (1) {
            struct sockaddr_in cli_addr;
            socklen_t clilen;
            clilen = sizeof(cli_addr);

            int client_socket  = accept(sock_descriptor, (struct sockaddr *) &cli_addr, &clilen);

            message_processing(client_socket);
            pthread_t pid;
            pthread_create(&pid, NULL, (void *) message_processing, &client_socket);
            pthread_join(pid, NULL);
         }
}

I create structures from this link : http://blog.fourthbit.com/2014/12/23/traffic-analysis-of-an-ssl-slash-tls-session/

when i run the program and connect to it using curl -I https://127.0.0.1:443 --insecure, it receives some data . the problem is when i print that data in logfile file , i get these value that all are incorrect except type1 :

*********************************
type1 : 22
version1 : 513
len1 : 256
type2 : 0
len2 : 31543142363974688046409855404
version2 : 4270624758.750651113
random : �&,�X�I�Y��|}

i'm new in c and specially in struct and i'm not sure the problem is occurred when i create the structs or when i try to print fields. can anybody help to figure out the problem.

7
  • Have you considered endianness? Commented Jan 7, 2020 at 13:34
  • Also think about the size of int, it's not fixed. Commented Jan 7, 2020 at 13:37
  • 1
    3 byte integer? Did you consider padding and memory layout of your struct? You know that int length[3] means an array of 3 integer variables, not an integer variable with 3 bytes, don't you? Commented Jan 7, 2020 at 14:27
  • 1
    I recomended not copy receive buffer to struct in block because struct fields could be aligjned to a word. Copy and convert each field from buffer to struct. A unsigned int length[3] has 3 sizeof(int) is diferent a length of 3 bytes. You must extract 3 bytes from buffer and convert to int. Commented Jan 7, 2020 at 14:48
  • 1
    unsigned int length[3]; is three unsigned int elements, each element being an unsigned int meaning its size if sizeof(unsigned int) * 3 which with typical 32-bit unsigned int means it's 12 bytes, not three! Commented Jan 7, 2020 at 17:42

1 Answer 1

4

You have a problem with wrong data types and with padding of your structures.

From your link, the TLS header contains:

  • 1 byte type
  • 2 bytes version
  • 2 bytes length

Your attempt to map this to a structure has some flaw:

struct ssl_header {
  uint8_t type;
  uint16_t   version;
  uint16_t   length;
};

For most architectures, a uint8_t has no specific alignment requirements while uint16_t is probably aligned on a 2byte boundary. This is achieved by inserting invisible padding bytes. While the header is 5 bytes, your struct contains 6 bytes or even more.

You might try to address this by using packed structs.

The second problem is you are using wrong types in your arrays.

The protocol definition contains a length field of 3 bytes and a version field of 2 bytes. In total these are 5 bytes.

Your struct looks like this:

  unsigned int length[3]; 
  unsigned int ssl_version[2];

This means you have 5 integers meaning 10, 20 or even 40 bytes in total.

Additionally you will have padding bytes also in this structure.

The layout of your structures is far off of the protocol definition.

You should not try to read a buffer directly into a memory location that is interpreted as a struct. Instead you should read and handle each field separately. Then you can properly handly endianess, integer fields of any length and don't need to take care about padding in your structs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.