1

I am having a serious problem transferring my HTTP connection socket program over to HTTPS connection socket code, how do I make only an HTTPS connection in pure C?

I am working on a package manager and am rewriting the connection.c file, the only thing this file contains is the code used to make the initial connection to the server containg packages, it does nothing else. I had this working 100% with an HTTP connection, however I need to move to an HTTPS connection and need to use LibreSSL; at the moment I am trying to use OpenSSL as I can't find anything on LibreSSL. The HTTP code I had is as follows:

#include <stdio.h>
#include <stdlib.h>

#include <sys/socket.h>
#include <arpa/inet.h>

#include <netinet/in.h>
#include <string.h>

#include <unistd.h>
#include "repos.h"

#include "resolv.h"

short connection()
{
    short socket_desc;
    socket_desc = socket(AF_INET, SOCK_STREAM, 0); /* create socket with IPv4 and TCP protocol */

    char host[17];

    if (socket_desc == -1)
        printf("could not create socket\n");

    struct sockaddr_in *serv_addr = calloc(1, sizeof(struct sockaddr_in));

    serv_addr->sin_family = AF_INET;
    serv_addr->sin_port = htons(80);

    resolv(DEFAULT_HOST, host); /* set repository to use */

    if (inet_pton(AF_INET, host, &serv_addr->sin_addr) <= 0) {
        printf("error");
        free(serv_addr);
        return -1;
    }

    if (connect(socket_desc, (struct sockaddr *)serv_addr, sizeof(*serv_addr)) < 0) {
        printf("connection failed\n");
        return 1;
    }

    else {
        printf("connection initialized\n");
        return 0;
    }

    /* close the connection */
    free(serv_addr);
    close(socket_desc);

    return 0;
}

This works 100% and I want to just port this over to HTTPS. After looking at the horribly formatted OpenSSL client.c example (see here: https://wiki.openssl.org/index.php/SSL/TLS_Client) I got that code working on my system (had to make some changes to it), and then went off to port over my HTTP code to HTTPS. I worked on it for a bit and thought I got it working, I have been debugging it but can't figure out why it keeps failing. The code is as follows:

#include <stdio.h>
#include <stdlib.h>

#include <sys/socket.h>
#include <arpa/inet.h>

#include <netinet/in.h>
#include <string.h>

#include <unistd.h>
#include <openssl/bio.h>

#include <openssl/ssl.h>
#include <openssl/err.h>

#include "repos.h"
#include "resolv.h"

    SSL *cSSL;

void initssl()
{
    SSL_load_error_strings();
    SSL_library_init();

    OpenSSL_add_all_algorithms();
}

void destroyssl()
{
    ERR_free_strings();
    EVP_cleanup();
}

void shutdownssl()
{
    SSL_shutdown(cSSL);
    SSL_free(cSSL);
}

int main()
{
    short socket_desc;
    short socket_ssl;

    char host[17];
    socklen_t sock_size;

    SSL_CTX *sslctx;

    initssl();
    socket_desc = socket(AF_INET, SOCK_STREAM, 0); /* create socket with IPv4 and TCP protocol */

    if (socket_desc == -1)
        printf("could not create socket\n");

    struct sockaddr_in *serv_addr = calloc(1, sizeof(struct sockaddr_in));

    serv_addr->sin_family = AF_INET;
    serv_addr->sin_port = htons(443);

    resolv(DEFAULT_HOST, host); /* resolve DEFAULT_HOST and store the ip in host */

    if (inet_pton(AF_INET, host, &serv_addr->sin_addr) <= 0) {
        printf("error");
        free(serv_addr);
        return -1;
    }

    bind(socket_desc, (struct sockaddr *)serv_addr, sizeof(struct sockaddr_in));
    listen(socket_desc, 5);

    sock_size = sizeof(struct sockaddr_in);
    socket_ssl = accept(socket_desc, (struct sockaddr *)serv_addr, &sock_size); /* this is where hang occurs, however I am usnure why. I am reading docs and such and if I figure this out I will post the fix; however I would love some advice/help if anyone sees my error */

    sslctx = SSL_CTX_new(SSLv23_server_method());
    SSL_CTX_set_options(sslctx, SSL_OP_SINGLE_DH_USE);

    short use_cert = SSL_CTX_use_certificate_file(sslctx, "/serverCertificate.pem" , SSL_FILETYPE_PEM);
    short use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "/serverCertificate.pem", SSL_FILETYPE_PEM);

    cSSL = SSL_new(sslctx);
    SSL_set_fd(cSSL, socket_ssl);

    char ssl_err = SSL_accept(cSSL);

    if(ssl_err <= 0) {
        printf("connection failed\n");
        shutdownssl();
    }

    else
        printf("connected\n");

    return 0;
}

Now I know it is missing some obvious things such as writing my own initssl (I am unsure why that isn't already in the lib, but I am starting to see why OpenBSD decided to fork). I left those out as I am more interested in this working with LibreSSL and don't believe you need them with LibreSSL. I tried using print statements to debug but they never get printed even when given at the top of main(). I am unsure why this isn't working and need some help getting this ported. The other files I wrote, repos.h and resolv.c can be seen below:

/* repos.h */
char DEFAULT_HOST[11] = "gitlab.com";
char DEFAULT_PAGE[24] = "Puffles_the_Dragon/core";
/* resolv.c */
#include <stdio.h>
#include <stdlib.h>

#include <string.h>
#include <arpa/inet.h>

#include <netdb.h>

short resolv(char *host, char *ip)
{
        struct hostent *hp = calloc(1, sizeof(struct hostent));
        hp = gethostbyname(host);

        if (hp == NULL) {
                fprintf(stderr, "gethostbyname() failed\n");
                exit(1);
        }

        else {
                short i = 0;

                while (hp->h_addr_list[i] != NULL) {
                inet_ntoa(*(struct in_addr *)(hp->h_addr_list[i]));
                i++;
                }

        strlcpy(ip, inet_ntoa(*(struct in_addr *)(hp->h_addr_list[0])), 16);
        }

        return 0;
}

I know some of these calls are outdated due to IPv6, but I am going to add for IPv6 after I get this all working and port from BSD libc to musl libc.

I expected the HTTPS code to run and connect to the server thus printing connected, but it just runs and doesn't fail or print anything.

  • `struct hostent *hp = calloc(1, sizeof(struct hostent)); hp = gethostbyname(host);` is nonsense. Specifying lengths for the string arrays is nonsense too, use `char DEFAULT_HOST[] = "gitlab.com";` Who says that sockets are shorts? – Antti Haapala Jul 21 '19 at 18:21
  • ^^^ More to the point, those two lines declaring, initializing, then overwriting the value of `hp` are a perfect memory leak in two short lines. only a naked malloc could be more direct. – WhozCraig Jul 21 '19 at 19:57
  • 1
    If I may ask, how would that cause a memory leak? I was looking over what memory leaks are and if I am correct zeroing out memory and then assigning it shouldn't cause one, however I am still learning and could be wrong. Along with this, I did another test and even with a `printf("test\n");` after the line `socklen_t sock_size;` nothing is printed. The reason most numeral variables are declared as type `short` is that I myself don't use int unless it is required. I know it is small, but I like to conserve all memory (even at that low of a level). –  Jul 21 '19 at 22:17
  • Just an update: I commented everything out and slowly line-by-line uncommented and the hang happens at `socket_ssl = accept(socket_desc, (struct sockaddr *)serv_addr, &sock_size);` –  Jul 21 '19 at 22:26

0 Answers0