SM2 algorithm encryption signature message syntax specification (three) how to construct signedData

The previous article has introduced the signed Data type in the National Secret Specification. Next, let’s talk about how to construct this type of data~~\( ̄︶ ̄)/ 

1. Construction process

The definition of the signature data type structure in the GM/T0010 specification is consistent with the RFC specification. According to the RFC specification, the process of constructing signature data involves the following steps:
       a. For each signer, he uses the message digest algorithm to calculate the digest value; (for the GM/T 0010 specification, the digest algorithm is SGD_SM3)
       b. For a signer, the message digest and related information are encrypted with their own private key (namely, signature); (For GM/T 0010 specification, the SM2 signature algorithm is used)
       c. For each signer, combine the encrypted message digest with other The signer specific information is placed in the signer_info value. The certificate, crl, etc. of each signer are also collected in this step;
       d. Put the digest algorithm of all signers, their signer_info value and content into the sign value together 

2. Coding implementation

The previous article has mentioned that the pkcs7 structure defined in the gmssl library cannot be used directly due to the OID, and the defined PKCS7_SIGNED structure cannot be used. Because the signed data content type in the PKCS7_SIGNED structure is defined as struct pkcs7_st type . As shown below

The content of the signed data is generally filled with Data type data, which corresponds to the OID in the RFC specification: 1.2.840.113549.1.7.1 , and the OID in the GM/T 0010 specification: 1.2.156.10197.6.1.4.2.1 .

That is to say, if you use PKCS7_SIGNED directly, the OID of the content type cannot be set to the OID value of the national secret standard. Therefore, it also needs to be realized through the ASN.1 library custom type. For custom ASN structure schemes , please refer to the previous article of the editor. I won't repeat it here.

//

(=゚ω゚)ノ---===≡≡≡ The operation is as fierce as a tiger...

OK editor has customized the required signature data structure ( SM2_SIGNED ) and the PKCS7 structure ( SM2SignedData ) for the signature data ;

Then according to the construction process, the relevant algorithm is called to calculate the digest value and the DER-encoded data of the signature value. (The specific algorithm each company has its own algorithm, or the sm2\sm3 algorithm of the gmssl library can also be used)

//

 The main code of the construction part is as follows:

/*oid refer to GM/T 0006*/
#define OID_SM2_1 "1.2.156.10197.1.301.1"           /*sm2-1 数字签名算法 */
#define OID_SM2_3 "1.2.156.10197.1.301.3"           /*sm2-3 公钥加密算法*/
#define OID_SM3 "1.2.156.10197.1.401"               /*SM3密码杂凑算法*/
#define OID_SM4 "1.2.156.10197.1.104"               /*SM4分组密码算法*/

/*oid refer to GM/T 0010*/
#define OID_SM2_Data               "1.2.156.10197.6.1.4.2.1"    //SM2算法消息语法规范- 数据类型
#define OID_SM2_Signed             "1.2.156.10197.6.1.4.2.2"    //SM2算法消息语法规范- 签名数据类型
#define OID_SM2_Enveloped          "1.2.156.10197.6.1.4.2.3"    //SM2算法消息语法规范- 数字信封数据类型  
#define OID_SM2_SignedAndEnveloped "1.2.156.10197.6.1.4.2.4"    //SM2算法消息语法规范- 签名及数字信封数据类型
#define OID_SM2_Encrypted          "1.2.156.10197.6.1.4.2.5"    //SM2算法消息语法规范- 加密数据类型
#define OID_SM2_KeyAgreementInfo   "1.2.156.10197.6.1.4.2.6"    //SM2算法消息语法规范- 密钥协商数据类型
/签名数据封装
	if ((p7 = SM2SignedData_new()) == NULL)
	{
        //TODO. 错误处理
		goto end;
	}

	//------------设置类型为sm2_signed
	if (!SM2_SignedData_set_type(p7, OID_SM2_Signed)) {
		//TODO. 错误处理
		goto end;
	}
	//------------填入contents 
	//根据规范理解应该为国密定义的oid:"1.2.156.10197.6.1.4.2.1".
	SM2_SignedData_content_new(p7, OID_SM2_Data); 
	ASN1_OCTET_STRING *os = p7->sign->contents->data;
	ASN1_STRING_set(os, pucData, uiDataLen);  //填入签名原文(即需要签名的数据)

	//------------构造签名者信息signerinfo
	PKCS7_SIGNER_INFO *si = NULL;
	if ((si = PKCS7_SIGNER_INFO_new()) == NULL)
	{
		//TODO. 错误处理
		goto end;
	}

	/* We now need to add another PKCS7_SIGNER_INFO entry */
	if (!ASN1_INTEGER_set(si->version, 1))
	{
		//TODO. 错误处理
		goto end;
	}
	if (!X509_NAME_set(&si->issuer_and_serial->issuer, X509_get_issuer_name(sig_cert)))
	{
		//TODO. 错误处理
		goto end;
	}

	/*
	* because ASN1_INTEGER_set is used to set a 'long' we will do things the ugly way.
	*/
	ASN1_INTEGER_free(si->issuer_and_serial->serial);
	if (!(si->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get_serialNumber(sig_cert))))
	{
		//TODO. 错误处理
		goto end;
	}

	/* Set the digest algorithms  对内容进行摘要计算的消息摘要算法(本规范采用sm3 "1.2.156.10197.1.401") */
	X509_ALGOR_set0(si->digest_alg, OBJ_nid2obj(NID_sm3), V_ASN1_NULL, NULL);

	/* Set the sign algorithms  sm2-1椭圆曲线数字签名算法标识符("1.2.156.10197.1.301.1" ) */
	X509_ALGOR_set0(si->digest_enc_alg, OBJ_nid2obj(NID_sm2sign), V_ASN1_NULL, NULL);

	//设置用签名者私钥进行签名的结果   DER编码后的数据
	/*注。这里用ASN1_STRING_set(),而不用ASN1_STRING_set0(). ASN1_STRING_set()是进行内存拷贝,而ASN1_STRING_set0()中是直接指针指向*/
	ASN1_STRING_set(si->enc_digest, &derSignature, derSignatureLen);

	//------------将签名者信息加入到PKCS7_ENVELOPE中
	if (!SM2_SignedData_add_signer(p7, si))
	{
		//TODO. 错误处理
		goto end;
	}
	//------------将签名者证书添加到PKCS7结构中
	if (!SM2_SignedData_add_certificate(p7, sig_cert))
	{
		//TODO. 错误处理
		goto end;
	}

	//------------Der编码
    //pucDerSignedData为缓冲区,用来存放DER编码后的数据;
    pTmp = NULL;
	pTmp = pucDerSignedData;
	if ((derP7Len = i2d_SM2SignedData(p7, &pTmp)) <= 0)
	{
		//TODO. 错误处理
		goto end;
	}
	///end

SM2_SignedData_set_type This method is designed according to the SM2SignedData structure, and is used to set its type according to the OID. The SM2_SIGNED signature structure object is created internally , and the version number of the SM2_SIGNED object is set . ( You can set it according to your own custom structure )

	ASN1_OBJECT *obj;

	obj = OBJ_txt2obj(oid, 1);

	if (0 == strcmp(oid, OID_SM2_Signed))
	{
		p7->type = obj;  //指定OID
        //创建SM2_SIGNED对象
		if ((p7->sign = SM2_SIGNED_new()) == NULL)
			goto err;
        //设置版本号
		if (!ASN1_INTEGER_set(p7->sign->version, 1))
		{
			SM2_SIGNED_free(p7->sign);
			p7->sign = NULL;
			goto err;
		}
	}

The SM2_SignedData_content_new method is a method designed according to the SM2SignedData structure. It is used to create a new SM2Data type object and point the contents of the SM2SignedData structure to this structure

	SM2Data *ret = NULL;
    //新建SM2Data结构对象
	if ((ret = SM2Data_new()) == NULL)
		goto err;
    //指定SM2Data对象的OID
	if (!SM2_Data_set_type(ret, oid))
		goto err;
    //将SM2Data包含于SMSignedData中
	if (!SM2_SignedData_set_content(p7, ret))
		goto err;

Only some of the main codes are posted above for your reference and at the same time to record for your own memory.

Finally, the singedData output by DER encoding can be opened and viewed with Asn1View, as follows:

    

Guess you like

Origin blog.csdn.net/lt4959/article/details/112559657