⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ca.cpp

📁 小型CA的完整代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// CA.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <locale.h>
#include "ca.h"
#include "pem.h"
#include <x509.h>
#include <x509v3.h>
#include <pkcs12.h>
#include <rand.h>

#include <engine.h>
#define EXT_COPY_NONE	0
#define EXT_COPY_ADD	1
#define EXT_COPY_ALL	2

BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
					 )
{
    return TRUE;
}

/*此函数可以将DER、PEM、P12文件公钥读出来*/
X509 *load_cert(BIO *cert/*输入BIO*/, int format/*格式*/,char * pwd,/*P12密码*/
				char * outMsg) //从DER、PEM、P12格式中读取公钥证书
{
	X509 * x=NULL;
	if 	(format == DER)
		x=d2i_X509_bio(cert,NULL);
	else if (format == PEM)
		x=PEM_read_bio_X509(cert,NULL,NULL,NULL);//PEM_read_bio_X509_AUX
	else if (format == P12)
	{
		PKCS12 *p12 = d2i_PKCS12_bio(cert, NULL);
		PKCS12_parse(p12, pwd, NULL, &x, NULL);
		PKCS12_free(p12);
		p12 = NULL;
	}
	else
	{
		sprintf(outMsg,"bad input format specified for input cert\n");
		goto end;
	}
end:
	if (x == NULL)
	{
		sprintf(outMsg,"unable to load certificate\n");
	}
	return(x);
}

X509 * LoadCert(char * cert,int certlen,char * outMsg)//枚举DER/PEM格式
{
	BIO * in=NULL;
	X509 * x509=NULL;

	if(certlen==0)//输入为磁盘文件
	{
		if((in=BIO_new_file(cert, "r")) == NULL)
		{
			sprintf(outMsg,"open CA certificate file error");
			return NULL;
		}
	}
	else//输入为内存中文件
	{
		if((in=BIO_new_mem_buf(cert,certlen))== NULL)//只读类型
		{
			sprintf(outMsg,"Make Mem Bio Error");
			return NULL;
		}
	}
	if((x509=load_cert(in,DER,NULL,outMsg))==NULL)//尝试DER
	{
		BIO_reset(in);//恢复bio
		x509=load_cert(in,PEM,NULL,outMsg);//尝试PEM
	}
	if (in != NULL) BIO_free(in);
	return x509;
}

EVP_PKEY *load_key(BIO *bio, int format, char *pass,char * outMsg)//枚举DER/PEM格式
{
	EVP_PKEY *pkey=NULL;

	if (format == DER)
	{
		pkey=d2i_PrivateKey_bio(bio, NULL);
	}
	else if (format == PEM)
	{
		pkey=PEM_read_bio_PrivateKey(bio,NULL,NULL,pass);
	}
	else if (format == P12)
	{
		PKCS12 *p12 = d2i_PKCS12_bio(bio, NULL);
		PKCS12_parse(p12, pass, &pkey, NULL, NULL);
		PKCS12_free(p12);
		p12 = NULL;
	}
	else
	{
		sprintf(outMsg,"bad input format specified for key\n");
		goto end;
	}
end:
	if (pkey == NULL)
		sprintf(outMsg,"unable to load Private Key\n");
	return(pkey);
}

