<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[观夏Note]]></title> 
<link>//gm.angeldm.com/index.php</link> 
<description><![CDATA[新技术番]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[观夏Note]]></copyright>
<item>
<link>//gm.angeldm.com/post//</link>
<title><![CDATA[OpenSSL制作中文证书专题]]></title> 
<author>果面 &lt;admin@yourname.com&gt;</author>
<category><![CDATA[网络应用]]></category>
<pubDate>Mon, 04 Aug 2008 12:48:46 +0000</pubDate> 
<guid>//gm.angeldm.com/post//</guid> 
<description>
<![CDATA[ 
	经常看见有人为制作中文证书的事情头痛，借论坛新张之际，本人把摸索中文证书制作的过程公开出来供大家参考，不当之处敬请提出批评。<br/>早在N年以前，本人就尝试用java写了一个小程序用来给自己制作证书玩的（那时候还不知道有openssl这个好东东），因为要依赖java环境运行而且中文信息显示乱码等问题，决定在网上找一个合适的开发库，一番比较后，在眼花缭乱中选择了openssl。<br/>刚接触openssl那些迷茫和....就不提了，意料中的事，很快就开始看人家的范例程序：<br/><br/>　　X509_NAME_add_entry_by_txt(name,"C", MBSTRING_ASC, "UK", -1, -1, 0);<br/>　　X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, "OpenSSL Group", -1, -1, 0);<br/><br/>哇，还是蛮简单的嘛，试试看－－My God! 中文还是乱码！<br/>别着急，意外发现有个牛人写了一个MiniCA，还有源码，先运行看看，还不错，中文出来了，显示正常！<br/>虽然自己制作的根证书不能用，虽然....但是还是蛮有兴致地制作了好一些证书，开始测试着玩....<br/>第一个测试就卡壳了，Outlook不认帐！<br/>去看MiniCA的源码吧：<br/>原来是使用了X509_NAME_add_entry_by_NID()函数，源码在处理字符串长度的时候出了点小瑕疵，于是修改了几行使长度准确无误（过程略），重新编译测试，结果Outlook还是不卖帐，又改一下，强制emailAddress域使用MBSTRING_ASC，还是不行。<br/>无奈，差点要放弃openssl了，仔细分析了从一些网站申请的证书，用makecert.exe又试制了一些，发现他们都是使用Unicode编码而不是UTF-8！<br/>阅读openssl的文档，看到这么一段文字：<br/>NOTES<br/>　　The use of string types such as MBSTRING_ASC or MBSTRING_UTF8 is<br/>　　strongly recommened for the type parameter. This allows the internal<br/>　　code to correctly determine the type of the field and to apply length<br/>　　checks according to the relevant standards. This is done using<br/>　　ASN1_STRING_set_by_NID().<br/>于是把源码中的B_ASN1_UTF8STRING改为MBSTRING_UTF8－－ok，Outlook通过了，只是CountryName域的“中国”消失了！<br/>再详细观察一下所生成的证书，内部居然是Unicode编码！<br/>转换为UTF-8之前还先要转成Unicode呢，有什么必要这么绕来绕去呢，直接用Unicode好不好？<br/>可是openssl没有定义Unicode，不过有一个MBSTRING_BMP和Unicode正好是反序编码，这就好办了：<br/>int Add_Name(X509_NAME *x509name, int type, USHORT *iput)//中英文处理<br/>&#123;<br/>　　int strType = 0;<br/>　　UCHAR *pp = (UCHAR *)&iput[1];<br/>　　if(*iput == 0) return 0;<br/>　　if(*pp)　　 //Unicode字串，须转换成BMP，:-(<br/>　　&#123;<br/>　　　　pp++; *iput *=2;<br/>　　　　do &#123; pp[strType] = pp[strType+2]; strType +=2;&#125;<br/>　　　　while((USHORT)strType != *iput);<br/>　　　　strType = MBSTRING_BMP;<br/>　　&#125;<br/>　　else &#123; strType = MBSTRING_ASC; pp +=2;&#125;<br/>　　return X509_NAME_add_entry_by_NID(x509name,type,strType,pp,(int)*iput,-1,0);<br/>&#125;<br/>其中*iput指向一个结构：<br/>　　USHORT　String_Length;//字符串实际长度（注意：是“字符串长度”而不是字节数，在Unicode情况下，要乘以2才是字节数）<br/>　　USHORT　String_Type;//字符串类型0=ASCII，1=Unicode<br/>　　UCHAR　String_Str[];//字符串本身<br/>把证书主题的每个域先按这个结构来处理好，然后组成一个总的结构，用以下的语句来调用Add_Name()，主题就正确形成了：<br/>　　ret=Add_Name(xname,NID_pkcs9_emailAddress,&DNSInfo->MAIL_l);<br/>　　ret=Add_Name(xname,NID_commonName,&DNSInfo->CN_l);<br/>　　ret=Add_Name(xname,NID_organizationalUnitName,&DNSInfo->OU_l);<br/>　　ret=Add_Name(xname,NID_organizationName,&DNSInfo->O_l);<br/>　　ret=Add_Name(xname,NID_localityName,&DNSInfo->L_l);<br/>　　ret=Add_Name(xname,NID_stateOrProvinceName,&DNSInfo->ST_l);<br/>　　ret=Add_Name(xname,NID_countryName,&DNSInfo->C_l);<br/>这样改可以后，CountryName域取“中国”仍然是不行的，那么还按标准取“CN”好了。<br/>经多方面测试，这样做出来的证书完全正常。<br/>最后提一下关于openssl.exe制作中文证书的方法，本人曾留意到openssl.conf文件里是可以设定为使用UTF-8编码的，可惜 Windows命令行下不可能直接输入UTF-8编码的字符，因此无法验证，后来在Linux环境下测试，因为Linux的终端就是使用UTF-8编码，所以不用做任何改编即可得到中文证书。
]]>
</description>
</item><item>
<link>//gm.angeldm.com/read.php?&amp;guid=0#topreply</link>
<title><![CDATA[[评论] OpenSSL制作中文证书专题]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>//gm.angeldm.com/read.php?&amp;guid=0#topreply</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>