📄 ca.cpp
字号:
// CA.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include <locale.h>
#include "ca.h"
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/pkcs12.h>
#include <openssl/rand.h>
//#include <sys/stat.h> stat() 可以得到文件状态
#define EXT_COPY_NONE 0
#define EXT_COPY_ADD 1
#define EXT_COPY_ALL 2
#define MAX_CERT_LEN 8192 //最大公钥长度
#define MAX_KEY_LEN 4096 //最大私钥长度
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
OpenSSL_add_all_algorithms(); //leak EVP_cleanup(void);
ERR_load_crypto_strings(); // leak ERR_free_strings()
//ENGINE_load_builtin_engines();
break;
case DLL_PROCESS_DETACH:
CONF_modules_unload(1);
EVP_cleanup();
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
ERR_free_strings();
CONF_modules_free();
break;
}
return TRUE;
}
void LastError(char * info)
{
/* BIO * mem = BIO_new(BIO_s_mem());
BIO_set_close(mem, BIO_CLOSE);
ERR_print_errors(mem);
BUF_MEM * bptr = NULL;
BIO_get_mem_ptr(mem, &bptr);
int len = bptr->length;
char * pbuf = new char[len+1];
memset(pbuf,0,len+1);
memcpy(pbuf,bptr->data,len);
delete [] pbuf;*/
}
/*此函数可以将DER、PEM、P12文件公钥读出来*/
X509 *load_cert(BIO * pBioCert/*输入BIO*/, const int iFormat/*格式*/,
const char * lpszPwd,/*P12密码*/
char * outMsg) //从DER、PEM、P12格式中加载公钥证书
{
X509 * x = NULL;
if(iFormat == DER)
x = d2i_X509_bio(pBioCert,NULL);
else if (iFormat == PEM)
x = PEM_read_bio_X509(pBioCert,NULL,NULL,NULL);//PEM_read_bio_X509_AUX
else if (iFormat == P12)
{
OpenSSL_add_all_algorithms();
PKCS12 *p12 = d2i_PKCS12_bio(pBioCert, NULL);
PKCS12_parse(p12, lpszPwd, NULL, &x, NULL);
PKCS12_free(p12);
p12 = NULL;
// EVP_cleanup();
}
else
{
sprintf(outMsg,"bad input format specified for input cert\n");
goto end;
}
end:
if (x == NULL)
{
sprintf(outMsg,"unable to load certificate\n");
}
else
sprintf(outMsg,"");
return(x);
}
X509 * LoadCert(const char * lpszCert,const int iCertlen,
const char * lpszPass,char * outMsg)//枚举DER/PEM格式
{
BIO * in = NULL;
X509 * x509 = NULL;
if(iCertlen == 0)//输入为磁盘文件
{
if((in = BIO_new_file(lpszCert, "r")) == NULL)
{
sprintf(outMsg,"open CA certificate file error");
return NULL;
}
}
else//输入为内存中文件
{
if((in = BIO_new_mem_buf((void *)lpszCert,iCertlen)) == NULL)//只读类型
{
sprintf(outMsg,"Make Mem Bio Error");
return NULL;
}
}
if((x509 = load_cert(in,DER,NULL,outMsg)) == NULL)//尝试DER
{
BIO_reset(in);//恢复bio
if((x509 = load_cert(in,PEM,NULL,outMsg)) == NULL)//尝试PEM
{
BIO_reset(in);//恢复bio
x509 = load_cert(in,P12,lpszPass,outMsg);//尝试P12
}
}
if (in != NULL) BIO_free(in);
return x509;
}
EVP_PKEY * load_key(BIO * pBioKey, const int iFormat, const char * lpszPass,char * outMsg)//枚举DER/PEM格式
{
EVP_PKEY * pkey = NULL;
OpenSSL_add_all_algorithms();
if (iFormat == DER)
{
if(NULL == lpszPass || strlen(lpszPass) == 0)
{
pkey = d2i_PrivateKey_bio(pBioKey, NULL);
}
else
{
//添加解密链
unsigned char key[EVP_MAX_KEY_LENGTH] = "";//算法最长的KEY长度
unsigned char iv[EVP_MAX_IV_LENGTH] = "";//算法最长的IV长度
BIO * bDec = NULL;
bDec = BIO_new(BIO_f_cipher());
const EVP_CIPHER * cipher = NULL;
cipher = EVP_des_ede3_cbc(); // 3DES-EDE-CBC
if(EVP_BytesToKey(cipher,EVP_sha1(),NULL,(unsigned char *)lpszPass,
strlen(lpszPass),1,key,iv))
{
BIO_set_cipher(bDec,cipher,key,iv, 0);//1-加密、0-解密
pBioKey = BIO_push(bDec, pBioKey);
BIO_flush(pBioKey);
pkey = d2i_PrivateKey_bio(pBioKey, NULL);//私钥解密
pBioKey = BIO_pop(pBioKey);
BIO_free(bDec);
}
else
{
strcpy(outMsg,"初始化key or iv 失败");
goto end;
}
}
}
else if (iFormat == PEM)
{
pkey = PEM_read_bio_PrivateKey(pBioKey,NULL,NULL,(void * )lpszPass);
}
else if (iFormat == P12)
{
PKCS12 *p12 = d2i_PKCS12_bio(pBioKey, NULL);
PKCS12_parse(p12, lpszPass, &pkey, NULL, NULL);
PKCS12_free(p12);
p12 = NULL;
}
else
{
sprintf(outMsg,"bad input format specified for key\n");
goto end;
}
end:
// EVP_cleanup();
if (pkey == NULL)
sprintf(outMsg,"unable to load Private Key\n");
else
sprintf(outMsg,"");
return(pkey);
}
EVP_PKEY * LoadKey(const char * lpszkey,const int iKeylen,const char * lpszPass,char * outMsg) //leak 4772
{
EVP_PKEY *pkey = NULL;
BIO * in = NULL;
if(iKeylen ==0 )//输入为磁盘文件
{
if((in = BIO_new_file(lpszkey, "r")) == NULL)
{
sprintf(outMsg,"open CA certificate file error");
goto end;
}
}
else//输入为内存中文件
{
if((in = BIO_new_mem_buf((void *)lpszkey,iKeylen)) == NULL)//只读类型
{
sprintf(outMsg,"Make Mem Bio Error");
goto end;
}
}
if((pkey = load_key(in,DER,lpszPass,outMsg)) == NULL)//尝试DER
{
BIO_reset(in);//BIO是可读写的,那么该BIO所有数据都会被清空;
//如果该BIO是只读的,那么该操作只会简单将指
//针指向原始位置,里面的数据可以再读.
if((pkey = load_key(in,PEM,lpszPass,outMsg)) == NULL)//尝试PEM
{
BIO_reset(in);
pkey = load_key(in,P12,lpszPass,outMsg);
}
}
end:
if (in != NULL)
{
BIO_flush(in);
BIO_free_all(in);
}
return pkey;
}
int Rand(const char * file,const 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 * pCert/*正被添加的证书*/,X509 * pRoot/*根证书(从中得到信息)*/,
const int iNid, const char * lpszValue)
{
X509_EXTENSION * ex = NULL;
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,pRoot, pCert, NULL, NULL, 0);
ex = X509V3_EXT_nconf_nid(NULL, &ctx, iNid, (char *)lpszValue);//X509V3_EXT_nconf
if (!ex)
{
return 0;
}
X509_add_ext(pCert,ex,-1);
X509_EXTENSION_free(ex);
return 1;
}
int Add_ExtCert(X509 *pCert/*正被添加的证书*/,X509 * pRoot/*根证书(从中得到信息)*/,
const char * lpszName, const char *lpszValue)
{
X509_EXTENSION * ex = NULL;
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, pRoot, pCert, NULL, NULL, 0);
ex = X509V3_EXT_conf(NULL, &ctx, (char *)lpszName, (char *)lpszValue);//X509V3_EXT_nconf
if (!ex)
{
return 0;
}
X509_add_ext(pCert,ex,-1);
X509_EXTENSION_free(ex);
return 1;
}
int AddExtCert(X509 *pCert/*正被添加的证书*/,X509 * pRoot/*根证书(从中得到信息)*/,
const stuCERTEXT * pCertExt)
{
/* This sets the 'context' of the extensions. */
/* No configuration database */
/* Issuer and subject certs: both the target since it is self signed,
* no request and no CRL
*/
//基本限制Note if the CA option is FALSE the pathlen option should be omitted.
// Add_ExtCert(pCert,pCert,NID_friendlyName, "130203197703060618");
//主题密钥标示符--------区分拥有者多对密钥
// Add_ExtCert(pCert,pCert,NID_subject_key_identifier, "hash");
//Authority密钥标示符----区分发行者有多个签名密钥时
// Add_ExtCert(pCert,pRoot, NID_authority_key_identifier, "keyid,issuer:always");
//密钥用法 ----数字签名、不可否认性、密钥加密、数据加密、密钥协商、证书签名、
//颁发者备用名称,URL:http://my.url.here/、不支持email copy
// Add_ExtCert(pCert,pCert, NID_issuer_alt_name,
// "DNS:hpxs,email:hpxs@hotmail.com,RID:1.2.3.4,URI:https://hpxs,IP:192.168.0.22");
//
//证书策略
// Add_ExtCert(pCert,pCert,NID_certificate_policies,"requireExplicitPolicy:3");
//颁发机构信息访问
// Add_ExtCert(pCert,pCert,NID_info_access,"OCSP;URI:https://hpxs");//或者caIssuers;URI:http://my.ca/ca.html
//CRL分发点
// Add_ExtCert(pCert,pCert, NID_crl_distribution_points, "URI:https://hpxs/hpxs.crl");
/* Some Netscape specific extensions */
// Add_ExtCert(ret,ret, NID_crl_number, "sslCA");
// Add_ExtCert(ret,px509, NID_netscape_comment, "See http://cert.umd.edu/root for details.");
/* In each case the 'value' of the extension is placed directly in the
extension. Currently supported extensions in this category are: nsBaseUrl,
nsRevocationUrl, nsCaRevocationUrl, nsRenewalUrl, nsCaPolicyUrl,
nsSslServerName and nsComment */
// Add_ExtCert(ret,px509, NID_netscape_cert_type, "client, server, email,objsign, reserved, sslCA,emailCA, objCA");
/*nsCertType (netscape certificate type) takes the flags: client, server, email,
objsign, reserved, sslCA, emailCA, objCA.*/
/* Maybe even add our own extension based on existing */
// nid = OBJ_create("1.3.6.1.4.1.5315.100.2.5", "Hpxs", "OC61108551");0.9.2342.19200300.100.1.1
// X509V3_EXT_add_alias(nid, NID_netscape_comment);
// Add_ExtCert(ret,ret, nid, "OC61108551");
while(pCertExt!=NULL)//遍历链表
{
if(OBJ_sn2nid(pCertExt->cName) == NID_authority_key_identifier)
{
Add_ExtCert(pCert, pRoot, OBJ_sn2nid(pCertExt->cName), (char *)pCertExt->cInfo);
}
else if(strstr(pCertExt->cName, ".") == NULL) //没有发现.
{
Add_ExtCert(pCert, pCert, OBJ_sn2nid(pCertExt->cName), (char *)pCertExt->cInfo);
}
else
{ //加入自定义信息begin
int nid;
nid = OBJ_create(pCertExt->cName, pCertExt->cName, pCertExt->cName);
if(nid != NID_undef)
{
X509V3_EXT_add_alias(nid, NID_netscape_comment);
Add_ExtCert(pCert,pCert, nid, pCertExt->cInfo);
}
OBJ_cleanup();
}
pCertExt = pCertExt->Link;
}
return 1;
}
void Ansi2Utf8(const LPSTR lpsrc, const int srclen, LPSTR lpdst, int& dstlen)
{
WCHAR * pwUnicode;
int len = MultiByteToWideChar(CP_ACP,0,(char*)lpsrc,srclen,NULL,0);
pwUnicode = new WCHAR[len];
memset(pwUnicode,0,len);
MultiByteToWideChar(CP_ACP,0 ,(char*)lpsrc,srclen,pwUnicode,len);
dstlen = WideCharToMultiByte(CP_UTF8,0,pwUnicode,len,NULL,0,NULL,NULL);
WideCharToMultiByte(CP_UTF8,0,pwUnicode,len,lpdst,dstlen,NULL,NULL);
delete []pwUnicode;
}
BOOL Add_Name(X509_NAME * px509Name,const int iNid/*c\cn*/,
const int iType/*V_ASN1_UTF8STRING*/,
const char * lpszInput/*中国*/,
const int iLen/*输入长度*/)//支持中文名称
{
if(NULL == lpszInput || strlen(lpszInput) == 0)
return FALSE;
if(iType == V_ASN1_UTF8STRING)
{
char lpdst[1024] = {0};
int dstlen = 0;
char input[256]={0};
strncpy(input, lpszInput, iLen);
Ansi2Utf8(input, iLen, lpdst, dstlen);
X509_NAME_add_entry_by_NID(px509Name,iNid,V_ASN1_UTF8STRING,(UCHAR *)lpdst,dstlen, -1, 0);
}
else
X509_NAME_add_entry_by_NID(px509Name,iNid,iType,(UCHAR *)lpszInput,iLen, -1, 0);
return TRUE;
}
BOOL Add_Name(X509_NAME * px509Name,const char * field/*c\cn*/,
const char * lpszInput/*中国*/,
const int iLen/*输入长度*/)//支持中文名称
{
if(NULL == lpszInput || strlen(lpszInput) == 0)
return FALSE;
BOOL bRet = FALSE;
int nid = NID_undef;
int iType = V_ASN1_UTF8STRING;
if(strstr(field, ".") == NULL) //没有发现.
{
nid = OBJ_txt2nid(field);
}
else
{
nid = OBJ_create(field, field, field);
}
if(nid != NID_undef)
{
if(NID_pkcs9_emailAddress == nid)
{
iType = V_ASN1_IA5STRING;
}
else
{
iType = V_ASN1_UTF8STRING;
}
bRet = Add_Name(px509Name, nid, iType, lpszInput, iLen);
}
OBJ_cleanup();
return bRet;
}
void AddName(X509_NAME * px509Name,const stuSUBJECT * pSubJect)
{
setlocale(LC_CTYPE, "");
while(pSubJect != NULL)//遍历链表
{
Add_Name(px509Name, (char *)pSubJect->cName, (char *)pSubJect->cInfo,strlen((char *)pSubJect->cInfo));
pSubJect = pSubJect->Link;
}
/*
Add_Name(px509Name,NID_stateOrProvinceName,V_ASN1_UTF8STRING,(char *)pSubJect->ST,strlen((char *)pSubJect->ST));
Add_Name(px509Name,NID_localityName,V_ASN1_UTF8STRING,(char *)pSubJect->L,strlen((char *)pSubJect->L));
Add_Name(px509Name,NID_organizationName,V_ASN1_UTF8STRING,(char *)pSubJect->O,strlen((char *)pSubJect->O));
Add_Name(px509Name,NID_organizationalUnitName,V_ASN1_UTF8STRING,(char *)pSubJect->OU,strlen((char *)pSubJect->OU));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -