[英]Sending APNS from ASPX/C# Page, Authentication with SSL
我一直在尝试获取Windows 2008 R2数据中心(在Amazon上)以使用Apple Push Notification Service-我已经看到了很多有关此问题的问题,但是没有一个现有的答案可以解决我的问题。 我正在使用带有TcpClient的SslStream编写此代码,并将其包装在一个名为SSLClient的类中。 我在AuthenticateAsClient行上不断收到“证书链是由不受信任的颁发机构颁发的”错误。 这是我的SSLClient(其中大部分来自将SslStream与TcpClient一起使用的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 Security Group上处于打开状态。 此外,我尝试了其他SslProtocols.Ssl3和SslProtocols.Tls。 苹果的CSR是从该服务器生成并完成的,委托证书是从其网站下载的( https://www.entrust.net/downloads/root_request.cfm# ),我只需在服务器上双击它们一次即可安装它们。
任何输入都会有所帮助
提前致谢。
我不确定SSL代码在C#中的外观(我在Java中实现了该外观),但是您是否不应该通过证书传递密码?
好了,在使用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文件,并从中获得证书.pem,第2行)获取从钥匙串访问中导出的.P12并使用密码保护,然后从中制作一个关键的.pem,然后3)取下刚制作的两个Pem,并从中创建一个新的p12。 这就是苹果的推送通知服务器最终接受我的P12。
希望这对您中的某些人有所帮助-我的头一直在思考证书,pfx,p12,pem等等等,现在已经花了一周的时间使此工具正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.