首页 电脑 电脑学堂 查看内容

程序中生成证书请求的两种方法(源码)

2005-5-3 12:54 878 1

摘要: 作者:Rainbow 程序中在web页面上生成证书请求的方法有两种,分别通过调用enumProviders接口和OpenSSL接口来实现。本文为您详细介绍这两种方法并提供相应的实例源代码。 一、...
关键词: 生成 接口 NULL AddEntry REQ PKEY err 证书 subject 密钥

作者:Rainbow 程序中在web页面上生成证书请求的方法有两种,分别通过调用enumProviders接口和OpenSSL接口来实现。本文为您详细介绍这两种方法并提供相应的实例源代码。 一、在web页面上生成证书请求 在本地生成的证书请求的方式适用于CA不备份私钥或者说该私钥用于签名的情况。 1、枚举CSP 生成私钥的时候是通过枚举本地的CSP进行的,这个功能只需要通过调用xenroll.dll的enumProviders接口来实现。举例如下: EnumProviders function EnumProviders()nCSPIndex=0ON ERROR resume nextdosProviderName=IControl.enumProviders(nCSPIndex, 0)if err.Number<>0 thenIf &H80070103=Err.Number ThenErr.Clearexit doelseif err.number = 438 thendocument.location="xenroll.dll"exit doelsemsgbox Err.descriptionexit doend ifend if/*在这里添加你自己对CSP的显示部分*/loopend function 2、另外几个接口 xenroll.dll与生成证书请求相关的另外几接口是: KeySpec ---用于设置或取得密钥的类型(即签名AT_SIGNATURE或密钥交换AT_KEYEXCHANGE)HashAlgorithm-- 用于设置或取得对证书进行散列的算法,可以为MD2/MD5/SHA1,默认是SHA1。GenKeyFlags---- 用于控制生成的私钥是否可以导出。默认是不可导出的,但可以设置成CRYPT_EXPORTABLE。或者按里的定义#define CRYPT_EXPORTABLE 0x00000001直接设置成1也可以。ProviderName-- 就是CSP的名字,就是从注册表时读的名字。 3、生成DN 自己可以做一个简单的网页用来接收输入信息,我们将用这些信息生成dn.如果有对DN不熟悉的可以看一下网站里pki/pmi版面的内容。 比如:我们可以用vbscript定义一个dn的变量,然后将它们拼接起来。   DN = "";DN = DN + "C=" + "\"" + cCountry + "\"" + ",";DN = DN + "S=" + "\"" + cState + "\"" + ",";DN = DN + "L=" + "\"" + cCity + "\"" + ",";DN = DN + "CN=" + "\"" + cName + "\"" + ",";DN = DN + "E=" + "\"" + cEMail + "\""; 4、调用CreatePKCS10接口 这个接口有两个参数第一个是上面所说的DN,另外一个是证书的用途,这里就一长串的OID,具体的用途可以看一下x.509 v3的rfx文档。 举例如下: szPKCS10 = IControl.CreatePKCS10(DN, "1.3.6.1.5.5.7.3.2"); 二、调用openssl接口生成请求 调用OpenSSL接口生成证书相对复杂一点,不过也可通过下面几个步骤来完成。 1、生成RSA密钥对 第一个参数是密钥的长度,第二个是RSA算法中的e,这个参数在pkcs#1中有建议, 这里取65535(细节请到安全标准栏目中下载相关文档) 示例代码如下: EVP_PKEY *pkey = NULL;RSA *rsa = NULL;rsa = RSA_generate_key(*(pReq->keylen),0x10001,NULL,NULL);pkey = EVP_PKEY_new();if(!EVP_PKEY_assign_RSA(pkey,rsa)){m_str.Format("%s","generate RSA key pair error");goto err;} 2、生成X509Name 在这里我用了一个类来处理 // 加一个条目int CX509Name::AddEntry(int key, char *value){ char *key_value[]={"countryName","stateOrProvinceName","localityName","organizationName","organizationalUnitName","commonName","emailAddress"};int nid;X509_NAME_ENTRY *ent;if(subject == NULL)return -1;if ((nid = OBJ_txt2nid(key_value[key])) == NID_undef)return -1;if (!(ent = X509_NAME_ENTRY_create_by_NID(NULL, nid,MBSTRING_ASC,(unsigned char*)value, -1)))return -1;if (X509_NAME_add_entry(subject, ent, -1, 0) != 1)return -1;return 1;}// 取得最终的结果X509_NAME* CX509Name::getName(REQ_INFO *p){if(p->szCN) AddEntry(0,p->szCN);if(p->szST) AddEntry(0,p->szST);if(p->szL) AddEntry(0,p->szL);if(p->szO) AddEntry(0,p->szO);if(p->szOU) AddEntry(0,p->szOU);if(p->szName) AddEntry(0,p->szName);if(p->szEmail) AddEntry(0,p->szEmail);return subject;} 3、设置好其它信息并签名 除了上面所的信息要设置以外,还要设置版本号、公钥、名字等。 req=X509_REQ_new();if(!req){goto err;}subject=x_name.getName(pReq);if(!subject){goto err;}if(!X509_REQ_set_version(req,0L)) goto err;if(!X509_REQ_set_subject_name(req,subject)) goto err;if(!X509_REQ_set_pubkey(req,pkey)) goto err;if(!X509_REQ_sign(req,pkey,digest)) goto err; 4、保存 // output private keyoutPvk = BIO_new_file(szPrivateKeyFileName, "w");if (!outPvk){m_str.Format("Error opening file %s", szPrivateKeyFileName);goto err;}if (pkey){if(szPrivateKeyPwd){int len =strlen(szPrivateKeyPwd);PEM_write_bio_PrivateKey(outPvk, pkey, EVP_des_ede3_cbc(),(unsigned char*)szPrivateKeyPwd,len, NULL, NULL);}elsePEM_write_bio_PrivateKey(outPvk, pkey, NULL,NULL,0, NULL, NULL);}// output certificate request fileoutReq = BIO_new_file(szReqFileName, "w");if (!outReq){m_str.Format("Error opening file %s", szReqFileName);goto err;}if (req){PEM_write_bio_X509_REQ(outReq, req);} 以上代码中是片段,仅供参考,本人能力有限,欢迎交流与指正,谢谢。
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

返回顶部