C#在Linux+Mono环境中使用微信支付证书

最近特殊的需求,要把微信平台一个功能页面部署到Linux(CentOS6.5)下,其中涉及到微信支付退款。

鉴于之前实践过mono+jexus+asp.net mvc的部署,于是问题重点在于解决对商户证书的调用问题。

 

查看微信支付官方文档关于证书的使用说明

  • ◆ apiclient_cert.p12是商户证书文件,除PHP外的开发均使用此证书文件。

  • ◆ 商户如果使用.NET环境开发,请确认Framework版本大于2.0,必须在操作系统上双击安装证书apiclient_cert.p12后才能被正常调用。

  • ◆ 商户证书调用或安装都需要使用到密码,该密码的值为微信商户号(mch_id)

  • ◆ PHP开发环境请使用商户证书文件apiclient_cert.pem和apiclient_key.pem ,rootca.pem是CA证书。

 

1.使用mono自带工具certmgr导入.p12证书

certmgr -add -c -m -p 密码 My ApiClient_cert.p12

2.编写测试程序

using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

public class TlsTest {
public static void Main(string[] args) { HttpWebResponse webreponse; string strHtml = "NO";
try { //系统必须已经导入cert指向的证书 string url =
"https://api.mch.weixin.qq.com/secapi/pay/refund";
//My即对应”个人“存储区,固定不可改变 X509Store store = new X509Store("My",
StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly|OpenFlags.OpenExistingOnly); X509Certificate cer = store.Certificates.Find(
X509FindType.FindByThumbprint,
"546FCAA50DB599C5439AC8139C69393D5DB243D0", false)[0]; //遍历证书查看Hash;windows下可直接双击安装,查看属性            //Console.WriteLine(store.Certificates.Count);            //foreach(var c in store.Certificates){            // //Console.WriteLine("{0},{1},{2},{3},{4},{5}", c.GetCertHashString(), c.FriendlyName, c.GetFormat(), c.IssuerName, c.SubjectName, c.Thumbprint);            //    if (c.GetCertHashString() == "546FCAA50DB599C5439AC8139C69393D5DB243D0")            //    {            //        Console.WriteLine("found");            //        cer = c;            //        break;            //    }            //} HttpWebRequest webrequest =
(HttpWebRequest)HttpWebRequest.Create(url); webrequest.ClientCertificates.Add(cer); webrequest.Method = "post"; webrequest.KeepAlive = true; webreponse = (HttpWebResponse)webrequest.GetResponse(); Stream stream = webreponse.GetResponseStream();
string resp = string.Empty;
using (StreamReader reader = new StreamReader(stream)) { resp = reader.ReadToEnd(); } strHtml = resp; }
catch (Exception exp) { strHtml = exp.ToString(); } Console.WriteLine(strHtml); } }

3.运行测试程序

mono SSLtest.exe

结果运行报错


System.Net.WebException: Error: TrustFailure (The authentication or 
decryption has failed.) ---> System.IO.IOException:
The authentication or decryption has failed. --->
System.IO.IOException: The authentication or decryption has failed.
---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate
received from server. Error code: 0xffffffff800b0109 at Mono.Security.Protocol.Tls.RecordProtocol.EndReceiveRecor
(IAsyncResult asyncResult) <0x40713980 + 0x0013e>
in <filename unknown>:0 at Mono.Security.Protocol.Tls.SslClientStream.SafeEndReceiveRecord
(IAsyncResult ar, Boolean ignoreEmpty) <0x407138b0 + 0x00031> in
<filename unknown>:0 at Mono.Security.Protocol.Tls.SslClientStream.NegotiateAsyncWorker
(IAsyncResult result) <0x4070d2d0 + 0x0023a>
in <filename unknown>:0 --- End of inner exception stack trace --- at Mono.Security.Protocol.Tls.SslClientStream.EndNegotiateHandshake
(IAsyncResult result) <0x40726300 + 0x000f3>
in <filename unknown>:0 at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback
(IAsyncResult asyncResult) <0x40726050 + 0x00086>
in <filename unknown>:0
--- End of inner exception stack trace --- at Mono.Security.Protocol.Tls.SslStreamBase.EndRead
(IAsyncResult asyncResult) <0x4070a990 + 0x00199>
in <filename unknown>:0 at Mono.Net.Security.Private.LegacySslStream.EndAuthenticateAsClient
(IAsyncResult asyncResult) <0x4070a8f0 + 0x00042>
in <filename unknown>:0 at Mono.Net.Security.Private.LegacySslStream.AuthenticateAsClient
(System.String targetHost,
System.Security.Cryptography.X509Certificates.
X509CertificateCollection clientCertificates,
SslProtocols enabledSslProtocols,
Boolean checkCertificateRevocation) <0x40704650 + 0x00055>
in <filename unknown>:0 at Mono.Net.Security.MonoTlsStream.CreateStream
(System.Byte[] buffer)
<0x40703e00 + 0x00145> in <filename unknown>:0 --- End of inner exception stack trace --- at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult)
<0x406fcf50 + 0x001ed> in <filename unknown>:0 at System.Net.HttpWebRequest.GetResponse () <0x406f5210 + 0x00053>
in <filename unknown>:0 at TlsTest.Main (System.String[] args) <0x406a7d80 + 0x002c6> in
<filename unknown>:0

 

