Showing posts with label source. Show all posts
Showing posts with label source. Show all posts

Wednesday, March 5, 2008

SSL HTTP POST

Hi, friends

I'm developing a module to connect C programs with WebServices and newly I've used OpenSSL. Actually it hasn't very difficult, although I had some problem. It's very important to set properly the method to use. I'm connecting with a JBoss HTTPs WebService and I had to set this one:


meth = TLSv1_client_method();
ctx = SSL_CTX_new (meth);

I copy bellow the main function I had used, to send the HTTP POST message, I hope it'll be usefull for you:

int sendPOST(void* sd, SSL* ssl, ;char* server, char* port, char* post, char* action, char* csoap, char *response){

int ret=0;
char msg[5000]="";
char buff[5000]="";
int err=0;
int len=0;
char header[200]="";

    // Setting HTTP Headers
    sprintf(msg,"POST %s HTTP/1.1\r\n", post);
    sprintf(header,"Host: %s:%s\r\n", server, port);
    len=strlen(msg) ;
    memcpy(msg + len , header, strlen(header));
    len+=strlen(header);
    strcpy(header,"Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n");
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    sprintf(header,"Content-Length: %d\r\n", strlen(datos));
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    sprintf(header,"SOAPAction: %s\r\n\r\n",action);
    memcpy(msg + len, header, strlen(header));
    len+=strlen(header);
    // Adding csoap
    memcpy(msg + len, datos, strlen(datos));

    if(sd!=NULL){
        // No SSL Connections

        err=send((int)sd, msg, len + strlen(datos),0);
        if (err == SOCKET_ERROR) {
            printf("send() failed with error: %d\n", WSAGetLastError());
            closesocket((int)sd);
            WSACleanup();
            exit(1);
        }

        do {
            err = recv((int)sd, buff, sizeof(buff) - 1, 0);
            if ( err > 0 )
                printf("Bytes received: %d\n", err);
            else if ( err == 0 )
                printf("Connection closed\n");
            else
                printf("recv failed with error: %d\n", WSAGetLastError());

        } while( err > 0 );


    }else{
        // SSL Connections
        err = SSL_write (ssl, msg, len + strlen(datos)); CHK_SSL(err);

        err = SSL_read (ssl, buff, sizeof(buff) - 1);
        CHK_SSL(err);
        buff[err] = '\0';

        SSL_shutdown (ssl);
    }

    strcpy(respuesta, buff);

    return ret;

}

Thursday, February 7, 2008

Create a certificate based on private key file

Well, this is another example of using OpenSSL API from Visual C++. In this case I needed to create a certificate from a private key file generated from openssl command line.

It isn’t so difficult, because is too similar to another examples have been told here before.

Bellow I list the code necessary to do this:

/* serv.cpp - Little SSL Server for Windows 01/02/2008 ccalvo@indra.es*/
/* working with openssl-0.9.8g */


#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/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>


#include <openssl/conf.h>
#include <openssl/x509v3.h>
#ifndef OPENSSL_NO_ENGINE
#include <openssl/engine.h>
#endif

int mkcert(X509 **x509p, RSA *rsa, int bits, int serial, int days);
int add_ext(X509 *cert, int nid, char *value);


/* Key Home */
#define HOME "./"
/* Key File */
#define KEYF HOME "mikey.des"

/* Check functions */
#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;

// Login information Callback
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 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;
X509* x509=NULL;
char* str;
char buf [4096];
SSL_METHOD *meth;
WORD wVersionRequested;
WSADATA wsaData;
FILE *privKey=NULL;
RSA *rsaPrivKey = NULL;
BIO *bio_err;
char pass[8]="carlos\n";

/* Open SSL Init */

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);
}

// Reading private Key from file
privKey=fopen(KEYF,"r");
if(privKey){
    rsaPrivKey = PEM_read_RSAPrivateKey(privKey, &rsaPrivKey, (pem_password_cb *)pass_cb, pass);
    fclose(privKey);
}

CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);

bio_err=BIO_new_fp(stderr, BIO_NOCLOSE);

// Creating a certificate
mkcert(&x509,rsaPrivKey,512,0,365);

// Keeping Key and Cert in the ctx
SSL_CTX_use_RSAPrivateKey(ctx, rsaPrivKey);
SSL_CTX_use_certificate(ctx, x509);

// clearing key and cert
X509_free(x509);
RSA_free(rsaPrivKey);

