//
CA.cpp : Defines the entry point for the DLL application.
//
#define sprintf_s sprintf
#include "stdafx.h"
#include <LOCALE.H>
#include "ca.h"
#include <OPENSSL pem.h>
#include <OPENSSL x509.h>
#include <OPENSSL x509v3.h>
#include <OPENSSL pkcs12.h>
#include <OPENSSL rand.h>
#include<STDLIB.H>
#include<STDIO.H>
#include <OPENSSL 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_s(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);
}
BOOL MakeReq(stuSUBJECT * reqInfo, /* 请求信息 */ int bits /* 位数 */, char * reqFile /* 证书请求文件 */,
char * priFile /* 私钥文件 */, char * outMsg /* 操作结果 */, int type)
{
X509_REQ *req=NULL;
EVP_PKEY *pkey=NULL;
BIO * breq=NULL,* bkey=NULL;
int i=0,j=0;
if(((breq=BIO_new_file(reqFile, "w"))== NULL)||((bkey=BIO_new_file(priFile, "w")) == NULL))
{
strcpy(outMsg,"Create File Error");
return false;
}
if(!mkReq(reqInfo,&req,&pkey,bits,outMsg))
{
strcpy(outMsg,"Make CertReq Error");
return false;
}
if(type==PEM)
{
i=PEM_write_bio_X509_REQ(breq,req);
j=PEM_write_bio_PrivateKey(bkey,pkey,NULL,NULL,0,NULL, NULL);
}
else if(type==DER)
{
i=i2d_X509_REQ_bio(breq,req);
j=i2d_PrivateKey_bio(bkey,pkey);
}
BIO_free(breq);
BIO_free(bkey);
X509_REQ_free(req);
EVP_PKEY_free(pkey);
if(!i||!j)
{
strcpy(outMsg,"Save Cert or Key File Error");
return false;
}
return true;
}
// end //
// //
/// begin /// /
int copy_extensions(X509 *x, X509_REQ *req, int copy_type) // 在证书中加入req自带扩展信息
{
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ext, *tmpext;
ASN1_OBJECT *obj;
int i, idx, ret = 0;
if (!x || !req || (copy_type == EXT_COPY_NONE))
return 1;
exts = X509_REQ_get_extensions(req);
for(i = 0; i < sk_X509_EXTENSION_num(exts); i++)
{
ext = sk_X509_EXTENSION_value(exts, i);
obj = X509_EXTENSION_get_object(ext);
idx = X509_get_ext_by_OBJ(x, obj, -1);
/* Does extension exist? */
if (idx != -1)
{
/* If normal copy don't override existing extension */
if (copy_type == EXT_COPY_ADD)
continue;
/* Delete all extensions of same type */
do
{
tmpext = X509_get_ext(x, idx);
X509_delete_ext(x, idx);
X509_EXTENSION_free(tmpext);
idx = X509_get_ext_by_OBJ(x, obj, -1);
} while (idx != -1);
}
if (!X509_add_ext(x, ext, -1))
goto end;
}
ret = 1;
end:
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
return ret;
}
int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, int serial,
char *startdate, char *enddate, int days,X509_REQ * req,stuKEYUSAGE * KUSAGE,
stuEKEYUSAGE * EKUSAGE, char * outMsg)
{
X509_NAME *name=NULL,*CAname=NULL;
X509 *ret=NULL;
X509_CINF *ci;
EVP_PKEY *pktmp;
int ok= -1,i=0;
// STACK_OF (X509_EXTENSION) * req_exts; // 如何释放??
char kusage[160]={0};
char ekusage[360]={0};
name=X509_REQ_get_subject_name(req);
if ((ret=X509_new()) == NULL)
{
ok=0;
goto err;
}
ci=ret->cert_info;
/* Make it an X509 v3 certificate. 版本1扩展 */
if (!X509_set_version(ret,2L)) // 版本
{
ok=0;
goto err;
}
ASN1_INTEGER_set(X509_get_serialNumber(ret),serial); // 序列号
if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) // 发行者
{
ok=0;
goto err;
}
if (strcmp(startdate,"today") == 0)
X509_gmtime_adj(X509_get_notBefore(ret),0); // 开始日期
else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate);
if (enddate == NULL)
X509_gmtime_adj(X509_get_notAfter(ret),( long)60*60*24*days); // 结束日期
else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate);
if (!X509_set_subject_name(ret,name)) // 主体 ---所有者
{
ok=0;
goto err;
}
pktmp=X509_REQ_get_pubkey(req);
i = X509_set_pubkey(ret,pktmp); // 公钥
EVP_PKEY_free(pktmp);
if (!i)
{
ok=0;
goto err;
}
// 加入req自带扩展信息,生成REQ文件时候加入的
if (!copy_extensions(ret, req, EXT_COPY_ALL))
{
strcpy("加入自带扩展信息失败",outMsg);
goto err;
}
/* Lets add the extensions, if there are any 加入标准扩展 */
// 基本限制Note if the CA option is false the pathlen option should be omitted.
Add_ExtCert(ret,ret,NID_basic_constraints, "critical,CA:FALSE,pathlen:1");
// 主题密钥标示符--------区分拥有者多对密钥
Add_ExtCert(ret,ret,NID_subject_key_identifier, "hash");
// Authority密钥标示符----区分发行者有多个签名密钥时
Add_ExtCert(ret,x509, NID_authority_key_identifier, "keyid,issuer:always");
// 密钥用法 ----数字签名、不可否认性、密钥加密、数据加密、密钥协商、证书签名、
// CRL签名、仅仅加密、仅仅解密
if(KUSAGE->DS)
strcpy(kusage,"digitalSignature");
if(KUSAGE->NR)
if(strlen(kusage)) // 添加
strcat(kusage, ",nonRepudiation");
else
strcpy(kusage,"nonRepudiation");
if(KUSAGE->KE)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyEncipherment");
else
strcpy(kusage,"keyEncipherment");
if(KUSAGE->DE)
if(strlen(kusage)) // 添加
strcat(kusage, ",dataEncipherment");
else
strcpy(kusage,"dataEncipherment");
if(KUSAGE->KA)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyAgreement");
else
strcpy(kusage,"keyAgreement");
if(KUSAGE->KC)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyCertSign");
else
strcpy(kusage,"keyCertSign");
if(KUSAGE->CS)
if(strlen(kusage)) // 添加
strcat(kusage, ",cRLSign");
else
strcpy(kusage,"cRLSign");
if(KUSAGE->EO)
if(strlen(kusage)) // 添加
strcat(kusage, ",encipherOnly");
else
strcpy(kusage,"encipherOnly");
if(KUSAGE->DO)
if(strlen(kusage)) // 添加
strcat(kusage, ",decipherOnly");
else
strcpy(kusage,"decipherOnly");
if(strlen(kusage))
Add_ExtCert(ret,ret, NID_key_usage, kusage);
// 增强型密钥用法--一般只用于末端证书RFC3280
// 增强用法 证书目的
// --------------------------------------------------------------------------------------------------------------
// 服务器验证 保证远程计算机的身份
// 客户端验证 向远程计算机证明您的身份
// 代码签名 确保软件来自软件发行商
// 安全电子邮件 保护软件在发行后不被改动
// 时间戳 保护电子邮件消息
// --------------------------------------------------------------------------------------------------------------
// 保证软件来自一个软件发行商
// 保护软件在发行后不被改动。
// 保证软件来自商业软件发行商
// 允许您用数字签名证书信任列表
// 允许联机事务处理/通讯的严格加密
// 允许加密磁盘上的数据
// 智能卡登录
// IP安全终端系统 允许 Internet 上的安全通讯
// IP安全隧道终止
// IP 安全用户
// --------------------------------------------------------------------------------------------------------------
if(EKUSAGE->SA)
strcpy(ekusage,"serverAuth");
if(EKUSAGE->CA)
if(strlen(ekusage)) // 添加
strcat(ekusage,",clientAuth");
else
strcpy(ekusage,"clientAuth");
if(EKUSAGE->CS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",codeSigning");
else
strcpy(ekusage,"codeSigning");
if(EKUSAGE->EP)
if(strlen(ekusage)) // 添加
strcat(ekusage,",emailProtection");
else
strcpy(ekusage,"emailProtection");
if(EKUSAGE->TS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",timeStamping");
else
strcpy(ekusage,"timeStamping");
if(EKUSAGE->msCC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msCodeCom");
else
strcpy(ekusage,"msCodeCom");
if(EKUSAGE->msCTLS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msCTLSign");
else
strcpy(ekusage,"msCTLSign");
if(EKUSAGE->msSGC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msSGC");
else
strcpy(ekusage,"msSGC");
if(EKUSAGE->msEFS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msEFS");
else
strcpy(ekusage,"msEFS");
if(EKUSAGE->msSC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msSmartcardLogin");
else
strcpy(ekusage,"msSmartcardLogin");
if(EKUSAGE->IP)
if(strlen(ekusage)) // 添加
strcat(ekusage,",ipsecEndSystem,ipsecTunnel,ipsecUser");
else
strcpy(ekusage,"ipsecEndSystem,ipsecTunnel,ipsecUser");
if(strlen(ekusage))
Add_ExtCert(ret,ret,NID_ext_key_usage,ekusage);
/*
Application keyUsage Values
SSL Client digitalSignature
SSL Server keyEncipherment
S/MIME Signing digitalSignature
S/MIME Encryption keyEncipherment
Certificate Signing keyCertSign
Object Signing digitalSignature */
// 颁发者备用名称,URL: http://my.url.here/ 、不支持email copy
Add_ExtCert(ret,ret, 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(ret,ret,NID_certificate_policies,"OK");
// 颁发机构信息访问
Add_ExtCert(ret,ret,NID_info_access,"OCSP;URI:https://hpxs"); // 或者caIssuers;URI: http://my.ca/ca.html
// CRL分发点
Add_ExtCert(ret,x509, NID_crl_distribution_points, "URI:https://hpxs/hpxs.crl");
/* Some Netscape specific extensions */
// Add_ExtCert(ret,ret, NID_crl_number, "sslCA");
// Add_ExtCert(ret,x509, 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,x509, 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 */
// 加入自定义信息begin
int nid;
nid = OBJ_create("1.2.3.4.9", "Hpxs", "I love OpenSSL!");
X509V3_EXT_add_alias(nid, NID_netscape_comment);
Add_ExtCert(ret,ret, nid, "I love OpenSSL");
// 加入自定义信息end
X509V3_EXT_cleanup(); // cleanup the extension code if any custom extensions have been added
if (!X509_sign(ret,pkey,dgst)) // 加入签名,签名算法
{
ok=0;
goto err;
}
ok=1;
err:
if (CAname != NULL)
X509_NAME_free(CAname);
if (ok <= 0)
{
if (ret != NULL) X509_free(ret);
ret=NULL;
}
else
*xret=ret;
return(ok);
}
int certify(X509 **xret, X509_REQ *req, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
int serial, char *startdate, char *enddate, int days,stuKEYUSAGE * KUSAGE,
stuEKEYUSAGE * EKUSAGE, char * outMsg)
{ // 返回公钥证书,请求文件,根私钥,根公钥,
EVP_PKEY *pktmp=NULL;
int ok= -1,i=0;
if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) // 得到公钥
{
sprintf(outMsg,"error unpacking public key\n");
ok=0;
goto err;
}
i=X509_REQ_verify(req,pktmp); // 证书请求里面有私要签名,这里验证一下,看此公钥主人是否持有私钥
EVP_PKEY_free(pktmp);
if (i < 0)
{
ok=0;
sprintf(outMsg,"Signature verification problems .\n");
goto err;
}
if (i == 0)
{
ok=0;
sprintf(outMsg,"Signature did not match the certificate request\n");
goto err;
}
ok=do_body(xret,pkey,x509,dgst,serial,startdate, enddate,
days,req,KUSAGE,EKUSAGE,outMsg);
err:
return(ok);
}
BOOL MakeCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */, char *reqfile /* 请求文件 */,stuKEYUSAGE * KUSAGE /* 密钥用法 */,
stuEKEYUSAGE * EKUSAGE /* 增强密钥用法 */, char *outfile /* 结果文件 */,
char * outMsg /* 操作结果 */, int type /* 结果类型DER,PEM */) // 通过证书请求,得到证书
{
int ret=1;
char * md=NULL;
EVP_PKEY *pkey=NULL;
X509 * x509=NULL;
X509_REQ *req=NULL;
X509 * x=NULL;
BIO * bcert=NULL,* reqbio=NULL;
int j;
const EVP_MD *dgst=NULL;
OpenSSL_add_all_digests(); // 加入签名算法
if((reqbio=BIO_new_file(reqfile, "r")) == NULL)
{
ret=0;
goto err;
}
if ((req=PEM_read_bio_X509_REQ(reqbio,NULL,NULL,NULL)) == NULL) // PEM_read_X509_REQ
{
BIO_reset(reqbio);
if ((req=d2i_X509_REQ_bio(reqbio,NULL)) == NULL)
{
sprintf(outMsg,"Error get certificate request");
ret=0;
goto err;
}
}
pkey=LoadKey(keyfile,keylen,NULL,outMsg);
if (pkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,pkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
md="sha1"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
j=certify(&x,req,pkey,x509,dgst, // 公钥证书out,请求文件,根私钥,根公钥,
serial,"today",enddate,days,KUSAGE,EKUSAGE,outMsg);
if (j <= 0)
{
ret=0;
goto err;
}
if(((bcert=BIO_new_file(outfile, "w"))== NULL))
{
strcpy(outMsg,"Create File Error");
goto err;
}
if (type==DER)
{
i2d_X509_bio(bcert,x);
}
else if(type==PEM)
{
PEM_write_bio_X509(bcert,x);
}
err:
if (reqbio != NULL) BIO_free(reqbio);
BIO_free_all(bcert);
EVP_PKEY_free(pkey);
X509_free(x509);
X509_free(x);
if (req != NULL) X509_REQ_free(req);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return ret;
}
/ end /// /
BOOL DirectCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */,stuCERT * sCERT /* 用户信息与密钥用法 */, int bits, char * cert /* 输出证书公钥 */, int * certl /* 长度 */,
char * key /* 输出证书私钥 */, int * keyl /* 长度 */, char * outMsg /* ,int type结果类型DER,PEM */) // 直接生成公私钥
{
X509_REQ * req=NULL;
EVP_PKEY * pkey=NULL, * prkey=NULL; // 证书私钥, // 根私钥
X509 * x509=NULL,* x=NULL; // 根公钥,证书公钥
BIO * memcert=NULL, * memkey=NULL; // 输出证书公私钥
BUF_MEM *bptrcert=NULL,*bptrkey=NULL;
int ret=1;
char * md=NULL;
int i=0,j=0,ok=0;
const EVP_MD *dgst=NULL;
OpenSSL_add_all_digests(); // 加入签名算法
memcert= BIO_new(BIO_s_mem());
memkey= BIO_new(BIO_s_mem());
BIO_set_close(memcert, BIO_CLOSE); /* BIO_free() free BUF_MEM */
BIO_set_close(memkey, BIO_CLOSE); /* BIO_free() free BUF_MEM */
prkey=LoadKey(keyfile,keylen,NULL,outMsg); // RAND_bytes
if (prkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,prkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
if(!mkReq(&(sCERT->SUBJECT),&req,&pkey, bits,outMsg))
{
sprintf(outMsg,"Make CertReq error");
ret = 0;
goto err;
}
md="sha1"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
ok=certify(&x,req,prkey,x509,dgst, // 公钥证书out,请求,根私钥,根公钥,
serial,"today",enddate,days,&(sCERT->KUSAGE),&(sCERT->EKUSAGE),outMsg);
if (ok <= 0)
{
ret=0;
goto err;
}
/* if (type==DER)
{
i=i2d_X509_bio(memcert,x);
j=i2d_PrivateKey_bio(memkey,pkey);//生成的结果错误!?????????????
}
else if(type==PEM)
*/ {
i=PEM_write_bio_X509(memcert,x);
j=PEM_write_bio_PrivateKey(memkey,pkey,NULL,NULL,0,NULL, NULL);
}
if(!i||!j)
{
strcpy(outMsg,"Get Mem Cert or Key File Error");
ret=0;
goto err;
}
BIO_get_mem_ptr(memcert, &bptrcert);
*certl=bptrcert->length;
memcpy(cert,bptrcert->data,*certl);
BIO_get_mem_ptr(memkey, &bptrkey);
*keyl=bptrkey->length;
memcpy(key,bptrkey->data,*keyl);
err:
BIO_free_all(memcert);
BIO_free_all(memkey);
EVP_PKEY_free(pkey);
EVP_PKEY_free(prkey);
X509_free(x509);
X509_free(x);
if (req != NULL) X509_REQ_free(req);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return ret;
}
/ /
/ begin //
/* 添加链表节点 */
void AddRevoke(stuREVOKE *& Head, int index,time_t time)
{
stuREVOKE * End= new stuREVOKE(index,time); // 钥增加的节点
if(Head==NULL)
{
Head=End;
}
else
{
stuREVOKE * p=Head;
while(p->Link!=NULL)
p=p->Link;
p->Link=End;
}
return;
}
int Add_ExtCrl(X509_CRL *crl /* 正被添加的证书 */,X509 * root /* 根证书(从中得到信息) */,
int nid, char *value)
{
X509V3_CTX ctx;
X509_EXTENSION *ex;
/* This sets the 'context' of the extensions. */
/* No configuration database */
// X509V3_set_ctx_nodb(&ctx);
X509V3_set_ctx(&ctx, root, NULL, NULL, crl, 0);
// issuerAltName authorityKeyIdentifier
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex)
return 0;
X509_CRL_add_ext(crl,ex,-1);
X509_EXTENSION_free(ex);
return 1;
}
BOOL MakeCrl( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen,
stuREVOKE * Head /* 作废链表 */,PNewCrlMem NewCrlMem /* 回调函数 */, char *& outCrl, int * crll, char * outfile /* crl文件 */,
char * outMsg /* 操作结果 */)
{
X509_CRL_INFO *ci = NULL;
X509_CRL *crl = NULL;
int ret=1,i=0;
char *key=NULL;
char *md=NULL;
EVP_PKEY *pkey=NULL;
X509 *x509=NULL;
BIO * in=NULL,* out=NULL;
const EVP_MD *dgst=NULL;
X509_REVOKED *r=NULL;
long crldays=30;
long crlhours=0;
stuREVOKE * temp =NULL;
BIO * memcrl=NULL;
BUF_MEM *bptrcrl=NULL;
OpenSSL_add_all_algorithms();
pkey=LoadKey(keyfile,keylen,NULL,outMsg);
if (pkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,pkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
md="md5"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
if ((crl=X509_CRL_new()) == NULL)
{
ret = 0;
goto err;
}
ci=crl->crl;
X509_NAME_free(ci->issuer);
ci->issuer=X509_NAME_dup(x509->cert_info->subject);
if (ci->issuer == NULL)
{
ret = 0;
goto err;
}
X509_gmtime_adj(ci->lastUpdate,0);
if (ci->nextUpdate == NULL)
ci->nextUpdate=ASN1_UTCTIME_new();
X509_gmtime_adj(ci->nextUpdate,(crldays*24+crlhours)*60*60);
if(!ci->revoked)
ci->revoked = sk_X509_REVOKED_new_null();
while(Head!=NULL) // 遍历链表
{
temp=Head;
X509_REVOKED *r = NULL;
BIGNUM *serial_bn = NULL;
r = X509_REVOKED_new();
ASN1_TIME_set(r->revocationDate,Head->time); // 时间
char index[100];
BN_hex2bn(&serial_bn,itoa(Head->Index,index,10)); // 序号
BN_to_ASN1_INTEGER(serial_bn,r->serialNumber);
sk_X509_REVOKED_push(ci->revoked,r);
Head=Head->Link;
delete temp;
}
// sk_X509_REVOKED_sort(ci->revoked);
for (i=0; i<SK_X509_REVOKED_NUM(CI->revoked); i++)
{
r=sk_X509_REVOKED_value(ci->revoked,i);
r->sequence=i;
}
if (ci->version == NULL)
if ((ci->version=ASN1_INTEGER_new()) == NULL)
{
ret = 0;
goto err;
}
ASN1_INTEGER_set(ci->version,1);
// issuerAltName authorityKeyIdentifier
// Add_ExtCrl(crl,x509,NID_subject_alt_name,"DNS:hpxs,email:hpxs@hotmail.com,RID:1.2.3.4,URI: https://hpxs ,IP:192.168.0.22");
Add_ExtCrl(crl,x509,NID_issuer_alt_name, "DNS:hpxs,email:hpxs@hotmail.com,RID:1.2.3.4,URI:https://hpxs,IP:192.168.0.22");
Add_ExtCrl(crl,x509,NID_authority_key_identifier, "keyid,issuer:always");
if (!X509_CRL_sign(crl,pkey,dgst))
{
ret = 0;
goto err;
}
if(NewCrlMem) // 输出内存
{
memcrl= BIO_new(BIO_s_mem());
BIO_set_close(memcrl, BIO_CLOSE); /* BIO_free() free BUF_MEM */
PEM_write_bio_X509_CRL(memcrl,crl);
BIO_get_mem_ptr(memcrl, &bptrcrl);
*crll=bptrcrl->length;
outCrl=NewCrlMem(*crll);
memcpy(outCrl,bptrcrl->data,*crll);
}
if(outfile) // 输出文件
{
out=BIO_new_file(outfile, "w");
if( out==NULL)
{
sprintf(outMsg,"%s is error",outfile);
ret = 0;
goto err;
}
PEM_write_bio_X509_CRL( out,crl);
}
X509V3_EXT_cleanup(); // cleanup the extension code if any custom extensions have been added
err:
if( out)
BIO_free_all( out);
if(memcrl)
BIO_free_all(memcrl);
BIO_free( in);
EVP_PKEY_free(pkey);
X509_CRL_free(crl);
X509_free(x509);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
if(ret==1)
strcpy(outMsg,"CRL制作成功");
return ret;
}
BOOL CertFormatConver( char * buf /* 文件内容或文件名称 */, int len /* 内存长度为0则buf为文件名 */,
char * pwd /* p12文件密码 */, char * pem /* 输出文件 */,
int outformat, char * out /* 操作结果 */)
{
EVP_PKEY *key=NULL;
X509 *cert=NULL;
BIO *biout=NULL;
int i=0;
// 输出文件
if ((biout=BIO_new_file(pem, "w")) == NULL)
{
return false;
}
cert = LoadCert(buf,len, out); // 首先尝试公钥,bio被改写
if(cert) // 输入文件为公钥文件
{
if (outformat == DER)
i=i2d_X509_bio(biout,cert);
else if (outformat == PEM)
{
// if (trustout) i=PEM_write_bio_X509_AUX(biout,x);
i=PEM_write_bio_X509(biout,cert);
}
if(!i) // 失败
strcpy( out,"保存公钥失败");
else
strcpy( out,"公钥证书格式转换成功");
}
else // 输入文件为私钥文件
{
key=LoadKey(buf,len,pwd, out);
if(!key)
{
strcpy( out,"不能识别的文件格式");
return false;
}
if(outformat==PEM)
{
PEM_write_bio_PrivateKey(biout, key, NULL, NULL, 0, 0, NULL);
}
if(outformat==DER)
{
i2d_PrivateKey_bio(biout,key); // 得到解密后的私钥
}
strcpy( out,"私钥证书格式转换成功");
}
if (biout != NULL) BIO_free(biout);
X509_free(cert);
EVP_PKEY_free(key);
return true;
}
// 分解p12包
BOOL ParseDB( char * strP12 /* 包文件 */, char * strPwd /* 私钥密码 */, char * strCert /* 公钥存放 */,
char * strkey /* 私钥存放 */, int outformat /* 输出格式 */, char * out /* 返回结果 */)
{
EVP_PKEY *key=NULL;
X509 *cert=NULL;
STACK_OF(X509) *ca = NULL;
BIO * bio=NULL,*bioCert=NULL,*bioKey=NULL;
PKCS12 *p12=NULL;
int i=0,j=0;
if((bio=BIO_new_file(strP12, "r")) == NULL)
{
strcpy( out,"打开文件错误");
return false;
}
SSLeay_add_all_algorithms();
p12 = d2i_PKCS12_bio(bio, NULL);
if (!PKCS12_parse(p12, strPwd, &key, &cert /* PEM */, &ca))
{
strcpy( out,"解包失败");
return false;
}
PKCS12_free(p12);
// 输出文件
if ((bioCert=BIO_new_file(strCert, "w")) == NULL)
{
return false;
}
if ((bioKey=BIO_new_file(strkey, "w")) == NULL)
{
return false;
}
if(outformat == DER)
{
i=i2d_X509_bio(bioCert,cert);
j=i2d_PrivateKey_bio(bioKey,key);
}
else if (outformat == PEM)
{
i=PEM_write_bio_X509(bioCert,cert);
j=PEM_write_bio_PrivateKey(bioKey, key, NULL, NULL, 0, 0, NULL);
}
if (bio != NULL) BIO_free(bio);
if (bioCert != NULL) BIO_free(bioCert);
if (bioKey != NULL) BIO_free(bioKey);
X509_free(cert);
EVP_PKEY_free(key);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
if(i!=0&&j!=0)
{
strcpy( out,"分解P12成功");
return true;
}
return false;
}
// 组合p12包
BOOL CreateDB( char * strP12 /* OUT包文件 */, char * strPwd /* IN密码 */, char * strCert /* IN公钥 */,
char * strkey /* IN私钥 */, char * out /* 返回结果 */)
{
FILE *fp=NULL;
EVP_PKEY *key=NULL;
X509 *cert=NULL;
PKCS12 *p12;
cert =LoadCert(strCert,0, out);
if(!cert)
{
strcpy( out,"读取公钥文件失败");
return false;
}
key=LoadKey(strkey,0,NULL, out); // 解密后私钥
if(!key)
{
strcpy( out,"读取私钥文件失败");
return false;
}
SSLeay_add_all_algorithms();
p12 = PKCS12_create(strPwd,"(hpxs)", key, cert, NULL, 0,0,0,0,0);
if(!p12)
{
strcpy( out,"创建p12结构失败");
return false;
}
if (!(fp = fopen(strP12, "wb")))
{
strcpy( out,"保存p12文件失败");
}
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);
fclose(fp);
strcpy( out,"合并P12成功");
X509_free(cert);
EVP_PKEY_free(key);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return true;
}
// 修改p12包密码
BOOL ChangePB( char * strP12 /* in包文件 */, char * strPwd /* IN原密码 */, char * strPwd2 /* IN新密码 */,
char * strOutP12 /* in包文件 */, char * out /* 返回结果 */)
{
FILE *fp=NULL;
EVP_PKEY *key=NULL;
X509 *cert=NULL;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12=NULL;
int len=0,wlen=0;
SSLeay_add_all_algorithms();
if (!(fp = fopen(strP12, "rb")))
{
strcpy( out,"打开文件错误");
return false;
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12)
{
strcpy( out,"读取包文件错误");
return false;
}
if (!PKCS12_parse(p12, strPwd, &key, &cert, &ca))
{
strcpy( out,"解包失败");
return false;
}
PKCS12_free(p12);
fclose(fp);
p12=NULL;
///
p12 = PKCS12_create(strPwd2,"(null)", key, cert, NULL, 0,0,0,0,0);
if(!p12)
{
strcpy( out,"创建p12结构失败");
return false;
}
if (!(fp = fopen(strOutP12, "wb")))
{
strcpy( out,"保存p12文件失败");
}
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);
fclose(fp);
strcpy( out,"转换P12密码成功");
X509_free(cert);
EVP_PKEY_free(key);
return true;
}
BOOL CertPairCheck( char * cert, char * key, char * out) // 检验公钥、私钥是否配对
{
EVP_PKEY *pkey=NULL;
X509 *x509=NULL;
x509=LoadCert(cert,0, out);
if(x509==NULL)
{
strcpy( out,"不能打开公钥文件");
return FALSE;
}
pkey=LoadKey(key,0,NULL, out);
if(pkey==NULL)
{
strcpy( out,"不能打开私钥文件");
X509_free(x509);
return FALSE;
}
if(X509_check_private_key(x509,pkey)) // 匹配
{
X509_free(x509);
EVP_PKEY_free(pkey);
return TRUE;
}
else
{
strcpy( out,"公私钥对不匹配");
X509_free(x509);
EVP_PKEY_free(pkey);
return FALSE;
}
}
//
#define sprintf_s sprintf
#include "stdafx.h"
#include <LOCALE.H>
#include "ca.h"
#include <OPENSSL pem.h>
#include <OPENSSL x509.h>
#include <OPENSSL x509v3.h>
#include <OPENSSL pkcs12.h>
#include <OPENSSL rand.h>
#include<STDLIB.H>
#include<STDIO.H>
#include <OPENSSL 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_s(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);
}
BOOL MakeReq(stuSUBJECT * reqInfo, /* 请求信息 */ int bits /* 位数 */, char * reqFile /* 证书请求文件 */,
char * priFile /* 私钥文件 */, char * outMsg /* 操作结果 */, int type)
{
X509_REQ *req=NULL;
EVP_PKEY *pkey=NULL;
BIO * breq=NULL,* bkey=NULL;
int i=0,j=0;
if(((breq=BIO_new_file(reqFile, "w"))== NULL)||((bkey=BIO_new_file(priFile, "w")) == NULL))
{
strcpy(outMsg,"Create File Error");
return false;
}
if(!mkReq(reqInfo,&req,&pkey,bits,outMsg))
{
strcpy(outMsg,"Make CertReq Error");
return false;
}
if(type==PEM)
{
i=PEM_write_bio_X509_REQ(breq,req);
j=PEM_write_bio_PrivateKey(bkey,pkey,NULL,NULL,0,NULL, NULL);
}
else if(type==DER)
{
i=i2d_X509_REQ_bio(breq,req);
j=i2d_PrivateKey_bio(bkey,pkey);
}
BIO_free(breq);
BIO_free(bkey);
X509_REQ_free(req);
EVP_PKEY_free(pkey);
if(!i||!j)
{
strcpy(outMsg,"Save Cert or Key File Error");
return false;
}
return true;
}
// end //
// //
/// begin /// /
int copy_extensions(X509 *x, X509_REQ *req, int copy_type) // 在证书中加入req自带扩展信息
{
STACK_OF(X509_EXTENSION) *exts = NULL;
X509_EXTENSION *ext, *tmpext;
ASN1_OBJECT *obj;
int i, idx, ret = 0;
if (!x || !req || (copy_type == EXT_COPY_NONE))
return 1;
exts = X509_REQ_get_extensions(req);
for(i = 0; i < sk_X509_EXTENSION_num(exts); i++)
{
ext = sk_X509_EXTENSION_value(exts, i);
obj = X509_EXTENSION_get_object(ext);
idx = X509_get_ext_by_OBJ(x, obj, -1);
/* Does extension exist? */
if (idx != -1)
{
/* If normal copy don't override existing extension */
if (copy_type == EXT_COPY_ADD)
continue;
/* Delete all extensions of same type */
do
{
tmpext = X509_get_ext(x, idx);
X509_delete_ext(x, idx);
X509_EXTENSION_free(tmpext);
idx = X509_get_ext_by_OBJ(x, obj, -1);
} while (idx != -1);
}
if (!X509_add_ext(x, ext, -1))
goto end;
}
ret = 1;
end:
sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free);
return ret;
}
int do_body(X509 **xret, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst, int serial,
char *startdate, char *enddate, int days,X509_REQ * req,stuKEYUSAGE * KUSAGE,
stuEKEYUSAGE * EKUSAGE, char * outMsg)
{
X509_NAME *name=NULL,*CAname=NULL;
X509 *ret=NULL;
X509_CINF *ci;
EVP_PKEY *pktmp;
int ok= -1,i=0;
// STACK_OF (X509_EXTENSION) * req_exts; // 如何释放??
char kusage[160]={0};
char ekusage[360]={0};
name=X509_REQ_get_subject_name(req);
if ((ret=X509_new()) == NULL)
{
ok=0;
goto err;
}
ci=ret->cert_info;
/* Make it an X509 v3 certificate. 版本1扩展 */
if (!X509_set_version(ret,2L)) // 版本
{
ok=0;
goto err;
}
ASN1_INTEGER_set(X509_get_serialNumber(ret),serial); // 序列号
if (!X509_set_issuer_name(ret,X509_get_subject_name(x509))) // 发行者
{
ok=0;
goto err;
}
if (strcmp(startdate,"today") == 0)
X509_gmtime_adj(X509_get_notBefore(ret),0); // 开始日期
else ASN1_UTCTIME_set_string(X509_get_notBefore(ret),startdate);
if (enddate == NULL)
X509_gmtime_adj(X509_get_notAfter(ret),( long)60*60*24*days); // 结束日期
else ASN1_UTCTIME_set_string(X509_get_notAfter(ret),enddate);
if (!X509_set_subject_name(ret,name)) // 主体 ---所有者
{
ok=0;
goto err;
}
pktmp=X509_REQ_get_pubkey(req);
i = X509_set_pubkey(ret,pktmp); // 公钥
EVP_PKEY_free(pktmp);
if (!i)
{
ok=0;
goto err;
}
// 加入req自带扩展信息,生成REQ文件时候加入的
if (!copy_extensions(ret, req, EXT_COPY_ALL))
{
strcpy("加入自带扩展信息失败",outMsg);
goto err;
}
/* Lets add the extensions, if there are any 加入标准扩展 */
// 基本限制Note if the CA option is false the pathlen option should be omitted.
Add_ExtCert(ret,ret,NID_basic_constraints, "critical,CA:FALSE,pathlen:1");
// 主题密钥标示符--------区分拥有者多对密钥
Add_ExtCert(ret,ret,NID_subject_key_identifier, "hash");
// Authority密钥标示符----区分发行者有多个签名密钥时
Add_ExtCert(ret,x509, NID_authority_key_identifier, "keyid,issuer:always");
// 密钥用法 ----数字签名、不可否认性、密钥加密、数据加密、密钥协商、证书签名、
// CRL签名、仅仅加密、仅仅解密
if(KUSAGE->DS)
strcpy(kusage,"digitalSignature");
if(KUSAGE->NR)
if(strlen(kusage)) // 添加
strcat(kusage, ",nonRepudiation");
else
strcpy(kusage,"nonRepudiation");
if(KUSAGE->KE)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyEncipherment");
else
strcpy(kusage,"keyEncipherment");
if(KUSAGE->DE)
if(strlen(kusage)) // 添加
strcat(kusage, ",dataEncipherment");
else
strcpy(kusage,"dataEncipherment");
if(KUSAGE->KA)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyAgreement");
else
strcpy(kusage,"keyAgreement");
if(KUSAGE->KC)
if(strlen(kusage)) // 添加
strcat(kusage, ",keyCertSign");
else
strcpy(kusage,"keyCertSign");
if(KUSAGE->CS)
if(strlen(kusage)) // 添加
strcat(kusage, ",cRLSign");
else
strcpy(kusage,"cRLSign");
if(KUSAGE->EO)
if(strlen(kusage)) // 添加
strcat(kusage, ",encipherOnly");
else
strcpy(kusage,"encipherOnly");
if(KUSAGE->DO)
if(strlen(kusage)) // 添加
strcat(kusage, ",decipherOnly");
else
strcpy(kusage,"decipherOnly");
if(strlen(kusage))
Add_ExtCert(ret,ret, NID_key_usage, kusage);
// 增强型密钥用法--一般只用于末端证书RFC3280
// 增强用法 证书目的
// --------------------------------------------------------------------------------------------------------------
// 服务器验证 保证远程计算机的身份
// 客户端验证 向远程计算机证明您的身份
// 代码签名 确保软件来自软件发行商
// 安全电子邮件 保护软件在发行后不被改动
// 时间戳 保护电子邮件消息
// --------------------------------------------------------------------------------------------------------------
// 保证软件来自一个软件发行商
// 保护软件在发行后不被改动。
// 保证软件来自商业软件发行商
// 允许您用数字签名证书信任列表
// 允许联机事务处理/通讯的严格加密
// 允许加密磁盘上的数据
// 智能卡登录
// IP安全终端系统 允许 Internet 上的安全通讯
// IP安全隧道终止
// IP 安全用户
// --------------------------------------------------------------------------------------------------------------
if(EKUSAGE->SA)
strcpy(ekusage,"serverAuth");
if(EKUSAGE->CA)
if(strlen(ekusage)) // 添加
strcat(ekusage,",clientAuth");
else
strcpy(ekusage,"clientAuth");
if(EKUSAGE->CS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",codeSigning");
else
strcpy(ekusage,"codeSigning");
if(EKUSAGE->EP)
if(strlen(ekusage)) // 添加
strcat(ekusage,",emailProtection");
else
strcpy(ekusage,"emailProtection");
if(EKUSAGE->TS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",timeStamping");
else
strcpy(ekusage,"timeStamping");
if(EKUSAGE->msCC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msCodeCom");
else
strcpy(ekusage,"msCodeCom");
if(EKUSAGE->msCTLS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msCTLSign");
else
strcpy(ekusage,"msCTLSign");
if(EKUSAGE->msSGC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msSGC");
else
strcpy(ekusage,"msSGC");
if(EKUSAGE->msEFS)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msEFS");
else
strcpy(ekusage,"msEFS");
if(EKUSAGE->msSC)
if(strlen(ekusage)) // 添加
strcat(ekusage,",msSmartcardLogin");
else
strcpy(ekusage,"msSmartcardLogin");
if(EKUSAGE->IP)
if(strlen(ekusage)) // 添加
strcat(ekusage,",ipsecEndSystem,ipsecTunnel,ipsecUser");
else
strcpy(ekusage,"ipsecEndSystem,ipsecTunnel,ipsecUser");
if(strlen(ekusage))
Add_ExtCert(ret,ret,NID_ext_key_usage,ekusage);
/*
Application keyUsage Values
SSL Client digitalSignature
SSL Server keyEncipherment
S/MIME Signing digitalSignature
S/MIME Encryption keyEncipherment
Certificate Signing keyCertSign
Object Signing digitalSignature */
// 颁发者备用名称,URL: http://my.url.here/ 、不支持email copy
Add_ExtCert(ret,ret, 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(ret,ret,NID_certificate_policies,"OK");
// 颁发机构信息访问
Add_ExtCert(ret,ret,NID_info_access,"OCSP;URI:https://hpxs"); // 或者caIssuers;URI: http://my.ca/ca.html
// CRL分发点
Add_ExtCert(ret,x509, NID_crl_distribution_points, "URI:https://hpxs/hpxs.crl");
/* Some Netscape specific extensions */
// Add_ExtCert(ret,ret, NID_crl_number, "sslCA");
// Add_ExtCert(ret,x509, 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,x509, 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 */
// 加入自定义信息begin
int nid;
nid = OBJ_create("1.2.3.4.9", "Hpxs", "I love OpenSSL!");
X509V3_EXT_add_alias(nid, NID_netscape_comment);
Add_ExtCert(ret,ret, nid, "I love OpenSSL");
// 加入自定义信息end
X509V3_EXT_cleanup(); // cleanup the extension code if any custom extensions have been added
if (!X509_sign(ret,pkey,dgst)) // 加入签名,签名算法
{
ok=0;
goto err;
}
ok=1;
err:
if (CAname != NULL)
X509_NAME_free(CAname);
if (ok <= 0)
{
if (ret != NULL) X509_free(ret);
ret=NULL;
}
else
*xret=ret;
return(ok);
}
int certify(X509 **xret, X509_REQ *req, EVP_PKEY *pkey, X509 *x509, const EVP_MD *dgst,
int serial, char *startdate, char *enddate, int days,stuKEYUSAGE * KUSAGE,
stuEKEYUSAGE * EKUSAGE, char * outMsg)
{ // 返回公钥证书,请求文件,根私钥,根公钥,
EVP_PKEY *pktmp=NULL;
int ok= -1,i=0;
if ((pktmp=X509_REQ_get_pubkey(req)) == NULL) // 得到公钥
{
sprintf(outMsg,"error unpacking public key\n");
ok=0;
goto err;
}
i=X509_REQ_verify(req,pktmp); // 证书请求里面有私要签名,这里验证一下,看此公钥主人是否持有私钥
EVP_PKEY_free(pktmp);
if (i < 0)
{
ok=0;
sprintf(outMsg,"Signature verification problems .\n");
goto err;
}
if (i == 0)
{
ok=0;
sprintf(outMsg,"Signature did not match the certificate request\n");
goto err;
}
ok=do_body(xret,pkey,x509,dgst,serial,startdate, enddate,
days,req,KUSAGE,EKUSAGE,outMsg);
err:
return(ok);
}
BOOL MakeCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */, char *reqfile /* 请求文件 */,stuKEYUSAGE * KUSAGE /* 密钥用法 */,
stuEKEYUSAGE * EKUSAGE /* 增强密钥用法 */, char *outfile /* 结果文件 */,
char * outMsg /* 操作结果 */, int type /* 结果类型DER,PEM */) // 通过证书请求,得到证书
{
int ret=1;
char * md=NULL;
EVP_PKEY *pkey=NULL;
X509 * x509=NULL;
X509_REQ *req=NULL;
X509 * x=NULL;
BIO * bcert=NULL,* reqbio=NULL;
int j;
const EVP_MD *dgst=NULL;
OpenSSL_add_all_digests(); // 加入签名算法
if((reqbio=BIO_new_file(reqfile, "r")) == NULL)
{
ret=0;
goto err;
}
if ((req=PEM_read_bio_X509_REQ(reqbio,NULL,NULL,NULL)) == NULL) // PEM_read_X509_REQ
{
BIO_reset(reqbio);
if ((req=d2i_X509_REQ_bio(reqbio,NULL)) == NULL)
{
sprintf(outMsg,"Error get certificate request");
ret=0;
goto err;
}
}
pkey=LoadKey(keyfile,keylen,NULL,outMsg);
if (pkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,pkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
md="sha1"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
j=certify(&x,req,pkey,x509,dgst, // 公钥证书out,请求文件,根私钥,根公钥,
serial,"today",enddate,days,KUSAGE,EKUSAGE,outMsg);
if (j <= 0)
{
ret=0;
goto err;
}
if(((bcert=BIO_new_file(outfile, "w"))== NULL))
{
strcpy(outMsg,"Create File Error");
goto err;
}
if (type==DER)
{
i2d_X509_bio(bcert,x);
}
else if(type==PEM)
{
PEM_write_bio_X509(bcert,x);
}
err:
if (reqbio != NULL) BIO_free(reqbio);
BIO_free_all(bcert);
EVP_PKEY_free(pkey);
X509_free(x509);
X509_free(x);
if (req != NULL) X509_REQ_free(req);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return ret;
}
/ end /// /
BOOL DirectCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */,stuCERT * sCERT /* 用户信息与密钥用法 */, int bits, char * cert /* 输出证书公钥 */, int * certl /* 长度 */,
char * key /* 输出证书私钥 */, int * keyl /* 长度 */, char * outMsg /* ,int type结果类型DER,PEM */) // 直接生成公私钥
{
X509_REQ * req=NULL;
EVP_PKEY * pkey=NULL, * prkey=NULL; // 证书私钥, // 根私钥
X509 * x509=NULL,* x=NULL; // 根公钥,证书公钥
BIO * memcert=NULL, * memkey=NULL; // 输出证书公私钥
BUF_MEM *bptrcert=NULL,*bptrkey=NULL;
int ret=1;
char * md=NULL;
int i=0,j=0,ok=0;
const EVP_MD *dgst=NULL;
OpenSSL_add_all_digests(); // 加入签名算法
memcert= BIO_new(BIO_s_mem());
memkey= BIO_new(BIO_s_mem());
BIO_set_close(memcert, BIO_CLOSE); /* BIO_free() free BUF_MEM */
BIO_set_close(memkey, BIO_CLOSE); /* BIO_free() free BUF_MEM */
prkey=LoadKey(keyfile,keylen,NULL,outMsg); // RAND_bytes
if (prkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,prkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
if(!mkReq(&(sCERT->SUBJECT),&req,&pkey, bits,outMsg))
{
sprintf(outMsg,"Make CertReq error");
ret = 0;
goto err;
}
md="sha1"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
ok=certify(&x,req,prkey,x509,dgst, // 公钥证书out,请求,根私钥,根公钥,
serial,"today",enddate,days,&(sCERT->KUSAGE),&(sCERT->EKUSAGE),outMsg);
if (ok <= 0)
{
ret=0;
goto err;
}
/* if (type==DER)
{
i=i2d_X509_bio(memcert,x);
j=i2d_PrivateKey_bio(memkey,pkey);//生成的结果错误!?????????????
}
else if(type==PEM)
*/ {
i=PEM_write_bio_X509(memcert,x);
j=PEM_write_bio_PrivateKey(memkey,pkey,NULL,NULL,0,NULL, NULL);
}
if(!i||!j)
{
strcpy(outMsg,"Get Mem Cert or Key File Error");
ret=0;
goto err;
}
BIO_get_mem_ptr(memcert, &bptrcert);
*certl=bptrcert->length;
memcpy(cert,bptrcert->data,*certl);
BIO_get_mem_ptr(memkey, &bptrkey);
*keyl=bptrkey->length;
memcpy(key,bptrkey->data,*keyl);
err:
BIO_free_all(memcert);
BIO_free_all(memkey);
EVP_PKEY_free(pkey);
EVP_PKEY_free(prkey);
X509_free(x509);
X509_free(x);
if (req != NULL) X509_REQ_free(req);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return ret;
}
/ /
/ begin //
/* 添加链表节点 */
void AddRevoke(stuREVOKE *& Head, int index,time_t time)
{
stuREVOKE * End= new stuREVOKE(index,time); // 钥增加的节点
if(Head==NULL)
{
Head=End;
}
else
{
stuREVOKE * p=Head;
while(p->Link!=NULL)
p=p->Link;
p->Link=End;
}
return;
}
int Add_ExtCrl(X509_CRL *crl /* 正被添加的证书 */,X509 * root /* 根证书(从中得到信息) */,
int nid, char *value)
{
X509V3_CTX ctx;
X509_EXTENSION *ex;
/* This sets the 'context' of the extensions. */
/* No configuration database */
// X509V3_set_ctx_nodb(&ctx);
X509V3_set_ctx(&ctx, root, NULL, NULL, crl, 0);
// issuerAltName authorityKeyIdentifier
ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
if (!ex)
return 0;
X509_CRL_add_ext(crl,ex,-1);
X509_EXTENSION_free(ex);
return 1;
}
BOOL MakeCrl( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen,
stuREVOKE * Head /* 作废链表 */,PNewCrlMem NewCrlMem /* 回调函数 */, char *& outCrl, int * crll, char * outfile /* crl文件 */,
char * outMsg /* 操作结果 */)
{
X509_CRL_INFO *ci = NULL;
X509_CRL *crl = NULL;
int ret=1,i=0;
char *key=NULL;
char *md=NULL;
EVP_PKEY *pkey=NULL;
X509 *x509=NULL;
BIO * in=NULL,* out=NULL;
const EVP_MD *dgst=NULL;
X509_REVOKED *r=NULL;
long crldays=30;
long crlhours=0;
stuREVOKE * temp =NULL;
BIO * memcrl=NULL;
BUF_MEM *bptrcrl=NULL;
OpenSSL_add_all_algorithms();
pkey=LoadKey(keyfile,keylen,NULL,outMsg);
if (pkey == NULL)
{
ret = 0;
goto err;
}
x509=LoadCert(certfile,certlen,outMsg);
if (x509 == NULL)
{
ret = 0;
goto err;
}
if (!X509_check_private_key(x509,pkey))
{
sprintf(outMsg,"CA certificate and CA private key do not match\n");
ret = 0;
goto err;
}
md="md5"; / /!!!!!!!!!!!!!!!!! /// /
if ((dgst=EVP_get_digestbyname(md)) == NULL) // return an EVP_MD structure when passed a digest name
{
sprintf(outMsg,"%s is an unsupported message digest type\n",md);
ret = 0;
goto err;
}
if ((crl=X509_CRL_new()) == NULL)
{
ret = 0;
goto err;
}
ci=crl->crl;
X509_NAME_free(ci->issuer);
ci->issuer=X509_NAME_dup(x509->cert_info->subject);
if (ci->issuer == NULL)
{
ret = 0;
goto err;
}
X509_gmtime_adj(ci->lastUpdate,0);
if (ci->nextUpdate == NULL)
ci->nextUpdate=ASN1_UTCTIME_new();
X509_gmtime_adj(ci->nextUpdate,(crldays*24+crlhours)*60*60);
if(!ci->revoked)
ci->revoked = sk_X509_REVOKED_new_null();
while(Head!=NULL) // 遍历链表
{
temp=Head;
X509_REVOKED *r = NULL;
BIGNUM *serial_bn = NULL;
r = X509_REVOKED_new();
ASN1_TIME_set(r->revocationDate,Head->time); // 时间
char index[100];
BN_hex2bn(&serial_bn,itoa(Head->Index,index,10)); // 序号
BN_to_ASN1_INTEGER(serial_bn,r->serialNumber);
sk_X509_REVOKED_push(ci->revoked,r);
Head=Head->Link;
delete temp;
}
// sk_X509_REVOKED_sort(ci->revoked);
for (i=0; i<SK_X509_REVOKED_NUM(CI->revoked); i++)
{
r=sk_X509_REVOKED_value(ci->revoked,i);
r->sequence=i;
}
if (ci->version == NULL)
if ((ci->version=ASN1_INTEGER_new()) == NULL)
{
ret = 0;
goto err;
}
ASN1_INTEGER_set(ci->version,1);
// issuerAltName authorityKeyIdentifier
// Add_ExtCrl(crl,x509,NID_subject_alt_name,"DNS:hpxs,email:hpxs@hotmail.com,RID:1.2.3.4,URI: https://hpxs ,IP:192.168.0.22");
Add_ExtCrl(crl,x509,NID_issuer_alt_name, "DNS:hpxs,email:hpxs@hotmail.com,RID:1.2.3.4,URI:https://hpxs,IP:192.168.0.22");
Add_ExtCrl(crl,x509,NID_authority_key_identifier, "keyid,issuer:always");
if (!X509_CRL_sign(crl,pkey,dgst))
{
ret = 0;
goto err;
}
if(NewCrlMem) // 输出内存
{
memcrl= BIO_new(BIO_s_mem());
BIO_set_close(memcrl, BIO_CLOSE); /* BIO_free() free BUF_MEM */
PEM_write_bio_X509_CRL(memcrl,crl);
BIO_get_mem_ptr(memcrl, &bptrcrl);
*crll=bptrcrl->length;
outCrl=NewCrlMem(*crll);
memcpy(outCrl,bptrcrl->data,*crll);
}
if(outfile) // 输出文件
{
out=BIO_new_file(outfile, "w");
if( out==NULL)
{
sprintf(outMsg,"%s is error",outfile);
ret = 0;
goto err;
}
PEM_write_bio_X509_CRL( out,crl);
}
X509V3_EXT_cleanup(); // cleanup the extension code if any custom extensions have been added
err:
if( out)
BIO_free_all( out);
if(memcrl)
BIO_free_all(memcrl);
BIO_free( in);
EVP_PKEY_free(pkey);
X509_CRL_free(crl);
X509_free(x509);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
if(ret==1)
strcpy(outMsg,"CRL制作成功");
return ret;
}
BOOL CertFormatConver( char * buf /* 文件内容或文件名称 */, int len /* 内存长度为0则buf为文件名 */,
char * pwd /* p12文件密码 */, char * pem /* 输出文件 */,
int outformat, char * out /* 操作结果 */)
{
EVP_PKEY *key=NULL;
X509 *cert=NULL;
BIO *biout=NULL;
int i=0;
// 输出文件
if ((biout=BIO_new_file(pem, "w")) == NULL)
{
return false;
}
cert = LoadCert(buf,len, out); // 首先尝试公钥,bio被改写
if(cert) // 输入文件为公钥文件
{
if (outformat == DER)
i=i2d_X509_bio(biout,cert);
else if (outformat == PEM)
{
// if (trustout) i=PEM_write_bio_X509_AUX(biout,x);
i=PEM_write_bio_X509(biout,cert);
}
if(!i) // 失败
strcpy( out,"保存公钥失败");
else
strcpy( out,"公钥证书格式转换成功");
}
else // 输入文件为私钥文件
{
key=LoadKey(buf,len,pwd, out);
if(!key)
{
strcpy( out,"不能识别的文件格式");
return false;
}
if(outformat==PEM)
{
PEM_write_bio_PrivateKey(biout, key, NULL, NULL, 0, 0, NULL);
}
if(outformat==DER)
{
i2d_PrivateKey_bio(biout,key); // 得到解密后的私钥
}
strcpy( out,"私钥证书格式转换成功");
}
if (biout != NULL) BIO_free(biout);
X509_free(cert);
EVP_PKEY_free(key);
return true;
}
// 分解p12包
BOOL ParseDB( char * strP12 /* 包文件 */, char * strPwd /* 私钥密码 */, char * strCert /* 公钥存放 */,
char * strkey /* 私钥存放 */, int outformat /* 输出格式 */, char * out /* 返回结果 */)
{
EVP_PKEY *key=NULL;
X509 *cert=NULL;
STACK_OF(X509) *ca = NULL;
BIO * bio=NULL,*bioCert=NULL,*bioKey=NULL;
PKCS12 *p12=NULL;
int i=0,j=0;
if((bio=BIO_new_file(strP12, "r")) == NULL)
{
strcpy( out,"打开文件错误");
return false;
}
SSLeay_add_all_algorithms();
p12 = d2i_PKCS12_bio(bio, NULL);
if (!PKCS12_parse(p12, strPwd, &key, &cert /* PEM */, &ca))
{
strcpy( out,"解包失败");
return false;
}
PKCS12_free(p12);
// 输出文件
if ((bioCert=BIO_new_file(strCert, "w")) == NULL)
{
return false;
}
if ((bioKey=BIO_new_file(strkey, "w")) == NULL)
{
return false;
}
if(outformat == DER)
{
i=i2d_X509_bio(bioCert,cert);
j=i2d_PrivateKey_bio(bioKey,key);
}
else if (outformat == PEM)
{
i=PEM_write_bio_X509(bioCert,cert);
j=PEM_write_bio_PrivateKey(bioKey, key, NULL, NULL, 0, 0, NULL);
}
if (bio != NULL) BIO_free(bio);
if (bioCert != NULL) BIO_free(bioCert);
if (bioKey != NULL) BIO_free(bioKey);
X509_free(cert);
EVP_PKEY_free(key);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
if(i!=0&&j!=0)
{
strcpy( out,"分解P12成功");
return true;
}
return false;
}
// 组合p12包
BOOL CreateDB( char * strP12 /* OUT包文件 */, char * strPwd /* IN密码 */, char * strCert /* IN公钥 */,
char * strkey /* IN私钥 */, char * out /* 返回结果 */)
{
FILE *fp=NULL;
EVP_PKEY *key=NULL;
X509 *cert=NULL;
PKCS12 *p12;
cert =LoadCert(strCert,0, out);
if(!cert)
{
strcpy( out,"读取公钥文件失败");
return false;
}
key=LoadKey(strkey,0,NULL, out); // 解密后私钥
if(!key)
{
strcpy( out,"读取私钥文件失败");
return false;
}
SSLeay_add_all_algorithms();
p12 = PKCS12_create(strPwd,"(hpxs)", key, cert, NULL, 0,0,0,0,0);
if(!p12)
{
strcpy( out,"创建p12结构失败");
return false;
}
if (!(fp = fopen(strP12, "wb")))
{
strcpy( out,"保存p12文件失败");
}
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);
fclose(fp);
strcpy( out,"合并P12成功");
X509_free(cert);
EVP_PKEY_free(key);
EVP_cleanup(); // frees all three stacks and sets their pointers to NULL ---- EVP_CIPHER
return true;
}
// 修改p12包密码
BOOL ChangePB( char * strP12 /* in包文件 */, char * strPwd /* IN原密码 */, char * strPwd2 /* IN新密码 */,
char * strOutP12 /* in包文件 */, char * out /* 返回结果 */)
{
FILE *fp=NULL;
EVP_PKEY *key=NULL;
X509 *cert=NULL;
STACK_OF(X509) *ca = NULL;
PKCS12 *p12=NULL;
int len=0,wlen=0;
SSLeay_add_all_algorithms();
if (!(fp = fopen(strP12, "rb")))
{
strcpy( out,"打开文件错误");
return false;
}
p12 = d2i_PKCS12_fp(fp, NULL);
fclose (fp);
if (!p12)
{
strcpy( out,"读取包文件错误");
return false;
}
if (!PKCS12_parse(p12, strPwd, &key, &cert, &ca))
{
strcpy( out,"解包失败");
return false;
}
PKCS12_free(p12);
fclose(fp);
p12=NULL;
///
p12 = PKCS12_create(strPwd2,"(null)", key, cert, NULL, 0,0,0,0,0);
if(!p12)
{
strcpy( out,"创建p12结构失败");
return false;
}
if (!(fp = fopen(strOutP12, "wb")))
{
strcpy( out,"保存p12文件失败");
}
i2d_PKCS12_fp(fp, p12);
PKCS12_free(p12);
fclose(fp);
strcpy( out,"转换P12密码成功");
X509_free(cert);
EVP_PKEY_free(key);
return true;
}
BOOL CertPairCheck( char * cert, char * key, char * out) // 检验公钥、私钥是否配对
{
EVP_PKEY *pkey=NULL;
X509 *x509=NULL;
x509=LoadCert(cert,0, out);
if(x509==NULL)
{
strcpy( out,"不能打开公钥文件");
return FALSE;
}
pkey=LoadKey(key,0,NULL, out);
if(pkey==NULL)
{
strcpy( out,"不能打开私钥文件");
X509_free(x509);
return FALSE;
}
if(X509_check_private_key(x509,pkey)) // 匹配
{
X509_free(x509);
EVP_PKEY_free(pkey);
return TRUE;
}
else
{
strcpy( out,"公私钥对不匹配");
X509_free(x509);
EVP_PKEY_free(pkey);
return FALSE;
}
}
#include
#define DER 1 // FORMAT_ASN1
#define PEM 3 /*定义格式*/
#define NET 4
#define P12 5
typedef char * (* PNewCrlMem)(UINT len);
struct stuSUBJECT // 个体信息
{
UCHAR C[4]; // 国家
UCHAR ST[4]; // 省份
UCHAR L[12]; // 城市
UCHAR O[48]; // 组织
UCHAR OU[24]; // 组织部门
UCHAR CN[12]; // 个人信息
UCHAR MAIL[24]; // 电子邮件
UCHAR PMAIL[24]; // 安全电子邮件
UCHAR T[12]; // 头衔
UCHAR D[12]; // 描述
UCHAR G[12]; // 曾用名
UCHAR I[12]; // 描述
UCHAR NAME[12]; // 描述
UCHAR S[12]; // 描述
UCHAR QUAL[12]; // 描述
UCHAR STN[12]; // 没有结构的名称
UCHAR PW[12]; // 挑战密码
UCHAR ADD[12]; // 无结构地址
stuSUBJECT()
{
memset( this,0, sizeof(stuSUBJECT));
}
};
struct stuKEYUSAGE // 密钥用途
{
BOOL DS; // Digital Signature
BOOL NR; // Non-Repudiation
BOOL KE; // Key Encipherment
BOOL DE; // Data Encipherment
BOOL KA; // keyAgreement
BOOL KC; // keyCertSign
BOOL CS; // cRLSign
BOOL EO; // Encipher Only
BOOL DO; // Decipher Only
stuKEYUSAGE()
{
memset( this,0, sizeof(stuKEYUSAGE));
}
};
struct stuEKEYUSAGE // 增强型密钥用途
{
BOOL SA; // 服务器验证
BOOL CA; // 客户端验证
BOOL CS; // 代码签名
BOOL EP; // 安全电子邮件
BOOL TS; // 时间戳
BOOL msCC; // 代码完整
BOOL msCTLS; // 可签名信任列表
BOOL msSGC; // 联机事务处理
BOOL msEFS; // 加密磁盘上的数据
BOOL msSC; // 智能卡登录
BOOL IP; // Internet
stuEKEYUSAGE()
{
memset( this,0, sizeof(stuEKEYUSAGE));
}
};
struct stuCERT // 三者之和
{
stuSUBJECT SUBJECT;
stuKEYUSAGE KUSAGE;
stuEKEYUSAGE EKUSAGE;
stuCERT()
{
memset( this,0, sizeof(stuCERT));
}
};
struct stuREVOKE // 证书作废结构链表
{
int Index; // 证书序号
time_t time; // 吊销时间
stuREVOKE * Link;
stuREVOKE()
{
memset( this,0, sizeof(stuREVOKE));
}
stuREVOKE( int index,time_t t)
{
Index=index;
time=t;;
Link=NULL;
}
};
/* 添加链表节点 */
void AddRevoke(stuREVOKE *& Head, int index,time_t time);
/* 证书格式转换函数 */
BOOL CertFormatConver( char * buf /* 内存区域,存储文件内容或文件名称 */, int len /* 内存长度==0则buf为文件名 */,
char * pwd /* p12文件密码 */, char * pem /* 输出文件 */, int outformat, char * out /* 操作结果 */);
/* 根证书生成函数,根据rootInfo信息,生成根证书公、私钥文件 */
BOOL MakeRoot(stuSUBJECT * rootInfo, /* 请求信息IN */ int bits /* 位数IN */, int serial /* 序列号IN */,
int days /* 有效期IN */, char * certFile /* 证书请求文件OUT */, char * priFile /* 私钥文件OUT */,
char * out /* 操作结果OUT */, int type=PEM /* 类型pem-der */);
/* 证书请求生成函数,根据reqInfo信息,生成用户证书私钥文件、证书请求文件 */
BOOL MakeReq(stuSUBJECT * reqInfo, /* 请求信息IN */ int bits /* 位数IN */, char * reqFile /* 证书请求文件OUT */,
char * priFile /* 私钥文件OUT */, char * out /* 操作结果OUT */, int type=PEM /* 类型pem-der */);
/* 证书生成函数,通过证书请求,生成用户证书公钥文件 */
BOOL MakeCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */, char *reqfile /* 请求文件 */,stuKEYUSAGE * KUSAGE /* 密钥用法 */,
stuEKEYUSAGE * EKUSAGE /* 增强密钥用法 */, char *outfile /* 结果文件 */,
char * outMsg /* 操作结果 */, int type /* 结果类型DER,PEM */); // 通过证书请求,得到证书
// 直接生成公私钥
BOOL DirectCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */,stuCERT * sCERT /* 用户信息与密钥用法 */, int bits, char * cert /* 输出证书公钥 */, int * certl /* 长度 */,
char * key /* 输出证书私钥 */, int * keyl /* 长度 */, char * outMsg /* ,int type结果类型DER,PEM */); // 直接生成公私钥
/* 黑名单生成函数 */
BOOL MakeCrl( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen,
stuREVOKE * Head /* 作废链表 */,PNewCrlMem NewCrlMem /* 回调函数 */, char *& outCrl, int * crll, char * outfile /* crl文件 */,
char * outMsg /* 操作结果 */);
/* 分解p12包 */
BOOL ParseDB( char * strP12 /* 包文件 */, char * strPwd /* 解包密码 */, char * strCert /* 公钥存放 */,
char * strkey /* 私钥存放 */, int outformat /* 输出格式 */, char * out /* 返回结果 */);
/* 组合p12包 */
BOOL CreateDB( char * strP12 /* 包文件IN */, char * strPwd /* 密码IN */, char * strCert /* 公钥存放IN */,
char * strkey /* 私钥存放IN */, char * out /* 返回结果OUT */);
BOOL ChangePB( char * strP12 /* IN包文件 */, char * strPwd /* IN原密码 */, char * strPwd2 /* IN新密码 */,
char * strOutP12 /* OUT包文件 */, char * out /* 返回结果OUT */);
// 检验公钥、私钥是否配对
BOOL CertPairCheck( char * cert, char * key, char * out); // 检验公钥、私钥是否配对
#define DER 1 // FORMAT_ASN1
#define PEM 3 /*定义格式*/
#define NET 4
#define P12 5
typedef char * (* PNewCrlMem)(UINT len);
struct stuSUBJECT // 个体信息
{
UCHAR C[4]; // 国家
UCHAR ST[4]; // 省份
UCHAR L[12]; // 城市
UCHAR O[48]; // 组织
UCHAR OU[24]; // 组织部门
UCHAR CN[12]; // 个人信息
UCHAR MAIL[24]; // 电子邮件
UCHAR PMAIL[24]; // 安全电子邮件
UCHAR T[12]; // 头衔
UCHAR D[12]; // 描述
UCHAR G[12]; // 曾用名
UCHAR I[12]; // 描述
UCHAR NAME[12]; // 描述
UCHAR S[12]; // 描述
UCHAR QUAL[12]; // 描述
UCHAR STN[12]; // 没有结构的名称
UCHAR PW[12]; // 挑战密码
UCHAR ADD[12]; // 无结构地址
stuSUBJECT()
{
memset( this,0, sizeof(stuSUBJECT));
}
};
struct stuKEYUSAGE // 密钥用途
{
BOOL DS; // Digital Signature
BOOL NR; // Non-Repudiation
BOOL KE; // Key Encipherment
BOOL DE; // Data Encipherment
BOOL KA; // keyAgreement
BOOL KC; // keyCertSign
BOOL CS; // cRLSign
BOOL EO; // Encipher Only
BOOL DO; // Decipher Only
stuKEYUSAGE()
{
memset( this,0, sizeof(stuKEYUSAGE));
}
};
struct stuEKEYUSAGE // 增强型密钥用途
{
BOOL SA; // 服务器验证
BOOL CA; // 客户端验证
BOOL CS; // 代码签名
BOOL EP; // 安全电子邮件
BOOL TS; // 时间戳
BOOL msCC; // 代码完整
BOOL msCTLS; // 可签名信任列表
BOOL msSGC; // 联机事务处理
BOOL msEFS; // 加密磁盘上的数据
BOOL msSC; // 智能卡登录
BOOL IP; // Internet
stuEKEYUSAGE()
{
memset( this,0, sizeof(stuEKEYUSAGE));
}
};
struct stuCERT // 三者之和
{
stuSUBJECT SUBJECT;
stuKEYUSAGE KUSAGE;
stuEKEYUSAGE EKUSAGE;
stuCERT()
{
memset( this,0, sizeof(stuCERT));
}
};
struct stuREVOKE // 证书作废结构链表
{
int Index; // 证书序号
time_t time; // 吊销时间
stuREVOKE * Link;
stuREVOKE()
{
memset( this,0, sizeof(stuREVOKE));
}
stuREVOKE( int index,time_t t)
{
Index=index;
time=t;;
Link=NULL;
}
};
/* 添加链表节点 */
void AddRevoke(stuREVOKE *& Head, int index,time_t time);
/* 证书格式转换函数 */
BOOL CertFormatConver( char * buf /* 内存区域,存储文件内容或文件名称 */, int len /* 内存长度==0则buf为文件名 */,
char * pwd /* p12文件密码 */, char * pem /* 输出文件 */, int outformat, char * out /* 操作结果 */);
/* 根证书生成函数,根据rootInfo信息,生成根证书公、私钥文件 */
BOOL MakeRoot(stuSUBJECT * rootInfo, /* 请求信息IN */ int bits /* 位数IN */, int serial /* 序列号IN */,
int days /* 有效期IN */, char * certFile /* 证书请求文件OUT */, char * priFile /* 私钥文件OUT */,
char * out /* 操作结果OUT */, int type=PEM /* 类型pem-der */);
/* 证书请求生成函数,根据reqInfo信息,生成用户证书私钥文件、证书请求文件 */
BOOL MakeReq(stuSUBJECT * reqInfo, /* 请求信息IN */ int bits /* 位数IN */, char * reqFile /* 证书请求文件OUT */,
char * priFile /* 私钥文件OUT */, char * out /* 操作结果OUT */, int type=PEM /* 类型pem-der */);
/* 证书生成函数,通过证书请求,生成用户证书公钥文件 */
BOOL MakeCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */, char *reqfile /* 请求文件 */,stuKEYUSAGE * KUSAGE /* 密钥用法 */,
stuEKEYUSAGE * EKUSAGE /* 增强密钥用法 */, char *outfile /* 结果文件 */,
char * outMsg /* 操作结果 */, int type /* 结果类型DER,PEM */); // 通过证书请求,得到证书
// 直接生成公私钥
BOOL DirectCert( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen, int serial /* 序列号 */, char *enddate /* 作废日期 */,
int days /* 有效期 */,stuCERT * sCERT /* 用户信息与密钥用法 */, int bits, char * cert /* 输出证书公钥 */, int * certl /* 长度 */,
char * key /* 输出证书私钥 */, int * keyl /* 长度 */, char * outMsg /* ,int type结果类型DER,PEM */); // 直接生成公私钥
/* 黑名单生成函数 */
BOOL MakeCrl( char *certfile /* 根证书公钥 */, int certlen, /* 为0则certfile为磁盘文件,否则为内存区域 */
char *keyfile /* 根证书私钥 */, int keylen,
stuREVOKE * Head /* 作废链表 */,PNewCrlMem NewCrlMem /* 回调函数 */, char *& outCrl, int * crll, char * outfile /* crl文件 */,
char * outMsg /* 操作结果 */);
/* 分解p12包 */
BOOL ParseDB( char * strP12 /* 包文件 */, char * strPwd /* 解包密码 */, char * strCert /* 公钥存放 */,
char * strkey /* 私钥存放 */, int outformat /* 输出格式 */, char * out /* 返回结果 */);
/* 组合p12包 */
BOOL CreateDB( char * strP12 /* 包文件IN */, char * strPwd /* 密码IN */, char * strCert /* 公钥存放IN */,
char * strkey /* 私钥存放IN */, char * out /* 返回结果OUT */);
BOOL ChangePB( char * strP12 /* IN包文件 */, char * strPwd /* IN原密码 */, char * strPwd2 /* IN新密码 */,
char * strOutP12 /* OUT包文件 */, char * out /* 返回结果OUT */);
// 检验公钥、私钥是否配对
BOOL CertPairCheck( char * cert, char * key, char * out); // 检验公钥、私钥是否配对