Showing posts with label PEM_read_RSAPrivateKey. Show all posts
Showing posts with label PEM_read_RSAPrivateKey. Show all posts

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.

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