Dana Vaughne
Dana Vaughne

Reputation: 25

SSL Socket in C cannot connect to some sites

I am having a partial failure with my code in that I can establish non-secure connections to places such as www.hp.com and www.google.com, but when adding SSL to the socket I can no longer connect to www.google.com even though I can still connect to www.hp.com

In response to this I did a fair bit of research and came up with mixed answers. I tried testing different sites, and the results were spotty. So I feel like I am missing a crucial portion of the SSL handshake here that is not readily apparent (at least to me).

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <errno.h>

#define SW_SUCCESS  1
#define SW_ERROR    0

typedef struct socket_info
{
    int SocketHandle;
    unsigned long AddressLong;
    unsigned short Port;
    char Host[256];
    char Address[16];
    char Request[256];
    char Agent[128];
    char Headers[512];
    SSL *SecureHandle;
    SSL_CTX *SecureContext;
    const SSL_METHOD *SecureMethod;
    BIO *SecureCertificate;
} SOCKETINFO, *PSOCKETINFO, *LPSOCKETINFO;


int secinit()
{
    OpenSSL_add_all_algorithms();
    ERR_load_BIO_strings();
    ERR_load_crypto_strings();
    SSL_load_error_strings();
    return SW_SUCCESS;
}


int rawclose(struct socket_info *psi)
{
    return (!close(psi->SocketHandle) ? SW_SUCCESS : SW_ERROR);
}

int secclose(struct socket_info *psi)
{
    SSL_free(psi->SecureHandle);
    SSL_CTX_free(psi->SecureContext);
    return (rawclose(psi) ? SW_SUCCESS : SW_ERROR);
}


int rawconnect(struct socket_info *psi)
{
    struct hostent *host;
    struct sockaddr_in addr;

    if ( (host = gethostbyname(psi->Host)) == NULL ) return SW_ERROR;

    if ( (psi->SocketHandle = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 )
    {
        psi->SocketHandle = 0;
        return SW_ERROR;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(psi->Port);
    addr.sin_addr.s_addr = *(long *)host->h_addr; 

    if ( connect(psi->SocketHandle, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1 )
    {
        psi->SocketHandle = 0;
        return SW_ERROR;
    }

    return SW_SUCCESS;
}



int secconnect(struct socket_info *psi)
{
    // Initialise certificate BIO.
    psi->SecureCertificate = BIO_new(BIO_s_file());
    if ( SSL_library_init() < 0 ) return SW_ERROR;

    // Initialise SSL method and deprecate SSLv2.
    psi->SecureMethod = SSLv23_client_method();
    if ( (psi->SecureContext = SSL_CTX_new(psi->SecureMethod)) == NULL ) return SW_ERROR;
    SSL_CTX_set_options(psi->SecureContext, SSL_OP_NO_SSLv2);
    psi->SecureHandle = SSL_new(psi->SecureContext);

    // Connect to host with raw socket.
    if ( !rawconnect(psi) )
    {
        SSL_free(psi->SecureHandle);
        SSL_CTX_free(psi->SecureContext);
        return SW_ERROR;
    }

    // Upgrade socket to SSL enabled.
    SSL_set_fd(psi->SecureHandle, psi->SocketHandle);
    if ( SSL_connect(psi->SecureHandle) != 1 )
    {
        SSL_free(psi->SecureHandle);
        close(psi->SocketHandle);
        SSL_CTX_free(psi->SecureContext);
        return SW_ERROR;
    }

    return SW_SUCCESS;
}


int main(int argc, char **argv)
{
    SOCKETINFO si;
    int ret;

    // SSLWrap module initialisation.
    if ( secinit() != SW_SUCCESS ) return SW_ERROR;

    memset(&si, 0, sizeof(si));
    strncpy(si.Host, "www.google.com", 10);
    si.Port = 80;
    if ( (ret = rawconnect(&si)) != SW_SUCCESS ) return SW_ERROR;
    if ( (ret = rawclose(&si)) != SW_SUCCESS ) return SW_ERROR;

    memset(&si, 0, sizeof(si));
    strncpy(si.Host, "www.google.com", 10);
    si.Port = 443;
    if ( (ret = secconnect(&si)) != SW_SUCCESS ) return SW_ERROR;
    if ( (ret = secclose(&si)) != SW_SUCCESS ) return SW_ERROR;

    return 0;
}

Upvotes: 1

Views: 290

Answers (1)

wildplasser
wildplasser

Reputation: 44250

strncpy(si.Host, "www.google.com", 10); 10 is too short; just use strcpy() here.

[also a strong advice: never use strncpy() , at least until you know what it does ...]


why is strncpy() considered evil? Mostly because it is confusing, at least for novice users. How?

using strncpy(dst, src, siz);:

  • If there is sufficient space in the destination buffer (strlen(src) < siz) , the restof the buffer will befilled with nullbytes
  • if there is not enough space (strlen(src) >= siz) , no more than sizbytes will be written to*dst, but the copied string wil not be nul-terminated.

The first case is not that important, a few cycles are wasted for writing the extra nulls. The second case can be disastrous if you expect the resulting string to be null-terminated. (most people do) This is why strncpy() raises red flags.


How to avoid strncpy() ? There are a few ways. one of the simplest:

len = strlen(src);
if (len >=siz) len=siz-1;
memcpy(dst, src, len);
dst[len]= 0;

Upvotes: 1

Related Questions