|
Posted on 2010-06-06 23:47 S.l.e!ep.¢% 阅读(3436) 评论(0) 编辑 收藏 引用 所属分类: OpenSSL
本软件包将每个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, -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);//检验公钥、私钥是否配对
|