📄 ca.cpp
字号:
// 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 + -