问题
A web service request over SSL raises a WebException on Monotouch v4.0.4.1:
'Error getting response stream (Write: The authentication or decryption has failed)'
Since the server's SSL certificate is self-signed (and btw I think it is not X.509), I am bypassing the certificate validation using ServicePointManager.ServerCertificateValidationCallback. The exact same code works fine on Windows .NET, where the web service call returns the correct result. On Monotouch adding a Writeline shows that the ServerCertificateValidationCallback delegate code is never reached.
Note: Although probably not relevant, the content of the request is SOAP with embedded WS-Security UsernameToken.
Has anyone got something like this to work on MonoTouch? Have seen reports of similar symptom but no resolution. The code and stacktrace are below, any comment appreciated. Can email a self-contained test case if wanted.
I gather there is an alternative approach using certmgr.exe to store the self-signed server certificate in the local trust store, but can't seem to find that app in the MonoTouch distribution. Could anyone point me to it?
..
public class Application
{
static void Main (string[] args)
{
UIApplication.Main (args);
}
}
// The name AppDelegate is referenced in the MainWindow.xib file.
public partial class AppDelegate : UIApplicationDelegate
{
// This method is invoked when the application has loaded its UI and its ready to run
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
// If you have defined a view, add it here:
// window.AddSubview (navigationController.View);
string soapResponse;
string soapRequest = @" SOAP envelope is here but omitted for brevity ";
soapResponse = WebService.Invoke("myOperation", soapRequest);
window.MakeKeyAndVisible ();
return true;
}
// This method is required in iPhoneOS 3.0
public override void OnActivated (UIApplication application)
{
}
}
public class WebService
{
public static string Invoke(string operation, string soapRequest)
// Input parameters:
// operation = WS operation name
// soapRequest = SOAP XML request
// Output parameter:
// SOAP XML response
{
HttpWebResponse response;
try
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, ssl) => true;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://myserver.com:7570/MyEndpoint");
request.Method = "POST";
request.Headers.Add("SOAPAction", "/MyEndpoint/" + operation);
request.ContentType = "text/xml;charset=UTF-8";
request.UserAgent = "Smartphone";
request.ContentLength = soapRequest.Length;
request.GetRequestStream().Write(System.Text.Encoding.UTF8.GetBytes(soapRequest), 0, soapRequest.Length);
request.GetRequestStream().Close();
response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
catch (WebException e)
{
throw new WebException(e.Message);
}
}
}
Stack trace (some names changed to protect the innocent, original available on request):
WS.WebService.Invoke (operation="myOperation", soapRequest="<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" \n\txmlns:ns1=\"http://mycompany/Common/Primitives/v1\" \n\txmlns:ns2=\"http://mycompany/Common/actions/externals/Order/v1\" \n\txmlns:ns3=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n\t<SOAP-ENV:Header> <wsse:Security SOAP-ENV:mustUnderstand=\"1\" \n\txmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\"> \n\t<wsse:UsernameToken wsu:Id=\"UsernameToken-1\" \n\txmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"> \n\t<wsse:Username>myusername</wsse:Username> <wsse:Password \n\tType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">mypw</wsse:Password> \n\t<wsse:Nonce>{0}</wsse:Nonce> \n\t<wsu:Created xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">{1}</wsu:Created> \n\t</wsse:UsernameToken> </wsse:Security> \n\t</SOAP-ENV:Header><SOAP-ENV:Body><ns2:tp_getOrderDetailRequest><ns2:header><ns1:source>TEAM</ns1:source>\n\t<ns1:userAccessKey>12345678901234567</ns1:userAccessKey></ns2:header>\n\t<ns2:OrderId>myid1</ns2:OrderId>\n\t<ns2:OrderId>myid2</ns2:OrderId>\n\t</ns2:tp_getOrderDetailRequest>\n\t</SOAP-ENV:Body>\n\t</SOAP-ENV:Envelope>") in /Users/billf/Projects/WS/WS/Main.cs:103
WS.AppDelegate.FinishedLaunching (app={MonoTouch.UIKit.UIApplication}, options=(null)) in /Users/billf/Projects/WS/WS/Main.cs:52
MonoTouch.UIKit.UIApplication.Main (args={string[0]}, principalClassName=(null), delegateClassName=(null)) in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:26
MonoTouch.UIKit.UIApplication.Main (args={string[0]}) in /Developer/MonoTouch/Source/monotouch/monotouch/UIKit/UIApplication.cs:31
WS.Application.Main (args={string[0]}) in /Users/billf/Projects/WS/WS/Main.cs:18
回答1:
MonoTouch (just like Mono) does not support TLS_DH* cipher suites (like TLS_DHE_DSS_WITH_AES_128_CBC_SHA).
When a server is configured to accept only them then the negotiation stage fails very early (an Alert is received from the server after the Client Hello message is sent) which explains why the callback was never called.
Ensure your server allows the more traditional cipher suites, e.g. the very secure (but slow) TLS_RSA_WITH_AES_256_CBC_SHA or the faster (and very common) Cipher Suite: TLS_RSA_WITH_RC4_128_[MD5|SHA], and Mono[Touch] should work well using them.
Note that this is unrelated to SOAP or web-services (and even X.509 certificates) - it's just plain SSL.
回答2:
1) An untrusted root certificate is not the only problem that could result in this exception.
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, ssl) => true;
Add a Console.WriteLine in there so you'll see if it gets called (or not).
throw new WebException(e.Message);
and another here, with full stack trace (not just the Message property).
2) Each application is isolated. This means that:
applications cannot updates the global iOS certificate stores (that would create security issues);
if a certmgr tool existed (for MT) it could only use a local (mono) store that would be usable only for itself (which would not be of any help for your own apps)
来源:https://stackoverflow.com/questions/6927140/monotouch-web-service-request-over-ssl-gets-authentication-or-decryption-has-fa