clinuxopensslmingw32cross-build

Why references to `OPENSSL_init_crypto' are undefined when I complile my app with crossbuilt openssl from source for windows 32 bit?


I have downloaded openssl from source, and I've built it like that (on linux using mingw32):

wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz
tar -xvf openssl-1.1.1q.tar.gz
cd ./openssl-1.1.1q
./Configure enable-tls1_3 enable-tls1_2 no-async --cross-compile-prefix=i686-w64-mingw32- mingw
make -j 16
make install

And I try to complile the following file main.c:

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>

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


// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
//#pragma comment (lib, "Mswsock.lib")
//#pragma comment (lib, "AdvApi32.lib")


#define DEFAULT_BUFLEN 512
#define FAIL    -1

#define WIN32_LEAN_AND_MEAN

SOCKET OpenConnection(char* hostname, int port)
{
    WSADATA wsaData;
    SOCKET ConnectSocket = INVALID_SOCKET;
    struct addrinfo* result = NULL;
    struct addrinfo* ptr = NULL;
    struct addrinfo hints;
    char recvbuf[DEFAULT_BUFLEN];
    int iResult;
    int recvbuflen = DEFAULT_BUFLEN;

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed with error: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    // Resolve the server address and port
    iResult = getaddrinfo("google.com", "449", &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed with error: %d\n", iResult);
        WSACleanup();
        return 1;
    }
    ptr = result;
    // Create a SOCKET for connecting to server
    ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
    if (ConnectSocket == INVALID_SOCKET) {
        printf("socket failed with error: %ld\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    // Connect to server.
    iResult = connect(ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        closesocket(ConnectSocket);
        ConnectSocket = INVALID_SOCKET;
    }
    return ConnectSocket;
}


SSL_CTX* InitCTX(void)
{
    OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
    SSL_load_error_strings();   /* Bring in and register error messages */
    const SSL_METHOD* method = TLSv1_2_client_method();  /* Create new client-method instance */
    SSL_CTX* ctx = SSL_CTX_new(method);   /* Create new context */
    if (ctx == NULL)
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    return ctx;
}


void ShowCerts(SSL* ssl)
{
    X509* cert;
    char* line;
    cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
    if (cert != NULL)
    {
        printf("Server certificates:\n");
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("Subject: %s\n", line);
        //free(line);       /* free the malloc'ed string */
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("Issuer: %s\n", line);
        //free(line);       /* free the malloc'ed string */
        X509_free(cert);     /* free the malloc'ed certificate copy */
    }
    else
        printf("Info: No client certificates configured.\n");
}

int main(int argc, char* argv[])
{
    char buf[1024];
    char acClientRequest[1024] = { 0 };

    SSL_library_init();
    char* hostname = "google.com";
    char* portnum = "449";

    SSL_CTX* ctx = InitCTX();
    int server = OpenConnection(hostname, atoi(portnum));
    SSL* ssl = SSL_new(ctx);      /* create new SSL connection state */
    SSL_set_fd(ssl, server);    /* attach the socket descriptor */


    if (SSL_connect(ssl) == FAIL) {
        ERR_print_errors_fp(stderr);
    } else {
        const char* cpRequestMessage = "";

        printf("\n\nConnected with %s encryption\n", SSL_get_cipher(ssl));
       
        /* get any certs */
        ShowCerts(ssl);   
        /* encrypt & send message */
        SSL_write(ssl, acClientRequest, strlen(acClientRequest));  

        /* get reply & decrypt */
        int bytes = SSL_read(ssl, buf, sizeof(buf)); 

        buf[bytes] = 0;
        printf("Received: \"%s\"\n", buf);
        /* release connection state */
        SSL_free(ssl);       
    }

    /* close socket */
    closesocket(server);   
    /* release context */
    SSL_CTX_free(ctx);        
    return 0;
}

Once I try to build it like this:

LANG=C i686-w64-mingw32-gcc main.c -lws2_32 -I"openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include" -fpermissive -o main.exe

I get the following errors:

LANG=C i686-w64-mingw32-gcc main.c -lws2_32 -I"openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include" -fpermissive -o main.exe
cc1: warning: command line option '-fpermissive' is valid for C++/ObjC++ but not for C
main.c: In function 'InitCTX':
main.c:77:5: warning: 'TLSv1_2_client_method' is deprecated [-Wdeprecated-declarations]
     const SSL_METHOD* method = TLSv1_2_client_method();  /* Create new client-method instance */
     ^~~~~
In file included from openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/e_os2.h:13:0,
                 from openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:15,
                 from main.c:8:
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:1901:45: note: declared here
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_client_method(void))
                                             ^
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/opensslconf.h:124:37: note: in definition of macro 'DECLARE_DEPRECATED'
 #   define DECLARE_DEPRECATED(f)    f __attribute__ ((deprecated));
                                     ^
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:1901:1: note: in expansion of macro 'DEPRECATEDIN_1_1_0'
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_client_method(void))
 ^
/tmp/ccvIModv.o:main.c:(.text+0x376): undefined reference to `OPENSSL_init_crypto'
/tmp/ccvIModv.o:main.c:(.text+0x392): undefined reference to `OPENSSL_init_ssl'
/tmp/ccvIModv.o:main.c:(.text+0x397): undefined reference to `TLSv1_2_client_method'
/tmp/ccvIModv.o:main.c:(.text+0x3a5): undefined reference to `SSL_CTX_new'
/tmp/ccvIModv.o:main.c:(.text+0x3be): undefined reference to `ERR_print_errors_fp'
/tmp/ccvIModv.o:main.c:(.text+0x3d9): undefined reference to `SSL_get_peer_certificate'
/tmp/ccvIModv.o:main.c:(.text+0x3fd): undefined reference to `X509_get_subject_name'
/tmp/ccvIModv.o:main.c:(.text+0x415): undefined reference to `X509_NAME_oneline'
/tmp/ccvIModv.o:main.c:(.text+0x436): undefined reference to `X509_get_issuer_name'
/tmp/ccvIModv.o:main.c:(.text+0x44e): undefined reference to `X509_NAME_oneline'
/tmp/ccvIModv.o:main.c:(.text+0x46f): undefined reference to `X509_free'
/tmp/ccvIModv.o:main.c:(.text+0x4ca): undefined reference to `OPENSSL_init_ssl'
/tmp/ccvIModv.o:main.c:(.text+0x508): undefined reference to `SSL_new'
/tmp/ccvIModv.o:main.c:(.text+0x51d): undefined reference to `SSL_set_fd'
/tmp/ccvIModv.o:main.c:(.text+0x528): undefined reference to `SSL_connect'
/tmp/ccvIModv.o:main.c:(.text+0x53d): undefined reference to `ERR_print_errors_fp'
/tmp/ccvIModv.o:main.c:(.text+0x554): undefined reference to `SSL_get_current_cipher'
/tmp/ccvIModv.o:main.c:(.text+0x55c): undefined reference to `SSL_CIPHER_get_name'
/tmp/ccvIModv.o:main.c:(.text+0x59e): undefined reference to `SSL_write'
/tmp/ccvIModv.o:main.c:(.text+0x5bb): undefined reference to `SSL_read'
/tmp/ccvIModv.o:main.c:(.text+0x5ed): undefined reference to `SSL_free'
/tmp/ccvIModv.o:main.c:(.text+0x608): undefined reference to `SSL_CTX_free'

If I try to use -lcrypto and -lssl flags:

LANG=C i686-w64-mingw32-gcc main.c -lws2_32 -lcrypto -lssl -I"openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include" -fpermissive -o main.exe

I get the following response:

cc1: warning: command line option '-fpermissive' is valid for C++/ObjC++ but not for C
main.c: In function 'InitCTX':
main.c:77:5: warning: 'TLSv1_2_client_method' is deprecated [-Wdeprecated-declarations]
     const SSL_METHOD* method = TLSv1_2_client_method();  /* Create new client-method instance */
     ^~~~~
In file included from openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/e_os2.h:13:0,
                 from openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:15,
                 from main.c:8:
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:1901:45: note: declared here
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_client_method(void))
                                             ^
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/opensslconf.h:124:37: note: in definition of macro 'DECLARE_DEPRECATED'
 #   define DECLARE_DEPRECATED(f)    f __attribute__ ((deprecated));
                                     ^
openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include/openssl/ssl.h:1901:1: note: in expansion of macro 'DEPRECATEDIN_1_1_0'
 DEPRECATEDIN_1_1_0(__owur const SSL_METHOD *TLSv1_2_client_method(void))
 ^
/usr/bin/i686-w64-mingw32-ld: cannot find -lctypto
/usr/bin/i686-w64-mingw32-ld: cannot find -lssl
collect2: error: ld returned 1 exit status

The question is why these are undefined:

/tmp/ccvIModv.o:main.c:(.text+0x376): undefined reference to `OPENSSL_init_crypto'
/tmp/ccvIModv.o:main.c:(.text+0x392): undefined reference to `OPENSSL_init_ssl'
/tmp/ccvIModv.o:main.c:(.text+0x397): undefined reference to `TLSv1_2_client_method'
/tmp/ccvIModv.o:main.c:(.text+0x3a5): undefined reference to `SSL_CTX_new'
/tmp/ccvIModv.o:main.c:(.text+0x3be): undefined reference to `ERR_print_errors_fp'
/tmp/ccvIModv.o:main.c:(.text+0x3d9): undefined reference to `SSL_get_peer_certificate'
/tmp/ccvIModv.o:main.c:(.text+0x3fd): undefined reference to `X509_get_subject_name'
/tmp/ccvIModv.o:main.c:(.text+0x415): undefined reference to `X509_NAME_oneline'
/tmp/ccvIModv.o:main.c:(.text+0x436): undefined reference to `X509_get_issuer_name'
/tmp/ccvIModv.o:main.c:(.text+0x44e): undefined reference to `X509_NAME_oneline'
/tmp/ccvIModv.o:main.c:(.text+0x46f): undefined reference to `X509_free'
/tmp/ccvIModv.o:main.c:(.text+0x4ca): undefined reference to `OPENSSL_init_ssl'
/tmp/ccvIModv.o:main.c:(.text+0x508): undefined reference to `SSL_new'
/tmp/ccvIModv.o:main.c:(.text+0x51d): undefined reference to `SSL_set_fd'
/tmp/ccvIModv.o:main.c:(.text+0x528): undefined reference to `SSL_connect'
/tmp/ccvIModv.o:main.c:(.text+0x53d): undefined reference to `ERR_print_errors_fp'
/tmp/ccvIModv.o:main.c:(.text+0x554): undefined reference to `SSL_get_current_cipher'
/tmp/ccvIModv.o:main.c:(.text+0x55c): undefined reference to `SSL_CIPHER_get_name'
/tmp/ccvIModv.o:main.c:(.text+0x59e): undefined reference to `SSL_write'
/tmp/ccvIModv.o:main.c:(.text+0x5bb): undefined reference to `SSL_read'
/tmp/ccvIModv.o:main.c:(.text+0x5ed): undefined reference to `SSL_free'
/tmp/ccvIModv.o:main.c:(.text+0x608): undefined reference to `SSL_CTX_free'

And how I can fix them?


Solution

  • As @Gerhardh has pointed out I must compile my application with:

    LANG=C i686-w64-mingw32-gcc main.c -lws2_32 -I"openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/include" -L"openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/lib" -fpermissive -o main.exe -lcrypto -lssl
    

    At openssl-1.1.1q/C:/Program Files (x86)/OpenSSL/ there are 2 folder that need to keep an eye-notice:

    Using -I param provide the full path towards includes dir and using -L param provide the path towards the lib dir.