Friday, January 25, 2008

SSL OpenSSL with Visual C++

Today I have another solution to work with SSL from Visual C++ using OpenSSL.

Well, the OpenSSL compilation was described before, so I can’t described here again. Click here if you want to know more about OpenSSL compilation

To work with SSL is easy with OpenSSL, really is a layer to add to our Windows Socket Projects.

The steps you’ll have to do are:

1. Add the OpenSSL libs (libeay32.lib, ssleay32.lib) to your project in Link options. Well, and touch some different options in this sheet, download the projects to see more about this point.
2. Add the OpenSSL header files to your main cpp.
3. And the OpenSSL SSL commands.

Here is the sample server code:


#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <winsock.h>

#include <openssl/rsa.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


/* certificates root path */
#define HOME "./"
/* certificate and private key */
#define CERTF HOME "micert.pem"
#define KEYF HOME "mikey.key"

/* checking fuctions */
#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }

int err;


void main ()
{
int err;
int listen_sd;
int sd;
struct sockaddr_in sa_serv;
struct sockaddr_in sa_cli;
int client_len;
SSL_CTX* ctx;
SSL* ssl;
X509* client_cert;
char* str;
char buf [4096];
SSL_METHOD *meth;
WORD wVersionRequested;
WSADATA wsaData;

/* SSL init. Keep the Key and the certificate in the context. */

SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
meth = SSLv23_server_method();
ctx = SSL_CTX_new (meth);
if (!ctx) {
    ERR_print_errors_fp(stderr);
    exit(2);
}

if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    exit(3);
}
if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {
    ERR_print_errors_fp(stderr);
    exit(4);
}

if (!SSL_CTX_check_private_key(ctx)) {
    fprintf(stderr,"The private Key don’t match with the certificate\n");
    exit(5);
}

/*****************************************************/
/*                                                   */
/* Socket Initialitation */
/*                                                   */
/*****************************************************/



wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup(wVersionRequested, &wsaData );
if ( err != 0 )
{
    printf("///Error in WSAStartup//%d\n",err);
    exit(err);

}

listen_sd = socket (AF_INET, SOCK_STREAM, 0);
printf("socket() return 0x%X (%d)\n", listen_sd, listen_sd);
CHK_ERR(listen_sd, "socket");

memset (&sa_serv, '\0', sizeof(sa_serv));
sa_serv.sin_family = AF_INET;
sa_serv.sin_addr.s_addr = INADDR_ANY;
sa_serv.sin_port = htons (9000); /* Server listen Port */

err = bind(listen_sd, (struct sockaddr*) &sa_serv,
sizeof (sa_serv));
CHK_ERR(err, "bind");

/*****************************************************/
/*                                                   */
/* setting listening */
/*                                                   */
/*****************************************************/

printf("listening\n");
err = listen (listen_sd, 5); CHK_ERR(err, "listen");

client_len = sizeof(sa_cli);
sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len);
CHK_ERR(sd, "accept");
closesocket (listen_sd);

printf ("Connection from %lx, port %x\n",
sa_cli.sin_addr.s_addr, sa_cli.sin_port);

/*****************************************************/
/*                                                   */
/* preparing SSL with the recived socket */
/*                                                   */
/*****************************************************/


ssl = SSL_new (ctx); CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_accept (ssl); CHK_SSL(err);

/* Showing cipher - optional */

printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

/* Get Client cert, if exist - optional */

client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL) {
    printf ("Client Certificate:\n");

    str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);
    CHK_NULL(str);
    printf ("\t subject: %s\n", str);
    OPENSSL_free (str);

    str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);
    CHK_NULL(str);
    printf ("\t issuer: %s\n", str);
    OPENSSL_free (str);

    /* Here we could check all we want about client certificate. */

    X509_free (client_cert);
} else
    printf ("The Client hasn’t certificate.\n");

/* Exchanging messages */

err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err);
buf[err] = '\0';
printf ("Read %d characters:'%s'\n", err, buf);

err = SSL_write (ssl, "I’m listening.", strlen("I’m listening.")); CHK_SSL(err);

/* Freeing resources */

closesocket (sd);
SSL_free (ssl);
SSL_CTX_free (ctx);
}

Bellow is the SSL Client Code.