EVP_PKEY * LoadKey(char * key,int keylen,char * pass,char * outMsg)
{
	EVP_PKEY *pkey=NULL;
	BIO * in=NULL;

	if(keylen==0)//输入为磁盘文件
	{
		if((in=BIO_new_file(key, "r")) == NULL)
		{
			sprintf(outMsg,"open CA certificate file error");
			return NULL;
		}
	}
	else//输入为内存中文件
	{
		if((in=BIO_new_mem_buf(key,keylen))== NULL)//只读类型
		{
			sprintf(outMsg,"Make Mem Bio Error");
			return NULL;
		}
	}

	if((pkey=load_key(in,DER,pass,outMsg))==NULL)//尝试DER
	{
		BIO_reset(in);//BIO是可读写的,那么该BIO所有数据都会被清空;
						//如果该BIO是只读的,那么该操作只会简单将指
						//针指向原始位置,里面的数据可以再读.
		pkey=load_key(in,PEM,pass,outMsg);//尝试PEM
	}
	if (in != NULL) BIO_free(in);
	return pkey;
}
int Rand(const char *file,int dont_warn,char * outMsg)//产生随机数,return 0 ---成功
{
	int consider_randfile = (file == NULL);
	char buffer[200];
	
	RAND_screen();
	if (file == NULL)
		file = RAND_file_name(buffer, sizeof buffer);
	else if (RAND_egd(file) > 0)
	{
	/* we try if the given filename is an EGD socket.
		if it is, we don't write anything back to the file. */
		return 1;
	}
	if (file == NULL || !RAND_load_file(file, -1))
	{
		if (RAND_status() == 0 && !dont_warn)
		{
			sprintf(outMsg,"unable to load 'random state'\n");
			sprintf(outMsg,"This means that the random number generator has not been seeded\n");
			if (consider_randfile) /* explanation does not apply when a file is explicitly named */
			{
				sprintf(outMsg,"Consider setting the RANDFILE environment variable to point at a file that\n");
				sprintf(outMsg,"'random' data can be kept in (the file will be overwritten).\n");
			}
		}
		return 0;
	}
	return 1;
}


///////////////////////// end ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
///////////////////////// begin //////////////////////////////////////

/* Add extension using V3 code: we can set the config file as NULL
* because we wont reference any other sections.
*/
int Add_ExtCert(X509 *cert/*正被添加的证书*/,X509 * root/*根证书(从中得到信息)*/, int nid, char *value)
{
	X509_EXTENSION *ex;
	X509V3_CTX ctx;
	/* This sets the 'context' of the extensions. */
	/* No configuration database */
	//	X509V3_set_ctx_nodb(&ctx);
	/* Issuer and subject certs: both the target since it is self signed,
	* no request and no CRL
	*/
	X509V3_set_ctx(&ctx,root, cert, NULL, NULL, 0);
	ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
	if (!ex)
		return 0;
	
	X509_add_ext(cert,ex,-1);
	X509_EXTENSION_free(ex);
	return 1;
}