4.发现错误原因是"Invalid certificate received from server",这个问题在Mono文档中已有说明:

That’s probably because you do not trust the site you are connecting to. Note that a default installation of Mono doesn’t trust anyone!

默认情况下,任何站点都不被Mono信任!

同时也给出了4个解决方案:

  • 使用cert-sync工具同步Mono和系统的证书存储区

  • 程序实现ICertificatePolicy自行决定信任规则

  • 使用certmgr.exe导入受信证书

  • 使用mozroots.exe自动导入常用的可信根证书

 

5.尝试解决方案2

ServicePointManager.ServerCertificateValidationCallback = 
new RemoteCertificateValidationCallback(CheckValidationResult);

private static bool CheckValidationResult(object sender,
X509Certificate c,
X509Chain chain, SslPolicyErrors errors) {
return true; }

报错问题虽然可以解决,但对所有情况均信任不是一个好的解决方法,根据X509Certificate c进行判断理应可行,没有再进一步探索

 

6.尝试解决方案4

使用mozroots自动下载安装常用的根证书

mozroots --import --sync

显示成功导入100+根证书,重新执行测试程序仍然报错。

这个结果一度使我认为此方法无效,但偶然在本地测试却通过了。

 

对比发现生效的下载路径是:

https://hg.mozilla.org/releases/mozilla-release/raw-file/default/
security/nss/lib/ckfw/builtins/certdata.txt

而无效的下载路径是:

http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins
/certdata.txt?raw=1

于是手动下载文件并指定mozroots安装指定的文件

wget https://hg.mozilla.org/releases/mozilla-release/raw-file/default
/security/nss/lib/ckfw/builtins/certdata.txt
mozroots --import --sync --file certdata.txt

这时,执行测试程序运行正常

<xml><return_code><![CDATA[FAIL]]></return_code>
<return_msg><![CDATA[post数据为空]]></return_msg>
</xml>

 

7.总结

使用mozroots是解决问题的简单方法,但由于mono版本问题会导致默认的下载文件并不有效。本地有效版本:mono 4.6.0.0,使用中已提示建议使用cert-sync [WARNING: mozroots is deprecated, please move to cert-sync instead.]

服务器版本:mono 4.4.1.0,默认下载文件无效,这不得不说是个坑。


原文链接:http://www.cnblogs.com/himax/p/how_to_use_wechat_cert_with_mono.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微信开发使用的cert,里面微信支付API共四份(证书pkcs12格式、证书pem格式、证书密钥pem格式、CA证书),为接口强制要求时需携带的证书文件证书属于敏感信息,请妥善保管不要泄露和被他人复制。 不同开发语言下的证书格式不同,以下为说明指引: 证书pkcs12格式(apiclient_cert.p12) 包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份 部分安全性要求较高的API需要使用证书来确认您的调用身份 windows上可以直接双击导入系统,导入过程会提示输入证书密码,证书密码默认为您的商户ID(如:10010000) 证书pem格式(apiclient_cert.pem) 从apiclient_cert.p12导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem 证书密钥pem格式(apiclient_key.pem) 从apiclient_cert.p12导出密钥部分的文件,为pem格式 部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供 您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem CA证书(rootca.pem) 微信支付api服务器上也部署了证明微信支付身份的服务器证书,您在使用api进行调用时也需要验证所调用服务器及域名的真实性 该文件为签署微信支付证书的权威机构的根证书,可以用来验证微信支付服务器证书的真实性 某些环境和工具已经内置了若干权威机构的根证书,无需引用该证书也可以正常进行验证,这里提供给您在未内置所必须根证书环境载入使用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值