I am trying to use the openssl api to implement the JA3 method (TLS fingerprinting method) on a personnal project. To do that I need to get some informations on the Client Hello packet and I am trying to do that with the openssl api https://www.openssl.org/docs/man1.1.1/man3/ . Firstly I downloaded a code which set up a TLS connection between my computer and a website and retrieved the certificat information. This program is running well, the tls connection is using TLS 1.3 and the certificat information are ok. Then I tried to retrieved the Client Hello packet to start implement the JA3 method. After few researches I found many function that may allow me to get the information I need : https://www.openssl.org/docs/man1.1.1/man3/SSL_client_hello_cb_fn.html . All of those function can only be call on the client hello callback function. This function can be called thanks to the SSL_CTX_set_client_hello_cb function. But in my case my function is never called. I am starting to be hopeless it's why I need your help. I really searched a lot to debug that but I didn't find a flag that can allow the callback function or something like that. Here is the program :
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.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>
int create_socket(char[], BIO *);
int callback(SSL *s, int *al, void *arg)
{
int * number = arg;
*number = (*number) + 1;
printf("\nWe are in the callback function !\n");
return SSL_CLIENT_HELLO_SUCCESS;
}
int main() {
char dest_url[] = "https://www.hp.com";
BIO *certbio = NULL;
BIO *outbio = NULL;
X509 *cert = NULL;
X509_NAME *certname = NULL;
const SSL_METHOD *method;
SSL_CTX *ctx;
struct ssl_st *ssl;
int server = 0;
OpenSSL_add_all_algorithms();
ERR_load_BIO_strings();
ERR_load_crypto_strings();
SSL_load_error_strings();
certbio = BIO_new(BIO_s_file());
outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
if(SSL_library_init() < 0)
BIO_printf(outbio, "Could not initialize the OpenSSL library !\n");
method = TLS_client_method();
if ( (ctx = SSL_CTX_new(method)) == NULL)
BIO_printf(outbio, "Unable to create a new SSL context structure.\n");
int hope = 12;
SSL_CTX_set_client_hello_cb(ctx, &callback, (void *)&hope);
ssl = SSL_new(ctx);
server = create_socket(dest_url, outbio);
if(server != 0)
BIO_printf(outbio, "Successfully made the TCP connection to: %s.\n", dest_url);
SSL_set_fd(ssl, server);
if ( SSL_connect(ssl) != 1 )
BIO_printf(outbio, "Error: Could not build a SSL session to: %s.\n", dest_url);
else
BIO_printf(outbio, "Successfully enabled SSL/TLS session to: %s.\n", dest_url);
cert = SSL_get_peer_certificate(ssl);
if (cert == NULL)
BIO_printf(outbio, "Error: Could not get a certificate from: %s.\n", dest_url);
else
BIO_printf(outbio, "Retrieved the server's certificate from: %s.\n", dest_url);
certname = X509_NAME_new();
certname = X509_get_subject_name(cert);
BIO_printf(outbio, "Displaying the certificate subject data:\n");
X509_NAME_print_ex(outbio, certname, 0, 0);
BIO_printf(outbio, "\n");
SSL_free(ssl);
close(server);
X509_free(cert);
SSL_CTX_free(ctx);
BIO_printf(outbio, "Finished SSL/TLS connection with server: %s.\n", dest_url);
printf("Hope value : %d \n", hope);
return(0);
}
int create_socket(char url_str[], BIO *out) {
int sockfd;
char hostname[256] = "";
char portnum[6] = "443";
char proto[6] = "";
char *tmp_ptr = NULL;
int port;
struct hostent *host;
struct sockaddr_in dest_addr;
if(url_str[strlen(url_str)] == '/')
url_str[strlen(url_str)] = '\0';
strncpy(proto, url_str, (strchr(url_str, ':')-url_str));
strncpy(hostname, strstr(url_str, "://")+3, sizeof(hostname));
if(strchr(hostname, ':')) {
tmp_ptr = strchr(hostname, ':');
/* the last : starts the port number, if avail, i.e. 8443 */
strncpy(portnum, tmp_ptr+1, sizeof(portnum));
*tmp_ptr = '\0';
}
port = atoi(portnum);
if ( (host = gethostbyname(hostname)) == NULL ) {
BIO_printf(out, "Error: Cannot resolve hostname %s.\n", hostname);
abort();
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
dest_addr.sin_family=AF_INET;
dest_addr.sin_port=htons(port);
dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
memset(&(dest_addr.sin_zero), '\0', 8);
tmp_ptr = inet_ntoa(dest_addr.sin_addr);
if ( connect(sockfd, (struct sockaddr *) &dest_addr,
sizeof(struct sockaddr)) == -1 ) {
BIO_printf(out, "Error: Cannot connect to host %s [%s] on port %d.\n",
hostname, tmp_ptr, port);
}
return sockfd;
}
I am waiting for your answer thanks guys.
The hint for what is going wrong is from the first line of the description in the doc that you linked to:
SSL_CTX_set_client_hello_cb() sets the callback function, which is automatically called during the early stages of ClientHello processing on the server.
This is called by a server when processing the received ClientHello. You have written a client and therefore it is never called.
As an alternative I suggest you look at SSL_CTX_set_msg_callback():
https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_msg_callback.html
From the docs:
SSL_CTX_set_msg_callback() or SSL_set_msg_callback() can be used to define a message callback function cb for observing all SSL/TLS protocol messages (such as handshake messages) that are received or sent, as well as other events that occur during processing.
Related
openssl_1.1.1_perl_dump.txt
We are trying to upgrade on Openssl version 1.1.1, with security layer from TLS 1.2 to TLS 1.3.
Our code base performs SSL handshake, and later use send & read/recv function to transfer data. *Note - it is working fine for TLS 1.2.
However when we switch to TLS 1.3, and data packets are not received for send & read/recv, but working only when we use SSL_write & SSL_read.
Below we have tried to make sample server & client program, where we use send & read/recv functions after successful SSL connection, here also it works fine for TLS 1.2, but in case of TLS 1.3 there is lag in packets received, the first response from server is blank, please refer outputs below. For out put of 'perl configdata.pm --dump' refer attachment.
Used steps mentioned as per this reference article https://help.ubuntu.com/community/OpenSSL - to create SSL certificates.
server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "/usr/include/openssl/ssl.h"
#include "/usr/include/openssl/crypto.h"
#include "/usr/include/openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 10) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
int isRoot()
{
if (getuid() != 0)
{
return 0;
}
else
{
return 1;
}
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
printf("\nSetting TLS1.3 method\n");
fflush(stdout);
method = TLS_server_method(); /* create new server-method instance */
}
else{
printf("\nSetting TLS1.2 method\n");
fflush(stdout);
method = TLSv1_2_server_method(); /* create new server-method instance */
}
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
SSL_CTX_load_verify_locations(ctx, "01.pem", "/home/qarun/aparopka/myCA/signedcerts");
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
//New lines - Force the client-side have a certificate
/*SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL);
SSL_CTX_set_verify_depth(ctx, 2);*/
//End new lines
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
sd = SSL_get_fd(ssl); /* get socket connection */
printf("\nsd: <%d>", sd);
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
/*if(SSL_do_handshake(ssl) <= 0){
printf("\n SSL_do_handshake failed....\n");
}*/
ShowCerts(ssl); /* get any certificates */
do{
//bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
//bytes = read(sd, buf, sizeof(buf));
bytes = recv(sd, buf, sizeof(buf), 0);
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
//SSL_write(ssl, reply, strlen(reply)); /* send reply */
send(sd, reply, strlen(reply), 0); // MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
}
else
ERR_print_errors_fp(stderr);
}while(bytes>0);
}
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if(!isRoot())
{
printf("This program must be run as root/sudo user!!");
//exit(0);
}
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
client.c
#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>
#define FAIL -1
//Added the LoadCertificates how in the server-side makes.
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_chain_file(ctx, CertFile ) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0){
printf("\nSetting TLS1.3 method\n");
fflush(stdout);
method = TLS_client_method(); /* create new server-method instance */
}
else{
printf("\nSetting TLS1.2 method\n");
fflush(stdout);
method = TLSv1_2_client_method(); /* create new server-method instance */
}
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0)
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2);
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 count, char *strings[])
{ SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char *hostname, *portnum;
if ( count != 3 )
{
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
LoadCertificates(ctx, "/home/qarun/aparopka/myCA/server_crt.pem", "/home/qarun/aparopka/myCA/server_key.pem");
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
int sd = SSL_get_fd(ssl);
int flip=1;
printf("\nsd: <%d>", sd);
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ //char *msg = "Hello???";
if(SSL_do_handshake(ssl) <= 0){
printf("\n client SSL_do_handshake failed....\n");
}
char msg[1024];
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
while(1){
bzero(msg, 1024);
bzero(buf, 1024);
printf("\nEnter message: ");
fgets(msg, 1024, stdin);
//SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
send(sd, msg, strlen(msg), 0); //MSG_NOSIGNAL | MSG_DONTWAIT); //MSG_CONFIRM);
//bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
//bytes = read(sd, buf, sizeof(buf));
bytes = recv(sd, buf, sizeof(buf), 0);
/* read again for TLS 1.3 only for first time */
/*char *imethod=getenv("TLS_METHOD");
if(imethod!=NULL && strncmp(imethod, "1.3", 3)==0
&& flip){
bytes = read(sd, buf, sizeof(buf));
flip=0;
}*/
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
}
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
Server & client Output with TLS 1.2
**$ ./ssl_server_working 2023**
Setting TLS1.2 method
Connection: 10.250.14.23:41152
sd: <4>No certificates.
Client msg: "first
"
Client msg: "second
"
Client msg: "third
"
**./ssl_client_working 10.250.14.23 2023**
Setting TLS1.2 method
sd: <3>Connected with ECDHE-RSA-AES256-GCM-SHA384 encryption
Server certificates:
Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari#quest.com/O=SharePlex/OU=IT Department
Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari#quest.com/O=SharePlex/OU=IT Department
Enter message: first
Received: "<html><body><pre>first
</pre></body></html>
"
Enter message: second
Received: "<html><body><pre>second
</pre></body></html>
"
Enter message: third
Received: "<html><body><pre>third
</pre></body></html>
"
Server & client output for TLS 1.3 : Note the response for first client request is blank, which is received in next response for second request.
export TLS_METHOD=1.3
**./ssl_server_working 2024**
Setting TLS1.3 method
Connection: 10.250.14.23:34012
sd: <4>No certificates.
Client msg: "first
"
Client msg: "second
"
Client msg: "third
"
**./ssl_client_working 10.250.14.23 2024**
Setting TLS1.3 method
sd: <3>Connected with TLS_AES_256_GCM_SHA384 encryption
Server certificates:
Subject: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari#quest.com/O=SharePlex/OU=IT Department
Issuer: /CN=MyOwn Root Certificate Authority/ST=CA/C=US/emailAddress=amit.paropkari#quest.com/O=SharePlex/OU=IT Department
Enter message: first
Received: ""
Enter message: second
Received: "<html><body><pre>first
</pre></body></html>
"
Enter message: third
Received: "<html><body><pre>second
</pre></body></html>
"
We got the answer for this. Turns out TLS 1.3 has added one more handshake step, where after server Finish message Client again sends Server finish message, server verifies it, & sends post-handshake protocol level message, called as 'NewSessionTicket message'. We can disable it with SSL_CTX_set_num_tickets method, before initiating SSL server.
SSL_set_num_tickets(ssl, 0); /* Disable post-handshake token */
sd = SSL_get_fd(ssl); /* get socket connection */
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
As for people concerned about this not being secure, in our case of requirement we only need initial secure authentication, and then we do session tunneling. After that if we use SSL_write SSL_read for every transaction (which are in huge volume & time constraint) , the encryption decryption step would degrade the performance. So we are using send & recv for sending data.
I am trying to build a ssl client and testing it with s_server provided by openssl. Until socket's connection, everything is fine but SSL_connect() fails and returns SSL_ERROR_SYSCALL.
SSL_ERROR_SYSCALL: Some I/O error occurred. The OpenSSL error queue may contain more information on the error. If the error queue is empty (i.e. ERR_get_error() returns 0), ret can be used to find out more about the error: If ret == 0, an EOF was observed that violates the protocol. If ret == -1, the underlying BIO reported an I/O error (for socket I/O on Unix systems, consult errno for details).
As documentation states, I further diagnosed with ERR_get_error() and it returned 0. How can I look errno in windows? On other side, server also doesn't show a lot.
D:\server>openssl s_server -accept 5555 -cert server.crt -key server.key -msg -debug
Using default temp DH parameters
ACCEPT
read from 0x600077c90 [0x600096e40] (11 bytes => 0 (0x0))
ERROR
shutting down SSL
CONNECTION CLOSED
EDIT Today I tried to print error string
err = SSL_connect(ssl);
ERR_error_string(SSL_get_error(ssl, err), buf);
printf("Error: %s\n", buf);
and the output was
Error: error:00000005:lib(0):func(0):DH lib
Which looks like something with Diffie-Hellman problem. there is another discussion about dH parameters but as they mentioned, I am not setting dh parameters myself.
Other similar questions talk about ssl version. I have also tried their suggestions but doesn't help.
Environment: I am on Windows, gcc (cygwin) compiler, openssl-1.02k
I also tried with errno but it returns No Error
case SSL_ERROR_SYSCALL:
perror(errno);
break;
Complete code from client is
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/crypto.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#define ON 1
#define OFF 0
#define RETURN_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(1); }
#define RETURN_NULL(x) if ((x)==NULL) exit (1)
int sock_conn;
SSL_CTX *ctx;
#define DEFAULT_BUF_SIZE 64
void handle_error(const char *file, int lineno, const char *msg) {
fprintf(stderr, "** %s:%i %s\n", file, lineno, msg);
ERR_print_errors_fp(stderr);
exit(1);
}
void Errors_SSL(const char * file, int line)
{
char *buf;
unsigned long code;
code = ERR_get_error();
while (code)
{
ERR_error_string(code, buf);
printf(buf);
printf("error code: %lu in %s line %d.\n", code, file, line);
code = ERR_get_error();
}
}
#define ssl_error() Errors_SSL( __FILE__, __LINE__)
#define int_error(msg) handle_error(__FILE__, __LINE__, msg)
void die(const char *msg) {
perror(msg);
exit(1);
}
int startTCPConnection()
{
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0 )
int_error("socket() fails");
struct sockaddr_in server_addr;
memset (&server_addr, '\0', sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(5555); /* Server Port number */
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); /* Server IP */
if ( connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 )
int_error("connect() fails");
printf("TCP Socket Connected\n");
return sock;
}
SSL_CTX *createSSLObject()
{
int verify_client = OFF;
SSL_CTX *ct = SSL_CTX_new(SSLv23_client_method());
if (ct == NULL)
int_error("SSL_CTX_new() returned 0");
if(verify_client == ON)
{
/* Load the client certificate into the SSL_CTX structure */
if (SSL_CTX_use_certificate_file(ct, "device.pem", SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Load the private-key corresponding to the client certificate */
if (SSL_CTX_use_PrivateKey_file(ct, "device.key", SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
exit(1);
}
/* Check if the client certificate and private-key matches */
if (!SSL_CTX_check_private_key(ct))
{
fprintf(stderr,"Private key does not match the certificate public key\n");
exit(1);
}
}
//SSL_CTX_set_mode(ct, SSL_MODE_AUTO_RETRY);
if (!SSL_CTX_load_verify_locations(ct, "rootCA.pem", NULL))
int_error("SSL_CTX_load_verify_locations() failed");
SSL_CTX_set_verify(ct, SSL_VERIFY_PEER, NULL);
SSL_CTX_set_verify_depth(ct,2);
return ct;
}
int main()
{
int err, e;
char hello[80];
//printf ("Message to be sent to the SSL server: ");
//fgets (hello, 80, stdin);
SSL_library_init(); // load all cipher and crypto algorithms
SSL_load_error_strings(); // error strings for libssl
ERR_load_BIO_strings();
ERR_load_crypto_strings(); // error strings for libcrypto
ctx = createSSLObject();
sock_conn = startTCPConnection();
SSL * ssl = SSL_new(ctx);
RETURN_NULL(ssl);
SSL_set_fd(ssl, sock_conn);
SSL_set_connect_state(ssl);
do
{
err = SSL_connect(ssl);
if (err < 0)
{
switch (SSL_get_error(ssl, err))
{
case SSL_ERROR_NONE:
printf("SSL_ERROR_NONE");
break;
case SSL_ERROR_ZERO_RETURN:
printf("SSL_ERROR_ZERO_RETURN");
break;
case SSL_ERROR_WANT_READ:
printf("SSL_ERROR_WANT_READ\n");
break;
case SSL_ERROR_WANT_WRITE:
printf("SSL_ERROR_WANT_WRITE\n");
break;
case SSL_ERROR_WANT_CONNECT: case SSL_ERROR_WANT_ACCEPT:
printf("SSL_ERROR_WANT_CONNECT || SSL_ERROR_WANT_ACCEPT\n");
break;
case SSL_ERROR_WANT_X509_LOOKUP:
printf("SSL_ERROR_WANT_X509_LOOKUP");
break;
case SSL_ERROR_SYSCALL:
do
{
e = ERR_get_error();
if (e > 0)
int_error("Error");
}while (e > 0);
printf("SSL_ERROR_SYSCALL\n");
break;
case SSL_ERROR_SSL:
printf("SSL_ERROR_SSL");
break;
default:
break;
}
//ERR_clear_error();
}
}while(SSL_is_init_finished(ssl) == 0);
printf ("SSL connection using %s\n", SSL_get_cipher (ssl));
X509 *server_cert = SSL_get_peer_certificate (ssl);
if (server_cert != NULL)
{
printf ("Server certificate:\n");
char *str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
printf ("\t subject: %s\n", str);
free (str);
str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
printf ("\t issuer: %s\n", str);
free(str);
X509_free (server_cert);
}
return 0;
}
A long time ago I got this problem and could not got any solution and never worked again due to time issue.
Note: I have also tried many off the shelf tutorial client examples from other people and all of them fails on connect. There is another non blocking socket solution, that works fine for me but I want to dig out why a blocking socket is failing.
I'm trying to create server busy by adding delay in the SSL Server code(given below) before accept(), then from the SSL client trying to connect to server. After approx 2 minutes i'm getting SSL error and client returns as expected.
When i try to analyse wireshark log i can seen "Client Hello TCP retramission" message 10 times. I'm trying to understand the reason and source of this retransmission. Is it in TCP Layer or SSL Layer?
I'm doing this on linux ubuntu 14.04 x86. Below are the ssl-server and ssl-client downloaded.
I tried changing /proc/sys/net/ipv4/tcp_retries2 but it doesn't effect the number of retries. From Wireshark log i can see the number of retries for client hello is 10.
Thanks in advance.
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
int OpenListener(int port)
{ int sd;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
perror("can't bind port");
abort();
}
if ( listen(sd, 1) != 0 )
{
perror("Can't configure listening port");
abort();
}
return sd;
}
int isRoot()
{
if (getuid() != 0)
{
return 0;
}
else
{
return 1;
}
}
SSL_CTX* InitServerCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
method = SSLv3_server_method(); /* create new server-method instance */
ctx = SSL_CTX_new(method); /* create new context from method */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
/* set the local certificate from CertFile */
if ( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if ( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if ( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */
{ char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
char *portnum;
if(!isRoot())
{
printf("This program must be run as root/sudo user!!");
exit(0);
}
if ( count != 2 )
{
printf("Usage: %s <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, "mycert.pem", "mycert.pem"); /* load certs */
server = OpenListener(atoi(portnum)); /* create server socket */
while (1)
{ struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL *ssl;
sleep(1200);
// sleep(12);
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
//Wait before close connection to check max connections error
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
}
close(server); /* close server socket */
SSL_CTX_free(ctx); /* release context */
}
SSL Client.c
//SSL-Client.c
#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>
#define FAIL -1
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{ SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = SSLv3_client_method(); /* Create new client-method instance */
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("No certificates.\n");
}
int main(int count, char *strings[])
{ SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
int bytes;
char *hostname, *portnum;
if ( count != 3 )
{
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
}
SSL_library_init();
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else
{ char *msg = "Hello???";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
SSL_write(ssl, msg, strlen(msg)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
printf("Received: \"%s\"\n", buf);
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
EDIT: Below is the Retransmission Message from the Wireshark log, SSL-Server is running on X.X.X.241, Client is on X.X.X.242
5 0.206404000 X.X.X.242 X.X.X.241 SSL 363 [TCP Retransmission] Client Hello
Your delay is added before accept not before SSL_accept. At this stage the tcp 3-way handshake has not completed, and therefore the SSL/TLS layer has not even started. What will be happening is the client will be sending a SYN packet, and the server responding only after a delay with an ACK packet. My recollection is the default is 5 SYN packet retries over 20 seconds; I can't immediately explain why you are seeing more than that, but it may be because you are attempting to acknowledge a SYN which itself has been replaced. The knob to adjust this is net.ipv4.tcp_syn_retries not tcp_retries2, and it needs to be adjusted on the client not the server.
There is no such thing (to my knowledge) as a 'TCP Hello Transmission'; that would seem to be a poor message client side. Perhaps the same routing opens the TCP connection and sends the SSL handshake.
I found a pretty good SSL/TLS server-client example in C and I wanted to adapt it for use with the BIO library. And I pretty much succeeded except one error I get when running the server:
$ ./ssl-server
68671:error:140950D3:SSL routines:SSL3_READ_N:read bio not set:/SourceCache/OpenSSL098/OpenSSL098-35.1/src/ssl/s3_pkt.c:203:
I'm using gcc -o ssl-server SSL-Server.c -lssl -lcrypto -Wall to compile the server:
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
#define PORT "2013"
SSL_CTX* InitServerCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = SSLv3_server_method();
ctx = SSL_CTX_new(method);
if( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
if( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
if( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
if( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("No certificates.\n");
}
}
void Servlet(SSL* ssl)
{
char buf[1024];
int sd, bytes;
if( SSL_accept(ssl) == FAIL )
{
ERR_print_errors_fp(stderr);
}
else
{
ShowCerts(ssl);
bytes = SSL_read(ssl, buf, sizeof(buf));
if( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
SSL_write(ssl, "back message", strlen("back message"));
}
else
{
ERR_print_errors_fp(stderr);
}
}
sd = SSL_get_fd(ssl);
SSL_free(ssl);
close(sd);
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
BIO *acc, *client;
SSL_library_init();
ctx = InitServerCTX();
LoadCertificates(ctx, "mycert.pem", "mycert.pem");
acc = BIO_new_accept(PORT);
if(!acc)
{
printf("Error creating server socket");
}
while(1)
{
if(BIO_do_accept(acc) <= 0)
{
printf("Error binding server socket");
}
SSL *ssl;
client = BIO_pop(acc);
if(!(ssl = SSL_new(ctx)))
{
printf("Error creating SSL context");
}
SSL_set_bio(ssl, client, client);
// Here should be created threads
Servlet(ssl);
}
SSL_CTX_free(ctx);
}
I'm using gcc -o ssl-client SSL-Client.c -lssl -lcrypto -Wall to compile the client:
//SSL-Client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.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>
#define FAIL -1
#define SERVER "localhost"
#define PORT "2013"
SSL_CTX* InitCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = SSLv3_client_method();
ctx = SSL_CTX_new(method);
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);
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);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("No certificates.\n");
}
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
SSL *ssl;
BIO *conn;
char buf[1024];
int bytes;
SSL_library_init();
ctx = InitCTX();
conn = BIO_new_connect(SERVER ":" PORT);
if(!conn)
{
printf("Error creating connection BIO");
}
if(BIO_do_connect(conn) <= 0)
{
printf("Error connecting to remote machine");
}
ssl = SSL_new(ctx);
SSL_set_bio(ssl, conn, conn);
if( SSL_connect(ssl) <= 0 )
{
printf("Error connecting SSL object");
}
else
{
printf("Connected!");
ShowCerts(ssl);
SSL_write(ssl, "ana are mere", strlen("ana are mere") );
bytes = SSL_read(ssl, buf, sizeof(buf));
printf("%s\n", buf);
SSL_free(ssl);
}
SSL_CTX_free(ctx);
return 0;
}
I'm generating the certificate with the openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem command.
Everything works well and the messages are sending OK. Please ignore the lack of error checking and excuse the total mess in the code, it's just for learning purposes.
Can anyone point me what's wrong? Also can you tell if I'm doing major mistakes, I'm trying to learn?(e.g. routine call order, major security problems, etc.)
Thanks!
According to the manual page (the example code at the bottom is very illustrative), the first call to BIO_do_accept() will set up the accept BIO and does nothing else. Only the second and all subsequent calls will be actual calls to accept connections. This is quite illustrative of why OpenSSL will never win an award for «most intuitive API design».
So what happens in your code? You only call BIO_do_accept() within the loop. First time through the loop, it will set up the BIO and return immediately. Your code calls Servlet() on the inexisting connection, and SSL_accept() fails, returning the error you are seeing. After Servlet() returns, your code loops happily into the second invocation of BIO_do_accept() which this time blocks, waiting for the first connection, and everything works as intended from here.
To fix this, you need to call BIO_do_accept() once before the loop, like this (using your broken style of error handling for consistency -- you really need to fix your error handling!):
[...]
acc = BIO_new_accept(PORT);
if(!acc)
{
printf("Error creating server socket");
}
/* first call is to set up accept BIO */
if(BIO_do_accept(acc) <= 0)
{
printf("Error calling BIO_do_accept() the first time");
}
while(1)
{
if(BIO_do_accept(acc) <= 0)
{
printf("Error binding server socket");
}
[...]
I have written a simple SSL Client/Server set of programs from a few tutorials I have found on the net - and these work fine. What I cant get my head around is the client side of things (See below)
It looks as if from the code the client connects to the SSL server, blindly accepts the certificate it provides then then uses it to encrypt/decrypt the data sent to and from the pair.
Should there not be something client side that validates the servers certificate for use? I mean I can change / swap the server side certificate with any new one and have it connect without so much as a wimper? How is this a secure method of connection? (or am I - as I suspect - missing something )
Many thanks
FR
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile);
int OpenConnection(const char *hostname, int port);
void ShowCerts(SSL* ssl);
SSL_CTX* InitCTX(void);
int main(int count, char *strings[]) {
char *hostname, *portnum;
char buf[1024];
SSL_CTX *ctx;
SSL *ssl;
int server;
int bytes;
if ( count != 3 ) {
printf("usage: %s <hostname> <portnum>\n", strings[0]);
exit(0);
} // if
hostname=strings[1];
portnum=strings[2];
printf("\nSSL Client 0.1\n~~~~~~~~~~~~~~~\n\n");
// Init. the SSL lib
SSL_library_init();
ctx = InitCTX();
printf("Client SSL lib init complete\n");
// Open the connection as normal
server = OpenConnection(hostname, atoi(portnum));
// Create new SSL connection state
ssl = SSL_new(ctx);
// Attach the socket descriptor
SSL_set_fd(ssl, server);
// Perform the connection
if ( SSL_connect(ssl) != FAIL ) {
char *msg = "Here is some data";
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
// Print any certs
ShowCerts(ssl);
// Encrypt & send message */
SSL_write(ssl, msg, strlen(msg));
// Get reply & decrypt
bytes = SSL_read(ssl, buf, sizeof(buf));
buf[bytes] = 0;
printf("Received: '%s'\n\n", buf);
// Release connection state
SSL_free(ssl);
} // if
else ERR_print_errors_fp(stderr);
// Close socket
close(server);
// Release context
SSL_CTX_free(ctx);
return 0;
} // main
SSL_CTX* InitCTX(void) {
SSL_METHOD const *method;
SSL_CTX *ctx;
// Load cryptos, et.al.
OpenSSL_add_all_algorithms();
// Bring in and register error messages
SSL_load_error_strings();
// Create new client-method instance
method = SSLv3_client_method();
// Create new context
ctx = SSL_CTX_new(method);
if ( ctx == NULL ) {
ERR_print_errors_fp(stderr);
abort();
} // if
return ctx;
} //InitCTX
int OpenConnection(const char *hostname, int port) {
int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL ) {
perror(hostname);
abort();
} // if
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) {
close(sd);
perror(hostname);
abort();
} // if
return sd;
} // OpenConnection
void ShowCerts(SSL* ssl) {
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL ) {
printf("\nServer certificate:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
// Free the malloc'ed string
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
// Free the malloc'ed string
free(line);
// Free the malloc'ed certificate copy
X509_free(cert);
} // if
else printf("No certificates.\n");
} // ShowCerts
You are correct. The connection is secure (from eavesdropping), has integrity (protection against injection, truncation, and modification), and authentication (peer is who he says he is in his certificate), all done automatically for you by the transport, but it still lacks authorization (is this the person I wanted to talk to, and what exactly is this person allowed to do in my application). Only the application can do that, inherently, so it is up to you to get the peer certificate, get its SubjectDN, relate that to some local user database, check for existence, check its roles, etc.
A "Secure Connection" can be seen as consisting of two things:
1 Authentication: Be sure to be connected to the partner (here: server) one expects to connect to
2 Encryption: Have the data (transferred by the connection) be protected against being read during transmission
The certificate received from the server can be used to accomplish 1. The certificate is not necessarily involved in 2.
On how to add verification of a server's certificate to your client, you might like to check out this SO answer: https://stackoverflow.com/a/12245023/694576 (which you could have done in the first place anyway ... ;->)
For details on TLS (successor to SSL and former SSL 3.x) please see here: http://en.wikipedia.org/wiki/Transport_Layer_Security