c# - 从 ASPX/C# 页面发送 APNS,使用 SSL 进行身份验证

标签 c# asp.net ssl push-notification apple-push-notifications

我一直在尝试让 Windows 2008 R2 数据中心(在亚马逊上)使用 Apple 推送通知服务 - 我已经看到很多关于其中一些的问题,但现有的答案都没有解决我的问题。我正在使用带有 TcpClient 的 SslStream 编写此代码,我将其包装在一个名为 SSLClient 的类中。我不断在 AuthenticateAsClient 行收到“证书链是由不受信任的机构颁发的”错误。这是我的 SSLClient(其中大部分从使用带有 TcpClient 的 SslStream 的 MSDN 示例开始):

public class SSLClient
{
    public delegate void OnSSLRequestHandler(SSLRequestEvent e);

    private string _machineName;
    private string [] _serverCertFilenames;
    private string [] _serverCertPasswords;

    public event OnSSLRequestHandler OnLoaded;

    public SSLClient(
        string machineName,
        string [] serverCertFilenames,
        string [] serverCertPasswords )
    {
        _machineName = machineName;
        _serverCertFilenames = serverCertFilenames;
        _serverCertPasswords = serverCertPasswords;
    }

    public bool ValidateServerCertificate(
          object sender,
          X509Certificate certificate,
          X509Chain chain,
          SslPolicyErrors sslPolicyErrors)
    {
       if (sslPolicyErrors == SslPolicyErrors.None)
            return true;

        // Do not allow this client to communicate with unauthenticated servers. 
        return false;
    }

    public void Load(byte[] sendData, int port = 443)  
    {
        // Create a TCP/IP client socket. 
        // machineName is the host running the server application.
        TcpClient client = new TcpClient(_machineName, port);

        // Create an SSL stream that will close the client's stream.
        SslStream sslStream = new SslStream(
            client.GetStream(), 
            false, 
            new RemoteCertificateValidationCallback (ValidateServerCertificate), 
            null
        );

        // The server name must match the name on the server certificate. 
        try 
        {
            X509Certificate2Collection xc = new X509Certificate2Collection();
            for (int i = 0; i < _serverCertFilenames.Length; i++)
            {
                string certName = _serverCertFilenames[i];
                string certPwd = _serverCertPasswords[i];

                X509Certificate2 x;
                if (certPwd != "")
                    x = new X509Certificate2(certName, certPwd);
                else
                    x = new X509Certificate2(certName);

                xc.Add(x);
            }

            sslStream.AuthenticateAsClient(_machineName, xc, SslProtocols.Ssl3, false);
        } 
        catch (AuthenticationException e)
        {
            string errMsg = "Exception: " + e.Message;


            if (e.InnerException != null)
                errMsg += ("\r\nInner exception: " + e.InnerException.Message);

            errMsg += ("\r\nAuthentication failed - closing the connection.");
            client.Close();

            // Just fires an event, ctor(success, message, response, SSLClient)
            if (OnLoaded != null)
                OnLoaded(new SSLRequestEvent(false, errMsg, null, this));

            return;
        }

        sslStream.Write(sendData);
        sslStream.Flush();

        // Read message from the server. 
        byte[] response = ReadMessage(sslStream);

        // Just fires an event, ctor(success, message, response, SSLClient)
        if (OnLoaded != null)
            OnLoaded(new SSLRequestEvent(true, "Success", response, this));

        // Close the client connection.
        client.Close();
    }

    private byte[] ReadMessage(SslStream sslStream)
    {
        MemoryStream ms = new MemoryStream();

        byte [] buffer = new byte[2048];

        int bytes = -1;
        do
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);

            ms.Write(buffer, 0, bytes);

        } while (bytes != 0);

        return ms.ToArray();
    }
}

使用的证书是我按照从 Apple 到我正在处理的测试移动应用程序的步骤操作的证书,以及似乎也需要的 4 个委托(delegate)证书。该类的用法如下:

public void DoAPNSPush()
{
    // Build the binary data to be sent
    byte[] bin = BuildAPNSMessage();

    // These certs are uploaded to the server next to this ASPX
    // and are being found and read correctly.
    string[] certs = new string[] {
        Server.MapPath("certs") + "\\MyPFX.pfx",
        Server.MapPath("certs") + "\\my_cert_from_apple.cer",
        Server.MapPath("certs") + "\\entrust_2048_ca.cer"
    };

    string[] pwds = new string[] {
        "password",
        "",
        ""
    };

    SSLClient ssl = new SSLClient("gateway.sandbox.push.apple.com", certs, pwds);
    ssl.OnLoaded += new SSLClient.OnSSLRequestHandler(onSSLLoaded);
    ssl.Load(bin, 2195);
}

public void onSSLLoaded(SSLRequestEvent e)
{
    // We never get here, but the event has the following members:
    //      bool e.Success
    //      string e.Message
    //      byte[] e.Response
    //      SSLClient e.Client
}

希望这不是 TLDR。身份验证仍然失败我可能做错了什么?我已经确保 Amazon 安全组上的端口 2195 已打开。此外,我还尝试了其他 SslProtocols.Ssl3 和 SslProtocols.Tls。 Apple 的 CSR 是从这个服务器生成并完成的,委托(delegate)证书是从他们的网站(https://www.entrust.net/downloads/root_request.cfm#)下载的,我只是在服务器上双击它们一次来安装它们。

任何输入都会有帮助

提前致谢。

最佳答案

我不确定 SSL 代码在 C# 中应该是什么样子(我用 Java 实现了它),但是你不应该用证书传递密码吗?

关于c# - 从 ASPX/C# 页面发送 APNS,使用 SSL 进行身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15117145/

相关文章:

android - 调试时生成的证书 SHA1 指纹与我正在使用的 keystore 不匹配

node.js - 如何在 Appfog 上设置 Node HTTPS

apache - 两个重定向 ssl apache

c# - 如何获得具有多个类型参数的泛型类的类型? - C#

C# 线程间通信

javascript - 如何解决在 .net 应用程序中实现 Jquery.SpellChecker 时出现的错误

c# - '/' 应用程序中的服务器错误。 <asp :ToolkitScriptManager ID ="ToolkitScriptManager1" runat ="server">

c# - 将 DbContext SaveChanges 与事务一起使用

c# - 如何从 IOwinContext 获取 HttpRequestBase

javascript - asp.net 未在复选框中显示选中和未选中状态