2013-02-27 27 views
1

我一直在試圖讓一個Windows 2008 R2數據中心(亞馬遜)利用蘋果推送通知服務認證發送APNS - 我已經看到了很多的問題,一些有關這一點,但現有的答案都沒有解決我的問題。我正在使用帶有TcpClient的SslStream來編寫這個文件,我將這個文件包裝在一個名爲SSLClient的類中。我一直收到AuthenticateAsClient行上的「證書鏈由不受信任的授權機構頒發」錯誤。這裏是我的SSLClient(大部分來自使用與TcpClient的一個SslStream的MSDN例子開始):使用的一個我按照步驟從ASPX/C#頁,使用SSL

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

的證書,從蘋果到我工作的一個測試移動應用以及似乎也需要的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。另外,我嘗試了其他SslProtocols.Ssl3和SslProtocols.Tls。蘋果公司的CSR是從這臺服務器生成並完成的,代理證書從他們的網站(https://www.entrust.net/downloads/root_request.cfm#)下載,我只需在服務器上雙擊它們即可安裝它們。

任何輸入將有幫助

在此先感謝。

回答

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號線),以從蘋果得到了.CER文件,並製作一個證書從第2行開始)。將你從你的鑰匙串訪問和密碼中導出的.P12文件保存起來,並從中取得一個關鍵的.pem文件,然後最後3)取出它剛剛製作的兩個文件夾,並從它們中創建一個新的p12文件。這是蘋果推送通知服務器最終從我接受的P12。

希望這有助於一些你在那裏 - 我的頭已經在紡紗證書,PFX的,P12的,PEM的,等,等了一個星期,現在得到這個東西的工作。

0

我不知道SSL代碼應該怎麼看起來像在C#(我在Java中實現這一點),但你不應該與證書傳遞密碼?

+0

奇怪的是,它沒有接受這些作爲,是因爲他們只是.CER文件,他們沒有密碼。我沒有更新它接受密碼,並在密碼中傳遞了.pfx,它也接受。我也確定我到處都使用了X509Certificate2Collection和X509Certificate2(我原本不是),現在我得到了一個不同的錯誤:「證書鏈由不受信任的權限頒發。」我會用這個更新我的帖子,謝謝。 – sidestepper 2013-02-27 23:40:43

+0

您是否必須使用委託證書?在Java安全性中,您將TrustManager和KeyManager證書傳遞給兩個獨立的參數。 TrustManager是可選的。 KeyManager使用從Apple獲得的證書(p12文件)進行初始化。 Apple只會要求您使用它們發出的證書才能使連接正常工作。 – Eran 2013-02-28 01:55:04

+0

我嘗試了各種各樣的有和沒有證書,它從來沒有工作 - 我想稍後再回來,但我不得不現在設置它 - 並決定嘗試使用第三方。我使用JavaPNS並通過蘋果創建了一個新證書。現在總是得到握手失敗。一旦我有更多,我會回到這個希望與答案和一些其他人可以使用,如果他們想要的代碼。 – sidestepper 2013-03-04 14:37:12