#include <stdio.h>
#include <memory.h>
#include <errno.h>
#include <sys/types.h>
#include <winsock.h>

#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }

void main ()
{
int err=0;
int sd;
struct sockaddr_in sa;
SSL_CTX* ctx;
SSL* ssl;
X509* scert;
char* txt;
char buff [4096];
SSL_METHOD *meth;
WORD wVersionRequested;
WSADATA wsaData;
SSLeay_add_ssl_algorithms();
meth = SSLv2_client_method();
SSL_load_error_strings();
ctx = SSL_CTX_new (meth); CHK_NULL(ctx);

CHK_SSL(err);

/*****************************************************/
/*                                                   */
/* Socket Init and connecting. */
/*                                                   */
/*****************************************************/


wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup(wVersionRequested, &wsaData );
if ( err != 0 )
{
    printf("///Error in WSAStartup //%d\n",err);
    exit(1);

}


sd = socket (AF_INET, SOCK_STREAM, 0);
CHK_ERR(sd, "socket");

memset (&sa, '\0', sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr ("127.0.0.1"); /* Server Ip */
sa.sin_port = htons (9000); /* Server port */

err = connect(sd, (struct sockaddr*) &sa,
sizeof(sa)); CHK_ERR(err, "connection");

/*****************************************************/
/*                                                   */
/* Starting SSL connection */
/*                                                   */
/*****************************************************/

ssl = SSL_new (ctx); CHK_NULL(ssl);
SSL_set_fd (ssl, sd);
err = SSL_connect (ssl); CHK_SSL(err);

/* Get the cipher - optional */

printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

/* Get Server certificate - optional */

scert = SSL_get_peer_certificate (ssl); CHK_NULL(scert);
printf ("Server Certificate:\n");

txt = X509_NAME_oneline (X509_get_subject_name (scert),0,0);
CHK_NULL(txt);
printf ("\t Subject: %s\n", txt);
OPENSSL_free (txt);

txt = X509_NAME_oneline (X509_get_issuer_name (scert),0,0);
CHK_NULL(txt);
printf ("\t Issuer: %s\n", txt);
OPENSSL_free (txt);

/* Here we can check what we wanted about the Server certificate */

X509_free (scert);

/*****************************************************/
/*                                                   */
/* Exchanging messages */
/*                                                   */
/*****************************************************/

err = SSL_write (ssl, "Is someone there?", strlen("Is someone there?")); CHK_SSL(err);

err = SSL_read (ssl, buff, sizeof(buff) - 1); CHK_SSL(err);
buff[err] = '\0';
printf ("Read %d characters:'%s'\n", err, buff);
SSL_shutdown (ssl); /* sending the SSL/TLS end*/

/* Freeing resources */

closesocket (sd);
SSL_free (ssl);
SSL_CTX_free (ctx);
}


If you want to download the client and Server projects, click here. Source Files

Thursday, January 24, 2008

RSA OpenSSL with Microsoft Visual C++

Hi, buddies, how long time? JE JE JE

Here I am newly with another solution.

I have been working with RSA for some time with Java, but now I wanted to work with RSA in pure C.

Well, there are several libraries to work with RSA in C, but I choose OpenSSL.

Another time I only have a Windows System to try, I’m in a customer and here there aren’t UNIX machines.

Well, I downloaded this OpenSSL version

http://www.openssl.org/source/openssl-0.9.8g.tar.gz

This package is a source code package, and you need to compile to work with it.

To compile OpenSSL on Windows with Microsoft Visual C++, you have to read the install instructions (INSTALL.W32), located in the root. You’ll need Perl, and you’ll have to configure Perl correctly to work with Visual C++, in the file INSTALL.W32 you’ll find everything what you need. But, basically you’ll have to run these instructions from the root OpenSSL path:

To configure Perl, don’t forget add the Perl bin path to your PATH environment variable:
>perl Configure VC-WIN32 --prefix=‘c:/some/openssl/dir ‘

If you don't want to use the assembly language files at all then run
> ms\do_ms

And finally, run the compilation:

For get OpenSSL libs, run:
> nmake -f ms\nt.mak

Or run this command to get OpenSSL dlls:
> nmake -f ms\ntdll.mak

If you want to generate the libs or dlls with debugger information, you’ll need to edit do_nt.bat or do_ntdll.bat, to add debug option to the command line in these lines:

perl util\mk1mf.pl no-asm debug VC-NT>ms\nt.mak
perl util\mk1mf.pl dll no-asm debug VC-NT>ms\ntdll.mak

These bats build the makes with DEBUG option; you’ll have to execute the nmake -f ms\nt.mak newly to get the new libraries.

Maybe you’ll need unicows.lib for this last compilation.
If you don’t have it into your PC, it’s here.
http://surfnet.dl.sourceforge.net/sourceforge/libunicows/libunicows-1.1.1-msvc6.zip

Well, after the compilation you’ll get some exes and two dlls or libs, it depends if you compile nt.mak (libs) or ntdlls.mak (dlls), the output directory name begins with out32.

Well, here is a sample source code that shows how to read private and public keys from files (private key file is encrypted), retrieving the keys, encrypting and decrypting.

The bold lines are important, they showed the problems that I found


#include <stdio.h>
#include <string.h>
#include "e_os.h"
#include <openssl\crypto.h>
#include <openssl\err.h>
#include <openssl\rand.h>
#include <openssl\bn.h>
#include "applink.c"
#include "pem.h"
#include <openssl\rsa.h>

// Callback for login information
int pass_cb(char *buf, int size, int rwflag, void *password)
{
strncpy(buf, "carlos", size);
buf[size - 1] = '\0';
return(strlen(buf));
}


int main(int argc, char *argv[])
{

RSA *rsaPrivKey = RSA_new();
RSA *rsaPubKey = RSA_new();
unsigned char inText[256];
FILE *pubKey = NULL;
FILE *privKey = NULL;
unsigned char sigBuffer[256];
int size;
unsigned char plainText[256];
int encSize;
char pass[7]="carlos\n";

// OpenSSL Init
_fmode=_O_BINARY;
CRYPTO_malloc_init();
ERR_load_crypto_strings();
OpenSSL_add_all_algorithms();
ENGINE_load_builtin_engines();

// End OpenSSL Init

// Opening Files generated with openSSL
pubKey=fopen("J:\\public.key", "r");
// Private Key file, encrypted with 3DESC
privKey=fopen("J:\\priv.key", "r");

// Reading Keys
if(privKey){
    rsaPrivKey = PEM_read_RSAPrivateKey(privKey, &rsaPrivKey,
        (pem_password_cb *)pass_cb, pass);
}
ERR_print_errors_fp(stdout);
if(pubKey)
{
    rsaPubKey = PEM_read_RSA_PUBKEY(pubKey, &rsaPubKey,
        NULL, NULL);
}

// Encrypting
strcpy(inText,"Carlos");
printf("String to encrypting: %s\n", inText );
size = strlen((char*)inText);
encSize=RSA_public_encrypt(size, inText,
sigBuffer, rsaPubKey, RSA_PKCS1_OAEP_PADDING);

// Decrypting
printf("encrypted string size: %d\n" ,encSize );
encSize=RSA_private_decrypt(encSize, sigBuffer, plainText,
rsaPrivKey, RSA_PKCS1_OAEP_PADDING);
memset(plainText+encSize,0,sizeof(plainText)-encSize);
printf("ret %s\n",plainText);
ERR_print_errors_fp(stdout);
printf("Decrypting result: %s\n", plainText );

// Free keys
RSA_free(rsaPubKey);
RSA_free(rsaPrivKey);

// unload OpenSSL
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);

CRYPTO_mem_leaks_fp(stderr);

return 0;
}

Here is the Visual C++ Project
Source Files




CSoap and Visual Studio

First of all, I’m sorry for my English, but I want to improve it and this is a good way.

Well, this is my first solution.

Many times I have had to connect a c program to a Web Service, in Windows with MFC is too easy. I have a dll, which connects the c program with whatever Web Service only updating some xml files.

But, when you need to connect a c program running in other OS, you'll need to try other solutions.

The best, for me, it's CSoap.

However when I had to develop that connection I only had Windows Systems and well, I tried to connect CSoap in a Visual Studio Project.

It wasn't easy for me to find examples about CSOAP for Visual C++, and that is why I put that solution here.

Here is the original link to my source files https://sourceforge.net/tracker/download.php?group_id=74977&atid=542567&file_id=250457&aid=1816455