/* $Id: PKI_Examples.c $ */
/*
This source code carries out a series of tests on the
functions in the CryptoSys PKI Toolkit.
The tests in themselves are pretty boring. Use the examples
as the basis for your hopefully-more-useful code.
It is not meant to be representative of good security coding.
There is minimal error checking here - we use assert as a blunt instrument -
and we make little or no effort to clean up passwords etc afterwards.
In particular, we save and display unencrypted private keys here to demonstrate certain techniques.
This should *never* be done in a real production program.
ALWAYS use the encrypted form and keep the private key string secret.
Use in conjunction with diCrPKI.lib and diCrPKI.dll (Version 2.9 or later).
Copyright (C) 2004-6 DI Management Services Pty Limited. All rights reserved.
Last updated:
$Date: 2006-08-09 05:51:00 $
$Revision: 2.9.0 $
*/
#if _MSC_VER >= 1100
/* Detect memory leaks in MSVC++ */
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#else
#include <stdlib.h>
#endif
#include "diCrPKI.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
/* COMPILER-SPECIFIC explicit link to library in same dir as this source.
* This works in MSVC and Borland - you may need to do otherwise
* to link to the library.
*/
#pragma comment(lib, ".\\diCrPKI.lib")
/* SYSTEM-SPECIFIC DIR FNS:
* Used in `make_new_test_dir' and `remove_test_dir' only.
*/
#ifdef unix
#define DELCMD "rm"
#else
#define DELCMD "DEL"
#endif
#ifdef _MSC_VER
/* MSVC functions */
#include <direct.h>
#define MKDIR(d) _mkdir(d)
#define CHDIR(d) _chdir(d)
#define RMDIR(d) _rmdir(d)
#define GETCWD(od, n) _getcwd(od, n)
#elif __BORLANDC__
/* Borland functions */
#include <dir.h>
#define MKDIR(d) mkdir(d)
#define CHDIR(d) chdir(d)
#define RMDIR(d) rmdir(d)
#define GETCWD(od, n) getcwd(od, n)
#elif unix
/* Linux functions */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#define MKDIR(d) mkdir(d, 0777)
#define CHDIR(d) chdir(d)
#define RMDIR(d) rmdir(d)
#define GETCWD(od, n) getcwd(od, n)
#else
/* Take a punt the compiler has inbuilt fns or die!
-- replace with your own here if necessary */
#define MKDIR(d) mkdir(d)
#define CHDIR(d) chdir(d)
#define RMDIR(d) rmdir(d)
#define GETCWD(od, n) getcwd(od, n)
#endif
/* Global variables */
char testdir[FILENAME_MAX];
char old_cwd[FILENAME_MAX];
char new_cwd[FILENAME_MAX];
int make_new_test_dir(void)
{
/* Added in Ver 2.2:
(1) Try and create a sub-dir in current working dir
(2) If that fails, use _tempnam
*/
unsigned char rbytes[4];
char hex[9];
/* Use PKI to generate a random address */
RNG_Bytes(rbytes, sizeof(rbytes), NULL, 0);
HASH_HexFromBytes(hex, sizeof(hex)-1, rbytes, sizeof(rbytes), 0);
/* Create a test directory */
sprintf(testdir, "pkitest.%s", hex);
printf("Trying to create test directory '%s'...\n", testdir);
/* Use system-specific fns to create and set as default dir */
if (MKDIR(testdir) != 0)
#ifdef _MSC_VER
{ /* Check added in version 2.2 in case we run this where we don't have permission */
char *tempname;
printf("Unable to create test directory '%s'. Trying with _tempnam...\n", testdir);
/* Now try using _tempnam (making a copy) */
tempname = _tempnam("\\", "pki");
strncpy(testdir, tempname, FILENAME_MAX-1);
free(tempname); /* _tempnam uses malloc */
if (MKDIR(testdir) != 0)
{
fprintf(stderr, "ERROR: unable to create a temp directory.");
exit(EXIT_FAILURE);
}
}
#else /* If not MSVC, we have just failed */
{
fprintf(stderr, "ERROR: unable to create a temp directory.");
exit(EXIT_FAILURE);
}
#endif
printf("Created test directory '%s' OK.\n", testdir);
/* Remember current working directory */
GETCWD(old_cwd, FILENAME_MAX-1);
/* Change CWD to our new temp dir */
CHDIR(testdir);
/* And check */
GETCWD(new_cwd, FILENAME_MAX-1);
printf("Current dir is '%s'\n", new_cwd);
return 0;
}
void remove_test_dir(char *dirname, char *old_cwd)
{
/* Use system commands to do the business
--see DELCMD macro above (NB strings concatenate) */
/* CAUTION: Use this carefully */
int res;
CHDIR(dirname);
system (DELCMD" *.txt");
system (DELCMD" *.cer");
system (DELCMD" *.bin");
system (DELCMD" *.p7*");
system (DELCMD" *.pfx");
system (DELCMD" *.xml");
/* Changed in Ver 2.2 to use stored CWD */
if (!old_cwd)
CHDIR("..");
else
CHDIR(old_cwd);
res = RMDIR(dirname);
if (res == 0)
printf("Removed test directory OK.\n");
else
printf("ERROR: (%d) failed to remove test directory.\n", res);
}
void create_test_files(void)
/* Create the test files we expect to find */
{
FILE *fp;
/* 1. SafeToDelete.txt */
fp = fopen("!ThisFolderIsSafeToDelete.txt", "wb");
assert(fp != NULL);
fprintf(fp, "This folder has been created by the CryptoSys PKI test program.\nIt can be safely deleted at any time.");
fclose(fp);
/* 2. Excontent.txt */
fp = fopen("excontent.txt", "wb");
assert(fp != NULL);
fprintf(fp, "This is some sample content.");
fclose(fp);
}
char *lookup_error(int errcode)
/* Looks up description of error msg and returns
ptr to static string
*/
{
static char errmsg[128];
errmsg[0] = '\0';
PKI_ErrorLookup(errmsg, sizeof(errmsg), errcode);
return errmsg;
}
static void disp_error(long result)
{
char szErrMsg[512];
long errcode;
PKI_LastError(szErrMsg, sizeof(szErrMsg)-1);
errcode = PKI_ErrorCode();
printf("ERROR Returned=%ld/ErrorCode=%ld: %s; %s\n", result, PKI_ErrorCode(),
lookup_error(errcode), szErrMsg);
}
static void pr_bytes(unsigned char *bytes, long nbytes)
{
long i;
for (i = 0; i < nbytes; i++)
{
if (i && (i % 32) == 0)
printf("\n");
else if (i && (i % 4) == 0)
printf(" ");
printf("%02x", *bytes++);
}
printf("\n");
}
static int cmp_files(char *file1, char *file2)
/* Compares two binary files: returns 0 if identical
or 1 if not identical or -1 if file error */
{
FILE *fp1, *fp2;
int c1, c2;
int result = 0; /* Innocent until proven guilty */
fp1 = fopen(file1, "rb");
if (fp1 == NULL)
return -1;
fp2 = fopen(file2, "rb");
if (fp2 == NULL)
{
fclose(fp1);
return -1;
}
while ((c1 = fgetc(fp1)) != EOF)
{
c2 = fgetc(fp2);
if (c2 == EOF)
{ /* File 2 is shorter than file 1 */
result = 1;
break;
}
if (c1 != c2)
{ /* Found a mis-match */
result = 1;
break;
}
}
if (feof(fp1))
{ /* Make sure file2 is same length */
if ((c2 = fgetc(fp2)) != EOF)
result = 1;
}
fclose(fp1);
fclose(fp2);
return result;
}
void show_version(void)
{
/* Changed in version 2.8: nMajor and nMinor no longer set and
PKI_Version now returns Major * 100 + Minor * 10 + Release
*/
long lRet;
/*long nMajor, nMinor;*/
char timestamp[256];
/*lRet = PKI_Version(&nMajor, &nMinor);*/
lRet = PKI_Version(NULL, NULL);
assert(lRet > 0);
printf("PKI_Version=%ld\n", lRet);
lRet = PKI_LicenceType(0);
assert(lRet > 0);
printf("PKI_LicenceType: %c\n", (char)lRet);
lRet = PKI_CompileTime(timestamp, sizeof(timestamp)-1);
assert(lRet > 0);
printf("Last Compiled [%s]\n", timestamp);
}
void carol_creates_keys(void)
/* Carol creates a 1024-bit RSA key pair with
the private key encrypted with password 'password'
*/
{
char *pubfile = "carol_pub.bin";
char *epkfile = "carol_epk.bin";
char *szPassword = "password";
long result;
time_t start, finish;
double duration;
printf("\nCarol creates a 1024-bit RSA key pair...\n");
start = clock();
result = RSA_MakeKeys(pubfile, epkfile, 1024, PKI_RSAEXP_EQ_65537, 50,
1000, szPassword, NULL, 0, PKI_KEYGEN_INDICATE);
finish = clock();
assert(result == 0);
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Time=%.3lf secs\n", duration);
printf("...created key files '%s' and '%s'\n", pubfile, epkfile);
}
void carol_creates_ca_cert(void)
{
char *certfile = "carol.cer";
char *epkfile = "carol_epk.bin";
char *password = "password";
char *distname = "C=AU;O=Example Corp;CN=Carol";
long result;
printf("\nCarol creates a self-signed CA certificate...\n");
/* Make an self-signed cert No. 1 valid for 10 years */
result = X509_MakeCertSelf(certfile, epkfile,
1, 10, distname, NULL, 0, password, PKI_X509_CA_TRUE);
assert(result == 0);
printf("Created self-signed X.509 certificate '%s'\n", certfile);
}
void ann_and_ben_create_keys(void)
/* Ann and Ben both create 512-bit key pairs
(NB we use 512 for speed in this demo)
both using 'password' as the password
(but they don't tell each other or Carol this fact!)
Ben's private key is secured using "pkcs5PBES2"/"des-EDE3-CBC"
instead of the default "pbeWithSHAAnd3-KeyTripleDES-CBC".
*/
{
char *annpubfile = "ann_pub.bin";
char *annepkfile = "ann_epk.bin";
char *benpubfile = "ben_pub.bin";
char *benepkfile = "ben_epk.bin";
char *szPassword = "password";
long keybits = 512;
long result;
time_t start, finish;
double duration;
printf("\nCreating 512-bit key pair for Ann...\n");
start = clock();
result = RSA_MakeKeys(annpubfile, annepkfile, keybits, PKI_RSAEXP_EQ_5, 50,
1000, szPassword, NULL, 0, 0);
finish = clock();
assert(result == 0);
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Time=%.3lf secs\n", duration);
printf("...created key files '%s' and '%s'\n", annpubfile, annepkfile);
printf("\nCreating 512-bit key pair for Ben...\n");
start = clock();
result = RSA_MakeKeys(benpubfile, benepkfile, keybits, PKI_RSAEXP_EQ_3, 50,
1000, szPassword, NULL, 0, PKI_PBES2_3DES);
finish = clock();
assert(result == 0);
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Time=%.3lf secs\n", duration);
printf("...created key files '%s' and '%s'\n", benpubfile, benepkfile);
}
void carol_makes_certs_for_ann_and_ben(void)
{
long result;
char *acertfile = "ann.cer";
char *bcertfile = "ben.cer";
char *issuercert = "carol.cer";
char *epkfile = "carol_epk.bin";
char *szPassword = "password";
printf("\nCarol makes X.509 certificates for Ann and Ben...\n");
/* Make two end-user certs valid for 2 years, signed by Carol */
result = X509_MakeCert(acertfile, issuercert, "ann_pub.bin", epkfile,
0x101, 2, "C=AU;O=Example Corp;CN=Ann", NULL, 0, szPassword, 0);
assert(result == 0);
printf("Created end-user X.509 certificate '%s'\n", acertfile);
result = X509_MakeCert(bcertfile, issuercert, "ben_pub.bin", epkfile,
0x102, 2, "C=AU;O=Example Corp;CN=Ben", "ben@example.com", 0, szPassword,
PKI_SIG_MD5RSA);
assert(result == 0);
printf("Created end-user X.509 certificate '%s'\n", bcertfile);
}
void ben_tests_his_keys_in_the_raw(void)
/* Ben uses the "raw" RSA functions to encrypt and sign some random data */
{
long result;
char *pubfile = "ben_pub.bin";
char *epkfile = "ben_epk.bin";
char *szPassword = "password";
long datalen;
unsigned char *data, *copy;
char *pubkeystr, *prikeystr;
long klen;
printf("\nBen tests his keys using the 'raw' RSA functions...\n");
/* Read in the keys to strings */
klen = RSA_ReadPublicKey(NULL, 0, pubfile, 0);
assert(klen > 0);
pubkeystr = malloc(klen+1); /* NB one extra */
assert(pubkeystr != NULL);
result = RSA_ReadPublicKey(pubkeystr, klen, pubfile, 0);
assert(result == klen);
klen = RSA_ReadEncPrivateKey(NULL, 0, epkfile, szPassword, 0);
assert(klen > 0);
prikeystr = malloc(klen+1); /* NB one extra */
assert(prikeystr != NULL);
result = RSA_ReadEncPrivateKey(prikeystr, klen, epkfile, szPassword, 0);
assert(result == klen);
/* Generate some random data, m, to test it with */
datalen = RSA_KeyBytes(pubkeystr);
data = malloc(datalen);
assert(data != NULL);
result = RNG_Bytes(data, datalen, "", 0);
assert (result == 0);
/* But make sure m < n */
data[0] = 0x0;
printf("Random data (%ld bytes)=\n", datalen);
pr_bytes(data, datalen);
/* Keep a copy for testing */
copy = malloc(datalen);
assert(copy != NULL);
memcpy(copy, data, datalen);
/* Encrypt with the public key */
result = RSA_RawPublic(data, datalen, pubkeystr, 0);
assert (result == 0);
printf("Encrypted data=\n");
pr_bytes(data, datalen);
/* Decrypt with the private key */
result = RSA_RawPrivate(data, datalen, prikeystr, 0);
/* check */
if (memcmp(copy, data, datalen) == 0)
printf("Encrypt/decrypt worked OK\n");
else
printf("Encrypt/decrypt FAILED!\n");
/* Sign: Encrypt with the private key */
result = RSA_RawPrivate(data, datalen, prikeystr, 0);
assert (result == 0);
printf("Signed data=\n");
pr_bytes(data, datalen);
/* Verify: Decrypt with the public key */
result = RSA_RawPublic(data, datalen, pubkeystr, 0);
/* check */
if (memcmp(copy, data, datalen) == 0)
printf("Sign/verify worked OK\n");
else
printf("Sign/verify FAILED!\n");
/* Make sure we wipe the private key string */
WIPE_Data(prikeystr, strlen(prikeystr));
free(copy);
free(data);
free(pubkeystr);
free(prikeystr);
}
void ann_sends_enc_msg_to_ben(void)
{
long result;
char *cmsfile = "cmsforben.p7m";
char *datafile = "excontent.txt";
char *bcertfile = "ben.cer";
printf("\nAnn sends an encrypted message to Ben...\n");
result = CMS_MakeEnvData(cmsfile, datafile, bcertfile, NULL, 0, 0);
/* NB expecting # recipients == 1 to be returned */
assert(result == 1);
printf("Created CMS enveloped-data file '%s'\n", cmsfile);
}
void ben_decrypts_msg_from_ann(void)
{
long result;
char *cmsfile = "cmsforben.p7m";
char *outfile = "textfromann.txt";
char *chkfile = "excontent.txt";
char *epkfile = "ben_epk.bin";
char *szPassword = "password";
char *prikeystr = NULL;
long klen;
printf("\nBen decryptes the message received from Ann...\n");
/* Get Ben's private key */
klen = RSA_ReadEncPrivateKey(NULL, 0, epkfile, szPassword, 0);
assert(klen > 0);
prikeystr = malloc(klen+1); /* NB one extra */
assert(prikeystr != NULL);
result = RSA_ReadEncPrivateKey(prikeystr, klen, epkfile, szPassword, 0);
assert(result == klen);
/* Decrypt the file */
result = CMS_ReadEnvData(outfile, cmsfile, NULL, prikeystr, 0);
if (!(result == 0)) disp_error(result);
assert(result == 0);
printf("Decrypted CMS enveloped-data to output file '%s'\n", outfile);
free(prikeystr);
/* Check we got what we started with */
if (cmp_files(outfile, chkfile) == 0)
printf("Decryption OK - files match.\n");
else
printf("Decryption failed - not what we started with!\n");
}
char *get_rsa_private_key(char *keyfile, char *password, long *pklen)
/* One-step wrapper function to get private key string from EPK file */
/* NB allocates memory - must be freed later by caller */
{
long klen;
char *key;
klen = RSA_ReadEncPrivateKey(NULL, 0, keyfile, password, 0);
if (klen <= 0) return NULL;
key = malloc(klen+1); /* NB one extra */
assert(key != NULL);
klen = RSA_ReadEncPrivateKey(key, klen, keyfile, password, 0);
/* If provided, set key length */
if (pklen) *pklen = klen;
return key;
}
void ann_sends_encmsg_ben_reads(void)
{
long result;
char *cmsfile = "forcarolandben.p7m";
char *bcertfile = "ben.cer";
char *certlist = "carol.cer;ben.cer";
char *msgtosend = "Be in bar at 7 pm wearing a red rose";
char *prikeystr = NULL;
char *msgrecvd;
long mlen;
printf("\nAnn sends an encrypted message and Ben reads it...\n");
/* Ann creates a CMS message file, this time from a string
that could be read by either Carol or Ben (see certlist) */
result = CMS_MakeEnvDataFromString(cmsfile, msgtosend, certlist, NULL, 0, 0);
/* NB expecting # recipients == 2 to be returned */
assert(result == 2);
printf("Created CMS enveloped-data file '%s'\n", cmsfile);
/* Ben reads it directly into a string, using his private key */
prikeystr = get_rsa_private_key("ben_epk.bin", "password", NULL);
assert(prikeystr != NULL);
/* How long is it? */
mlen = CMS_ReadEnvDataToString(NULL, 0, cmsfile, bcertfile, prikeystr, 0);
printf("CMS_ReadEnvDataIntoString returns %ld\n", mlen);
assert(mlen > 0);
msgrecvd = malloc(mlen+1); /* NB one extra */
mlen = CMS_ReadEnvDataToString(msgrecvd, mlen, cmsfile, bcertfile, prikeystr, 0);
assert(mlen > 0);
printf("Message is '%s'\n", msgrecvd);
/* Check they are the same */
result = strcmp(msgrecvd, msgtosend);
if (result == 0)
printf("SUCCESS: messages match.\n");
else
printf("ERROR: messages do not match!\n");
assert(result == 0);
/* clean up */
free(prikeystr);
free(msgrecvd);
}
void ann_sends_encr_base64_ben_reads(void)
{
long result;
char *cmsfile = "forbenp7m.txt";
char *bcertfile = "ben.cer";
char *msgtosend = "Be in bar at 7 pm wearing a red rose";
char *prikeystr = NULL;
char *msgrecvd;
long mlen;
printf("\nAnn sends an encrypted message in base64 format...\n");
/* Ann creates a CMS message file in base64 format */
result = CMS_MakeEnvDataFromString(cmsfile, msgtosend, bcertfile, NULL, 0, PKI_CMS_FORMAT_BASE64);
/* NB expecting # recipients == 1 to be returned */
assert(result == 1);
printf("Created CMS enveloped-data file '%s'\n", cmsfile);
/* Ben reads it directly into a string */
prikeystr = get_rsa_private_key("ben_epk.bin", "password", NULL);
assert(prikeystr != NULL);
/* How long is it? */
mlen = CMS_ReadEnvDataToString(NULL, 0, cmsfile, bcertfile, prikeystr, PKI_CMS_FORMAT_BASE64);
printf("CMS_ReadEnvDataIntoString returns %ld\n", mlen);
if (mlen <= 0) disp_error(mlen);
assert(mlen > 0);
msgrecvd = malloc(mlen+1); /* NB one extra */
mlen = CMS_ReadEnvDataToString(msgrecvd, mlen, cmsfile, bcertfile, prikeystr, PKI_CMS_FORMAT_BASE64);
if (mlen <= 0) disp_error(mlen);
assert(mlen > 0);
printf("Message is '%s'\n", msgrecvd);
/* Check they are the same */
result = strcmp(msgrecvd, msgtosend);
if (result == 0)
printf("SUCCESS: messages match.\n");
else
printf("ERROR: messages do not match!\n");
assert(result == 0);
/* clean up */
free(prikeystr);
free(msgrecvd);
}
void ann_signs_msg(void)
{
long result;
char *sigfile = "signedbyann.p7m";
char *infile = "excontent.txt";
char *epkfile = "ann_epk.bin";
char *certfile = "ann.cer";
char *szPassword = "password";
char *prikeystr = NULL;
long klen;
printf("\nAnn signs a message...\n");
prikeystr = get_rsa_private_key(epkfile, szPassword, &klen);
assert(prikeystr != NULL);
result = CMS_MakeSigData(sigfile, infile, certfile, prikeystr, 0);
if (result) disp_error(result);
assert(result == 0);
printf("Created CMS signed-data file '%s'\n", sigfile);
free(prikeystr);
}
void ben_verifies_msg_from_ann(void)
/* Actually could be verified by anybody who has Ann's cert */
{
char *sigfile = "signedbyann.p7m";
char *data = NULL;
long datalen;
char hexdigest[41];
char hashcontent[41];
long hashlen;
long hashalg;
printf("\nBen verifies the signed message received from Ann...\n");
/* 1. Get the content data out of the signed-data file */
datalen = CMS_ReadSigDataToString(NULL, 0, sigfile, 0);
printf("CMS_ReadSigDataToString returns %ld\n", datalen);
assert(datalen > 0);
data = malloc(datalen+1);
assert(data != NULL);
datalen = CMS_ReadSigDataToString(data, datalen, sigfile, 0);
printf("Signed content is '%s'\n", data);
/* 2. Get the message digest hash from signed-data */
hashalg = CMS_GetSigDataDigest(hexdigest, sizeof(hexdigest)-1, sigfile, NULL, 0);
printf("CMS_ReadSigDataToString returns %ld\n", datalen);
assert(hashalg >= 0);
printf("Signed digest = %s\n", hexdigest);
/* 3. Make an independent hash of content */
hashlen = HASH_HexFromBytes(hashcontent, sizeof(hashcontent)-1, data, datalen, hashalg);
printf("Content digest = %s\n", hashcontent);
/* 4. Compare the hash digests */
if (strncmp(hashcontent, hexdigest, hashlen) == 0)
printf("SUCCESS: Message digests match\n");
else
printf("FAILURE: digests do not match!\n");
/* Clean up */
free(data);
}
void ben_reads_signed_data(void)
/* Ben reads the signed-data from Ann, saving as a file */
{
char *sigfile = "signedbyann.p7m";
char *outfile = "signedfromann.txt";
char *origfile = "excontent.txt";
long result;
printf("\nBen reads the signed-data received from Ann...\n");
result = CMS_ReadSigData(outfile, sigfile, 0);
printf("CMS_ReadSigData returns %ld\n", result);
/* Compare this file with original */
result = cmp_files(outfile, origfile);
if (result == 0)
printf("SUCCESS: signed data matches original file\n");
else
printf("FAILURE: signed data does NOT match original file\n");
assert(result == 0);
}
void ann_signs_base64_ben_verifies(void)
/* Ann creates a signed-data object in base64 format; Ben verifies it. */
{
long result;
char *szContent = "This is some sample content.";
char *sigfile = "signedbyannp7m.txt";
char *epkfile = "ann_epk.bin";
char *certfile = "ann.cer";
char *szPassword = "password";
char *prikeystr = NULL;
long klen;
char *data = NULL;
long datalen;
char hexdigest[41];
char hashcontent[41];
long hashlen;
long hashalg;
printf("\nAnn creates a signed-data object in base64 format and Ben verifies it...\n");
prikeystr = get_rsa_private_key(epkfile, szPassword, &klen);
assert(prikeystr != NULL);
result = CMS_MakeSigDataFromString(sigfile, szContent, certfile, prikeystr, PKI_CMS_FORMAT_BASE64);
if (result) disp_error(result);
assert(result == 0);
printf("Created base64 CMS signed-data file '%s' from string\n", sigfile);
free(prikeystr);
/* 1. Get the content data out of the signed-data file */
datalen = CMS_ReadSigDataToString(NULL, 0, sigfile, PKI_CMS_FORMAT_BASE64);
printf("CMS_ReadSigDataToString returns %ld\n", datalen);
if (datalen <= 0) disp_error(datalen);
assert(datalen > 0);
data = malloc(datalen+1);
assert(data != NULL);
datalen = CMS_ReadSigDataToString(data, datalen, sigfile, PKI_CMS_FORMAT_BASE64);
if (datalen <= 0) disp_error(datalen);
assert(datalen > 0);
printf("Signed content is '%s'\n", data);
/* 2. Get the message digest hash from signed-data */
hashalg = CMS_GetSigDataDigest(hexdigest, sizeof(hexdigest)-1, sigfile, NULL, PKI_CMS_FORMAT_BASE64);
printf("CMS_GetSigDataDigest returns %ld\n", datalen);
if (hashalg < 0) disp_error(hashalg);
assert(hashalg >= 0);
printf("Signed digest = %s\n", hexdigest);
/* 3. Make an independent hash of content */
hashlen = HASH_HexFromBytes(hashcontent, sizeof(hashcontent)-1, data, datalen, hashalg);
printf("Content digest = %s\n", hashcontent);
/* 4. Compare the hash digests */
if (strncmp(hashcontent, hexdigest, hashlen) == 0)
printf("SUCCESS: Message digests match\n");
else
printf("FAILURE: digests do not match!\n");
/* Alternatively, just verify (new in version 2.8) */
result = CMS_VerifySigData(sigfile, "", "", PKI_CMS_FORMAT_BASE64);
printf("CMS_VerifySigData returns %ld (expecting 0 => verified signature and content OK)\n", result);
if (result != 0) disp_error(result);
assert(result == 0);
/* And while we're here, we'll query the signed data file (new v2.8) */
datalen = CMS_QuerySigData(NULL, 0, sigfile, "signatureAlgorithm", PKI_CMS_FORMAT_BASE64);
printf("CMS_QuerySigData returns %ld\n", datalen);
assert(datalen > 0);
data = realloc(data, datalen+1);
datalen = CMS_QuerySigData(data, datalen, sigfile, "signatureAlgorithm", PKI_CMS_FORMAT_BASE64);
printf("signatureAlgorithm='%s'\n", data);
/* Clean up */
free(data);
}
#define RAND_DATA_LEN 32
void ben_signs_det_msg(void)
{
char *detsigfile = "detsigbyben.p7s";
char *epkfile = "ben_epk.bin";
char *certfile = "ben.cer";
char *datafile = "datafromben.txt";
char data[RAND_DATA_LEN+1] = { 0 };
const int datalen = RAND_DATA_LEN;
char hexdigest[41];
char *prikey;
long klen;
long result;
int i, cr;
FILE *fp;
printf("\nBen signs a detached message...\n");
/* Ben creates some random text */
srand((unsigned)time(NULL));
for (i = 0; i < datalen; i++)
{
/* Random printable characters between 32 and 127 */
cr = (rand() % 95) + ' ';
data[i] = cr;
}
data[i] = 0;
printf("Ben's random text is '%s'\n", data);
/* Save to a file */
fp = fopen(datafile, "w");
assert(fp != NULL);
fwrite(data, 1, RAND_DATA_LEN, fp);
fclose(fp);
/* Compute hash digest using MD5 */
HASH_HexFromBytes(hexdigest, sizeof(hexdigest)-1, (unsigned char*)data, datalen, PKI_HASH_MD5);
printf("MD5(data)=%s\n", hexdigest);
/* Get private key */
prikey = get_rsa_private_key(epkfile, "password", &klen);
assert(prikey != NULL);
/* Make a detached signature file using MD5 */
result = CMS_MakeDetachedSig(detsigfile, hexdigest, certfile, prikey, PKI_HASH_MD5);
if (result != 0) disp_error(result);
printf("Created detached signature file '%s'\n", detsigfile);
free(prikey);
}
void ann_verifies_det_msg_from_ben(void)
/* Ben must send both the original content and the detached signature to ann */
{
char *datafile = "datafromben.txt";
char *detsigfile = "detsigbyben.p7s";
char *data = NULL;
long datalen;
char hexdigest[41];
char hashcontent[41];
long hashlen;
long hashalg;
FILE *fp;
printf("\nAnn verifies the detached signature received from Ben...\n");
/* 1. Get the content data out of the separate file */
fp = fopen(datafile, "r");
assert(fp != NULL);
for (datalen = 0; fgetc(fp) != EOF; datalen++)
;
rewind(fp);
data = malloc(datalen);
assert(data != NULL);
fread(data, 1, datalen, fp);
fclose(fp);
/* 2. Get the message digest hash from signed-data */
hashalg = CMS_GetSigDataDigest(hexdigest, sizeof(hexdigest)-1, detsigfile, NULL, 0);
printf("CMS_ReadSigDataToString returns %ld\n", datalen);
assert(hashalg >= 0);
printf("Signed digest = %s\n", hexdigest);
/* 3. Make an independent hash of content */
hashlen = HASH_HexFromBytes(hashcontent, sizeof(hashcontent)-1, data, datalen, hashalg);
printf("Content digest = %s\n", hashcontent);
/* 4. Compare the hash digests */
if (strncmp(hashcontent, hexdigest, hashlen) == 0)
printf("SUCCESS: Message digests match\n");
else
printf("FAILURE: digests do not match!\n");
/* Clean up */
free(data);
}
void ben_makes_crs(void)
/* Ben prepares a certificate signing request in both PEM and binary formats */
{
char *reqfile = "ben_crs.txt";
char *reqfilebin = "ben_crs.bin";
char *epkfile = "ben_epk.bin";
char *password = "password";
char *dn = "CN=ben;O=Example Corp;OU=Bens Unit;L=Bensville;S=California;C=US";
long result;
printf("\nBen prepares a certificate signing request (CRS)...\n");
result = X509_CertRequest(reqfile, epkfile, dn, "", password, 0);
assert(result == 0);
printf("Created certificate request '%s'\n", reqfile);
result = X509_CertRequest(reqfilebin, epkfile, dn, "", password, PKI_X509_FORMAT_BIN);
assert(result == 0);
printf("Created binary-format certificate request '%s'\n", reqfilebin);
}
void ann_verifies_her_cert(void)
{
char *certfile = "ann.cer";
char *issuercert = "carol.cer";
char *benscert = "ben.cer";
char thumb[41];
char digest[41];
long diglen;
unsigned char *data;
long datalen;
FILE *fp;
int c;
long result;
char szDate[32];
time_t ltime;
struct tm *tmnow;
printf("\nAnn verifies her certificate...\n");
/* Check dates */
result = X509_CertIssuedOn(certfile, szDate, sizeof(szDate)-1, 0);
printf("X509_CertIssuedOn returns %ld: ", result);
if (result > 0)
printf("%s\n", szDate);
else
printf("FAILURE: Unable to find ValidFrom date in %s.\n", certfile);
assert(result > 0);
result = X509_CertExpiresOn(certfile, szDate, sizeof(szDate)-1, 0);
printf("X509_CertExpiresOn returns %ld: ", result);
if (result > 0)
printf("%s\n", szDate);
else
printf("FAILURE: Unable to find ValidTo date in %s.\n", certfile);
assert(result > 0);
/* Check system clock */
time(<ime);
tmnow = gmtime(<ime);
printf("Time now is %04d-%02d-%02dT%02d:%02d:%02dZ\n",
tmnow->tm_year+1900, tmnow->tm_mon+1, tmnow->tm_mday,
tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec);
/* Catch cert created in the first minute of the hour (which will not yet be valid) */
if (0 == tmnow->tm_min)
printf("Skipping cert validity test as we are in first minute of the hour.\n");
else
{
/* Is Ann's cert valid? */
result = X509_CertIsValidNow(certfile, 0);
printf("X509_CertIsValidNow returns %ld: ", result);
if (result == 0)
printf("Certificate '%s' is valid now.\n", certfile);
else
printf("FAILURE: Certificate '%s' is NOT valid now.\n", certfile);
assert(result == 0);
}
/* Was it issued by Carol? */
result = X509_VerifyCert(certfile, issuercert, 0);
printf("X509_VerifyCert returns %ld: ", result);
if (result == 0)
printf("Certificate '%s' was issued by '%s'.\n", certfile, issuercert);
else
printf("FAILURE: Certificate '%s' was NOT issued by '%s'.\n", certfile, issuercert);
assert(result == 0);
/* Was it issued by Ben? */
result = X509_VerifyCert(certfile, benscert, 0);
printf("X509_VerifyCert returns %ld: ", result);
if (result == 0)
printf("Certificate '%s' was issued by '%s'.\n", certfile, benscert);
else
printf("Certificate '%s' was NOT issued by '%s'.\n", certfile, benscert);
assert(result == -1);
/* What is the thumbprint? */
result = X509_CertThumb(certfile, thumb, sizeof(thumb)-1, 0);
assert(result > 0);
printf("Ann's certificate has thumbprint: %s\n", thumb);
/* Check it the long way... */
/* (i) Read in the file to memory */
fp = fopen(certfile, "rb");
assert(fp != NULL);
for (datalen = 0; (c = fgetc(fp)) != EOF; datalen++)
;
data = malloc(datalen);
assert(data != NULL);
rewind(fp);
fread(data, 1, datalen, fp);
fclose(fp);
/* (ii) Make a hash digest of the data */
diglen = HASH_HexFromBytes(digest, sizeof(digest)-1, data, datalen, PKI_HASH_SHA1);
assert(diglen > 0);
printf("Hash digest of file data is : %s\n", digest);
free(data);
/* (iii) Compare */
result = strncmp(digest, thumb, diglen);
if (result == 0)
printf("SUCCESS: digest matches the 'thumbprint'\n");
else
printf("FAILURE: digest does not match thumbprint\n");
assert(result == 0);
}
void ben_reads_and_saves_his_keys(void)
/* How to save the keys in different formats - CAUTION! */
{
char *epkfile = "ben_epk.bin";
char *prifile = "ben_pri.bin";
char *pbkfile = "ben_pub.bin";
char *newpubk = "ben_newpub.bin";
char *xmlpubfile = "ben_pub.xml";
long result;
char *pubkeystr, *prikeystr, *chkkeystr;
char *xmlstr;
long klen, nbits, nbits1, xlen;
char password[256];
long pwdlen, i;
FILE *fp;
printf("\nBen reads and saves his RSA keys in different formats...\n");
/* Prompt for private key password */
printf("Prompt the user for the private-key password...\n");
printf("Hint: the password is 'password'\n");
pwdlen = PWD_Prompt(password, sizeof(password)-1, "Hint: Password is 'password'");
/* Fail gently if wrong password entered */
if (strcmp(password, "password"))
{
printf("Woops! That was the wrong password.\n");
return;
}
/* Read and re-save the public key */
klen = RSA_ReadPublicKey(NULL, 0, pbkfile, 0);
assert(klen >= 0);
pubkeystr = malloc(klen+1); /* NB always one extra */
assert(pubkeystr != NULL);
klen = RSA_ReadPublicKey(pubkeystr, klen, pbkfile, 0);
assert(klen >= 0);
printf("Ben's public key string (in 'internal' format)=%s\n", pubkeystr);
/* How long is the key? */
nbits = RSA_KeyBits(pubkeystr);
printf("Ben's public key is %ld bits long\n", nbits);
/* Save again */
result = RSA_SavePublicKey(newpubk, pubkeystr, 0);
assert(result == 0);
printf("Saved as '%s'\n", newpubk);
/* Check the same */
assert(cmp_files(newpubk, pbkfile) == 0);
/* Read encrypted key and save as unencrypted - VERY INSECURE! */
klen = RSA_ReadEncPrivateKey(NULL, 0, epkfile, password, 0);
assert(klen >= 0);
prikeystr = malloc(klen+1); /* NB always one extra */
assert(prikeystr != NULL);
klen = RSA_ReadEncPrivateKey(prikeystr, klen, epkfile, password, 0);
assert(klen >= 0);
/* WARNING: you should never show this string in practice! */
printf("Ben's private key string (in 'internal' format)=%s\n", prikeystr);
/* How long is the key? */
nbits1 = RSA_KeyBits(prikeystr);
printf("Ben's private key is %ld bits long\n", nbits1);
assert(nbits == nbits1);
/* Save as unencrypted */
result = RSA_SavePrivateKeyInfo(prifile, prikeystr, 0);
assert(result == 0);
printf("Saved as '%s'\n", prifile);
/* Read in unencrypted private key */
klen = RSA_ReadPrivateKeyInfo(NULL, 0, prifile, 0);
assert(klen >= 0);
chkkeystr = malloc(klen+1);
assert(chkkeystr != 0);
klen = RSA_ReadPrivateKeyInfo(chkkeystr, klen, prifile, 0);
assert(klen >= 0);
/* Check against original */
result = strcmp(chkkeystr, prikeystr);
if (result == 0)
printf("Private keys match OK\n");
else
printf("FAILURE: private keys do NOT match\n");
assert(result == 0);
/* Convert public key string to XML format */
xlen = RSA_ToXMLString(NULL, 0, pubkeystr, 0);
assert(xlen > 0);
xmlstr = malloc(xlen+1); /* NB one extra for a string */
assert(xmlstr != NULL);
xlen = RSA_ToXMLString(xmlstr, xlen, pubkeystr, 0);
assert(xlen > 0);
printf("Public key in XML format=\n%s\n", xmlstr);
/* Save as an XML file */
fp = fopen(xmlpubfile, "w");
assert(fp != NULL);
fprintf(fp, "<?xml version=\"1.0\"?>\n");
fprintf(fp, "%s\n", xmlstr);
assert(fclose(fp) == 0);
printf("Created file '%s'\n", xmlpubfile);
/* Clear the password */
result = WIPE_Data(password, pwdlen);
assert(result == 0);
/* Check all zeroised */
for (i = 0; i < pwdlen; i++)
assert(password[i] == 0);
/* Wipe the unecrypted key file */
result = WIPE_File(prifile, 0);
assert(result == 0);
printf("%s has been securely wiped\n", prifile);
/* Wipe the private key string */
result = WIPE_Data(prikeystr, strlen(prikeystr));
assert(result == 0);
free(pubkeystr);
free(prikeystr);
free(chkkeystr);
free(xmlstr);
}
void carol_reads_public_key_from_cert(void)
{
char *pbkfile = "carol_pub.bin";
char *certfile = "carol.cer";
long result;
char *pubkeystr, *pubkeystr1;
long klen, nbits, nbits1;
printf("\nCarol extracts her public key from her X.509 certificate...\n");
/* Read in public key from X.509 certificate */
klen = RSA_GetPublicKeyFromCert(NULL, 0, certfile, 0);
assert(klen >= 0);
pubkeystr = malloc(klen+1);
assert(pubkeystr != NULL);
klen = RSA_GetPublicKeyFromCert(pubkeystr, klen, certfile, 0);
assert(klen >= 0);
nbits = RSA_KeyBits(pubkeystr);
printf("Carol's key is %ld bits long\n", nbits);
/* And from public key file */
klen = RSA_ReadPublicKey(NULL, 0, pbkfile, 0);
assert(klen >= 0);
pubkeystr1 = malloc(klen+1);
assert(pubkeystr1 != NULL);
klen = RSA_ReadPublicKey(pubkeystr1, klen, pbkfile, 0);
assert(klen >= 0);
nbits1 = RSA_KeyBits(pubkeystr1);
assert(nbits1 == nbits);
result = strcmp(pubkeystr1, pubkeystr);
if (result == 0)
printf("Public keys match OK\n");
else
printf("FAILURE: public keys do NOT match\n");
assert(result == 0);
free(pubkeystr);
free(pubkeystr1);
}
void ann_makes_cert_chain(void)
/* Ann creates a PKCS#7 certificate chain with her cert and the issuer's (carol's)
then she extracts the certificates from it */
{
long result;
char *certlist;
char *p7file = "ann.p7c";
char certname[256], distname[256];
int ncerts, index;
printf("\nAnn makes a PKCS7 certificate chain...\n");
/* Create list of certs in chain separated by semicolons */
certlist = "carol.cer;ann.cer";
/* Make a certs-only signed data file */
result = CMS_MakeSigData(p7file, "", certlist, "", PKI_CMS_CERTS_ONLY);
printf("CMS_MakeSigData returns %ld (expecting 0)\n", result);
assert(result == 0);
printf("Created PKCS#7 cert chain file '%s'\n", p7file);
/* Now extract all the certificates from it */
index = 0; /* How many certs? */
ncerts = X509_GetCertFromP7Chain(NULL, p7file, index, 0);
printf("X509_GetCertFromP7Chain(0) returns %d (= no of certs)\n", ncerts);
assert(ncerts > 0);
for (index = 1; index <= ncerts; index++)
{
sprintf(certname, "cert%d.cer", index);
result = X509_GetCertFromP7Chain(certname, p7file, index, 0);
printf("X509_GetCertFromP7Chain(%d) returns %ld (= file size)\n", index, result);
assert(result > 0);
/* Query the certificate */
result = X509_CertSubjectName(certname, distname, sizeof(distname)-1, "", 0);
assert(result > 0);
printf("%s has subject name '%s'\n", certname, distname);
}
}
void ben_makes_pfx(void)
/* Ben creates a PKCS#12 PFX file with his encrypted private key and certificate
then he verifies the signature and extracts his key and certificate from it */
{
char *pfxfile = "ben.pfx";
char *certfile = "ben.cer";
char *epkfile = "ben_epk.bin";
char *password = "password";
char *certcopy = "ben_copy.cer";
char *epkcopy = "ben_epk_copy.bin";
long result;
printf("\nBen makes a PKCS12 PFX file...\n");
/* Create the PFX file */
result = PFX_MakeFile(pfxfile, certfile, epkfile, password, "Ben's Friendly ID", 0);
printf("PFX_MakeFile returns %ld (expecting 0)\n", result);
assert(result == 0);
printf("Created PKCS#12 file '%s'\n", pfxfile);
/* Verify the signature */
result = PFX_VerifySig(pfxfile, password, 0);
printf("PFX_VerifySig returns %ld (expecting 0 => verified OK)\n", result);
assert(result == 0);
/* Extract the private key (still encrypted) */
result = RSA_GetPrivateKeyFromPFX(epkcopy, pfxfile, 0);
printf("RSA_GetPrivateKeyFromPFX returns %ld (= file size)\n", result);
assert(result > 0);
printf("Extracted encrypted private key file '%s'\n", epkcopy);
/* can we read the key? */
result = RSA_ReadEncPrivateKey(NULL, 0, epkcopy, password, 0);
printf("RSA_ReadEncPrivateKey returns %ld (= internal key size)\n", result);
assert(result > 0);
/* Extract the certificate */
result = X509_GetCertFromPFX(certcopy, pfxfile, "", 0);
printf("X509_GetCertFromPFX returns %ld (= file size)\n", result);
assert(result > 0);
printf("Extracted certificate file '%s'\n", certcopy);
/* compare with original */
result = cmp_files(certcopy, certfile);
printf("%s to original file\n", (result == 0 ? "EQUAL" : "NOT EQUAL"));
assert(result == 0);
}
void ben_encrypts_raw_key(void)
/* Ben has a 192-bit session key (Content Encryption Key, CEK) he wants to send encrypted to ann */
/* INPUT: CEK; CEK length; Ann's public key file.
OUTPUT: encrypted block.
*/
{
long result;
char *pubfile = "ann_pub.bin";
unsigned char cek[24] =
{ /* 0xffeeddccbbaa99887766554433221100fedcba9876543210 */
0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
unsigned char *block;
char *pubkeystr;
long klen, blocklen, ceklen;
char *fname = "raw_enc_key_for_ann.bin";
FILE *fp;
printf("\nBen uses 'raw' RSA to encrypt a secret for Ann...\n");
/* Read in Ann's public key to internal string */
klen = RSA_ReadPublicKey(NULL, 0, pubfile, 0);
assert(klen > 0);
pubkeystr = malloc(klen+1); /* NB one extra */
assert(pubkeystr != NULL);
result = RSA_ReadPublicKey(pubkeystr, klen, pubfile, 0);
assert(result == klen);
/* Create a block equal in length to the RSA key modulus */
blocklen = RSA_KeyBytes(pubkeystr);
assert(blocklen > 0);
block = malloc(blocklen);
assert(block != NULL);
/* Encode the message (i.e. the CEK) for encryption */
ceklen = sizeof(cek);
result = RSA_EncodeMsg(block, blocklen, cek, ceklen, PKI_EME_PKCSV1_5);
assert(result == 0);
printf("CEK=\n");
pr_bytes(cek, ceklen);
printf("Block before encryption=\n");
pr_bytes(block, blocklen);
/* Encrypt the block using the RSA public key */
result = RSA_RawPublic(block, blocklen, pubkeystr, 0);
assert(result == 0);
printf("Encrypted block=\n");
pr_bytes(block, blocklen);
/* Save as a binary file (and send to Ann) */
fp = fopen(fname, "wb");
assert(fp != NULL);
fwrite(block, 1, blocklen, fp);
fclose(fp);
printf("Saved encrypted key as file '%s'\n", fname);
free(pubkeystr);
free(block);
}
void ann_decrypts_raw_key(void)
/* Ann decrypts the session key (CEK) from Ben using her RSA private key */
/* INPUT: encrypted block; Ann's private key file; password.
OUTPUT: CEK.
*/
{
long result;
char *epkfile = "ann_epk.bin";
char *szPassword = "password";
unsigned char *block, *cek;
char *prikeystr;
long klen, blocklen, ceklen;
char *fname = "raw_enc_key_for_ann.bin";
FILE *fp;
printf("\nAnn decrypts the 'raw' data from Ben...\n");
/* Read in Ann's private key to an internal string */
klen = RSA_ReadEncPrivateKey(NULL, 0, epkfile, szPassword, 0);
assert(klen > 0);
prikeystr = malloc(klen+1); /* NB one extra */
assert(prikeystr != NULL);
result = RSA_ReadEncPrivateKey(prikeystr, klen, epkfile, szPassword, 0);
assert(result == klen);
/* Create a block equal in length to the RSA key modulus */
blocklen = RSA_KeyBytes(prikeystr);
assert(blocklen > 0);
block = malloc(blocklen);
assert(block != NULL);
/* Read in the encrypted data from the binary file
-- it MUST be the same length as the key */
fp = fopen(fname, "rb");
assert(fp != NULL);
result = fread(block, 1, blocklen, fp);
fclose(fp);
assert (result == blocklen);
printf("Encrypted block=\n");
pr_bytes(block, blocklen);
/* Decrypt the block using the RSA private key */
result = RSA_RawPrivate(block, blocklen, prikeystr, 0);
assert(result == 0);
printf("Decrypted block=\n");
pr_bytes(block, blocklen);
/* Decode the block to extract the message (the CEK) */
/* how long is it? */
ceklen = RSA_DecodeMsg(NULL, 0, block, blocklen, PKI_EME_PKCSV1_5);
printf("RSA_DecodeMsg returns %ld\n", ceklen);
assert(ceklen > 0);
/* allocate memory and extract */
cek = malloc(ceklen);
result = RSA_DecodeMsg(cek, ceklen, block, blocklen, PKI_EME_PKCSV1_5);
assert(result == ceklen);
printf("CEK=\n");
pr_bytes(cek, ceklen);
/* Now use the CEK ... */
/* Make sure we wipe the private key string and CEK */
WIPE_Data(prikeystr, strlen(prikeystr));
WIPE_Data(cek, ceklen);
free(prikeystr);
free(block);
free(cek);
}
void ann_signs_raw_msg(void)
/* Ann uses raw RSA to sign a message (actually its message digest) */
/* INPUT: Message-to-be-signed; hash algorithm to use (SHA-1); Ann's private key file; password.
OUTPUT: signature value.
*/
{
long result;
char *epkfile = "ann_epk.bin";
char *szPassword = "password";
char *msg = "This is some sample content.";
unsigned char hash[PKI_SHA1_BYTES];
unsigned char *block;
char *prikeystr;
long klen, blocklen, hashlen;
char *fname = "raw_sig_by_ann.bin";
FILE *fp;
printf("\nAnn uses raw RSA to sign a message...\n");
/* Ann reads in her private key */
klen = RSA_ReadEncPrivateKey(NULL, 0, epkfile, szPassword, 0);
assert(klen > 0);
prikeystr = malloc(klen+1); /* NB one extra */
assert(prikeystr != NULL);
result = RSA_ReadEncPrivateKey(prikeystr, klen, epkfile, szPassword, 0);
assert(result == klen);
/* Create a block equal in length to the RSA key modulus */
blocklen = RSA_KeyBytes(prikeystr);
assert(blocklen > 0);
block = malloc(blocklen);
assert(block != NULL);
/* Compute the SHA-1 message digest of the message-to-be-signed */
hashlen = sizeof(hash);
result = HASH_Bytes(hash, hashlen, (unsigned char *)msg, strlen(msg), PKI_HASH_SHA1);
printf("SHA-1('%s')=\n", msg);
pr_bytes(hash, hashlen);
/* Encode the message digest for signature (EMSA) */
result = RSA_EncodeMsg(block, blocklen, hash, hashlen,
PKI_EMSIG_PKCSV1_5 + PKI_HASH_SHA1 + PKI_EMSIG_DIGESTONLY);
assert(result == 0);
printf("Block before signing=\n");
pr_bytes(block, blocklen);
/* (NOTE: we could have omitted the digest computation above and encoded the message
directly without using the PKI_EMSIG_DIGESTONLY option.) */
/* Sign the block using the private key */
result = RSA_RawPrivate(block, blocklen, prikeystr, 0);
assert(result == 0);
printf("Signature block=\n");
pr_bytes(block, blocklen);
/* Save as a binary file (and send to Ben) */
fp = fopen(fname, "wb");
assert(fp != NULL);
fwrite(block, 1, blocklen, fp);
fclose(fp);
printf("Saved signature value as file '%s'\n", fname);
/* Make sure we wipe the private key string */
WIPE_Data(prikeystr, strlen(prikeystr));
free(prikeystr);
free(block);
}
void ben_verifies_raw_msg(void)
/* Ben verifies the raw RSA signature received from Ann */
/* INPUT: signature value; Ann's public key file; HASH(message-to-be-verified); hash algorithm used (SHA-1).
OUTPUT: "Valid signature" or "Invalid signature".
*/
{
long result;
char *pubfile = "ann_pub.bin";
unsigned char cfhash[PKI_SHA1_BYTES] =
{ /* 406aec085279ba6e16022d9e0629c0229687dd48 */
0x40, 0x6A, 0xEC, 0x08, 0x52, 0x79, 0xBA, 0x6E,
0x16, 0x02, 0x2D, 0x9E, 0x06, 0x29, 0xC0, 0x22,
0x96, 0x87, 0xDD, 0x48 };
unsigned char *block, *hash;
char *pubkeystr;
long klen, blocklen, hashlen;
char *fname = "raw_sig_by_ann.bin";
FILE *fp;
printf("\nBen verifies the raw RSA signature received from Ann...\n");
/* Ann reads in her private key */
klen = RSA_ReadPublicKey(NULL, 0, pubfile, 0);
assert(klen > 0);
pubkeystr = malloc(klen+1); /* NB one extra */
assert(pubkeystr != NULL);
result = RSA_ReadPublicKey(pubkeystr, klen, pubfile, 0);
assert(result == klen);
/* Create a block equal in length to the RSA key modulus */
blocklen = RSA_KeyBytes(pubkeystr);
assert(blocklen > 0);
block = malloc(blocklen);
assert(block != NULL);
/* Read in the signature value from the binary file
-- it MUST be the same length as the key */
fp = fopen(fname, "rb");
assert(fp != NULL);
result = fread(block, 1, blocklen, fp);
fclose(fp);
assert (result == blocklen);
printf("Signature value=\n");
pr_bytes(block, blocklen);
/* Verify the block by decrypting using the RSA public key */
result = RSA_RawPublic(block, blocklen, pubkeystr, 0);
assert(result == 0);
printf("Decrypted block=\n");
pr_bytes(block, blocklen);
/* Decode the block to extract the message digest */
/* how long is it? */
hashlen = RSA_DecodeMsg(NULL, 0, block, blocklen, PKI_EMSIG_PKCSV1_5);
printf("RSA_DecodeMsg returns %ld\n", hashlen);
assert(hashlen > 0);
/* allocate memory and extract */
hash = malloc(hashlen);
result = RSA_DecodeMsg(hash, hashlen, block, blocklen, PKI_EMSIG_PKCSV1_5);
assert(result == hashlen);
printf("HASH= ");
pr_bytes(hash, hashlen);
/* Ben has already independently computed the message digest,
so he compares the two digest values */
printf("HASH'=");
pr_bytes(cfhash, sizeof(cfhash));
result = memcmp(cfhash, hash, hashlen);
printf("%s\n", (result == 0 ? "Valid signature" : "INVALID SIGNATURE"));
assert (result == 0);
/* Clean up */
free(pubkeystr);
free(block);
free(hash);
}
int main()
{
int c;
/* MSVC memory leak checking stuff */
#if _MSC_VER >= 1100
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );
#endif
make_new_test_dir();
create_test_files();
show_version();
carol_creates_keys();
carol_creates_ca_cert();
ann_and_ben_create_keys();
carol_makes_certs_for_ann_and_ben();
ben_tests_his_keys_in_the_raw();
ann_sends_enc_msg_to_ben();
ben_decrypts_msg_from_ann();
ann_sends_encmsg_ben_reads();
ann_sends_encr_base64_ben_reads();
ann_signs_msg();
ben_verifies_msg_from_ann();
ben_reads_signed_data();
ben_signs_det_msg();
ann_verifies_det_msg_from_ben();
ann_signs_base64_ben_verifies();
ben_makes_crs();
ann_verifies_her_cert();
ben_reads_and_saves_his_keys();
carol_reads_public_key_from_cert();
ann_makes_cert_chain();
ben_makes_pfx();
ben_encrypts_raw_key();
ann_decrypts_raw_key();
ann_signs_raw_msg();
ben_verifies_raw_msg();
printf("\nAll done.\n");
/* Option to clean up */
printf("The directory '%s' has been created by this test program.\n"
"Do you want to remove this directory? Y/N: ", testdir);
c = getchar();
if (c == 'Y' || c == 'y')
remove_test_dir(testdir, old_cwd);
return 0;
}