openssl - programming analysis of digital certificate

Posted by rubing on Thu, 10 Feb 2022 15:10:35 +0100

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);

Topics: OpenSSL