6

i wrote an script, who can create an connection to an HTTP Server and shows the content of the website in the console. Very easy.

But i want to connect to an https server and do the same procedures. I searched at google and didn't found what i searched.

Please help me and give me an tutorial who can i use the openssl library.

I tried myself on the openssl library, but the library is very complicated and difficult to understand.

Here is my code of the http client:

#include <iostream>
#include <ctype.h>
#include <cstring>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <string>
#include <arpa/inet.h>
#include <openssl/ssl.h>

using namespace std;

int sock;
struct sockaddr_in client;
int PORT = 80;

int main(int argc, char const *argv[])
{
    bzero(&client, sizeof(client));
    client.sin_family = AF_INET;
    client.sin_port = htons( PORT );
    client.sin_addr.s_addr = inet_addr("172.16.0.6");

    sock = socket(AF_INET, SOCK_STREAM, 0);

    if (sock < 0) {
        cout << "Error creating socket." << endl;
        exit(1);
    }

    if ( connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0 ) {
        close(sock);
        cout << "Could not connect" << endl;
        exit(1);
    }

    stringstream ss;
    ss << "GET /" << "\r\n"
    << "Host: 172.16.1.4\r\n"
    << "Accept: application/json\r\n"
    << "Connection: close"
    << "\r\n\r\n";
    string request = ss.str();

    if (send(sock, request.c_str(), request.length(), 0) != (int)request.length()) {
        cout << "Error sending request." << endl;
        exit(1);
    }

    char cur;
    while ( read(sock, &cur, 1) > 0 ) {
        cout << cur;
    }

    return 0;
}
Hball
  • 89
  • 1
  • 1
  • 5
  • 4
    Yes, the OpenSSL library is above average, in terms of complexity and difficulty to use. Not only do you have to figure out how to use it, you also have to have a good working knowledge of the technology behind SSL/TLS. Start reading its documentation. Get a book on implementing SSL applications, and start reading that book, too. No, there are no shortcuts, and no magic wands one can waive, and make an SSL client pop out of thin air. There is no alternative to investing significant time and effort in studying and learning how to use the library. – Sam Varshavchik Dec 19 '16 at 19:35
  • yeah i know. a little knowledge of TLS/SSL exists. But i need an "fast" solution for the c++ program. Now i found a good way: I use the libcurl library. Here is already an HTTPS implementation. thank you very much! – Hball Dec 19 '16 at 20:03
  • 2
    Using OpenSSL, the simplest approach would be to replace `connect()`, `read()` and `send()` with `ssl_connect()`, `ssl_read()` and `ssl_write()`, respectively. That does mean re-writing your existing socket logic, since HTTP and HTTPS will use different code paths. If you want to reuse your existing socket code and just add OpenSSL on top of it, you can use OpenSSL's `BIO` API, which allows you to continue using `connect()`, `read()` and `send()`, you just associate some dedicated memory buffers to handle the encrypted data back and forth. There are **tons** of examples if you look around. – Remy Lebeau Dec 19 '16 at 20:10
  • What version of the HTTP standard do you think your code complies with? I know of no version that supports headers but permits you to omit a version number. – David Schwartz Aug 18 '21 at 23:06

1 Answers1

20

Here is a sample SSL client that connects to https://about.google/intl/en/ and prints downloaded a page : SSLClient.cpp

//============================================================================
// Name        : SSLClient.cpp
// Compiling   : g++ -c -o SSLClient.o SSLClient.cpp
//               g++ -o SSLClient SSLClient.o -lssl -lcrypto
//============================================================================
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <string.h>

using namespace std;
    
SSL *ssl;
int sock;
    
int RecvPacket()
{
    int len=100;
    char buf[1000000];
    do {
        len=SSL_read(ssl, buf, 100);
        buf[len]=0;
        printf("%s\n",buf);
//        fprintf(fp, "%s",buf);
    } while (len > 0);
    if (len < 0) {
        int err = SSL_get_error(ssl, len);
    if (err == SSL_ERROR_WANT_READ)
            return 0;
        if (err == SSL_ERROR_WANT_WRITE)
            return 0;
        if (err == SSL_ERROR_ZERO_RETURN || err == SSL_ERROR_SYSCALL || err == SSL_ERROR_SSL)
            return -1;
    }
}
    
int SendPacket(const char *buf)
{
    int len = SSL_write(ssl, buf, strlen(buf));
    if (len < 0) {
        int err = SSL_get_error(ssl, len);
        switch (err) {
        case SSL_ERROR_WANT_WRITE:
            return 0;
        case SSL_ERROR_WANT_READ:
            return 0;
        case SSL_ERROR_ZERO_RETURN:
        case SSL_ERROR_SYSCALL:
        case SSL_ERROR_SSL:
        default:
            return -1;
        }
    }
}
    
void log_ssl()
{
    int err;
    while (err = ERR_get_error()) {
        char *str = ERR_error_string(err, 0);
        if (!str)
            return;
        printf(str);
        printf("\n");
        fflush(stdout);
    }
}
    
int main(int argc, char *argv[])
{
    int s;
    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) {
        printf("Error creating socket.\n");
        return -1;
    }
    struct sockaddr_in sa;
    memset (&sa, 0, sizeof(sa));
    sa.sin_family      = AF_INET;
    sa.sin_addr.s_addr = inet_addr("173.194.222.139"); // address of google.ru
    sa.sin_port        = htons (443); 
    socklen_t socklen = sizeof(sa);
    if (connect(s, (struct sockaddr *)&sa, socklen)) {
        printf("Error connecting to server.\n");
        return -1;
    }
    SSL_library_init();
    SSLeay_add_ssl_algorithms();
    SSL_load_error_strings();
    const SSL_METHOD *meth = TLSv1_2_client_method();
    SSL_CTX *ctx = SSL_CTX_new (meth);
    ssl = SSL_new (ctx);
    if (!ssl) {
        printf("Error creating SSL.\n");
        log_ssl();
        return -1;
    }
    sock = SSL_get_fd(ssl);
    SSL_set_fd(ssl, s);
    int err = SSL_connect(ssl);
    if (err <= 0) {
        printf("Error creating SSL connection.  err=%x\n", err);
        log_ssl();
        fflush(stdout);
        return -1;
    }
    printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
    
    char *request = "GET https://about.google/intl/en/ HTTP/1.1\r\n\r\n";       
    SendPacket(request);
    RecvPacket();
    return 0;
}

Note that if you want to exchange data between client and server with openssl, you might need to process error codes SSL_ERROR_WANT_READ and SSL_ERROR_WANT_WRITE as described in documentation. But it's not necessary here as HTTPS protocol is serial.

O.logN
  • 326
  • 1
  • 5