dear all
i'm a Msc student that uses NS3 simulator to do some researches. my target
for right now is to make a sample code for a client and a server then add
it to the simulator
as a brief
1-the client send a certificate request and the server send the certificate
to the client
2- the client create a shared key and encrypt it using function
RSA_public_encrypt and create some data and sign the data and encrypted
shared key and send (client certificate and the data and the encrypted
shared key and the sign (of both encrypted shared key and the data)) to the
server side
3- the server will verify the certificate and decrypt the encrypted shared
key using its private key. and verify the sign using the public key
extracted from the client certificate
i have created the certificate and its working well and verified and the
encrypted shared key is done
my problem is
1- how to sign both the data and encrypted shared key with the private key
of the client even i have only RSA structure
2- the encrypted shared key should be encrypted by the public key of the
server which can be extracted from the server certificate but the method it
self RSA_public_encrypt got RSA structure as an argument
3-how can i verify the sign
do i need to make all of the data and encrypted shared key to digest then
sign it ???? even i don't separated private and public key i have only RSA
structure and how to do that
thanks allot for help
--
Warmest regards and best wishes for a good health,*urs sincerely *
*mero*
//============================================================================
// Name : certificate.cpp
// Author : Amir
// Version :
// Copyright : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================
#include <iostream>
#include "server.h"
#include "client.h"
using namespace std;
int main()
{
clock_t start, end;
double msecs;
start = clock();
Client clientest;
Server servertest;
X509 *cert;
cert = servertest.CreateCertificate(clientest.MakeSignedCertReq());
clientest.SetCert(cert);
clientest.CertConverter();
X509 *test;
test = clientest.GetCert();
servertest.CheckCert(cert);
int serial = 0;
serial = clientest.ExtractCertSerial();
cout<<"client serial is "<<serial<<endl;
clientest.SetSharedKey();
clientest.EncryptSharedKey();
clientest.SetData(DATA_SIZE);
clientest.SignData();
clientest.SetDigestData(DATA_SIZE,RSA_KEY_SIZE);
X509 *certtest = NULL;
unsigned char data[DATA_SIZE];
unsigned char signeddata[RSA_KEY_SIZE];
servertest.client->GetData(certtest,data,DATA_SIZE,signeddata,RSA_KEY_SIZE);
//int serverserial = 0;
//serverserial = servertest.ExtractCertSerial();
//cout<<"server serial is "<<serverserial<<endl;
end = clock();
msecs = ((double) (end - start)) * 1000 / CLOCKS_PER_SEC;
cout<<"time is "<<msecs<<"msec"<<endl;
return 0;
}
/*
* client.cc
*
* Created on: Sep 17, 2014
* Author: amirale32
*/
#include "client.h"
Client :: Client()
{
m_myCertReq = X509_REQ_new();
m_myCert = X509_new();
m_name = X509_NAME_new();
m_rsa_keyPair = RSA_new();
m_puk = EVP_PKEY_new();
GenerateRSAKeyPair();
}
Client :: ~Client()
{
X509_REQ_free(m_myCertReq);
X509_free(m_myCert);
RSA_free(m_rsa_keyPair);
}
void
Client :: GenerateRSAKeyPair ( )
{
m_rsa_keyPair = RSA_generate_key((8*RSA_KEY_SIZE),RSA_F4,NULL,NULL);
BIO *pubout = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "clrsa.pem";
pubout = BIO_new_file(szPath,"wb");
PEM_write_bio_RSAPublicKey (pubout , m_rsa_keyPair);
BIO_free(pubout);
}
void
Client::SetPublicKey()
{
EVP_PKEY_assign_RSA(m_puk,m_rsa_keyPair);
BIO *out = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "cpuky.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_PUBKEY(out,m_puk);
}
X509_REQ*
Client::MakeSignedCertReq()
{
//adds all digest algorithms to the table
OpenSSL_add_all_digests();
SetPublicKey();
//include the public key in the req
X509_REQ_set_pubkey(m_myCertReq,m_puk);
//set the subject name of the request
m_name=X509_REQ_get_subject_name(m_myCertReq);
//set the request
X509_NAME_add_entry_by_txt(m_name,"C",MBSTRING_ASC, (const unsigned char *)"UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_name,"CN",MBSTRING_ASC, (const unsigned char *)"OpenSSL Group", -1, -1, 0);
//sign the req
X509_REQ_sign(m_myCertReq,m_puk,EVP_sha1());
BIO *out = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "req.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_X509_REQ(out,m_myCertReq);
BIO_free(out);
return m_myCertReq;
}
void
Client::SetCert(X509 *cert)
{
m_myCert = cert;
BIO *out = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "clcrt.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_X509 (out , cert);
}
int
Client::CertConverter()
{
int len = i2d_X509(m_myCert, NULL);
unsigned char *buf, *p;
buf = (unsigned char *)OPENSSL_malloc(len);
p = buf;
i2d_X509(m_myCert, &p);
unsigned char certarray[len];
for (int i = 0 ; i<len ; i++)
{
certarray[i] = *(p-len+i);
}
cout<<"cert len is "<<len<<endl;
cout << "converted client cert is"<<endl;
for (int j = 0 ; j<len ; j++)
{
printf("0x%.2x ", certarray[j]);
}
cout<<endl;
X509 *certtest;
unsigned char *buf1;
buf1 = certarray;
const unsigned char *p1 = buf1;
p1 = buf1;
certtest = d2i_X509(NULL, &p1, CERT_SIZE);
FILE * fcert;
fcert = fopen("certarray.pem", "wb");
PEM_write_X509(
fcert, //write the certificate to the file we've opened
certtest //our certificate
);
return 0;
}
X509*
Client::GetCert()
{
return m_myCert;
}
int
Client::ExtractCertSerial()
{
int serial = 0;
unsigned char **out = NULL;
ASN1_INTEGER *asn1_serial = NULL;
asn1_serial = X509_get_serialNumber(m_myCert);
serial = i2d_ASN1_INTEGER(asn1_serial, out);
return (serial);
}
void
Client::SetDigestData(int datasize, int keysize)
{
for (int i = 0; i<datasize ; i++)
{
m_digestData[i] = m_Data[i];
}
for (int j = 0 ; j <keysize ; j++ )
{
m_digestData[(datasize+j)] = m_encryptedSharedKey[j];
}
cout <<"digest data is"<<endl;
for (int k = 0 ; k< (datasize + keysize ); k++)
{
printf("0x%.2x ", m_digestData[k]);
}
cout<<endl;
}
void
Client::CreateDigest()
{
}
void
Client::SetData(int size)
{
cout<<"data is "<<endl;
for (int i = 0 ; i<size ; i++)
{
m_Data[i]=i;
printf("0x%.2x ", m_Data[i]);
}
cout<<endl;
}
void
Client::SignData()
{
int padding = RSA_PKCS1_PADDING;
RSA_private_encrypt(DATA_SIZE, m_Data, m_signedData, m_rsa_keyPair , padding);
cout<<"sign data is "<<endl;
for (int i = 0 ; i <RSA_KEY_SIZE;i++)
{
printf("0x%.2x ", m_signedData[i]);
}
cout<<endl;
}
void
Client::SetSharedKey()
{
cout<<"shared key is "<<endl;
for (int i = 0; i<SHARED_KEY_SIZE ; i++)
{
m_sharedKey[i] = i;
printf("0x%.2x ", m_sharedKey[i]);
}
cout<<endl;
}
void
Client::EncryptSharedKey()
{
int padding = RSA_PKCS1_PADDING;
RSA_public_encrypt(SHARED_KEY_SIZE,m_sharedKey,m_encryptedSharedKey,m_rsa_keyPair,padding);
cout<<"encrypted shared key is "<<endl;
for (int i = 0 ; i<RSA_KEY_SIZE ; i++)
{
printf("0x%.2x ", m_encryptedSharedKey[i]);
}
cout<<endl;
}
void
Client::GetData(X509* cert, unsigned char data[], int datasize,unsigned char signeddata[], int signsize)
{
cert = GetCert();
for(int i = 0 ; i< datasize ; i++)
{
data [i] = m_Data[i];
}
for (int j = 0 ; j<signsize ; j++)
{
signeddata[j] = m_signedData[j];
}
}
/*
* client.h
*
* Created on: Sep 17, 2014
* Author: amirale32
*/
#ifndef CLIENT_H_
#define CLIENT_H_
#define MAX_FILE_NAME_SIZE 20
#define RSA_KEY_SIZE 256 //bytes
#define CERT_SIZE 727
#define SHARED_KEY_SIZE 32 //bytes
#define DATA_SIZE 13
#include <stdlib.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "server.h"
class Client
{
public:
Client();
~Client();
void GenerateRSAKeyPair ();
void SetPublicKey ();
X509_REQ *MakeSignedCertReq();
void SetCert (X509 *cert);
X509 *GetCert();
int CertConverter ();
int ExtractCertSerial ();
void SetSharedKey();
void EncryptSharedKey();
void SetDigestData(int datasize,int keysize);
void CreateDigest();
void SetData(int size);
void SignData();
void GetData(X509 *cert,unsigned char data[],int datasize, unsigned char signeddata[],int signsize );
private:
X509_REQ *m_myCertReq;
X509 *m_myCert;
X509_NAME *m_name;
RSA *m_rsa_keyPair;
EVP_PKEY *m_puk;
unsigned char m_Data[DATA_SIZE];
unsigned char m_signedData[RSA_KEY_SIZE ];
unsigned char m_encryptedSharedKey[RSA_KEY_SIZE];
unsigned char m_sharedKey[SHARED_KEY_SIZE];
unsigned char m_digestData[DATA_SIZE+RSA_KEY_SIZE];
unsigned char m_digestOutput[256];
};
#endif /* CLIENT_H_ */
#include "server.h"
Server::Server()
{
m_myCert = X509_new();
m_caKeyPairs = RSA_new();
m_pukey = EVP_PKEY_new();
m_issuerName = X509_NAME_new();
GenerateMyKeyPairs();
CreateMyCertificate();
}
Server::~Server()
{
X509_free(m_myCert);
RSA_free(m_caKeyPairs);
X509_NAME_free(m_issuerName);
}
X509*
Server::CreateCertificate(X509_REQ* req)
{
X509 *m_req_reply;
m_req_reply = X509_new();
X509_NAME *subject = NULL;
EVP_PKEY *pkey = NULL;
//check Request signature matches the certificate request
pkey = X509_REQ_get_pubkey(req);
ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2);
X509_gmtime_adj(X509_get_notBefore(m_req_reply), 0);
X509_gmtime_adj(X509_get_notAfter(m_req_reply), 31536000L);
X509_set_pubkey(m_req_reply, pkey);
X509_NAME *issuerSubject = X509_get_subject_name(m_myCert);
X509_set_issuer_name(m_req_reply, issuerSubject);
//extract the subject of the request
subject = X509_REQ_get_subject_name(req);
X509_set_subject_name(m_req_reply, subject);
X509_get_subject_name(m_req_reply);
X509_sign(m_req_reply, m_pukey, EVP_sha1());
return m_req_reply;
}
void
Server::CreateMyCertificate()
{
// we use rsa pairs and assign it into evp_key
SetPublicKey();
// properties of the certificate
//set the serial number
ASN1_INTEGER_set(X509_get_serialNumber(m_myCert), 1);
//set the time validity
X509_gmtime_adj(X509_get_notBefore(m_myCert), 0);
X509_gmtime_adj(X509_get_notAfter(m_myCert), 31536000L);
//set the public key of the cert to be signed
X509_set_pubkey(m_myCert, m_pukey);
//this is a self-signed certificate, we set the name of the issuer to the name of the subject
m_issuerName = X509_get_subject_name(m_myCert);
X509_NAME_add_entry_by_txt(m_issuerName, "C", MBSTRING_ASC,
(unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "O", MBSTRING_ASC,
(unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
//set the issuer name
X509_set_issuer_name(m_myCert, m_issuerName);
//sign the cert
X509_sign(m_myCert, m_pukey, EVP_sha1());
FILE * fcert;
fcert = fopen("cacert.pem", "wb");
PEM_write_X509(
fcert, /* write the certificate to the file we've opened */
m_myCert /* our certificate */
);
}
void
Server::GenerateMyKeyPairs()
{
m_caKeyPairs = RSA_generate_key((8*RSA_KEY_SIZE),RSA_F4 , NULL , NULL);
BIO *pubout = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "carsa.pem";
pubout = BIO_new_file(szPath,"wb");
PEM_write_bio_RSAPublicKey (pubout , m_caKeyPairs);
BIO_free(pubout);
}
void
Server::SetPublicKey()
{
EVP_PKEY_assign_RSA(m_pukey,m_caKeyPairs);
BIO *out = NULL;
const char szPath[MAX_FILE_NAME_SIZE] = "caevp.pem";
out = BIO_new_file(szPath,"wb");
EVP_PKEY_print_private(out, m_pukey,
0, NULL);
BIO_free(out);
out = BIO_new_file("prkey.pem","wb");
PEM_write_bio_PrivateKey(
out, /* write the key to the file we've opened */
m_pukey, /* our key from earlier */
EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
(unsigned char *)"replace_me", /* passphrase required for decrypting the key on disk */
10, /* length of the passphrase string */
NULL, /* callback for requesting a password */
NULL /* data to pass to the callback */
);
}
int
Server::CheckCert(X509* clientcert)
{
int status = 0;
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
//store the trusted cert into ctx
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, m_myCert);
//put the trusted cert and cert then verify it
X509_STORE_CTX_init(ctx,store, clientcert, NULL);
status = X509_verify_cert(ctx);
if (status == 1)
{
cout<<"verified succesfully"<<endl;
}
else
{
cout<<"verifiy fail"<<endl;
cout << X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
}
return status;
}
bool
Server::CheckData(X509 *clientcert,unsigned char data[],int datasize, unsigned char signeddata[],int signsize)
{
bool certstatus;
bool signstatus;
if (CheckCert(clientcert) == 1)
{
certstatus = true;
}
else
{
certstatus = false;
}
if ((certstatus && signstatus) == true)
{
return true;
}
return false;
}
/*
* server.cc
*
* Created on: Sep 17, 2014
* Author: amirale32
*/
/*
* server.h
*
* Created on: Sep 17, 2014
* Author: amirale32
*/
#ifndef SERVER_H_
#define SERVER_H_
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include "client.h"
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#define MAX_FILE_NAME_SIZE 20
#define RSA_KEY_SIZE 256 //bytes
#define CERT_SIZE 727
#define DATA_SIZE 13
using namespace std;
class Client;
class Server
{
public:
Server();
~Server();
X509 *CreateCertificate (X509_REQ *req);
void CreateMyCertificate();
void GenerateMyKeyPairs ( );
void SetPublicKey ();
int CheckCert (X509 *clientcert);
bool CheckData(X509 *cert,unsigned char data[],int datasize, unsigned char signeddata[],int signsize);
Client *client;
private:
X509 *m_myCert;
RSA *m_caKeyPairs;
EVP_PKEY *m_pukey;
X509_NAME *m_issuerName;
};
#endif /* SERVER_H_ */