通常的X509证书是国际通用的RSA证书,现在国家推出了自己的加密算法,SM2算法,本文根据自己工作中遇到的情况,试图讲一下国密SM证书的有效性验证。

证书在本地存储一般是DER(二进制)格式的,网络传输则是base64格式,需要解码。

 

        可以用Asn1View工具查看二进制文件的十六进制格式,查看证书可以看到

java加载国密证书链 国密证书验证_4D

SM2证书是TLV格式的,分为三大模块,第一模块是证书的实际内容,第二个模块是证书使用的签名算法,其实就是一个oid,目前windows是无法识别这个oid的,所以双击查看证书的时候,证书签名算法选项只是显示一串oid,第三个模块,就是证书的签名值。要取出证书的实际内容,证书的签名值,就要了解下TLV格式。下面只说下取出签名的方法,

java加载国密证书链 国密证书验证_公钥密码_02

图中选中部分就是签名,但是要国密是使用ECC签名,要将签名数据封装成ECC签名块,定义格式如下:typedef struct Struct_ECCPUBLICKEYBLOB{
 ULONG BitLen;          //模数的实际位长度,必须是8的倍数
 BYTE XCoordinate[ECC_MAX_XCOORDINATE_BITS_LEN / 8];//曲线上点的X坐标,有限域上的整数
 BYTE YCoordinate[ECC_MAX_YCOORDINATE_BITS_LEN / 8];//曲线上点的Y坐标,有限域上的整数
}ECCPUBLICKEYBLOB, *PECCPUBLICKEYBLOB;

上图有两个中以02开头,20为长度,后面的数据就是ECCPUBLICKEYBLOB的两个分量了,取出来拷贝进去就行了。

下面就是验签模块了,复制网友们的总结吧:

注意:国密局的SM2证书验签时,需要对上面的数据进行数据填充(填充方式详见PBOC3.0规范第17部分)。

我猜测是这样的规则:如果签名后的数据不是TLV格式的,则直接进行SM3计算,否则就需要进行数据填充。

下面一步步对数据进行操作:

第一步,组建数据ZA并计算HASH值

00 80(用户ID的bit位长度)

31 32 33 34 35 36 37 38 31 32 33 34 35 36 37 38(用户ID)

FF FF FF FE FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 FF FF FF FF FF FF FF FC (椭圆曲线公钥密码算法推荐曲线参数a)

28 E9 FA 9E 9D 9F 5E 34 4D 5A 9E 4B CF 65 09 A7 F3 97 89 F5 15 AB 8F 92 DD BC BD 41 4D 94 0E 93 (椭圆曲线公钥密码算法推荐曲线参数b)

32 C4 AE 2C 1F 19 81 19 5F 99 04 46 6A 39 C9 94 8F E3 0B BF F2 66 0B E1 71 5A 45

89 33 4C 74 C7 (椭圆曲线公钥密码算法推荐曲线参数Gx)

BC 37 36 A2 F4 F6 77 9C 59 BD CE E3 6B 69 21 53 D0 A9 87 7C C6 2A 47 40 02 DF 32 E5 21 39 F0 A0(椭圆曲线公钥密码算法推荐曲线参数Gy)

D6 9C 2F 1E EC 3B FB 6B 95 B3 0C 28 08 5C 77 B1 25 D7 7A 9C 39 52 5D 81 90 76 8F 37 D6 B2 05 B5(公钥X)

89 DC D3 16 BB E7 D8 9A 9D C2 19 17 F1 77 99 E6 98 53 1F 5E 6E 3E 10 BD 31 37 0B 25 9C 3F 81 C3(公钥Y)

对上面数据进行SM3计算得到

4D 38 D2 95 8C A7 FD 2C FA E3 AF 04 48 69 59 CF 92 C8 EF 48 E8 B8 3A 05 C1 12 E7 39 D5 F1 81 D0

 

第二步,上面的SM3结果加上数据M,再进行SM3计算得到

HASH值:C3 B0 2E 50 0A 8B 60 B7 7D ED CF 6F 4C 11 BE F8 D5 6E 5C DE 70 8C 72 06 56 54 FD 7B 21 67 91 5A

用SM2公钥验签即可成功。