bool Add_Name(X509_NAME * x509name,int type/*c\cn*/,char * iput/*中国*/,
			  int ilen/*输入长度*/,char * outMsg)//支持中文名称
{
	wchar_t * ws,wc;
	ASN1_STRING stmp, *str = &stmp;
  	UCHAR cbuf[256]={0};
    int wslen, wcnt,i;
	char input[256]={0};
	strncpy(input, iput, ilen);
    wslen = strlen(input) + 1;
	if(wslen==1)
		return true;
    ws =new unsigned short[sizeof(wchar_t) * wslen];	
    if ((wcnt = mbstowcs(ws, input, wslen)) == -1)
	{
        sprintf(outMsg,"mbstowcs convert error");
        delete ws;
        return false;				
    }
	for(i=0;i<(int)wcslen(ws);i++)
	{ 
		wc=ws[i];
		cbuf[2*i]=wc/256;
		cbuf[2*i+1]=wc%256;
	}

    ASN1_mbstring_copy(&str, cbuf, 2*wslen, MBSTRING_BMP, B_ASN1_UTF8STRING);
	X509_NAME_add_entry_by_NID(x509name,type,V_ASN1_UTF8STRING,stmp.data,stmp.length, -1, 0);
	delete ws;
	return true;
}
bool mkRoot(stuSUBJECT * rootInfo,X509 **x509p/*out公钥*/, EVP_PKEY **pkeyp/*out私钥*/, 
		   int bits/*位数*/, int serial/*序列号*/, int days/*有效期*/,char * out/*操作结果*/)
{
	X509 *x;
	EVP_PKEY *pk;
	RSA *rsa;
	X509_NAME *name=NULL;
	int i=0,len=0;
	if ((pkeyp == NULL) || (*pkeyp == NULL))
	{
		if ((pk=EVP_PKEY_new()) == NULL)
		{
			abort(); 
			return false;
		}
	}
	else
		pk= *pkeyp;
	
	if ((x509p == NULL) || (*x509p == NULL))
	{
		if ((x=X509_new()) == NULL)
			goto err;
	}
	else
		x= *x509p;

	Rand(NULL,1,out);//产生随机数种子
	rsa=RSA_generate_key(bits,RSA_F4,0/*回调函数callback*/,NULL);//产生密钥对,//RSA存储了公钥私钥
	if (!EVP_PKEY_assign_RSA(pk,rsa))//完成RSA密钥的pkey结构初始工作,当pk不为NULL的时候,返回1,否则返回0
	{
		abort();
		goto err;
	}
	rsa=NULL;
	
	X509_set_version(x,2);//版本号,显示+1
	ASN1_INTEGER_set(X509_get_serialNumber(x),serial);//序列号
	X509_gmtime_adj(X509_get_notBefore(x),0);//起始时间
	X509_gmtime_adj(X509_get_notAfter(x),(long)60*60*24*days);//结束时间
	X509_set_pubkey(x,pk);//公钥
	
	name=X509_get_subject_name(x);
	
	/* This function creates and adds the entry, working out the
	* correct string type and performing checks on its length.
	* Normally we'd check the return value for errors...
	*/

	//C-国家,ST-省,L-城市,O-组织,OU-部门,CN-个体,T-title,D-description,G-givenName,I-initials,
	//Email-emailAddress,S-surname,SN-serialNumber,dnQualifier-dnQualifier,unstructuredName,challengePassword,unstructuredAddress,

	setlocale(LC_CTYPE, "");

	Add_Name(name,NID_countryName,(char *)rootInfo->C,sizeof(rootInfo->C),out);
	Add_Name(name,NID_stateOrProvinceName,(char *)rootInfo->ST,sizeof(rootInfo->ST),out);
	Add_Name(name,NID_localityName,(char *)rootInfo->L,sizeof(rootInfo->L),out);
	Add_Name(name,NID_organizationName,(char *)rootInfo->O,sizeof(rootInfo->O),out);
	Add_Name(name,NID_organizationalUnitName,(char *)rootInfo->OU,sizeof(rootInfo->OU),out);
	Add_Name(name,NID_commonName,(char *)rootInfo->CN,sizeof(rootInfo->CN),out);
	Add_Name(name,NID_pkcs9_emailAddress,(char *)rootInfo->MAIL,sizeof(rootInfo->MAIL),out);
	Add_Name(name,NID_email_protect,(char *)rootInfo->PMAIL,sizeof(rootInfo->PMAIL),out);

	
	Add_Name(name,NID_title,(char *)rootInfo->T,sizeof(rootInfo->T),out);
	Add_Name(name,NID_description,(char *)rootInfo->D,sizeof(rootInfo->D),out);
	Add_Name(name,NID_givenName,(char *)rootInfo->G,sizeof(rootInfo->G),out);	
	Add_Name(name,NID_initials,(char *)rootInfo->I,sizeof(rootInfo->I),out);
	Add_Name(name,NID_name,(char *)rootInfo->NAME,sizeof(rootInfo->NAME),out);	
	Add_Name(name,NID_surname,(char *)rootInfo->S,sizeof(rootInfo->S),out);
	Add_Name(name,NID_dnQualifier,(char *)rootInfo->QUAL,sizeof(rootInfo->QUAL),out);
	Add_Name(name,NID_pkcs9_unstructuredName,(char *)rootInfo->STN,sizeof(rootInfo->STN),out);
	Add_Name(name,NID_pkcs9_challengePassword,(char *)rootInfo->PW,sizeof(rootInfo->PW),out);
	Add_Name(name,NID_pkcs9_unstructuredAddress,(char *)rootInfo->ADD,sizeof(rootInfo->ADD),out);

	/* Its self signed so set the issuer name to be the same as the
	* subject.
	*/
	
	X509_set_issuer_name(x,name);//设置发行者名称等同于上面的

	//加入扩展信息
	/* Add various extensions: standard extensions */
	Add_ExtCert(x,x,NID_basic_constraints, "critical,CA:TRUE");
	//主题密钥标示符---当发行者有多个签名密钥时
	Add_ExtCert(x,x,NID_subject_key_identifier, "hash");
	//颁发机构密钥标示符
	Add_ExtCert(x,x,NID_authority_key_identifier, "keyid:always");
	//密钥用法
	Add_ExtCert(x,x,NID_key_usage, "nonRepudiation,digitalSignature,keyEncipherment");
	Add_ExtCert(x,x,NID_domainComponent, "no");	
	Add_ExtCert(x,x,NID_Domain, "no");
	/* Some Netscape specific extensions */
//	Add_ExtCert(x, NID_netscape_cert_type, "sslCA");
//	Add_ExtCert(x, NID_netscape_comment, "example comment extension");//netscape_comment
	
	
	/* Maybe even add our own extension based on existing */
	//加入自定义信息begin
//	int nid;
//	nid = OBJ_create("1.2.3.4.9", "Hpxs", "I love you!");
//	X509V3_EXT_add_alias(nid, NID_netscape_comment);
//	Add_ExtCert(x, nid, "I love you");
	//加入自定义信息end
	X509V3_EXT_cleanup();//cleanup the extension code if any custom extensions have been added
	if (!X509_sign(x,pk,EVP_sha1()))//签名算法EVP_sha1,EVP_md5,用私钥签名公钥
	{
		strcpy(out,"证书签名失败");
		goto err;
	}
	*x509p=x;
	*pkeyp=pk;
	return true;
err:
	return false;
}


