◆苗新亮 雷 波 刘 栋
(中国电子科技集团公司第三十研究所 四川 610041)
采用OpenSSL签发的RSA证书,通过Windows的证书查看器发现,公钥部分经过了ASN.1编码,在实际公钥的基础上增加了ASN.1编码的头部和尾部。而采用OpenSSL签发的ECC证书,通过Windows的证书查看器发现,公钥部分并没有采用ASN.1编码:证书中的公钥起始部分仅比实际公钥多了一个字节,即“04”。那么这个“04”的具体含义是什么?为什么会在ECC的证书里出现?能否不要这个“04”?下面将对这一系列问题进行分析回答。
根据美国国家标准ANSI X9.62中的描述:一个椭圆曲线点P(不是无穷远点O)由两个域元素表示,x坐标和y坐标,标记为P=(xp,yp)。这个点可以使用x坐标xp和一个确定比特zp压缩表示为(xp,zp),这个确定比特zp衍生自x坐标xp和y坐标yp。
IEEE标准 1363TM-2000中也对椭圆曲线点的压缩进行了描述,并与美国国家标准 ANSI X9.62基本一致。在IEEE标准1363aTM-2004中对椭圆曲线点的压缩形式进行了扩展,将原有的压缩形式定义为LSB压缩形式,扩展增加了SORT压缩形式。LSB压缩形式是指压缩比特是yp或ypxp−1的整数表示的最低有效位。SORT压缩形式是指压缩比特是yp和y'p整数表示的比较结果。其中,点是点的逆,在素数域Fp中y'p=−yp,在二元扩域 F2中
在我国的SM2椭圆曲线公钥密码算法标准中,采用的压缩形式与美国国家标准ANSI X9.62基本相同。在OpenSSL中,点的压缩完全遵循了美国国家标准ANSI X9.62,即采用了LSB压缩形式。ANSI X9.62中的压缩过程如下:
1.1.1 素数域上的点压缩
(2)计算αmodp的平方根β。如果没有平方根存在则报错;
(3)如果β最右侧一个比特与zp相等,那么设置yp=β,否则设置yp=p−β。
1.1.2 二元扩域上的点压缩
只要能够获得P的x坐标xp和zp,yp就能重新计算出来,详细计算方式如下:
②寻找一个域元素β,使得,如果没有解则报错;
在美国国家标准ANSI X9.62定义了点与八位字节串的相互转换方式,以便于必要的时候以字符串的形式展示。无穷远点O使用一个八位字节串(octet string)表示为PC=00。一个非无穷远点的圆曲线点可以表示为一个以下三种形式的字符串:压缩形式、非压缩形式、混合形式。标准中直接使用了IEEE标准1363TM-2000的一些结论。
在IEEE标准1363TM-2000中,点与八位字节串的相互转换方式不仅定义了这三种表示形式,还清楚的定义出了具体格式:
其中,PC是一个固定格式的字节,使用二进制表示为000UC。如果是非压缩形式或混合形式,U比特等于1,否则于0。如果是压缩形式或混合形式,C比特等于1,否则等于0。如果是压缩形式或混合形式,特等于zp,否则等于0。
XP是xp的八位字节串表示。如果是压缩形式或混合形式,YP是yp的八位字节串表示,否则YP为空。
IEEE标准1363aTM-2004对PC的格式进行修订,使用二进制表示为。其中,如果采用了SORT压缩形式,S比特为1,否则为0。其他定义的内容没有变化。
在我国的SM2椭圆曲线公钥密码算法标准中,采用的转换方式与美国国家标准ANSI X9.62基本相同。
在OpenSSL中,点的转换完全遵循了美国国家标准ANSI X9.62,与IEEE标准1363TM-2000保持一致。ANSI X9.62中的转换过程如下:
1.2.1 点到八位字节串的转换
输出:一个八位字节串PO。如果选用压缩方式,得到的PO中有L+1个字节。如果选用不压缩或者混合形式,得到的PO中有2L+1个字节。(其中,
按照如下步骤进行点到八位字节串的转换获得PO:
(1)将x坐标xp转换成八位字节串XP;
(2)如果选择压缩形式,则采用如下步骤:
①计算zp;
②如果zp为0,则设置单字节变量PC=02,如果zp为1,则设置PC=03;
(3)如果选择不压缩形式,则采用如下步骤:
①将y坐标yp转换成八位字节串YP;
(4)如果采用混合形式,则采用如下步骤:
①将y坐标yp转换成八位字节串YP;
②计算zp;
③如果zp为0,则设置单字节变量PC=06,如果zp为1,则设置PC=07;
1.2.2 八位字节串到点的转换
输入:定义在素数域Fp上椭圆曲线的域元素a和b,一个八位字节串PO。如果选用压缩方式,PO的长度为L+1字节。如果选用不压缩或者混合形式,PO的长度为2L+1字节。(其中,
按照如下步骤进行八位字节串到点的转换获得P:
(1)如果选用压缩形式,PO可以解析为如果选用非压缩形式或混合形式,PO可以解析为。其中,PC是一个字节,XP是一个长度为L的字节串,YP是一个长度为L的字节串;
(2)将八位字节串XP转换为xp;
(3)如果使用的是压缩形式,则采用如下步骤:
①检查PC是02还是03,如果都不是则报错;
②如果PC是02,则设置;如果PC是03,则设置
(4)如果使用的是未压缩形式,则采用如下步骤:
①检查PC是否是04,如果不是则报错;
②将八位字节串YP转换为yp;
(5)如果使用的是混合形式,则采用如下步骤:
①检查PC是06还是07,如果都不是则报错;
②将八位字节串YP转换为yp;
③如果PC是06,则设置;如果PC是07,则设置
④执行以下一个或两个步骤:
(6)如果q是一个素数,则验证,如果不是这种情形则报错。如果,则验证,如果不是这种情形则报错;
其实,采用OpenSSL签发出的ECC证书,可以通过修改OpenSSL源码,去掉这个椭圆曲线点的压缩形式标识“04”,通过Windows证书查看器看到的公钥就是实际的公钥。
在OpenSSL中关于椭圆曲线点的压缩形式定义在cryptoecec.h文件中,是一个名为point_conversion_form_t的枚举类型,具体如下:
/** Enum for the point conversion form as defined in X9.62(ECDSA)
*for the encoding of a elliptic curve point(x,y)*/
typedef enum {
/** the point is encoded as z||x,where the octet z specifies
*which solution of the quadratic equation y is */
POINT_CONVERSION_COMPRESSED = 2,
/** the point is encoded as z||x||y,where z is the octet 0x02 */
POINT_CONVERSION_UNCOMPRESSED=4,
/** the point is encoded as z||x||y,where the octet z specifies
技术与应用
* which solution of the quadratic equation y is */
POINT_CONVERSION_HYBRID = 6,
} point_conversion_form_t;
2.2.1 修改定义
虽然在OpenSSL中只定义了上述三种标识,但是从IEEE标准1363aTM-2004可以看出,还有08等几种定义。因此,需要在point_conversion_form_t枚举中增加一种与之不冲突的定义POINT_CONVERSION_COPYED=16,即对x和y直接拷贝,或者可以理解为将点直接编码为的形式。
2.2.2 修改点到八位字节串的转换处理
OpenSSL在其源码中提供了素数域和二元扩域两个椭圆曲线点EC_POINT到八位字节串的转换。因此,需要分别修改cryptoecec2_oct.c中的ec_GF2m_simple_point2oct函数和cryptoececp_oct.c中的ec_GFp_simple_point2oct函数。两者的修改方式基本相同:当form参数为POINT_CONVERSION_COPYED时,不再将form填入输出缓冲区buf的首字节中,并且返回值为两倍的模长2*field_len。
2.2.3 修改八位字节串到点的转换处理
OpenSSL中素数域和二元扩域上八位字节串转换成椭圆曲线点EC_POINT实现函数是:cryptoecec2_oct.c中的ec_GF2m_simple_oct2point函数和cryptoececp_oct.c中的ec_GFp_simple_oct2point函数。如果八位字节串的长度为2*field_len,则认为椭圆曲线点的压缩形式form 为POINT_CONVERSION_COPYED,即只对x和y进行了自然连接,并从正确的位置提取x和y。
2.2.4 修改从缓冲区解码私钥对象的处理
修改OpenSSL中从缓冲区解码获得私钥对象的d2i_ECPrivateKey函数实现。用获取到的公钥八位字节串的长度pub_oct_len对模长field_len求余数,余数为0时,则认为只对x和y进行了自然连接,压缩形式为POINT_CONVERSION_COPYED,余数为1时则通过公钥部分的首字节计算压缩形式。最后将获得的压缩形式,赋值给私钥对象的conv_form属性。
采用相同的方式修改OpenSSL中从缓冲区解码获得公钥对象的o2i_ECPublicKey函数实现。
在调用OpenSSL时,签发证书时,需要明确使用POINT_CONVERSION_COPYED标识,作为form的值传递给证书签发函数。
如果仅仅是进行证书签发测试,通过OpenSSL自身提供的工具就可实现。不过还需要修改该工具,使其能够支持POINT_CONVERSION_COPYED。修改apps目录中的ec.c和ecparam.c中对“-conv_form”选项的处理,当参数为“copyed”时,将form设置为POINT_CONVERSION_COPYED使用。
然后按照如下步骤签发椭圆曲线证书:
(1)采用prime256v1椭圆曲线产生一个密钥文件:openssl ecparam -out Ecc.key -name prime256v1 –genkey;
(2)利用密钥文件产生证书请求,并输入证书相关信息:openssl req -key Ecc.key -new -out Ecc.req;
(3)使用密钥文件Ecc.key将证书请求Ecc.req签发成证书文件,即一个自签发证书,或者叫做根证书:openssl x509 -req -in Ecc.req -signkey Ecc.key -out Ecc.cer。
通过上述步骤签发出的证书Ecc.cer,通过Windows查看器打开后,能够看到该证书的公钥部分已经没有“04”了。
通过对ANSI X9.62、IEEE 1363TM-2000、IEEE 1363aTM-2004、SM2椭圆曲线公钥密码算法等标准的解读,对OpenSSL源码的修改,不但可以签发出不带压缩形式标识的椭圆曲线证书,也可以利用已修改的OpenSSL,对椭圆曲线证书进行验证。
经过修改的OpenSSL,可在一些非常规标准特殊行业中进行应用。签发出的椭圆曲线证书,可在嵌入式应用等无法集成庞大的OpenSSL的小微型应用中使用。