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]