First off I want to warn you there is alot of code here! I want the client to connect to the server using RSA with the OpenSSL library. When I launch the server everything is fine but when I try and connect with the client the connection failed with Error: error 1408A0C1: SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher. Thanks for your consideration but I have to warn you again there is alot of code here. If you are interested I am creating a TCP connection to a Java applet protected with RSA. This is not my program I found it all jumbled on the 'net. If you could add your own simple source for this purpose in the comments I would appreciate it!
// THIS IS THE CLIENT FOR THE CONNECTION
#include <openssl/bio.h> // BIO objects for I/O
#include <openssl/ssl.h> // SSL and SSL_CTX for SSL connections
#include <openssl/err.h> // Error reporting
#include <stdio.h> // If you don't know what this is for stop reading now.
void openssltest(void);
int main(int argc, char** argv) {
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
openssltest(); // We'll define this later.
return 0;
}
void openssltest() {
// Set up a SSL_CTX object, which will tell our BIO object how to do its work
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
// Create a SSL object pointer, which our BIO object will provide.
SSL* ssl;
// Create our BIO object for SSL connections.
BIO* bio = BIO_new_ssl_connect(ctx);
// Failure?
if (bio == NULL) {
printf("Error creating BIO!\n");
ERR_print_errors_fp(stderr);
// We need to free up the SSL_CTX before we leave.
SSL_CTX_free(ctx);
return;
}
// Makes ssl point to bio's SSL object.
BIO_get_ssl(bio, &ssl);
// Set the SSL to automatically retry on failure.
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
// We're connection to google.com on port 443.
BIO_set_conn_hostname(bio, "127.0.0.1:6789");
// Same as before, try to connect.
if (BIO_do_connect(bio) <= 0) {
printf("Failed to connect!");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Now we need to do the SSL handshake, so we can communicate.
if (BIO_do_handshake(bio) <= 0) {
printf("Failed to do SSL handshake!");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
// Create a buffer for grabbing information from the page.
char buf[1024];
memset(buf, 0, sizeof(buf));
// Create a buffer for the reqest we'll send to the server
char send[1024];
memset(send, 0, sizeof(send));
// Create our GET request.
strcat(send, "GET / HTTP/1.1\nHost:google.com\nUser Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)\nConnection: Close\n\n");
// BIO_puts sends a null-terminated string to the server. In this case it's our GET request.
BIO_puts(bio, send);
// Loop while there's information to be read.
while (1) {
// BIO_read() reads data from the server into a buffer. It returns the number of characters read in.
int x = BIO_read(bio, buf, sizeof(buf) - 1);
// If we haven't read in anything, assume there's nothing more to be sent since we used Connection: Close.
if (x == 0) {
break;
}
// If BIO_read() returns a negative number, there was an error
else if (x < 0) {
// BIO_should_retry lets us know if we should keep trying to read data or not.
if (!BIO_should_retry(bio)) {
printf("\nRead Failed!\n");
BIO_free_all(bio);
SSL_CTX_free(ctx);
return;
}
}
// We actually got some data, without errors!
else {
// Null-terminate our buffer, just in case
buf[x] = 0;
// Echo what the server sent to the screen
printf("%s", buf);
}
}
// Free up that BIO object we created.
BIO_free_all(bio);
// Remember, we also need to free up that SSL_CTX object!
SSL_CTX_free(ctx);
// Return.
return;
}
// THIS IS THE SERVER FOR THE CONNECTION
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <iostream>
#include <stdio.h>
#include <winsock2.h>
#define PASSWORD "passme"
void serverThread();
int main(int argc, char** argv) {
CRYPTO_malloc_init(); // Initialize malloc, free, etc for OpenSSL's use
SSL_library_init(); // Initialize OpenSSL's SSL libraries
SSL_load_error_strings(); // Load SSL error strings
ERR_load_BIO_strings(); // Load BIO error strings
OpenSSL_add_all_algorithms(); // Load all available encryption algorithms
serverThread();
return 0;
}
void serverThread() {
// First, we need to initialize Winsock.
WSADATA wsadata;
int ret = WSAStartup(0x101, &wsadata);
if (ret != 0) {
printf("WSAStartup() failed with: %d!\n", GetLastError());
return;
}
// Next we need to create a server socket.
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in sockaddrin;
// Internet socket
sockaddrin.sin_family = AF_INET;
// Accept any IP
sockaddrin.sin_addr.s_addr = INADDR_ANY;
// Use port 6789
sockaddrin.sin_port = htons(6789);
// Valid socket?
if (server == INVALID_SOCKET) {
printf("Error creating server socket!");
return;
}
// Now bind to the port
ret = bind(server, (sockaddr*) &(sockaddrin), sizeof(sockaddrin));
if (ret != 0) {
printf("Error binding to port!\n");
return;
}
// Start listening for connections
// Second param is max number of connections
ret = listen(server, 50);
if (ret != 0) {
printf("Error listening for connections!\n");
return;
}
// Set up to accept connections
SOCKET client;
sockaddr_in clientsockaddrin;
int len = sizeof(clientsockaddrin);
printf("Server ready to accept connections!\n");
while (1) {
// Block until a connection is ready
client = accept(server, (sockaddr*) &clientsockaddrin, &len);
printf("Connection recieved from %s!\n", inet_ntoa(clientsockaddrin.sin_addr));
// Notice that we use server_method instead of client_method
SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
BIO* bio = BIO_new_file("dh1024.pem", "r");
// Did we get a handle to the file?
if (bio == NULL) {
printf("Couldn't open DH param file!\n");
break;
}
// Read in the DH params.
DH* ret = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
// Free up the BIO object.
BIO_free(bio);
// Set up our SSL_CTX to use the DH parameters.
if (SSL_CTX_set_tmp_dh(ctx, ret) < 0) {
printf("Couldn't set DH parameters!\n");
break;
}
// Now we need to generate a RSA key for use.
// 1024-bit key. If you want to use something stronger, go ahead but it must be a power of 2. Upper limit should be 4096.
RSA* rsa = RSA_generate_key(1024, RSA_F4, NULL, NULL);
// Set up our SSL_CTX to use the generated RSA key.
if (!SSL_CTX_set_tmp_rsa(ctx, rsa)) {
printf("Couldn't set RSA key!\n");
// We don't break out here because it's not a requirement for the RSA key to be set. It does help to have it.
}
// Free up the RSA structure.
RSA_free(rsa);
SSL_CTX_set_cipher_list(ctx, "ALL");
// Set up our SSL object as before
SSL* ssl = SSL_new(ctx);
// Set up our BIO object to use the client socket
BIO* sslclient = BIO_new_socket(client, BIO_NOCLOSE);
// Set up our SSL object to use the BIO.
SSL_set_bio(ssl, sslclient, sslclient);
// Do SSL handshaking.
int r = SSL_accept(ssl);
// Something failed. Print out all the error information, since all of it may be relevant to the problem.
if (r != 1) {
printf("SSL_accept() returned %d\n", r);
printf("Error in SSL_accept(): %d\n", SSL_get_error(ssl, r));
char error[65535];
ERR_error_string_n(ERR_get_error(), error, 65535);
printf("Error: %s\n\n", error);
ERR_print_errors(sslclient);
int err = WSAGetLastError();
printf("WSA: %d\n", err);
break;
}
}
}
int password_callback(char* buffer, int num, int rwflag, void* userdata) {
if (num < (strlen(PASSWORD) + 1)) {
return(0);
}
strcpy(buffer, PASSWORD);
return strlen(PASSWORD);
}
int verify_callback(int ok, X509_STORE_CTX* store) {
char data[255];
if (!ok) {
X509* cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
printf("Error with certificate at depth: %d!\n", depth);
X509_NAME_oneline(X509_get_issuer_name(cert), data, 255);
printf("\tIssuer: %s\n", data);
X509_NAME_oneline(X509_get_subject_name(cert), data, 255);
printf("\tSubject: %s\n", data);
printf("\tError %d: %s\n", err, X509_verify_cert_error_string(err));
}
return ok;
}
Usually that error indicates you have not configured an RSA key in your server. In order to use RSA ciphersuites your server must have a certificate with an RSA key properly configured.
Related
I'm trying to test with OpenSSL DTLS by making a program that creates a client and server socket to echo strings between the sockets; However, when I try to test out DTLSv1_Listen() function my program seems to pause even when I am not trying connecting or sending data between the sockets. note: I am using a post 1.0.2 OpenSSL which is after DTLSv1_Listen() was rewritten.
Here is my complete C++ winsock specific code:
#include <stdio.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
//#include <openssl/applink.c>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
struct DTLSStuff { //struct to contain DTLS object instances
SSL_CTX *ctx;
SSL *ssl;
BIO *bio;
};
void DTLSErr() { //DTLS error reporting
ERR_print_errors_fp(stderr);
exit(1);
}
int newSocket(sockaddr_in addr) { //creates a socket and returns the file descriptor //TODO expand for multi-platform
WSADATA wsaData;
int fd;
int iResult;
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData); //Initialize Winsock
if (iResult != 0) { printf("WSAStartup failed: %d\n", iResult); exit(1); }
fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("Unable to create socket"); exit(1); } //create socket
printf("New Socket: %i\n", fd);
if (bind(fd, (struct sockaddr *)&addr, sizeof(sockaddr)) < 0) { printf("bind failed with error %u\n", WSAGetLastError()); exit(1); }
return fd; //file descriptor
}
void InitCTX(SSL_CTX *ctx, bool IsClient) { //Takes a ctx object and initializes it for DTLS communication
if (IsClient) {
if(SSL_CTX_use_certificate_chain_file(ctx, "client-cert.pem") < 0) { printf("Failed loading client cert");}
if(SSL_CTX_use_PrivateKey_file(ctx, "client-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
else {
if (SSL_CTX_use_certificate_chain_file(ctx, "server-cert.pem") < 0) { printf("Failed loading client cert"); }
if (SSL_CTX_use_PrivateKey_file(ctx, "server-key.pem", SSL_FILETYPE_PEM) < 0) { printf("Failed loading client key"); }
}
//SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cert); //omitted for testing
//SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie); //omitted for testing
//SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie); //omitted for testing
SSL_CTX_set_read_ahead(ctx, 1);
}
int main() { //creates client and server sockets and DTLS objects. TODO: have client complete handshake with server socket and send a message and have the server echo it back to client socket
BIO_ADDR *faux_addr = BIO_ADDR_new(); // for DTLSv1_listen(), since we are this is both client and server (meaning client address is known) it is only used to satisfy parameters.
ERR_load_BIO_strings();
SSL_load_error_strings();
SSL_library_init();
//Set up addresses
sockaddr_in client_addr;
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(25501);
client_addr.sin_addr.s_addr = INADDR_ANY;
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(25500);
server_addr.sin_addr.s_addr = INADDR_ANY;
//*********CLIENT
DTLSStuff ClientInf;
ClientInf.ctx = SSL_CTX_new(DTLSv1_client_method());
InitCTX(ClientInf.ctx,true);
int ClientFD = newSocket(client_addr);
ClientInf.bio = BIO_new_dgram(ClientFD, BIO_NOCLOSE);
ClientInf.ssl = SSL_new(ClientInf.ctx);
//SSL_set_options(ClientInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ClientInf.ssl, ClientInf.bio, ClientInf.bio);
//*********SERVER
DTLSStuff ServerInf;
ServerInf.ctx = SSL_CTX_new(DTLSv1_server_method());
InitCTX(ServerInf.ctx,false);
int ServerFD = newSocket(server_addr);
ServerInf.bio = BIO_new_dgram(ServerFD, BIO_NOCLOSE);
ServerInf.ssl = SSL_new(ServerInf.ctx);
//SSL_set_options(ServerInf.ssl, SSL_OP_COOKIE_EXCHANGE); //omitted for testing
SSL_set_bio(ServerInf.ssl, ServerInf.bio, ServerInf.bio);
printf("Listen attempt...\n");
int ret = DTLSv1_listen(ServerInf.ssl, faux_addr);
if (ret < 0) { DTLSErr(); }
printf("this print should occur, but it never does");
exit(1);
}
I expect the results to be as follow:
NewSocket: 356
NewSocket: 360
Listen attempt...
this print should occur but it never does
However when running the program it never prints the last line. The program seems to respond as I am able to cancel the executable by ctrl+c so I am assuming it has not crashed or froze, but aside from that I am at a loss. My understanding is that the method should return 0 if nothing happens, >1 if it heard a clienthello, and <0 if an error occurred.
Also, a somewhat related question: Since DTLSv1_Listen() requires a BIO_ADDR to store the incoming requests address does that mean that separate client and servers programs will both require 2 sockets if they want to be able to both send and listen? Normally UDP clients and servers only need a single socket, but I cannot seem to figure a design to retain this with OpenSSL's DTLS.
I thank you for your time.
I don't see anywhere in your code where you set the socket to be non-blocking. In the default blocking mode when you attempt to read from the socket your program will pause until data has arrived. If you don't want that then make sure your set the appropriate option (I'm not a Windows programmer, but ioctlsocket seems to do the job: https://msdn.microsoft.com/en-us/library/windows/desktop/ms738573(v=vs.85).aspx)
does that mean that separate client and servers programs will both require 2 sockets if they want to be able to both send and listen
When using DTLSv1_listen() you are using the socket in an unconnected state, so you may receive UDP packets from multiple clients. DTLS is connection based so once DTLSv1_listen() returns successfully you are supposed to create a "connected" socket to the client address. So you have one socket for listening for new connections, and one socket per client communicating with your server.
I'm trying to connect SSL sockets between my Qt application (using QSslSockets) and my c++ server running SSL sockets (using openssl)..
Server Code:
int create_socket(int port)
{
int s;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("Unable to create socket");
exit(EXIT_FAILURE);
}
if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
perror("Unable to bind");
exit(EXIT_FAILURE);
}
if (listen(s, 1) < 0) {
perror("Unable to listen");
exit(EXIT_FAILURE);
}
return s;
}
void init_openssl()
{
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
}
void cleanup_openssl()
{
EVP_cleanup();
}
SSL_CTX *create_context()
{
const SSL_METHOD *method;
SSL_CTX *ctx;
method = SSLv23_server_method();
ctx = SSL_CTX_new(method);
if (!ctx) {
perror("Unable to create SSL context");
ERR_print_errors_fp(stderr);
exit(EXIT_FAILURE);
}
return ctx;
}
void configure_context(SSL_CTX *ctx)
{
if(SSL_CTX_use_certificate_file(ctx, "/root/myCA/server_crt.pem", SSL_FILETYPE_PEM) > 0)
{
std::cout<<"Cert found"<<std::endl;
}
if (SSL_CTX_use_PrivateKey_file(ctx, "/root/myCA/server_key.pem", SSL_FILETYPE_PEM) > 0 ) {
std::cout<<"Key found"<<std::endl;
}
if(SSL_CTX_check_private_key(ctx) > 0)
{
std::cout<<"Key valid"<<std::endl;
}
}
int main(int argc, char **argv)
{
int sock;
SSL_CTX *ctx;
init_openssl();
ctx = create_context();
configure_context(ctx);
sock = create_socket(3000);
while(1) {
struct sockaddr_in addr;
uint len = sizeof(addr);
SSL *ssl;
const char reply[] = "test\n";
int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client > 0) {
std::cout<<"Client accepted..."<<std::endl;
}
else
{
perror("Unable to accept");
exit(EXIT_FAILURE);
}
ssl = SSL_new(ctx);
SSL_set_fd(ssl, client);
if (SSL_accept(ssl) <= 0) {
ERR_print_errors_fp(stderr);
}
else {
SSL_write(ssl, reply, strlen(reply));
}
SSL_free(ssl);
close(client);
}
close(sock);
SSL_CTX_free(ctx);
cleanup_openssl();
}
Qt Client Code:
SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
{
connect(&client,SIGNAL(encrypted()),this,SLOT(ConnectionEstablished()));
connect(&client,SIGNAL(sslErrors(const QList<QSslError>&)),this,SLOT(ErrorOccured(const QList<QSslError> &)));
QList<QSslCertificate>
trusted_ca=QSslCertificate::fromPath("/Users/test/Desktop/server_crt.pem");
if(trusted_ca.empty())
{
qDebug()<<"Error not trusted Ca.";
}
client.setCaCertificates(trusted_ca);
client.connectToHostEncrypted(*my ip address*,3000);
}
void SSLSOCKET::ErrorOccured(const QList<QSslError> &error)
{
qDebug()<<"ERROR HERE----:";
qDebug()<<error;
}
void SSLSOCKET::ConnectionEstablished()
{
qDebug()<<"CONNECTION WORKED------:";
if(!client.waitForEncrypted())
{
qDebug()<<client.errorString();
}
else
{
qDebug()<<"Encrypted Connection Established...";
}
}
I can see the connection being made between the client and server, however the client.waitForEncrypted() is showing 'Unknown Error'..
Any ideas?
You are calling waitForEncrypted() inside of your connected() handler. The client hasn't actually initiated the SSL handshake yet, so you can't wait on it yet. Per the connectToHostEncrypted() documentation:
Starts an encrypted connection to the device hostname on port, using mode as the OpenMode. This is equivalent to calling connectToHost() to establish the connection, followed by a call to startClientEncryption(). The protocol parameter can be used to specify which network protocol to use (eg. IPv4 or IPv6).
QSslSocket first enters the HostLookupState. Then, after entering either the event loop or one of the waitFor...() functions, it enters the ConnectingState, emits connected(), and then initiates the SSL client handshake. At each state change, QSslSocket emits signal stateChanged().
If you want to handle connected() like this, you will have to use connectToHost() instead of connectToHostEncrypted(), and then call startClientEncryption() separately:
SSLSOCKET::SSLSOCKET(QObject *parent):QObject(parent)
{
connect(&client, SIGNAL(connected()), this, SLOT(ConnectionEstablished()));
...
client.connectToHost(*my ip address*, 3000);
}
void SSLSOCKET::ConnectionEstablished()
{
client.startClientEncryption();
if (!client.waitForEncrypted())
...
}
EDIT: scratch that. I thought you were handling the connected() signal, but I see now that you are handling the encrypted() signal instead. In that case:
If the SSL handshake is successful, QSslSocket emits encrypted().
So you don't need to use waitForEncrypted() at all:
void SSLSOCKET::ConnectionEstablished()
{
qDebug()<<"CONNECTION WORKED------:";
qDebug()<<"Encrypted Connection Established...";
}
Even if you did call it, it should simply return true:
Waits until the socket has completed the SSL handshake and has emitted encrypted(), or msecs milliseconds, whichever comes first. If encrypted() has been emitted, this function returns true; otherwise (e.g., the socket is disconnected, or the SSL handshake fails), false is returned.
So, unless the socket is being disconnected after the handshake completes, or encrypted() is being emitted before the encrypted state is actually changed, or some other unforeseen error is occurring, I don't see any reason for waitForEncrypted() to return false inside of the encrypted() handler.
I have a problem with some source code regarding OpenSSL and Cpp. For some reason it runs fine but doesn't open a socket! When I try to connect to it using s_client I get 'Connect: No Error". When I run netstat I get no open port. It should open a port on 12120. I even disabled my firewall temporarly and it didn't help! BTW I'm using Windows 7. Thanks for your consideration! My program just says everythings fine and it starts blocking at the second *BIO_do_accept( abio );*
#include "stdio.h"
#include "string.h"
#include "openssl/bio.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
int password_callback(char *buf, int size, int rwflag, void *userdata)
{
/* For the purposes of this demonstration, the password is "dw" */
printf("*** Callback function called\n");
strcpy(buf, "dw");
return 1;
}
int main()
{
SSL_CTX *ctx;
SSL *ssl;
BIO *bio, *abio, *out, *sbio;
int (*callback)(char *, int, int, void *) = &password_callback;
printf("Secure Programming with the OpenSSL API, Part 4:\n");
printf("Serving it up in a secure manner\n\n");
SSL_load_error_strings();
ERR_load_BIO_strings();
SSL_library_init();
ERR_load_SSL_strings();
OpenSSL_add_all_algorithms();
printf("Attempting to create SSL context... ");
ctx = SSL_CTX_new( SSLv23_server_method() );
if(ctx == NULL)
{
printf("Failed. Aborting.\n");
return 0;
}
printf("\nLoading certificates...\n");
SSL_CTX_set_default_passwd_cb(ctx, callback);
if(!SSL_CTX_use_certificate_file(ctx, "certificate.pem", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
if(!SSL_CTX_use_PrivateKey_file(ctx, "private.key", SSL_FILETYPE_PEM))
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
printf("Attempting to create BIO object... ");
bio = BIO_new_ssl(ctx, 0);
if(bio == NULL)
{
printf("Failed. Aborting.\n");
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
return 0;
}
printf("\nAttempting to set up BIO for SSL...\n");
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
abio = BIO_new_accept("12120");
BIO_set_accept_bios(abio, bio);
printf("Waiting for incoming connection...\n");
if(BIO_do_accept(abio) <= 0)
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx); SSL_library_init();
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
if(BIO_do_accept(abio) <= 0)
{
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
out = BIO_pop(abio);
if(BIO_do_handshake(out) <= 0)
{
printf("Handshake failed.\n");
ERR_print_errors_fp(stdout);
SSL_CTX_free(ctx);
BIO_free_all(bio);
BIO_free_all(abio);
return 0;
}
BIO_puts(out, "Hello\n");
BIO_flush(out);
BIO_free_all(out);
BIO_free_all(bio);
BIO_free_all(abio);
SSL_CTX_free(ctx);
}
What exactly are you expecting here? You should see port 12120 in LISTENING state. Your client should then be able to connect. Your server then does another accept, which will prevent it reading any I/O on the accepted port, and will ultimately block your client too. I don't know why you are doing two accept's in a row but it's your code.
From the OpenSSL Documentation for BIO_do_accept():
BIO_do_accept() serves two functions. When it is first called, after
the accept BIO has been setup, it will attempt to create the accept
socket and bind an address to it. Second and subsequent calls to
BIO_do_accept() will await an incoming connection, or request a retry
in non-blocking mode.
I've written (rather, copied from a tutorial :P) a winsock server, in c++ which waits for the client to send a message and then closes. The server works when both the client and the server are on my PC, but when i move the client to another computer, it fails.
I think it's a problem with my ip adress but 192.168.254.4 is what i get when i type ipconfig \all in command prompt.
Server
//******************************************************************************
//
// Main.cpp
//
// Main source file of the Listener program, which employs blocking sockets and
// Winsock to listen for outside connections.
//
// If you are not using the included Dev-C++ project file, be sure to link with
// the Winsock library, usually wsock32.lib or something similarly named.
//
// Author: Johnnie Rose, Jr. (johnnie2#hal-pc.org)
// Date: 1/08/03 (version 2)
// Website: http://www.hal-pc.org/~johnnie2/winsock.html
//
//******************************************************************************
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#define NETWORK_ERROR -1
#define NETWORK_OK 0
void ReportError(int, const char *);
using namespace std;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) {
WORD sockVersion;
WSADATA wsaData;
int nret;
sockVersion = MAKEWORD(2, 2); // We'd like Winsock version 1.1
// We begin by initializing Winsock
WSAStartup(sockVersion, &wsaData);
// Next, create the listening socket
SOCKET listeningSocket;
listeningSocket = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (listeningSocket == INVALID_SOCKET) {
nret = WSAGetLastError(); // Get a more detailed error
ReportError(nret, "socket()"); // Report the error with our custom function
WSACleanup(); // Shutdown Winsock
return NETWORK_ERROR; // Return an error value
}
// Use a SOCKADDR_IN struct to fill in address information
SOCKADDR_IN serverInfo;
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr.s_addr = INADDR_ANY; // Since this socket is listening for
// connections, any local address will do
serverInfo.sin_port = htons(8888); // Convert integer 8888 to network-byte order
// and insert into the port field
// Bind the socket to our local server address
nret = bind(listeningSocket, (LPSOCKADDR)&serverInfo, sizeof(struct sockaddr));
if (nret == SOCKET_ERROR) {
nret = WSAGetLastError();
ReportError(nret, "bind()");
WSACleanup();
return NETWORK_ERROR;
}
// Make the socket listen
nret = listen(listeningSocket, 10); // Up to 10 connections may wait at any
// one time to be accept()'ed
if (nret == SOCKET_ERROR) {
nret = WSAGetLastError();
ReportError(nret, "listen()");
WSACleanup();
return NETWORK_ERROR;
}
// Wait for a client
cout << "Waiting for client" << endl;
SOCKET theClient;
theClient = accept(listeningSocket,
NULL, // Address of a sockaddr structure (see explanation below)
NULL); // Address of a variable containing size of sockaddr struct
if (theClient == INVALID_SOCKET) {
nret = WSAGetLastError();
ReportError(nret, "accept()");
WSACleanup();
return NETWORK_ERROR;
}
char Buffer[256];
recv(theClient, Buffer, 256, 0);
printf(Buffer, 2);
// Send and receive from the client, and finally,
closesocket(theClient);
closesocket(listeningSocket);
// Shutdown Winsock
WSACleanup();
system("PAUSE");
return NETWORK_OK;
}
void ReportError(int errorCode, const char *whichFunc) {
char errorMsg[92]; // Declare a buffer to hold
// the generated error message
ZeroMemory(errorMsg, 92); // Automatically NULL-terminate the string
// The following line copies the phrase, whichFunc string, and integer errorCode into the buffer
sprintf(errorMsg, "Call to %s returned error %d!", (char *)whichFunc, errorCode);
MessageBox(NULL, errorMsg, "socketIndication", MB_OK);
}
Client
//******************************************************************************
//
// Main.cpp
//
// Main source file of the Connector program, which employs blocking sockets and
// Winsock to connect to an outside server.
//
// If you are not using the included Dev-C++ project file, be sure to link with
// the Winsock library, usually wsock32.lib or something similarly named.
//
// Author: Johnnie Rose, Jr. (johnnie2#hal-pc.org)
// Date: 1/08/03 (version 2)
// Website: http://www.hal-pc.org/~johnnie2/winsock.html
//
//******************************************************************************
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <iostream>
#define NETWORK_ERROR -1
#define NETWORK_OK 0
void ReportError(int, const char *);
using namespace std;
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmd, int nShow) {
WORD sockVersion;
WSADATA wsaData;
int nret;
cout <<"Loading WinSock" << endl;
sockVersion = MAKEWORD(2, 2);
// Initialize Winsock as before
WSAStartup(sockVersion, &wsaData);
// Store information about the server
LPHOSTENT hostEntry;
in_addr iaHost;
iaHost.s_addr = inet_addr("192.168.254.4");
hostEntry = gethostbyaddr((const char *)&iaHost, sizeof(struct in_addr), AF_INET); // Specifying the server by its name;
// another option is gethostbyaddr()
if (!hostEntry) {
nret = WSAGetLastError();
ReportError(nret, "gethostbyaddr()"); // Report the error as before
WSACleanup();
return NETWORK_ERROR;
}
// Create the socket
cout <<"Creating Socket";
SOCKET theSocket;
theSocket = socket(AF_INET, // Go over TCP/IP
SOCK_STREAM, // This is a stream-oriented socket
IPPROTO_TCP); // Use TCP rather than UDP
if (theSocket == INVALID_SOCKET) {
nret = WSAGetLastError();
ReportError(nret, "socket()");
WSACleanup();
return NETWORK_ERROR;
}
// Fill a SOCKADDR_IN struct with address information
SOCKADDR_IN serverInfo;
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr = *((LPIN_ADDR)*hostEntry->h_addr_list); // See the explanation in the tutorial
serverInfo.sin_port = htons(8888); // Change to network-byte order and
// insert into port field
cout << "Connecting to server" << endl;
// Connect to the server
nret = connect(theSocket,
(LPSOCKADDR)&serverInfo,
sizeof(struct sockaddr));
if (nret == SOCKET_ERROR) {
nret = WSAGetLastError();
ReportError(nret, "connect()");
WSACleanup();
return NETWORK_ERROR;
}
// Successfully connected!
char* Buffer;
send(theSocket, "A", 1, 0);
recv(theSocket, Buffer, 256,0);
printf(Buffer,256);
// Send/receive, then cleanup:
closesocket(theSocket);
WSACleanup();
system("PAUSE");
return 0;
}
void ReportError(int errorCode, const char *whichFunc) {
char errorMsg[92]; // Declare a buffer to hold
// the generated error message
ZeroMemory(errorMsg, 92); // Automatically NULL-terminate the string
// The following line copies the phrase, whichFunc string, and integer errorCode into the buffer
sprintf(errorMsg, "Call to %s returned error %d!", (char *)whichFunc, errorCode);
MessageBox(NULL, errorMsg, "socketIndication", MB_OK);
}
If you're running the unmodified client code on a different machine, it's probably still trying to connect to a server on "localhost", which is not what you want. [Edit: OP has updated his client code and is now using an IP address.]
In a typical home/office LAN setup, you probably want to use IP addresses rather than
hostnames to specify the server to use. You may also need to check that the network
port you've specified is not blocked by software firewalls on the client or server
machines, or by a hardware firewall or router between the server and client.
One way to debug such a problem is to use a tool like Wireshark to monitor
the network traffic between the client and server. Are packets leaving the client's machine when it attempts to establish a connection? Are the requests seen by the server's machine? Is one side or the other prematurely closing the connection? Remember that firewalls can block outgoing traffic as well as incoming traffic...
I have a quick question. I set this client up as a sort of example, so I do not do a lot of extra work with it; I wanted to get the basic idea working first. I have it working so far, with one exception:
If I start it up, I can see the data being sent across on the other side (I use python+twisted). I can write with no problems, the problem comes when I read. On the server side, I am able to see the text coming in and being sent back out again. But on the client side, things are delayed. I have to send three commands to see something coming out.
for example:
I send hello <newline> cruel <newline> world<newline> and get hello echoed back to me, only after I hit enter on world.
Could someone point out why or give me some hints?
Here is the code.
#include <openssl/ssl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <fcntl.h>
#include <cstdio>
//used for printing an error and then exiting.
inline void error(const char* message)
{
fprintf(stderr, "%s\n", message);
exit(EXIT_FAILURE);
}
//the buffer size we will be working with:
#define MAX_BUFF 4096
int main()
{
int ret; //used for holding bytes read.
int flag = 1; //our IOCTL flag.
char buff[MAX_BUFF]; //a buffer for holding i/o data.
fd_set rdesc, wdesc, srset, swset; //file descriptor sets.
timeval tv; //used for holding the time select should wait.
SSL_CTX* context = NULL; //ssl context.
SSL* ssl = NULL; //main ssl object.
sockaddr_in addr; //server socket address.
int sock = 0;
//clean out the struct:
bzero(&addr, sizeof(sockaddr_in));
//then fill it in.
addr.sin_family = AF_INET;
addr.sin_port = htons(4000);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
//create the socket
sock=socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
error("Error creating initial socket.");
}
//initialize SSL.
SSL_load_error_strings();
SSL_library_init();
//create the ssl context
context = SSL_CTX_new(TLSv1_client_method());
if (!context)
{
error("Could not create SSL context.");
}
//connect the socket to the server.
if (connect(sock, (sockaddr*)&addr, sizeof(sockaddr_in)) < 0)
{
error("Could not connect to specified socket.");
}
//create the ssl object.
ssl = SSL_new(context);
if (!ssl)
{
error("Could not create ssl object.");
}
//try to set the socket as the fd for the ssl object.
if (!SSL_set_fd(ssl, sock))
{
error("Error, could not bind fd to the ssl object.");
}
//link ssl up with the socket.
if (!SSL_connect(ssl))
{
error("Could not perform ssl handshake.");
}
ioctl(sock, FIONBIO, &flag);
//set our file descriptor sets.
FD_SET(fileno(stdin), &wdesc);
FD_SET(sock, &rdesc);
//wait for data, read, then print.
while (1)
{
//we need to zero out our i/o buffer.
bzero(buff, MAX_BUFF);
//initialize our temp fd sets.
srset = rdesc;
swset = wdesc;
//each time select finishes it changes this to how much time it actually slept, so we need to reset it.
tv.tv_usec = 50*1000; //50 ms
tv.tv_sec = 0;
//perform the actual select operation.
select(sock+1, &srset, &swset, NULL, &tv);
//check to see if data was written on stdin (user input)
if (FD_ISSET(fileno(stdin), &swset))
{
//read inputted data.
ret = read(fileno(stdin), buff, MAX_BUFF);
if (ret)
{
//write it to the socket.
SSL_write(ssl, buff, ret);
}
}
//check to see if we received anything.
if (FD_ISSET(sock, &srset))
{
printf("in if.\n");
//read it
ret = SSL_read(ssl, buff, MAX_BUFF);
printf("%d\n", ret);
if (ret)
{
//write it to screen.
printf("%s\n", buff);
}
}
}
return 0;
}