I'm writing a ssl client code using TLSv1.2 to connect a server, but always getting errors that cannot find openssl APIs, searched internet but didn't find much info similar to my situation.
My code is as below:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#define FAIL -1
SSL_CTX* init_ssl_ctx();
static int verify_cb(int ok, X509_STORE_CTX *store);
int main()
{
int sockfd;
struct sockaddr_in servaddr;
int ret;
struct sockaddr sockaddr;
int port = 8443;
//string ns_addr = "55.0.0.5";
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(8443);
inet_pton(AF_INET, "55.0.0.5", &servaddr.sin_addr);
sockfd = socket(PF_INET, SOCK_STREAM, 1); //tcp
if (sockfd < 0)
{
printf("sockfd fail with %d, %s\n", sockfd, strerror(errno));
return 0;
}
int reuse_opt = 1;
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_opt, sizeof(reuse_opt));
if (ret < 0)
{
printf("setsocketopt fail with %d, %s\n", ret, strerror(errno));
close(sockfd);
return 0;
}
int flags = fcntl(sockfd, F_GETFL, 0);
if (flags < 0)
{
printf("fcntl fail with %d, %s\n", flags, strerror(errno));
close(sockfd);
return 0;
}
ret = bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (ret < 0)
{
printf("bind fail with %d, %s\n", ret, strerror(errno));
close(sockfd);
return 0;
}
ret = connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (ret < 0)
{
printf("bind fail with %d, %s\n", ret, strerror(errno));
close(sockfd);
return 0;
}
SSL_CTX* ssl_ctx = init_ssl_ctx();
if (ssl_ctx == NULL)
{
close(sockfd);
return 0;
}
SSL *p_ssl = SSL_new(ssl_ctx);
if (p_ssl == NULL)
{
printf("SSL_new fail\n");
close(sockfd);
return 0;
}
BIO *p_bio = BIO_new_socket(sockfd, BIO_NOCLOSE);
if (p_bio == NULL)
{
printf("BIO_new_socket fail\n");
close(sockfd);
SSL_free(p_ssl);
return 0;
}
SSL_set_bio(p_ssl, p_bio, p_bio);
SSL_clear_options(p_ssl, SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3);
long vermasks = SSL_OP_NO_SSLv2;
vermasks |= SSL_OP_NO_TLSv1_3;
SSL_set_options(p_ssl, SSL_OP_ALL | vermasks);
SSL_set_verify(p_ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | SSL_VERIFY_CLIENT_ONCE, verify_cb);
SSL_set_verify_depth(p_ssl, 4);
ret = SSL_connect(p_ssl);
int err = SSL_get_error(p_ssl, ret);
printf("SSL_connect err = %d\n", err);
return 0;
}
static int verify_cb(int ok, X509_STORE_CTX *store)
{
printf("SSL_set_verify fail\n");
return ok;
}
SSL_CTX* init_ssl_ctx()
{
SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
if (ssl_ctx == NULL)
{
printf("SSL_CTX_new fail\n");
return NULL;
}
long vermasks = SSL_OP_NO_SSLv2;
vermasks |= SSL_OP_NO_TLSv1_3;
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | vermasks);
//Two standardized session resumption mechanisms that require two different data sharing designs:
//Session IDs RFC 5246, and Session Tickets RFC 5077. Both will be disabled by calling openssl APIs as below.
//For details, please check SBC-23917
SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF);
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET | SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
SSL_CTX_set_num_tickets(ssl_ctx, 0);
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
//set ALPN as HTTP/2
unsigned char protos[] = {
2, 'h', '2'
};
unsigned int protos_len = sizeof(protos);
if (SSL_CTX_set_alpn_protos(ssl_ctx, protos, protos_len) != 0)
{
printf("SSL_CTX_set_alpn_protos fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
if (SSL_CTX_set_cipher_list(ssl_ctx, "ALL:!DH:!EXP:!RC4:@STRENGTH") != 1)
{
printf("SSL_CTX_set_cipher_list fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
char* CAfile = "CaListApple.pem";
if (SSL_CTX_load_verify_locations(ssl_ctx, CAfile, NULL) != 1)
{
printf("SSL_CTX_load_verify_locations fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
char *client_cert_file = "CertificateAppleV4D.pem";
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert_file) != 1)
{
printf("SSL_CTX_use_certificate_chain_file fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, client_cert_file, SSL_FILETYPE_PEM) != 1)
{
printf("SSL_CTX_use_PrivateKey_file fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
if (SSL_CTX_check_private_key(ssl_ctx) != 1)
{
printf("SSL_CTX_check_private_key fail\n");
SSL_CTX_free(ssl_ctx);
return NULL;
}
return ssl_ctx;
}
OS is ubuntu 20.04 LTS:
Description: Ubuntu 20.04 LTS
openssl version 1.1.1f:
OpenSSL 1.1.1f 31 Mar 2020
built on: Mon Apr 20 11:53:50 2020 UTC
platform: debian-amd64
options: bn(64,64) rc4(8x,int) des(int) blowfish(ptr)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -Wa,--noexecstack -g -O2 -fdebug-prefix-map=/build/openssl-P_ODHM/openssl-1.1.1f=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_TLS_SECURITY_LEVEL=2 -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_CPUID_OBJ -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DKECCAK1600_ASM -DRC4_ASM -DMD5_ASM -DAESNI_ASM -DVPAES_ASM -DGHASH_ASM -DECP_NISTZ256_ASM -DX25519_ASM -DPOLY1305_ASM -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-1.1"
Seeding source: os-specific
$ dpkg -l | grep ssl
ii libflac8:amd64 1.3.3-1build1 amd64 Free Lossless Audio Codec - runtime C library
ii libssl-dev:amd64 1.1.1f-1ubuntu2 amd64 Secure Sockets Layer toolkit - development files
ii libssl1.1:amd64 1.1.1f-1ubuntu2 amd64 Secure Sockets Layer toolkit - shared libraries
ii libxmlsec1-openssl:amd64 1.2.28-2 amd64 Openssl engine for the XML security library
ii libzstd1:amd64 1.4.4+dfsg-3 amd64 fast lossless compression algorithm
ii openssl 1.1.1f-1ubuntu2 amd64 Secure Sockets Layer toolkit - cryptographic utility
ii python3-openssl 19.0.0-1build1 all Python 3 wrapper around the OpenSSL library
Tried several build commands:
g++ -lssl -lcrypto -o ssl_client ssl_client.cpp
g++ -lrt -lssl -lcrypto -o ssl_client ssl_client.cpp
g++ -L/lib/x86_64-linux-gnu -lrt -lssl -lcrypto -o ssl_client ssl_client.cpp
g++ -L/usr/lib/ssl -lrt -lssl -lcrypto -o ssl_client ssl_client.cpp
g++ -L/usr/lib/x86_64-linux-gnu -lrt -lssl -lcrypto -o ssl_client ssl_client.cpp
Always got error:
/usr/bin/ld: /tmp/ccA1Fl3A.o: in function `main':
ssl_client.cpp:(.text+0x25c): undefined reference to `SSL_new'
/usr/bin/ld: ssl_client.cpp:(.text+0x296): undefined reference to `BIO_new_socket'
/usr/bin/ld: ssl_client.cpp:(.text+0x2c3): undefined reference to `SSL_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x2e4): undefined reference to `SSL_set_bio'
/usr/bin/ld: ssl_client.cpp:(.text+0x2f5): undefined reference to `SSL_clear_options'
/usr/bin/ld: ssl_client.cpp:(.text+0x320): undefined reference to `SSL_set_options'
/usr/bin/ld: ssl_client.cpp:(.text+0x338): undefined reference to `SSL_set_verify'
/usr/bin/ld: ssl_client.cpp:(.text+0x349): undefined reference to `SSL_set_verify_depth'
/usr/bin/ld: ssl_client.cpp:(.text+0x355): undefined reference to `SSL_connect'
/usr/bin/ld: ssl_client.cpp:(.text+0x369): undefined reference to `SSL_get_error'
/usr/bin/ld: /tmp/ccA1Fl3A.o: in function `init_ssl_ctx()':
ssl_client.cpp:(.text+0x3e1): undefined reference to `TLS_client_method'
/usr/bin/ld: ssl_client.cpp:(.text+0x3e9): undefined reference to `SSL_CTX_new'
/usr/bin/ld: ssl_client.cpp:(.text+0x435): undefined reference to `SSL_CTX_set_options'
/usr/bin/ld: ssl_client.cpp:(.text+0x450): undefined reference to `SSL_CTX_ctrl'
/usr/bin/ld: ssl_client.cpp:(.text+0x461): undefined reference to `SSL_CTX_set_options'
/usr/bin/ld: ssl_client.cpp:(.text+0x472): undefined reference to `SSL_CTX_set_num_tickets'
/usr/bin/ld: ssl_client.cpp:(.text+0x48d): undefined reference to `SSL_CTX_ctrl'
/usr/bin/ld: ssl_client.cpp:(.text+0x4b4): undefined reference to `SSL_CTX_set_alpn_protos'
/usr/bin/ld: ssl_client.cpp:(.text+0x4d5): undefined reference to `SSL_CTX_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x4f2): undefined reference to `SSL_CTX_set_cipher_list'
/usr/bin/ld: ssl_client.cpp:(.text+0x514): undefined reference to `SSL_CTX_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x541): undefined reference to `SSL_CTX_load_verify_locations'
/usr/bin/ld: ssl_client.cpp:(.text+0x563): undefined reference to `SSL_CTX_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x58b): undefined reference to `SSL_CTX_use_certificate_chain_file'
/usr/bin/ld: ssl_client.cpp:(.text+0x5ad): undefined reference to `SSL_CTX_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x5cc): undefined reference to `SSL_CTX_use_PrivateKey_file'
/usr/bin/ld: ssl_client.cpp:(.text+0x5ee): undefined reference to `SSL_CTX_free'
/usr/bin/ld: ssl_client.cpp:(.text+0x601): undefined reference to `SSL_CTX_check_private_key'
/usr/bin/ld: ssl_client.cpp:(.text+0x623): undefined reference to `SSL_CTX_free'
collect2: error: ld returned 1 exit status
Not sure what I missed? Appreciate your suggestions.
-lssl -lcrypto
must be last in the command
g++ -o ssl_client ssl_client.cpp -lssl -lcrypto
Thank you so much, the problem solved. I didn't aware there's order restrict of the -l parameters.