BOOL MakeRoot(stuSUBJECT * rootInfo,/*信息*/int bits/*位数*/, int serial/*序列号*/, 
			  int days/*有效期*/,char * certFile/*证书文件*/,char * priFile/*私钥文件*/,
			  char * outMsg/*操作结果*/,int type/*类型pem-der*/)
{
	
	X509 *x509=NULL;
	EVP_PKEY *pkey=NULL;
	BIO * bcert=NULL,* bkey=NULL;
	bool ret=true;
	int i=0,j=0;

	if(((bcert=BIO_new_file(certFile, "w"))== NULL)||((bkey=BIO_new_file(priFile, "w")) == NULL))
	{
		strcpy(outMsg,"Create File Error");
		return false;
	}
	if(mkRoot(rootInfo,&x509,&pkey,bits,serial,days,outMsg))
	{
		if (type==DER)
		{
			i=i2d_X509_bio(bcert,x509);//returns 1 for success 
			j=i2d_PrivateKey_bio(bkey,pkey);
		}
		else if(type==PEM)
		{
			i=PEM_write_bio_X509(bcert,x509);
			j=PEM_write_bio_PrivateKey(bkey,pkey,NULL,NULL,0,NULL, NULL);
		}
		if(!i||!j)
		{
			ret=false;
			strcpy(outMsg,"Save Cert or Key File Error");
		}
	}
	else
		ret=false;
	BIO_free(bcert);
	BIO_free(bkey);
	X509_free(x509);
	EVP_PKEY_free(pkey);
	return ret;

}

///////////////////////// end ////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
///////////////////////// begin //////////////////////////////////////

/* Add extension using V3 code: we can set the config file as NULL
 * because we wont reference any other sections.
 */
int Add_ExtReq(STACK_OF(X509_REQUEST) *sk, int nid, char *value)
{
	X509_EXTENSION *ex;
	ex = X509V3_EXT_conf_nid(NULL, NULL, nid, value);
	if (!ex)
		return 0;
	sk_X509_EXTENSION_push(sk, ex);
	
	return 1;
}
	
