zoukankan      html  css  js  c++  java
  • 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.EndReceiveRecord (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,默认下载文件无效,这不得不说是个坑。

  • 相关阅读:
    【Difference Between Primes HDU
    【Pet HDU
    《Java程序设计实验》 软件工程18-1,3 OO实验2
    【数据结构作业】-【带头结点的单链表就地逆置】
    【Miscalculation UVALive
    【Bit String Reordering UVALive
    【Bazinga HDU
    (转载)博弈汇总【巴什博奕,威佐夫博弈,尼姆博弈,斐波那契博弈】
    【Audiophobia UVA
    【Calling Circles UVA
  • 原文地址:https://www.cnblogs.com/himax/p/how_to_use_wechat_cert_with_mono.html
Copyright © 2011-2022 走看看