I have got this assignment of establishing a communication between client and server using openSSL:
[1] Client --> Server: Prompt to ask the user to input a number X
[2] Server --> Client: X + 1.
[3] Client --> Check whether the answer from the server is correct, and output the result. The client
repeats step 1.
I have done the following steps but I am getting segmentation fault, can you guys suggest me where I am going wrong
sserver.cc
#include <openssl/ssl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
if (argc != 4) {
printf("./exec CertFile KeyFile port");
return -1;
}
char* cert_file = argv[1];
char* key_file = argv[2];
int port = atoi(argv[3]);
// init the ssl lib
SSL_library_init();
//SSL_METHOD* method;
//SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
const SSL_METHOD* method = SSLv3_server_method();
SSL_CTX *ctx = SSL_CTX_new(method);
// load the server's certificate
SSL_CTX_use_certificate_file(ctx, cert_file, SSL_FILETYPE_PEM);
// load the server's private key
SSL_CTX_use_PrivateKey_file(ctx, key_file, SSL_FILETYPE_PEM);
// check the private against the known certificate
if (!SSL_CTX_check_private_key(ctx)) {
printf("Private key does not match\n");
abort();
}
// standard tcp server setup and connection
int sd, client;
struct sockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sd, (struct sockaddr*)&addr, sizeof(addr));
listen(sd, 10);
client = accept(sd, 0, 0);
SSL* ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
SSL_accept(ssl);
char buf[1024];
int buf_size = 1024;
int ClientResponse,StoredValue;
int TempValue;
// real work here
while(1) {
// read message from client, plus one, then send back to client
//ClientResponse=SSL_read(ssl,(void*)StoredValue,3);
ClientResponse=SSL_read(ssl,(void*)buf,buf_size);
ClientResponse=ClientResponse+1;
SSL_write(ssl,(const void*)ClientResponse,buf_size);
}
client = SSL_get_fd(ssl);
SSL_free(ssl);
close(sd);
}
sclient.cc
#include <openssl/ssl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if (argc != 3) {
printf("./exec hostname port");
return -1;
}
char* hostname = argv[1];
int port = atoi(argv[2]);
// init the ssl lib
SSL_library_init();
printf("client...1\n");
//SSL_METHOD* method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
const SSL_METHOD* method = SSLv3_client_method();
ctx = SSL_CTX_new(method);
// create a standard tcp client
int server;
struct hostent* host;
struct sockaddr_in addr;
printf("client...2\n");
host = gethostbyname(hostname);
server = socket(PF_INET, SOCK_STREAM, 0);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
printf("client...3\n");
connect(server, (struct sockaddr*)&addr, sizeof(addr));
printf("client...4\n");
SSL* ssl;
ssl = SSL_new(ctx);
SSL_set_fd(ssl, server);
printf("client...5\n");
int sv = SSL_connect(ssl);
printf("client...6\n");
printf("sv = %d\n", sv);
if (sv != 1) {
printf("Can't establish ssl connection with server...\n");
// send a string to
SSL_free(ssl);
return -1;
}
int UserInput,ServerOutput;
int StoredValue;
int TempValue;
// real work here
while(1) {
// 1. ask the user to input a random number, and send to server using SSL library
printf("Enter a number user:\n");
scanf("%d",&UserInput);
TempValue=UserInput;
SSL_write(ssl,(const void*)UserInput,TempValue);
// 2. wait for the response from the server
// 3. Check if the response is correct or not
ServerOutput=SSL_read(ssl,(void*)StoredValue,TempValue);
if(ServerOutput==UserInput)
printf("\nCorrect %d",UserInput);
else
printf("\nFalse");
}
SSL_free(ssl);
}
You work with pointers incorrectly.
In server part code should be like this:
SSL_read(ssl, &TempValue, sizeof(TempValue));
TempValue++;
SSL_write(ssl, &TempValue, sizeof(TempValue));
Client part:
SSL_write(ssl, &UserInput, sizeof(UserInput));
SSL_read(ssl, &ServerOutput, sizeof(ServerOutput));
printf("UserInput=%d, ServerOutput=%d\n", UserInput, ServerOutput);
Also read in documentation what should return SSL_read and SSL_write
Related
I'm trying to make a client/server program with the OpenSSL that can set up a secure connection and then pass encrypted messages back and forth. I'm using a self-signed certificate for the server and a private key for the client. When a connection is established, I use SSL_accept() to initiate the handshake. This is where the program breaks. On the client-side, the error message is:
140104940065408:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1543:SSL alert number 40
and on the server-side the error message is:
140062094398080:error:1417A0C1:SSL routines:tls_post_process_client_hello:no shared cipher:../ssl/statem/statem_srvr.c:2283:
I'm very new to OpenSSL and to cryptography in general so I'm quite lost as to how to proceed from here. Any help would be greatly appreciated. I'll post the full code for the client and server below.
Client Program:
#include <errno.h> /*USING THE ERROR LIBRARY FOR FINDING ERRORS*/
#include <stdio.h> /*standard i/o*/
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#include <malloc.h> /*FOR MEMORY ALLOCATION */
#include <string.h> /*using fgets funtions for geting input from user*/
#include <sys/socket.h> /*for creating sockets*/
#include <resolv.h> /*server to find out the runner's IP address*/
#include <netdb.h> /*definitions for network database operations */
#include <openssl/ssl.h> /*using openssl function's and certificates and configuring them*/
#include <openssl/err.h> /* helps in finding out openssl errors*/
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#define FAIL -1 /*for error output == -1 */
#define BUFFER 1024 /*buffer for reading messages*/
// CLIENT PROGRAM
//code from: https://github.com/ElectronSz/Encrypted-Chat-Server-Using-C-Programming-and-OpenSSL-AES-DES
int OpenConnection(const char *hostname, int port) {
int sd;
struct hostent *host;
struct sockaddr_in addr; /*creating the sockets*/
if ( (host = gethostbyname(hostname)) == NULL ) {
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0); /* setting the connection as tcp it creates endpoint for connection */
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 ) /*initiate a connection on a socket*/ {
close(sd);
perror(hostname);
abort();
}
return sd;
}
void LoadKey(SSL_CTX* ctx, char* KeyFile) /* to load a certificate into an SSL_CTX structure*/ {
/* 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();
}
}
SSL_CTX* InitCTX(void) /*creating and setting up ssl context structure*/ {
const 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 = TLS_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) /*show the ceritficates to server and match them but here we are not using any client certificate*/ {
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[]) /* getting port and ip as an argument*/ {
SSL_CTX *ctx;
int server;
SSL *ssl;
char buf[1024];
char input[BUFFER];
int bytes;
char *hostname, *portnum;
pid_t cpid; /* fork variable*/
if ( count != 3 ) {
printf("usage: %s \n", strings[0]);
exit(0);
}
SSL_library_init(); /*load encryption and hash algo's in ssl*/
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
//SSL_CTX_set_ciphersuites(ctx, OSSL_default_ciphersuites());
LoadKey(ctx, "client.pem"); /* load certs */
server = OpenConnection(hostname, atoi(portnum)); /*converting ascii port to interger */
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
//SSL_set_ciphersuites(ssl, OSSL_default_ciphersuites());
/* Host common name */
// Not necessarily needed
//SSL_set_tlsext_host_name(ssl, "Conor");
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */ {
ERR_print_errors_fp(stderr);
} else {
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl);
/* get any certs */
cpid=fork();
/*Fork system call is used to create a new process*/
if(cpid==0) {
while(1) {
fflush(stdout);
printf("\nMESSAGE TO SERVER:");
fgets(input, BUFFER, stdin);
SSL_write(ssl, input, strlen(input)); /* encrypt & send message */
}
} else {
while(1) {
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 ) {
buf[bytes] = 0;
printf("\nMESSAGE FROM SERVER: %s\n", buf);
printf("\nMESSAGE TO SERVER:");
fflush(stdout);
}
}
}
SSL_free(ssl); /* release connection state */
}
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
Server Program:
//#include <openssl/applink.c>
#include <unistd.h> /*FOR USING FORK for at a time send and receive messages*/
#include <errno.h> /*USING THE ERROR LIBRARY FOR FINDING ERRORS*/
#include <malloc.h> /*FOR MEMORY ALLOCATION */
#include <string.h> /*using fgets funtions for geting input from user*/
#include <arpa/inet.h> /*for using ascii to network bit*/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h> /* network to asii bit */
#include <resolv.h> /*server to find out the runner's IP address*/
#include <stdio.h> /*standard i/o*/
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <inttypes.h>
#define FAIL -1 /*for error output == -1 */
#define BUFFER 1024 /*buffer for reading messages*/
// SERVER PROGRAM
void InitializeSSL() {
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_algorithms();
}
void DestroySSL() {
ERR_free_strings();
EVP_cleanup();
}
void ShutdownSSL(SSL* cSSL) {
SSL_shutdown(cSSL);
SSL_free(cSSL);
}
int OpenListener(int port) {
int sd;
struct sockaddr_in addr; /*creating the sockets*/
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr)); /*free output the garbage space in memory*/
addr.sin_family = AF_INET; /*getting ip address form machine */
addr.sin_port = htons(port); /* converting host bit to n/w bit */
addr.sin_addr.s_addr = INADDR_ANY;
if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) /* assiging the ip address and port*/ {
perror("can't bind port"); /* reporting error using errno.h library */
abort(); /*if error will be there then abort the process */
}
if ( listen(sd, 10) != 0 ) /*for listening to max of 10 clients in the queue*/ {
perror("Can't configure listening port"); /* reporting error using errno.h library */
abort(); /*if erroor will be there then abort the process */
}
return sd;
}
void Servlet(SSL* ssl) /* Serve the connection -- threadable */ {
char buf[1024];
int sd, bytes;
char input[BUFFER];
pid_t cpid;
//Here is the SSL Accept portion. Now all reads and writes must use SSL
int ret = SSL_accept(ssl);
printf("%d\n", ret);
if (ret == 0) {
/* Hard error */
exit(-1);
} else if ( ret == -1 ) /* do SSL-protocol accept */ {
printf("Handshake Error %d\n", SSL_get_error(ssl, ret));
ERR_print_errors_fp(stderr);
exit(-1);
}
/*Fork system call is used to create a new process*/
cpid=fork();
if(cpid==0) {
while(1) {
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request and read message from server*/
if ( bytes > 0 ) {
buf[bytes] = 0;
printf("\nMESSAGE FROM CLIENT: %s\n", buf);
printf("\nMESSAGE TO CLIENT:");
fflush(stdout);
} else {
ERR_print_errors_fp(stderr);
}
}
} else {
while(1) {
fflush(stdout);
printf("\nMESSAGE TO CLIENT:");
fgets(input, BUFFER, stdin); /* get request and reply to client*/
SSL_write(ssl, input, strlen(input));
}
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
bool str_to_uint16(char *str, uint16_t *res) {
char *end;
errno = 0;
intmax_t val = strtoimax(str, &end, 10);
if (errno == ERANGE || val < 0 || val > UINT16_MAX || end == str || *end != '\0') {
return false;
}
*res = (uint16_t) val;
return true;
}
int main(int count, char *strings[]) /* getting port as a argument*/ {
int sockfd, newsockfd;
SSL_CTX *sslctx;
SSL *cSSL;
char buf[1024];
char input[BUFFER];
int bytes;
char *portnum;
pid_t cpid; /* fork variable*/
if ( count != 2 ) {
printf("Usage: %s <portnum> \n", strings[0]); /*send the usage guide if syntax of setting port is different*/
exit(0);
}
portnum = strings[1];
uint16_t temp;
uint16_t *aPortNumber = &temp;
if (str_to_uint16(portnum, aPortNumber) == false) {
printf("Port number must be between 0 and 65535.");
exit(1);
}
InitializeSSL();
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd< 0) {
//Log and Error
exit(1);
}
struct sockaddr_in saiServerAddress;
bzero((char *) &saiServerAddress, sizeof(saiServerAddress));
saiServerAddress.sin_family = AF_INET;
saiServerAddress.sin_addr.s_addr = INADDR_ANY;
saiServerAddress.sin_port = htons(*aPortNumber);
bind(sockfd, (struct sockaddr *) &saiServerAddress, sizeof(saiServerAddress));
struct sockaddr_in cli_addr;
socklen_t len = sizeof(cli_addr);
listen(sockfd,5);
newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &len);
sslctx = SSL_CTX_new( TLS_server_method());
// check return values vvvv
int use_cert = SSL_CTX_use_certificate_file(sslctx, "server.pem" , SSL_FILETYPE_PEM);
if (use_cert == 0) {
ERR_print_errors_fp(stderr);
exit(-1);
}
int use_prv = SSL_CTX_use_PrivateKey_file(sslctx, "private-key.pem", SSL_FILETYPE_PEM);
if (use_prv == 0) {
ERR_print_errors_fp(stderr);
exit(-1);
}
cSSL = SSL_new(sslctx);
SSL_set_fd(cSSL, newsockfd );
//SSL_CTX_set_ciphersuites(sslctx, cipher_list.c_str());
//SSL_set_ciphersuites(cSSL, cipher_list.c_str());
Servlet(cSSL);
ShutdownSSL(cSSL);
return 0;
}
I have written a basic client server code in c socket programming using the TCP/IP protocol but i cant figure out how to make it connect to different clients and send/receive different data to and from them as a function to the client (meaning if its the first client send him that data and if its that client send him the other data) and so on.
This is the only results i have found were sending the same data to different clients.
Current Server:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <netinet/in.h>
int main() {
char server_message[100] = {0};
int server_socket = 0;
int client_socket = 0;
struct sockaddr_in server_address;
server_socket = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(9002);
server_address.sin_addr.s_addr = INADDR_ANY;
// bind the socket to our specified IP and port
bind(server_socket, (struct sockaddr*) &server_address, sizeof(server_address));
listen(server_socket, 2);
client_socket = accept(server_socket, NULL, NULL);
printf("Please enter a massage:");
fgets(server_message, 100, stdin);
send(client_socket, server_message, sizeof(server_message), 0);
close(server_socket);
return 0;
}
By using original code from geeksforgeeks and Myst comment we can solve it.
You have one server that serves on local host 127.0.0.1, and can have multiple clients for this example i assume 5 clients are enough.
Run server once, and run many client to connect seprately to that server.
Server.c
// Server side C/C++ program to demonstrate Socket programming
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
#define STRING_SIZE 100
#define BUFFER_SIZE 100
int main(int argc, char const *argv[])
{
int server_fd, new_socket[5], valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
for (int i=0;i<5;i++){
if ((new_socket[i] = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
valread = read(new_socket[i], buffer, 1024);
printf("%s\n", buffer);
char send_buf[STRING_SIZE] = "hello";
char buf[BUFFER_SIZE]={0};
sprintf(buf, "%d", i);
strcat(send_buf, buf);
send(new_socket[i], send_buf, strlen(send_buf), 0);
//printf("Hello message sent\n");
}
return 0;
}
Client.c
// Client side C/C++ program to demonstrate Socket programming
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
send(sock , hello , strlen(hello) , 0 );
//printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n", buffer);
return 0;
}
Run
After compiling codes with gcc client.c -o client and gcc server.c -o server
Open one terminal for server and start server by run ./server.
Now you can connect many client [up to 5] to it by running ./client.
I'm sorry for such a big block of code, but I'm so lost as to what is happening, I have no idea where the problem might be...
I am trying to get a VERY minimal dtls server going and I can't get the client and server to finish handshaking.
Here is my code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/opensslv.h>
int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
cookie = "cookie";
cookie_len = 5;
return 1;
}
int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len)
{
return 1;
}
int dtls_verify_callback (int ok, X509_STORE_CTX *ctx) {
/* This function should ask the user
* if he trusts the received certificate.
* Here we always trust.
*/
return 1;
}
int main() {
char buff[FILENAME_MAX];
getcwd(buff, FILENAME_MAX);
union {
struct sockaddr_storage ss;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} client_addr;
struct sockaddr_in server_addr;
const int on = 1, off = 0;
memset(&server_addr, 0, sizeof(server_addr));
memset(&client_addr, 0, sizeof(client_addr));
int res;
SSL *ssl;
BIO *bio;
int sock;
struct timeval timeout;
SSL_CTX *ctx = SSL_CTX_new(DTLS_server_method());
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
if(!SSL_CTX_use_certificate_file(ctx, "/home/matthew/CLionProjects/OpenSSL.Test/cmake-build-debug/certs/cert.crt", SSL_FILETYPE_PEM))
{
perror("cert");
exit(EXIT_FAILURE);
}
if(!SSL_CTX_use_PrivateKey_file(ctx, "/home/matthew/CLionProjects/OpenSSL.Test/cmake-build-debug/certs/key.key", SSL_FILETYPE_PEM))
{
perror("key");
exit(EXIT_FAILURE);
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx, 1);
SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx, &verify_cookie);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(1114);
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(EXIT_FAILURE);
}
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, (socklen_t) sizeof(on)) < 0)
{
perror("set reuse address");
exit(EXIT_FAILURE);
}
if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*) &on, (socklen_t) sizeof(on)) < 0)
{
perror("set reuse port");
exit(EXIT_FAILURE);
}
if(bind(sock, (const struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
perror("bind");
exit(EXIT_FAILURE);
}
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
/* Create BIO */
bio = BIO_new_dgram(sock, BIO_NOCLOSE);
/* Set and activate timeouts */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
ssl = SSL_new(ctx);
SSL_set_bio(ssl, bio, bio);
SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
if(!SSL_set_fd(ssl, sock))
{
perror("set fd");
exit(EXIT_FAILURE);
}
res = 0;
while(res <= 0)
{
res = DTLSv1_listen(ssl, (BIO_ADDR *) &client_addr);
if(res < 0)
{
perror("dtls listen"); <--- "Destination address required"
exit(EXIT_FAILURE);
}
}
SSL_accept(ssl);
printf("Hello, World!\n");
return 0;
}
I've added error checks in every nook and cranny I can think of...
What happens is, it loops over DTLSv1_accept() fine until a connection is attempted. As soon as the client tries to connect (sends the Client Hello), DTLSv1_accept() return -1. A call to SSL_get_error gives me 5, which is an SSL_ERROR_SYSCALL.
So I do perror and get Destination address required...
AFAIK the whole point of DTLSv1_listen is to listen for any incoming Client Hellos and populate the BIO_ADDR with the client's address once the handshake is finished...
I am using this to test the server:
openssl s_client -dtls -connect 127.0.0.1:1114
I've spent many hours on this. I am about to give up on OpenSSL and try libressl...
Any help is greatly appreciated.
P.S. the code is complete, in that it should compile and run if you want to try it out.
Thanks!
There are two significant problems in your code sample.
First your code to generate a cookie is not correct. You are supposed to create the
cookie and store it in the location pointed to by cookie, and then fill in the length of the cookie in *cookie_len. So the code should like this:
int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
memcpy(cookie, "cookie", 6);
*cookie_len = 6;
return 1;
}
However, the most important error comes later when setting up the SSL object for use. OpenSSL has the concept of a BIO for abstracting the underlying transport layer. In order to do DTLS over UDP you need to use a "dgram" BIO. You do this bit correctly:
/* Create BIO */
bio = BIO_new_dgram(sock, BIO_NOCLOSE);
/* Set and activate timeouts */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
ssl = SSL_new(ctx);
SSL_set_bio(ssl, bio, bio);
So at this point the SSL object is correctly setup for the DTLSv1_listen() call. However you then do this:
if(!SSL_set_fd(ssl, sock))
{
perror("set fd");
exit(EXIT_FAILURE);
}
The SSL_set_fd function is an alternative to the SSL_set_bio function. What it does is take the supplied fd, wraps it in a "socket" BIO and then calls SSL_set_bio() with the result. A socket BIO is primarily useful for standard TLS and can't be used for DTLS. So the effect of the above code is to throw away the dgram BIO that you previously set up.
In my tests, if I made the generate_cookie change I suggested above, and removed the SSL_set_fd line, it all started to work as expected.
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 have to write these codes in c. I have already generate the certificate of one terminate t1: t1.pem, which is generated by openssl. The communication between the terminates t1 and t2 has been established via socket in c.
Now I want to send this certificate to another terminate t2.and I want t2 to receive the certificate, verify it and answer with an acceptance to t1. When t1 get this acceptance, it will the rest of stuffs..
But I don't know how to do these things.
For example, I transmit t1.pem as a string? But in t2 side, how can I do to verify? I know there are functions in openssl to do so, but I'm not so clear about it. At last, normally, the acceptance should be like how?
#.#...a lot of questions here.. sorry...if someone could give me some guide..
Thanks a lot in advance!
If you are trying to establish communication using openssl have a look at this OpenSSL tutorial.
here's some starting notes for you ...
server
{
SSL_CTX_new()
SSL_CTX_* set_cipher_list,set_mode,set_options
SSL_CTX_* set_default_passwd_cb,use_certificate_file,use_PrivateKey_file etc
SSL_new()
SSL_set_fd(,socket)
SSL_set_accept_state()
SSL_read()/SSL_write()
SSL_shutdown()
SSL_free()
SSL_CTX_free()
}
client
{
SSL_CTX_new()
SSL_CTX_* set_cipher_list,set_mode,options
SSL_CTX_* load_verify_locations,set_verify etc
SSL_new()
SSL_set_fd(,socket)
SSL_set_connect_state()
SSL_read()/SSL_write()
SSL_shutdown()
SSL_free()
SSL_CTX_free()
}
Here is a sample code which should help you:
Server
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main()
{
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int result = 0;
//ssl initiation
SSL_library_init();
SSL_load_error_strings();
SSL_METHOD *meth = SSLv3_server_method();
SSL_CTX *ctx = SSL_CTX_new(meth);
SSL_CTX_use_certificate_file(ctx, "server_crt.pem", SSL_FILETYPE_PEM);
SSL_CTX_use_PrivateKey_file(ctx, "server_key.pem", SSL_FILETYPE_PEM);
//unnamed socket
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
//naming
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
result = bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
if(result<0)
{
printf("\nBinding Error");
}
//connection
listen(server_sockfd, 5);
while(1)
{
char ch;
printf("server waiting\n");
//accept connection
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
printf("\nConnected\n");
SSL* ssl;
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client_sockfd);
//handshake
SSL_accept(ssl);
printf("\nHandshake Done\n");
//exchage message
result = SSL_read(ssl, &ch, sizeof(ch));
if(result<0)
{
printf("\nreading Error");
}
++ch;
result = SSL_write(ssl, &ch, sizeof(ch));
if(result<0)
{
printf("\nwriting Error");
}
close(client_sockfd);
}
}
Client
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
void check_cert(SSL* ssl)
{
//ssl initiation
/*SSL_library_init();
SSL_load_error_strings();
const SSL_METHOD *meth;
meth = SSLv3_method();
SSL_CTX *ctx;
SSL *_ssl;
ctx = SSL_CTX_new(meth);*/
}
int main()
{
int sockfd;
int len;
struct sockaddr_in address;
int result=0;
char ch = 'A';
//ssl initiation
SSL_library_init();
SSL_load_error_strings();
SSL_METHOD *meth;
meth = SSLv3_client_method();
SSL_CTX *ctx;
SSL* ssl;
ctx = SSL_CTX_new(meth);
result = SSL_CTX_load_verify_locations(ctx, "cacert.pem", 0);
//result = SSL_CTX_load_verify_locations(ctx, NULL, "/home/cdac/Desktop/test/cert");
printf("\nCA load result = %d\n", result);
printf("\nSSL initialized");
//socket for client
sockfd = socket(AF_INET, SOCK_STREAM, 0);
//naming socket
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(9734);
len = sizeof(address);
printf("length====\n%d",len);
printf("Socket done\n");
//connecting server
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result <0)
{
perror("oops: client\n");
exit(1);
}
else
{
printf("Socket Connected\n");
}
//ssl-ing the connection
ssl = SSL_new(ctx);
BIO *sbio;
sbio = BIO_new(BIO_s_socket());
BIO_set_fd(sbio, sockfd, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);
//SSL_CTX_set_verify_depth(ctx, 1);
//SSL_set_fd(ssl, sockfd);
result = SSL_connect(ssl);
printf("SSL_connect: %d\n", result);
if(SSL_get_peer_certificate(ssl)!=NULL)
{
//check cert
//check_cert(ssl);
//getting the CA certificate
//_ssl = SSL_new(ctx);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
int result_long = SSL_get_verify_result(ssl);
printf("\nCertificate Check Result: %d", result_long);
if (SSL_get_verify_result(ssl) != X509_V_OK)
{
printf("\nCertiticate Verification Failed\n");
return 0;
//exit(1);
}
else
{
printf("\nCertiticate Verification Succeeded");
}
}
//taking input
printf("\nSay Char: \n");
scanf("%c",&ch);
//exchanging data
SSL_write(ssl, &ch, 1);
SSL_read(ssl, &ch, 1);
printf("char from server = %c\n", ch);
SSL_shutdown(ssl);
close(sockfd);
exit(0);
}
The codes are simple and self explanatory.