int mkReq(stuSUBJECT * reqInfo,X509_REQ **req, EVP_PKEY **pkeyp, int bits,char * out)
{
	X509_REQ *x;
	EVP_PKEY *pk;
	RSA *rsa;
	X509_NAME *name=NULL;
	ASN1_STRING stmp, *str = &stmp;
	
	STACK_OF(X509_EXTENSION) *exts = NULL;
	
	if ((pk=EVP_PKEY_new()) == NULL)
		goto err;
	
	if ((x=X509_REQ_new()) == NULL)
		goto err;
	Rand(NULL,1,out);//产生随机数种子
	rsa=RSA_generate_key(bits,RSA_F4,0/*回调函数callback*/,NULL);//产生密钥对
	//PEM_write_bio_RSAPrivateKey
	if (!EVP_PKEY_assign_RSA(pk,rsa))
		goto err;
	
	rsa=NULL;
	
	X509_REQ_set_pubkey(x,pk);
	
	name=X509_REQ_get_subject_name(x);
	
	/* This function creates and adds the entry, working out the
	* correct string type and performing checks on its length.
	* Normally we'd check the return value for errors...
	*/

	setlocale(LC_CTYPE, "");

	Add_Name(name,NID_countryName,(char *)reqInfo->C,sizeof(reqInfo->C),out);
	Add_Name(name,NID_stateOrProvinceName,(char *)reqInfo->ST,sizeof(reqInfo->ST),out);
	Add_Name(name,NID_localityName,(char *)reqInfo->L,sizeof(reqInfo->L),out);
	Add_Name(name,NID_organizationName,(char *)reqInfo->O,sizeof(reqInfo->O),out);
	Add_Name(name,NID_organizationalUnitName,(char *)reqInfo->OU,sizeof(reqInfo->OU),out);
	Add_Name(name,NID_commonName,(char *)reqInfo->CN,sizeof(reqInfo->CN),out);
	Add_Name(name,NID_pkcs9_emailAddress,(char *)reqInfo->MAIL,sizeof(reqInfo->MAIL),out);
	Add_Name(name,NID_email_protect,(char *)reqInfo->PMAIL,sizeof(reqInfo->PMAIL),out);

	Add_Name(name,NID_title,(char *)reqInfo->T,sizeof(reqInfo->T),out);
	Add_Name(name,NID_description,(char *)reqInfo->D,sizeof(reqInfo->D),out);
	Add_Name(name,NID_givenName,(char *)reqInfo->G,sizeof(reqInfo->G),out);
	Add_Name(name,NID_initials,(char *)reqInfo->I,sizeof(reqInfo->I),out);
	Add_Name(name,NID_name,(char *)reqInfo->NAME,sizeof(reqInfo->NAME),out);	
	Add_Name(name,NID_surname,(char *)reqInfo->S,sizeof(reqInfo->S),out);
	Add_Name(name,NID_dnQualifier,(char *)reqInfo->QUAL,sizeof(reqInfo->QUAL),out);
	Add_Name(name,NID_pkcs9_unstructuredName,(char *)reqInfo->STN,sizeof(reqInfo->STN),out);
	Add_Name(name,NID_pkcs9_challengePassword,(char *)reqInfo->PW,sizeof(reqInfo->PW),out);
	Add_Name(name,NID_pkcs9_unstructuredAddress,(char *)reqInfo->ADD,sizeof(reqInfo->ADD),out);


	/* Certificate requests can contain extensions, which can be used
		* to indicate the extensions the requestor would like added to 
		* their certificate. CAs might ignore them however or even choke
		* if they are present.
	*/
	
	/* For request extensions they are all packed in a single attribute.
	* We save them in a STACK and add them all at once later...
	*/
	
	exts = sk_X509_EXTENSION_new_null();
	/* Standard extenions */
	//主题备用名称,URL:http://my.url.here/、支持email  copy
	Add_ExtReq(exts, NID_subject_alt_name, "DNS:localhost,email:hpxs@hotmail.com,RID:1.2.3.4,URI:192.168.2.22,IP:C0A80216");

	//加入自定义扩展
	int nid;
	nid = OBJ_create("1.3.6.1.4.1.5315.100.2.5", "UserID", "User ID Number");
	X509V3_EXT_add_alias(nid, NID_netscape_comment);
	Add_ExtReq(exts, nid, "ID130203197703060618");
	/* Now we've created the extensions we add them to the request */

	X509_REQ_add_extensions(x, exts);
	sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);	
	X509V3_EXT_cleanup();//cleanup the extension code if any custom extensions have been added
	
	if (!X509_REQ_sign(x,pk,EVP_sha1()))//用自己的公钥签名私钥
		goto err;
	
	*req=x;
	*pkeyp=pk;
	return(1);
err:
	return(0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -