获取平台证书

更新时间:2025.04.07

场景介绍

调用获取平台证书V2接口之前,请前往微信支付商户平台升级API证书,升级后才可成功调用本接口。

接口调用请求说明

请求Url

https://api.mch.weixin.qq.com/risk/getcertficates

是否需要证书

请求方式

POST、XML

签名方式

HMAC-SHA256

请求参数

名称

变量名

必填

类型

示例值

描述

商户号

mch_id

String(32)

1900000109

微信支付分配的商户号

随机字符串

nonce_str

String(32)

5K8264ILTKCH16CQ2502SI8ZNMTM67VS

随机字符串,不长于32位。推荐随机数生成算法

签名

sign

String(64)

C380BEC2BFD727A4B6845133519F3AD6C380BEC2BFD727A4B6845133519F3AD6

签名,详见签名生成算法

签名方式

sign_type

String(32)

HMAC-SHA256

暂只支持HMAC-SHA256

请求参数示例:

1<xml>
2<sign_type>HMAC-SHA256</sign_type>
3<nonce_str>abcdef</nonce_str>
4<mch_id>1900006511</mch_id>
5<sign>FD29B578B31C509B45B7C2779803D9E41B68E6B84AEB1EBDE47DCA00049B649B</sign>
6</xml>

返回结果

名称

变量名

必填

类型

示例值

描述

返回状态码

return_code

String(16)

SUCCESS

SUCCESS/FAIL
此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息

return_msg

String(128)

签名失败

返回信息,如非空,为错误原因
签名失败
参数格式校验错误

当return_code为SUCCESS的时候,还会包括以下字段:

名称

变量名

必填

类型

示例值

描述

商户号

mch_id

String(32)

1900000109

调用接口提交的商户号

随机字符串

nonce_str

String(32)

5K8264ILTKCH16CQ2502SI8ZNMTM67VS

微信返回的随机字符串

签名

sign

String(64)

C380BEC2BFD727A4B6845133519F3AD6C380BEC2BFD727A4B6845133519F3AD6

微信返回的签名,详见签名生成算法

业务结果

result_code

String(16)

SUCCESS

SUCCESS:支付成功
FAIL:根据err_code的指引决定下一步操作。

错误代码

err_code

String(32)

SYSTEMERROR

详细参见错误列表

错误代码描述

err_code_des

String(128)

系统错误

错误返回的信息描述,详见收银员操作指引列表

当return_code 和result_code都为SUCCESS的时,还会包括以下字段:

名称

变量名

必填

类型

示例值

描述

平台证书信息

certificates

String(6000)

 

包含了平台证书序列号serial_no、证书启用时间effective_time、证书弃用时间expire_time、加密证书信息包encrypt_certificate,请根据平台证书解密指引获取证书明文(证书明文为PEM格式),方可使用

举例如下:

1<xml>
2<return_code><![CDATA[SUCCESS]]></return_code>
3<return_msg><![CDATA[OK]]></return_msg>
4<result_code><![CDATA[SUCCESS]]></result_code>
5<nonce_str><![CDATA[PnDRNZSFzpp2ieUq]]></nonce_str>
6<sign><![CDATA[AD5919F5FE6D77C308ABEE1A4021CB9839C3F04D7C2FE68FC765011EA3BBEB0F]]></sign>
7<mch_id><![CDATA[1900006511]]></mch_id>
8<certificates><![CDATA[{"data":[{"serial_no":"42A5C4F7F70D57D0576BBEDA0E0928D6E5C4F003","effective_time":"2017-08-18 14:52:04","expire_time":"2022-08-17 14:52:04","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"bfcb2bd59c97","associated_data":"certificate","ciphertext":"vQ4N+lLNvtIhaV5Gqao44mbYBSaz3bZ4Md3M4f+OuquEJrp+/v4gA//UZqnQ1G0roYqnSMfcsRFj7ItTCP0tbYregpYqBKd4NSLiF/m1o01JD/9nzd3pBwBUJenUzvE1cuMO+fookaBYr+Z5AfesXUUmvl5qAbD3Yj+5GuMIkTCQcn4W6rls/W2YDo3o3T9sWtl5A/5w+U/Wsb9/UefNow6ND+2MAWRm1GK5tRTkBGVKMt699SM4p0pUns3D4g3slz6zeYIFY3+x+NzrxNq+Ov7I4e/wkp1s3QJd3vctDC4j5btvpCvdEIrBmzzTKzmJ+qhHIRVpXqiMTtOWSpCcTCptUt4v/ZrIlMihESdruDv7Zj4984+4tzBqmQ/Mt1Bwbs8RyKYe2UufmXSMyOeCW06TtkXduZ7M2QSKE4kTlRerEGPatymglepMnjpSMX/CnwaSaHcIBWN2oNjAcuBdMGFlbv05owBlkEZm4sRgZR9EMDIX/N469TUsJ3yXVLuN2k6XaAEM5wpX/Hc15R1o1rhpnLjGZpZoKOVpmcyqw5/0uBQgAAaTXOGgr6L2mrSsp9Au4J0hIX/SjfrjaovXEZTvSM+1oGlJmRVLZ+jxjTD/al7X2xsjTleYYggp4EN4aaC4DTwUNcAAzhHF9R7e+bIfyopa2FF+exXC9kZUYLywg9bwKOJwhkykz7NM669gXLjlyEu6W9gIa8sa3HKSfeLfcpTan7Ev9BjRbowQYmn7RZEyvizKJHJU3ge04OImeJFY4fT8JahzaOT8BQnvP4g2ZT65r4jQwXEbFqOJNH5SdRlTL+3oCqkgMx+1wccaj9ZKqxY9EFDwZgjLZWoySJvIbDQfEayo1pRzlcF9MbuFyGH0vblRLSx3viCc/q6oUkx2OjRw1Hp3sdtFGZMS2OE1+xICymLPglHuMzGkGYwl7ZxbotiXKkqAN46Zd7hNcTwHhxMjQXcoaUoGNEKK1fRZrBv0eUjhES8GbZvzS7+Xm1SR8dKTNMQyEvFesUY143nFt1GK+/bJR+0l2dz0zgpJGAS4yKBkWdsTng0a/jzRbMryRy+fAjWGfvHlVcXXD5b51kx1P3pxcQdMe3K0al+40gLilbegFUVPXhZ04BVgxiWHfeRPnDVwVXFzHG7MAjmPWS0PFzJupZExuy+jxIf5oyHLcYjnl2jwNNcWdzm5AFWYqy5oQI88lcOBx1X+fGuZTKAopk8/2zCa7uu9ILSyVBf801wagINDhxSNemoDoRPE0lvIYE/ax7RQehQ2Q3F2JNmpP6EfP1KZsT6nSWLBf1M5tvX/pAsPbYowNCgrwXLa68L5e03ScplSZrJWP7H3UcGxq9fRLgOYnF7ocRr0iviSRGVmSDqdtpIWwhb+UoAw4347hTQsEHRhYQdR6fTryiANB+H+6SnRJany/cozFV11J03w6h9Lmx95OJGYwF8Cei8S3pNkHpq90o7eUq2PmfS/wwxL3ZyJFPS8OY05zR4ykRnwir4L2X1RyCVoV34AAzVsvr93fVNPHtY3yf+i6sDWb4yGaXaYMM/cOnNs7wrxME44in+YZtPduI+8MZ5EGTbaqjJzrGnrbDnb515OOXg6gk+eV+bJkMXxxoNQGOkLCCI5pN+wrrokXRYhFZbYSkLd/rkg+T3JS23nO1TYOejewvatmQ97i9OFxNrwxOzDL9E87jLj26Wm+VSbm/SNafEh0eU0owwyVskg7evUe7XxcBErXC8M87MuK6AJo/IhhivYlEb/d+wG2r0gV7VesAjYC2n3ZAI1oz78WMMTmj6IqXgDc20uNmGYX0IEB+cxpJwejEfV72ArStqzumUzw3YhvD4L7Ozq0b6Y2gao88MONn9nevnydq5IvsG0bsGutXCFwjhYGxLyqigGIkVkXeq+BbxFpNxbogkB43cM"}}]}]]></certificates>
9</xml>

 

平台证书解密指引

●“加密后的证书内容”解密算法:

  1. 从微信支付商户平台上获取商户的APIv3密钥记为`key`

  1. 1、针对`algorithm`中描述的算法(目前为`AEAD_AES_256_GCM`),取得对应的参数`nonce`和`associated_data`。

  2. 2、使用`key`、`nonce`和`associated_data`,对数据密文`ciphertext`进行解密,得到平台证书的原文,

  3. 3、将原文写入文件,使用该文件对敏感字段进行加密。

注: `AEAD_AES_256_GCM`算法的接口细节,请参考rfc5116。微信支付使用的密钥`key`长度为 32 个字节,随机串`nonce`长度 12 个字节,`associated_data`长度小于 16 个字节并可能为空。
很多编程语言支持`AEAD_AES_256_GCM`算法,如java语言中的Cipher、SecretKey、GCMParameterSpec、Base64等类。(java与php代码示例如下)

●以下代码为AEAD_AES_256_GCM的解密java示例代码,未经充分测试,仅供参考。

1package com.qq.weixin.mch.api.examples;
2import java.security.PublicKey;
3import javax.crypto.Cipher;
4import javax.crypto.spec.GCMParameterSpec;
5import javax.crypto.spec.SecretKeySpec;
6import javax.security.cert.X509Certificate;
7import java.util.Base64;
8public class AesGcmExample2 {
9private static final String ALGORITHM = "AES/GCM/NoPadding";
10private static final int TAG_LENGTH_BIT = 128;
11private static final int NONCE_LENGTH_BYTE = 12;
12private static final String AES_KEY = ""; // APIv3密钥
13private static final String TRANSFORMATION_PKCS1Padding = "RSA/ECB/PKCS1Padding";
14private static String aesgcmDecrypt(String aad, String iv, String cipherText) throws Exception {
15final Cipher cipher = Cipher.getInstance(ALGORITHM, "SunJCE");
16SecretKeySpec key = new SecretKeySpec(AES_KEY.getBytes(), "AES");
17GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, iv.getBytes());
18cipher.init(Cipher.DECRYPT_MODE, key, spec);
19cipher.updateAAD(aad.getBytes());
20return new String(cipher.doFinal(Base64.getDecoder().decode(cipherText)));
21}
22
23public static void main(String[] args) {
24final String associatedData = ""; // encrypt_certificate.associated_data
25final String nonce = ""; // encrypt_certificate.nonce
26final String cipherText = ""; // encrypt_certificate.ciphertext
27try {
28String wechatpayCert = aesgcmDecrypt(associatedData, nonce, cipherText);
29} catch (Exception e) {
30e.printStackTrace();
31}
32}
33}

●以下代码为AEAD_AES_256_GCM的解密php示例代码,未经充分测试,仅供参考。

1//region 证书解密start
2public function decodePem(){
3$ciphertext = '加密后的证书内容';
4$nonce = '加密证书的随机串,加密证书的随机串';
5$associated_data = '加密证书的随机串,固定值: certificate';
6$key = '你的APIv3密钥';
7
8$check_sodium_mod = extension_loaded('sodium');
9if($check_sodium_mod === false){
10echo '没有安装sodium模块';die;
11}
12$check_aes256gcm = sodium_crypto_aead_aes256gcm_is_available();
13if($check_aes256gcm === false){
14echo '当前不支持aes256gcm';die;
15}
16
17$pem = sodium_crypto_aead_aes256gcm_decrypt(base64_decode($ciphertext),$associated_data,$nonce,$key);
18var_dump($pem); //这是解密出来的证书内容,复制出来保存就行了
19}
20//endregion 证书解密end

●以下代码为AEAD_AES_256_GCM的解密C#示例代码,未经充分测试,仅供参考。

1public static string AesGcmDecrypt(string content, string key, string ivs)
2{
3byte[] bytes = Encoding.UTF8.GetBytes(key);
4byte[] bytes2 = Encoding.UTF8.GetBytes(ivs);
5byte[] array = Convert.FromBase64String(content);
6byte[] bytes3 = Encoding.UTF8.GetBytes("certificate");
7GcmBlockCipher gcmBlockCipher = new GcmBlockCipher(new AesEngine());
8AeadParameters aeadParameters = new AeadParameters(new KeyParameter(bytes), 128, bytes2, bytes3);
9gcmBlockCipher.Init(false, aeadParameters);
10byte[] array2 = new byte[gcmBlockCipher.GetOutputSize(array.Length)];
11int num = gcmBlockCipher.ProcessBytes(array, 0, array.Length, array2, 0);
12
13gcmBlockCipher.DoFinal(array2, num);
14
15return Encoding.UTF8.GetString(array2);
16}

 

反馈
咨询
目录
置顶