Hi there folks!
I was wondering if someone could help me out in creating an x509 cert and
self signing it.?
This is how I tried to do it:
--Made DSA
--Created key pair
--Created x509 cert
--stuffed pub key in the x509 cert
--stuffed misc. info into cert -- name, etc..
--signed the cert with its private key
--verified the cert with is public key -- only it won't verify. The
X509_verify() function returns a -1.
Anywho..I pasted my source code in and I'd *REALLY* appreciate if someone
could take a look at it and tell me where I went wrong. (oh I took out a lot
of my error checking to conserve space, as well as some overly "explainy"
comments -- so in my deleting of these items I may have killed a ";" or
two... )
Thanks so much in advance. I look forward to hearing from you.
--Andrea
email: [EMAIL PROTECTED]
------------------------------------ CODE BELOW, PLEASE LOOK :)
-------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <iostream.h> // for cin\cout
#include <fstream.h> // for File I\O
#include <string.h> // for strlen
#include "dsa.h" // for DSA functions
#include "crypto.h" // CRYTPO functions
#include "x509.h" // for X509 functions
#include "sha.h" // for SHA1 functions
#include "asn1.h" // for ASN1 functions
#include "pem.h" // for PEM functions
#include "ssl.h" // for SSL functions
#include "err.h" // for ERR functions
#include "evp.h" // for EVP functions
void main()
{
const int MAX = 50; // max length of a string
// used for allocating
space
// for char*
const int KEYLENGTH = 512; // length of a key.
511<KL<1025
// ==============> GENERATE PARAMETERS
DSA* dsa = NULL; // make a ptr to a DSA
structure
dsa = DSA_new(); // make a new dsa
// GENERATE PARAMETERS
int pBits = KEYLENGTH; // bits in a key
int seedLen = 20; // starting seed for psuedo random generator
dsa = DSA_generate_parameters(pBits, NULL, seedLen, NULL, NULL, NULL,
NULL);
// GENERATE KEYS
int done = 0;
done = DSA_generate_key(dsa);
// checking to make sure that the keys now point to something, not NULL
// ==============> CREATE X509 CERTIFICATE
X509* x509; // pointer to an X509
x509 = X509_new(); // create a new one
// Convert the dsa->pub_key into an EVP_KEY so that it can be used to
set
// the cert's public key field using X509_set_pubkey().
EVP_PKEY* pkey; // ptr to an EVP_PKEY
pkey = EVP_PKEY_new(); // make a new key
int ok = 0; // generic var to hold the return
// values of functions, i.e.
1 | 0
// to see if they worked
// correctly. Unless
otherwise
// indicated, all functions
who's
// return value is put into
"ok"
// has 1 returned if
successful
// and 0 returned otherwise.
// This var will be used
// throughout the rest of the
code
ok = EVP_PKEY_assign(pkey, EVP_PKEY_DSA, (char*)(dsa)); // call assign
// function,
// so pkey
// is now a
valid EVP_KEY
ok = 0; // set generic var
back to 0
ok = X509_set_pubkey(x509, pkey); // put pub key info into
cert
// TIME TO FILL IN THE CERT!
// Get user info (name, subj. etc) to make cert
// ISSUER NAME
unsigned char* organizationIssuerName = NULL; // pts to the
organization
// that the issuer
belongs
// to. i.e. the
Certificate
// Authority's (CA)
name
organizationIssuerName = new unsigned char[MAX]; // make some space
organizationIssuerName = (unsigned char*)("Good Cert Co."); // generic
info
int len = 0; // another generic var.
// This will be used
// thoughout the program
to
// hold the length of
some
// data string.
len = strlen((char*)organizationIssuerName); // get len of
organization
int type = V_ASN1_PRINTABLESTRING; // so its a printable string. ASN1
has
// tons of types that one can use
here.
X509_NAME_ENTRY* organizationIssuerNameEntry; // the NAME ENTRY (NE)
that
// will be used to hold
the
// ASN1 objects, etc,
that
// will later be stuffed
into
// an X509_NAME (N).
organizationIssuerNameEntry = X509_NAME_ENTRY_create_by_NID(NULL,
NID_organizationName,
type,
organizationIssuerName,
len);
unsigned char* countryIssuerName = NULL; // to pt to the
// Issuer's country
countryIssuerName = new unsigned char[MAX]; // allocate space
countryIssuerName = (unsigned char*)("Timbuktu"); // put in the info
len = 0; // set the len back
zero
len = strlen((char*)countryIssuerName); // get len of
string
X509_NAME_ENTRY* countryIssuerNameEntry; // the NE to hold the
country
countryIssuerNameEntry = X509_NAME_ENTRY_create_by_NID(NULL,
NID_countryName, type,
countryIssuerName,
len);
ok = 0;
X509_NAME* issuerName; // ptr to an X509_NAME to hold the
issuer
// NE's info. A NAME is made a stack
of
// NE's.
issuerName = X509_NAME_new(); // allocate space
int loc = -1; // it'll be reset to the number of
elements
// on the stack, that way we don't
need to
// keep track of how many NE's have
been
// put on the stack
int set = -1; // so that the NE gets appended to the
// prev. stack
// Add the NE's to the N stack
ok = X509_NAME_add_entry(issuerName, organizationIssuerNameEntry, loc,
set);
// Same thing, add another NE to the N stack.
ok = 0;
ok = X509_NAME_add_entry(issuerName, countryIssuerNameEntry, loc, set);
// Stuff that N that we just created from a stack of NE's into the cert.
ok = 0;
ok = X509_set_issuer_name(x509, issuerName); // set issuer name
// SUBJECT NAME -- i.e. the entity holding the private key that
corresponds
// to the cert's public key
unsigned char* commonName = NULL; // hold the
subjects
// common name
i.e
// Joe Shmoe
commonName = new unsigned char[MAX]; // allocate
space
commonName = (unsigned char*)("Joe Shmoe"); // stuff generic info
len = 0; // set the len
back
// to 0
len = strlen((char*)commonName); // get len of
the
// string
// make a X509_NAME_ENTRY using the create_by_NID() function call
X509_NAME_ENTRY* commonNameEntry; // ptr to a name entry
commonNameEntry = X509_NAME_ENTRY_create_by_NID(NULL,
NID_commonName, type,
commonName, len);
unsigned char* countryName = NULL; // holds the subject's country
name
countryName = new unsigned char[MAX]; // allocate space!
countryName = (unsigned char*)("USA"); // stuff generic country info
len = 0; // set length back to zero
len = strlen((char*)countryName); // get the string len
// make the X509_NAME_ENTRY to hold the country name
X509_NAME_ENTRY* countryNameEntry; // ptr to a country name entry
countryNameEntry = X509_NAME_ENTRY_create_by_NID(NULL, NID_countryName,
type,
countryName, len);
unsigned char* organizationalUnitName = NULL; // the subjects
organizational
// unit name, i.e. IAL
organizationalUnitName = new unsigned char[MAX]; // allocate space
organizationalUnitName = (unsigned char*)("Intel Architecture Lab"); //
info
len = 0 ; // set the length of the string back
to 0
len = strlen((char*)organizationalUnitName); // get string len
// make the X509_NAME_ENTRY to hold the organizational unit name
X509_NAME_ENTRY* organizationalUnitNameEntry;
organizationalUnitNameEntry = X509_NAME_ENTRY_create_by_NID(NULL,
NID_organizationalUnitName,
type, organizationalUnitName,
len);
unsigned char* organizationName = NULL; // subject's organization's name
organizationName = new unsigned char[MAX]; // allocate space
organizationName = (unsigned char*)("CompanyY"); // stuff in some
info
len = 0; // set the len back
to 0
len = strlen((char*)organizationName); // get strlen
// make the X509_NAME_ENTRY to hold the organization name
X509_NAME_ENTRY* organizationNameEntry;
organizationNameEntry = X509_NAME_ENTRY_create_by_NID(NULL,
NID_organizationName,
type,
organizationName,
len);
// Now make an X509_NAME with those 4 NAME_ENTRYs: commonNameEntry,
// countryNameEntry, organizationalUnitNameEntry, and
organizationNameEntry
X509_NAME* subjectName; // ptr to subjects "name"
subjectName = X509_NAME_new(); // create a new NAME
loc = -1; // it'll be reset to the
// number of elements on
// the stack.
set = 1; // gets appended to prev.
set
// add a NE (countryNameEntry) to the stack
ok = 0;
ok = X509_NAME_add_entry(subjectName, countryNameEntry, loc, set);
// add another NE (commonNameEntry) to the stack in the N
ok = 0;
ok = X509_NAME_add_entry(subjectName, commonNameEntry, loc, set);
// keep on addin' NE's (add organizationUnitNameEntry this time)!
ok = 0;
ok = X509_NAME_add_entry(subjectName, organizationalUnitNameEntry,
loc, set);
// add another NE (organizationNameEntry) to the stack of them in
the N
ok = 0;
ok = X509_NAME_add_entry(subjectName, organizationNameEntry, loc, set);
// set the subject's "name" on the cert, which really consists of
all those
// NE's that we just stuffed into the N.
ok = 0;
ok = X509_set_subject_name(x509, subjectName); // set issuer name
// SET VERSION
ok = 0;
ok = X509_set_version(x509, NID_X509); // version set to X509
// SET NOT BEFORE TIME
ASN1_UTCTIME* UTCTIMEnotBefore; // make a ptr to an ASN1_UTCTIME
object
// which is what we use to store
// some time data..
UTCTIMEnotBefore = ASN1_UTCTIME_new(); // make a new one i.e allocate
space
char* timeNotBefore; // to hold the GMT as a string
// (Grenage Mean Time)
// going to store a time
timeNotBefore = new char[MAX]; // allocate space
timeNotBefore = "790311064508Z"; // put generic info in.
ok = 0;
ok = ASN1_UTCTIME_set_string(UTCTIMEnotBefore, timeNotBefore); // put
that
// big
time char
//
string into the
// ASN1
object
// stuff that time into the cert
ok = 0;
ok = X509_set_notBefore(x509, UTCTIMEnotBefore);
// SET TIME NOT AFTER
ASN1_UTCTIME* UTCTIMEnotAfter;
UTCTIMEnotAfter = ASN1_UTCTIME_new(); // make a new one
char* timeNotAfter; // to hold the GMT
string
timeNotAfter = new char[MAX]; // allocate space
timeNotAfter = "990807053011Z"; ok = 0;
ok = ASN1_UTCTIME_set_string(UTCTIMEnotAfter, timeNotAfter); // stuff
that
// time
char string into the
// ASN1
object just created
// stuff the TIME NOT AFTER into the cert
ok = 0;
ok = X509_set_notAfter(x509, UTCTIMEnotAfter); // stuffing it in there
now
// SET SERIAL NUMBER
ASN1_INTEGER* ASN1serialNumber; // make a ptr to an oject
that
// holds the serial number
ASN1serialNumber = ASN1_INTEGER_new(); // make a new one
long serialNumber = 12345678; // generic info
ok = 0;
ok = ASN1_INTEGER_set(ASN1serialNumber, serialNumber); // stuff that
long
// in the ASN1 obj.
// Now stuff the serial number into the cert
ok = 0;
ok = X509_set_serialNumber(x509, ASN1serialNumber); // stuffing now!
// SIGN THE CERT ====> I THINK SOMETHING IS WRONG AROUND HERE, SINCE
IT WON'T VERIFY.
// use the pkey which is of type EVP_PKEY to be an object that is sent
along
// to help sign a cert
unsigned int sig_len = 0; // length of the
signature
// write DSA private key to a .pem file
FILE* privateKeyFile;
static char keyfile[] = "key.pem"; // has private key in
pem format
privateKeyFile = fopen(keyfile, "w+"); // open key.pem for
writing
// PEM_write_DSAPrivateKey();
PEM_write_DSAPrivateKey(privateKeyFile, dsa,
NULL, // don't need ENV_CIPHER fumction to encrypt
NULL, // for requiring password
KEYLENGTH, // length of the key
NULL); // no call back function needed
fclose(privateKeyFile); // close the file
// now extract key from file
privateKeyFile = fopen(keyfile, "r"); // open file for
reading
if(privateKeyFile == NULL) // error check
{
cerr<<"Error in making privateKeyFile the handle of the
keyfile"<<endl;
cerr<<"Program is now exiting....."<<endl;
exit(1);
}
EVP_PKEY* privateKey;
// read the private key from the pem file, convert it into an
// EVP_PKEY and store it in privateKey
privateKey = (EVP_PKEY*)PEM_ASN1_read ((char *(*)())d2i_PrivateKey,
PEM_STRING_EVP_PKEY,
privateKeyFile,
NULL, NULL);
if(privateKeyFile==NULL) // error check
{
ERR_print_errors_fp(stderr);
exit(1);
}
sig_len = X509_sign(x509, privateKey, EVP_dss1());
cout<<"X509_sign reports sig_len = "<<sig_len<<endl;
if(sig_len <= 0) // error check
{
cout<<endl<<endl;
cout<<"ERROR: in signing cert X509_sign()"<<endl;
cerr<<"Program is now EXITING!...."<<endl;
exit(1);
} // end if file writing error, i.e. ok == 0
// WRITE INFO TO A FILE TO SEE IF IT LOOKS RIGHT
// We will now write the cert into a human-readable file using a
function
// who's sole purpose in life is to do just that: X509_print_fp()
// We do this for another way to error check, by making sure that all
the
// info we stuffed into the cert actually got into the right place.
// =====> WHEN I WRITE IT TO THE FILE, IT "looks" RIGHT
FILE* certFP; // pointer to
the cert file
certFP = fopen("cert_info", "w+"); // open
"cert_info" for writing
ok = 0;
ok = X509_print_fp(certFP, x509); // write the
cert x509 to the file
if(ok == 0) // error check
{
cout<<endl<<endl;
cout<<"ERROR: in writing cert to file 'cert_info'"<<endl;
cerr<<"Program is now EXITING!...."<<endl;
exit(1);
} // end if file writing error, i.e. ok == 0
fclose(certFP); // close the file
// WRITE INFO TO A .PEM FILE
// Now we will write the X509 to "blah.pem" --a file which has the form:
// -----BEGIN CERTIFICATE-----
// KLDJFKL;JDSKF;LJSD;OSFIU87349DF0985-8_&**U
// DKJF;KL*&*FUD;LFJ 78Y7987&*^FLKJLF98Y98Y75
// DLKFJD;LSKAJFOP*#EPOIJHPODHUPIOULKJ^^&#HKJ
// -----END CERTIFICATE-----
// The X509 cert is DER-encoded then base64-encoded and then stuffed
into
// the .pem file.
FILE* pemFP; // pointer to
the .pem file
static char certFile[] = "cert.pem"; // file to
write the.pem info to
pemFP = fopen(certFile, "w+"); // open
"blah.pem" for writing
ok = 0;
ok = PEM_write_X509(pemFP, x509); // stuff the
x509 in pem form into
// the file
if(ok == 0) // error check
{
cout<<endl<<endl;
cout<<"ERROR: in wrting to .pem file"<<endl;
cerr<<"Program is now EXITING!...."<<endl;
exit(1);
} // end if file writing to .PEM error, i.e. ok == 0
fclose(pemFP); // close the
file
cout<<"Pem file written!"<<endl; //<<<<<<<<<<<<<<<<<<<<
// VERIFY CERT SIGNING
// read the public key by pulling the cert out of the cert file
pemFP = fopen(certFile, "r"); // open file
for reading
if(pemFP == NULL) // error check
{
cerr<<"ERROR: handle for certFile, for reading, not made properly."
<<endl;
cerr<<"Program is now exiting....."<<endl;
exit(1);
} // end if pemFP == NULL
X509* x509CheckingCert;
x509CheckingCert = (X509*)PEM_ASN1_read ((char *(*)())d2i_X509,
PEM_STRING_X509,
pemFP, NULL, NULL);
if(x509CheckingCert == NULL) // error check
{
ERR_print_errors_fp(stderr);
exit(1);
} // end if x509CheckingCert == NULL
fclose(pemFP); // close the file
// Get public key
EVP_PKEY* publicKey;
publicKey = X509_get_pubkey(x509);
if(publicKey == NULL) // error check
{
ERR_print_errors_fp(stderr);
exit(1);
} // end if publicKey == NULL
// now verify the signature
cout<<"now I am here"<<endl;
ok = 0;
ok = X509_verify(x509CheckingCert, publicKey); // <============= THIS
RETURNS -1
if(ok != 1) // error check
{
cerr<<"ERROR: X509_verify() did not return 1"<<endl;
ERR_print_errors_fp(stderr);
cerr<<"Program is now EXITING!!"<<endl;
exit(1); // <============================== SINCE OK = -1, IT DIES
HERE!
} // end if err != 1
cout<<"Signature Verified! Thank Goodness!"<<endl;
cout<<"Press any key to continue"<<endl;
char blah;
cin>>blah;
cout<<endl<<"-----DONE-----"<<endl<<endl;
// just so we know where we are ;)
cout<<endl<<"-----DONE-----"<<endl<<endl;
} // end main
______________________________________________________________________
OpenSSL Project http://www.openssl.org
Development Mailing List [EMAIL PROTECTED]
Automated List Manager [EMAIL PROTECTED]