Original link: http://www.cangfengzhe.com/wangluoanquan/37.html
This article mainly introduces the programming and analysis of digital certificate, a very core element in PKI public key system. When communicating with SSL, SET and other security protocols, the digital certificate is used for identity authentication between the communication parties, and encrypts the transmission data by relying on the digital certificate and asymmetric encryption algorithm, or negotiates the shared key of the communication parties according to the digital certificate. Therefore, if users want to develop their own applications and realize identity authentication, they must analyze the digital certificate. According to the analysis results, the end users who meet certain conditions can access.
1. Introduction to certificate format
Most of the existing digital certificates adopt X.509 specification, which is mainly composed of the following information: version number, certificate serial number, validity period (certificate effective time and expiration time), user information (name, unit, organization, city, country, etc.), issuer information, other expansion information, owner's public key, CA's overall signature of the certificate
OPENSSL development kit realizes all operations of X.509 certificate analysis, such as obtaining the certificate version, public key, owner information, issuer information, validity period, etc. here is how to analyze the certificate information we need through programming.
2. Certificate analysis programming
2.1 introduction to data structure
10. 509 certificate has a special data structure in OPENSSL to facilitate users' operation. Its structure is as follows:
struct x509_st { X509_CINF *cert_info; X509_ALGOR *sig_alg; ASN1_BIT_STRING *signature; int valid; int references; char *name; CRYPTO_EX_DATA ex_data; long ex_pathlen; long ex_pcpathlen; unsigned long ex_flags; unsigned long ex_kusage; unsigned long ex_xkusage; unsigned long ex_nscert; ASN1_OCTET_STRING *skid; struct AUTHORITY_KEYID_st *akid; X509_POLICY_CACHE *policy_cache; #ifndef OPENSSL_NO_SHA unsigned char sha1_hash[SHA_DIGEST_LENGTH]; #endif X509_CERT_AUX *aux; };
This structure represents a complete digital certificate. The meanings are as follows:
cert_info: certificate subject information;
sig_alg: signature algorithm;
Signature: signature value, which stores the result of CA signing the certificate;
valid: whether it is a legal certificate. 1 is legal and 0 is unknown;
References: the number of references, plus one if referenced once;
name: certificate holder information;
ex_data: extended data structure, used to store user-defined information;
ex_pathlen: certificate path length;
ex_kusage: key usage;
ex_xkusage: extended key usage;
ex_nscert: Netscape certificate type;
Ski: principal key identification;
akid: issuer key identification;
policy_cache: various policy caches;
sha1_hash: store the SHA1 summary value of the certificate;
aux: auxiliary information;
Among them, certificate subject information - X509_CINF structure is defined as follows:
typedef struct x509_cinf_st { ASN1_INTEGER *version; //Certificate version ASN1_INTEGER *serialNumber; //serial number X509_ALGOR *signature; //signature algorithm X509_NAME *issuer; //Issuer X509_VAL *validity; // Effective time X509_NAME *subject; // holder X509_PUBKEY *key; // Public key ASN1_BIT_STRING *issuerUID; // Issuer unique ID ASN1_BIT_STRING *subjectUID; // Unique identification of the holder STACK_OF(X509_EXTENSION) *extensions; // Extension } X509_CINF;
2.2 function introduction
According to the above structure, we can read the certificate information in the structure through programming. Here are some common functions.
(1) Code conversion function
Digital certificates are divided into DER code and PEM code, so the corresponding operations are different. For DER encoded certificates, we can use the function: x509 * d2i_ X509 (x509 * * Cert, unsigned char * * D, int len), returns a structure pointer of X.509. For PEM encoded certificates, I didn't find a function to realize encoding conversion, but I can realize this function through the BIO function provided by OPENSSL: call BIO first_ new_ File() returns a BIO structure, and then through PEM_read_bio_X509() returns an X.509 structure.
(2) Obtain certificate information
In fact, the operation of obtaining certificate information is only to parse X509 and X509_ The operation of cinf structure can obtain information such as certificate version, issuer information, certificate owner information, validity period, certificate public key and so on. The main functions are as follows:
X509_get_version(); // Obtain the certificate version;
X509_get_issuer_name(); // Get certificate issuer information
X509_get_subjiect_name(); // Obtain certificate owner information
X509_get_notBefore(); // Start date of obtaining certificate
X509_get_notAfter(); // Obtain certificate end date
X509_get_pubkey(); // Get certificate public key
The specific programming code and parameters are introduced to you.
2.3 programming
Through the introduction of the above functions and structures, the following programming is very simple to analyze a digital certificate. Here, I have written a software for analyzing certificates, and the key codes are as follows:
fp=fopen(filename.GetBuffer(0),"rb"); if(fp==NULL) { MessageBox("Error reading certificate"); return ; } Certlen=fread(Cert,1,4096,fp); fclose(fp); //Judge whether it is a user certificate encoded by DER and convert it into X509 structure pTmp=Cert; usrCert = d2i_X509(NULL,(const unsigned char ** )&pTmp,Certlen); if(usrCert==NULL) { BIO *b; /* Judge whether it is a digital certificate in PEM format */ b=BIO_new_file(filename.GetBuffer(0),"r"); usrCert=PEM_read_bio_X509(b,NULL,NULL,NULL); BIO_free(b); if(usrCert==NULL) { MessageBox("Conversion format error!"); return; } } //Resolve certificate X509_NAME *issuer = NULL;//X509_NAME structure, which saves the certificate issuer information X509_NAME *subject = NULL;//X509_NAME structure to save the certificate owner information //Get certificate version Version = X509_get_version(usrCert); //Get certificate issuer information, x509_ The name structure holds a number of information, including country, organization, Department, common name, mail, etc. issuer = X509_get_issuer_name(usrCert); //Get x509_ Number of name entries entriesNum = sk_X509_NAME_ENTRY_num(issuer->entries); //Cycle to read the information of each entry for(i=0;i<entriesNum;i++) { //Get the I-th entry value name_entry = sk_X509_NAME_ENTRY_value(issuer->entries,i); //Get object ID Nid = OBJ_obj2nid(name_entry->object); //Determine the type of item code if(name_entry->value->type==V_ASN1_UTF8STRING) //Convert UTF8 encoded data into visible characters { nUtf8 = 2*name_entry->value->length; pUtf8 = (unsigned short *)malloc(nUtf8); memset(pUtf8,0,nUtf8); rv = MultiByteToWideChar( CP_UTF8, 0, (char*)name_entry->value->data, name_entry->value->length, pUtf8, nUtf8); rv = WideCharToMultiByte( CP_ACP, 0, pUtf8, rv, (char*)msginfo, nUtf8, NULL, NULL); free(pUtf8); pUtf8 = NULL; msginfoLen = rv; msginfo[msginfoLen]='\0'; } else { msginfoLen=name_entry->value->length; memcpy(msginfo,name_entry->value->data,msginfoLen); msginfo[msginfoLen]='\0'; } //Print out information according to NID switch(Nid) { case NID_countryName://country tmp.Format("issuer 's countryName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_stateOrProvinceName://province tmp.Format("issuer 's ProvinceName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_localityName://region tmp.Format("issuer 's localityName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationName://organization tmp.Format("issuer 's organizationName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_organizationalUnitName://Company tmp.Format("issuer 's organizationalUnitName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_commonName://Common name tmp.Format("issuer 's commonName:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; case NID_pkcs9_emailAddress://Mail tmp.Format("issuer 's emailAddress:%s\n",msginfo); m_list.InsertString(-1,tmp); tmp.Empty(); break; }//end switch } //Obtain the subject information of the certificate, which is similar to the previous one, and is omitted here subject = X509_get_subject_name(usrCert); ......... //Get certificate effective date time = X509_get_notBefore(usrCert); tmp.Format("Cert notBefore:%s\n",time->data); m_list.InsertString(-1,tmp); tmp.Empty(); //Get certificate expiration date time = X509_get_notAfter(usrCert); tmp.Format("Cert notAfter:%s\n",time->data); m_list.InsertString(-1,tmp); tmp.Empty(); //Get certificate public key pubKey = X509_get_pubkey(usrCert); pTmp=derpubkey; //Convert the certificate public key into DER encoded data derpubkeyLen=i2d_PublicKey(pubKey,&pTmp); printf("PublicKey is: \n"); for(i = 0; i < derpubkeyLen; i++) { CString tmpp; tmpp.Format("%02x", derpubkey[i]); tmp=tmp+tmpp; } m_list.InsertString(-1,tmp); //Free structure memory X509_free(usrCert);