S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
本软件包将每个openssl的apps程序做成一个可直接运行调试的VC Console 类型应用程序,方便研究和运用openssl的朋友,避免了openssl在windows下的编译问题,并且因为可以在VC环境下进行调试,使得对openssl的各个应用程序的流程更容易理解,这对openssl初学者尤

// 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, 
-10);   
    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 (!|| !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 
*= 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, 
00, 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, 00, 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);//检验公钥、私钥是否配对 

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理