1

Windows 2008 R2 データセンター (Amazon 上) で Apple プッシュ通知サービスを利用しようとしています - これについて多くの質問を見てきましたが、既存の回答のどれも私の問題を解決していません。これは、SSLClient というクラスにラップした TcpClient を含む SslStream を使用して書いています。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 つの委託証明書です。このクラスの使用法は次のとおりです。

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 ではありません。認証がまだ失敗するというのは、何が間違っている可能性がありますか? ポート 2195 が Amazon セキュリティ グループで開いていることを確認しました。さらに、他の SslProtocols.Ssl3 と SslProtocols.Tls も試しました。Apple の CSR はこのサーバーから生成されて完了し、entrust 証明書は Web サイト ( https://www.entrust.net/downloads/root_request.cfm# ) からダウンロードされ、サーバー上で一度ダブルクリックしてそれらをインストールします。

どんな入力でも役に立ちます

前もって感謝します。

4

2 に答える 2

0

SSLコードがC#でどのように表示されるかはわかりませんが(これはJavaで実装しました)、証明書と一緒にパスワードを渡すべきではありませんか?

于 2013-02-27T16:42:20.130 に答える
0

よし、JavaPNS でしばらく作業した後、動作するようになりました。私の問題は主に証明書に関するものでした。Apple の .p12 と .cer を新しい p12 (openSSL を使用) に変換する必要があることが判明するまで、Apple は接続を受け入れてプッシュを実行しませんでした。その後、SSLClient コードを修正し、それも機能するようにしました。

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

private string _remoteHost;
private string [] _serverCertFilenames;
private string [] _serverCertPasswords;

public event OnSSLRequestHandler OnLoaded;

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

public bool ValidateServerCertificate(
      object sender,
      X509Certificate certificate,
      X509Chain chain,
      SslPolicyErrors sslPolicyErrors)
{
    return true;
}

public void Load(byte[] sendData, int port = 443)  
{
    // Create a TCP/IP client socket. 
    TcpClient client = new TcpClient(_remoteHost, port);

    // Create an SSL stream utilizing the TcpClient
    SslStream sslStream = new SslStream(
        client.GetStream(), 
        false, 
        new RemoteCertificateValidationCallback (ValidateServerCertificate), 
        null
    );

    try 
    {
        X509Certificate2Collection xc = new X509Certificate2Collection();

        for (int i = 0; i < _serverCertFilenames.Length; i++)
        {
            X509Certificate2 x = new X509Certificate2(
                _serverCertFilenames[i],
                _serverCertPasswords[i] );

            xc.Add(x);
        }

        sslStream.AuthenticateAsClient(_remoteHost, xc, SslProtocols.Default, true);
    }
    catch (AuthenticationException e)
    {
        client.Close();
        sslStream.Close();

        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);

    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[1024];

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

        ms.Write(buffer, 0, bytes);

    } while (bytes != 0);

    return ms.ToArray();
}
}

使い方は以前と同じです。ここでの最大のトリックは、必要な openSSL コマンドでした。

openssl x509 -in "path_to_apple_cert.cer" -inform DER -out "path_to_an_output_Cert.pem" -outform PEM
openssl pkcs12 -nocerts -in "path_to_exported_p12_from_apple_cer.p12" -out "path_to_an_output_Key.pem" -passin pass:your_p12_password -passout pass:your_new_p12_password
openssl pkcs12 -export -inkey "path_to_an_output_Key.pem" -in "path_to_an_output_Cert.pem" -out "path_to_final_p12.p12" -passin pass:your_new_p12_password -passout pass:your_final_p12_password

それは厄介に見えるかもしれませんが、実際に行っていることは次のとおりです: 行 1) Apple から取得した .CER ファイルを取得し、そこから証明書 .pem を作成します。行 2) キーチェーン アクセスからエクスポートした .P12 を取得し、パスワードで保護しそこからキー .pem を作成し、最後に 3) 作成したばかりの 2 つの pem を取得し、それらから新しい p12 を作成します。これは、Apple のプッシュ通知サーバーが私から受け取った P12 です。

これがあなたの何人かを助けることを願っています-私の頭は、証明書、pfx、p12、pemなどについて1週間回転しており、現在、この機能が機能しています。

于 2013-03-06T00:35:17.377 に答える