// checking key is valid to cert
if (!SSL_CTX_check_private_key(ctx)) {
    fprintf(stderr,"The private key don’t match with cert public key\n");
    exit(5);
}

/*****************************************************/
/*                                                   */
/* Init Sockets Layer */
/*                                                   */
/*****************************************************/



wVersionRequested = MAKEWORD( 1, 1 );
err = WSAStartup(wVersionRequested, &wsaData );
if ( err != 0 )
{
    printf("///WSAStartup Error//%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 (1111); /* Puerto del Servidor */

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);

/*****************************************************/
/*                                                   */
/* Setting SSL */
/*                                                   */
/*****************************************************/


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

/* Show cipher information - optional */

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

/* Getting client cert, if exist - optional */

client_cert = SSL_get_peer_certificate (ssl);
if (client_cert != NULL) {
    printf ("Client Cert:\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 can check all we want about client cert, before freeing. */

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

/* Messaging exchange */

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 to you.", strlen("I’m listening to you.")); CHK_SSL(err);

/* Freeing resources */

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

CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);

CRYPTO_mem_leaks_fp(stderr);
#ifndef OPENSSL_NO_ENGINE
    ENGINE_cleanup();
#endif

BIO_free(bio_err);

return(0);
}

void callback(int p, int n, void *arg)
{
char c='B';

if (p == 0) c='.';
if (p == 1) c='+';
if (p == 2) c='*';
if (p == 3) c='\n';
fputc(c,stderr);
}

int mkcert(X509 **x509p, RSA *rsa, int bits, int serial, int days)
{
X509 *x;
EVP_PKEY *pk;

X509_NAME *name=NULL;

if ((pk=EVP_PKEY_new()) == NULL)
{
    abort();
    return(0);
}


if ((x509p == NULL) (*x509p == NULL))
{
    if ((x=X509_new()) == NULL)
        goto err;
}
else
x= *x509p;

if (!EVP_PKEY_assign_RSA(pk,rsa))
{
    abort();
    goto err;
}
rsa=NULL;

X509_set_version(x,2);
ASN1_INTEGER_set(X509_get_serialNumber(x),serial);
X509_gmtime_adj(X509_get_notBefore(x),0);
X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);
X509_set_pubkey(x,pk);

name=X509_get_subject_name(x);

/* This function creates and adds the entry, working out the
* correct string type and performing checks on its length.
* Normally we'd check the return value for errors...
*/

X509_NAME_add_entry_by_txt(name,"C",
MBSTRING_ASC, (unsigned char*)"ES", -1, -1, 0);
X509_NAME_add_entry_by_txt(name,"CN",
MBSTRING_ASC, (unsigned char*)"MyCompany", -1, -1, 0);

/* Its self signed so set the issuer name to be the same as the
* subject.
*/

X509_set_issuer_name(x,name);

/* Add various extensions: standard extensions */
add_ext(x, NID_basic_constraints, "critical,CA:TRUE");
add_ext(x, NID_key_usage, "critical,keyCertSign,cRLSign");

add_ext(x, NID_subject_key_identifier, "hash");

/* Some Netscape specific extensions */
add_ext(x, NID_netscape_cert_type, "sslCA");

add_ext(x, NID_netscape_comment, "example comment extension");


#ifdef CUSTOM_EXT
/* Maybe even add our own extension based on existing */
{
int nid;
nid = OBJ_create("1.2.3.4", "MyAlias", "My Test Alias Extension");
X509V3_EXT_add_alias(nid, NID_netscape_comment);
add_ext(x, nid, "example comment alias");
}
#endif

if (!X509_sign(x,pk,EVP_md5()))
    goto err;

*x509p=x;
return(0);
err:
return(1);
}

/* Add extension using V3 code: we can set the config file as NULL
* because we wont reference any other sections.
*/


int add_ext(X509 *cert, int nid, char *value)
{
X509_EXTENSION *ex;
X509V3_CTX ctx;
/* This sets the 'context' of the extensions. */
/* No configuration database */

X509V3_set_ctx_nodb(&ctx);
/* Issuer and subject certs: both the target since it is self signed,
* no request and no CRL
*/

X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex)
    return 0;

X509_add_ext(cert,ex,-1);
X509_EXTENSION_free(ex);
return 1;
}


If you want to download the VC++ proyect click here.

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

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