Adding .pfx certificate to HttpWebRequest fails from Web application - c#

I have created a Asp.net web application-C#, where I need to send a HttpWebRequest with a .pfx certificate.
I have installed the certificate to the personal certificates folder(added rights for user NETWORK SERVICE) and able to see it in the X509Certificate2Collection and no issues while adding the certificate to the HttpWebRequest.
But it throws cannot connect to server error while fetching the response (HttpWebResponse)req.GetResponse()
I am facing this issue only from web application, the same code works fine(got the correct response) when i tried using a C# console application.
X509Store oLocalMachineStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
X509Certificate2Collection oCertColl;
X509Certificate oCert = new X509Certificate();
oLocalMachineStore.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadOnly);
oCertColl = oLocalMachineStore.Certificates.Find(System.Security.Cryptography.X509Certificates.X509FindType.FindByIssuerName, "mycertificate issuer", false);
oLocalMachineStore.Close();
foreach (X509Certificate oCertFromStore in oCertColl)
{
if (oCertFromStore.Issuer.Contains("mycertificate issuer"))
{
oCert = oCertFromStore;
oCert.Import(#"certlocation\mycertificate.pfx", "pwd", X509KeyStorageFlags.MachineKeySet);
break;
}
}
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("destination URL");
req.ClientCertificates.Add(oCert);
req.UserAgent = "LOL API Client";
req.Accept = "application/json";
req.Method = WebRequestMethods.Http.Get;
string result = null;
using (HttpWebResponse resp = (HttpWebResponse)req.GetResponse())
{
StreamReader reader = new StreamReader(resp.GetResponseStream());
result = reader.ReadToEnd();
}

The issue got resolved after adding proxy to the http request.
req.Proxy = New Net.WebProxy("ProxyURL", False);
But still i have no idea, how it worked when i tried with the same code from a console application with out adding proxy.
If anyone has any idea on this please share.

Related

Cannot use client certificate from certificate store, only by loading from file

I am using WebRequest to connect to a webpage that uses https.
If I try to use a client certificate that is in the personal store in LocalMachine by using
var myStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
myStore.Open(OpenFlags.ReadOnly);
var clientCertificates = myStore.Certificates.Find(X509FindType.FindBySubjectName, "foobar",
validOnly: false);
and then I create a connection with
var req = (HttpWebRequest)WebRequest.Create("https://theserver.com/the/url");
req.Method = "POST";
req.ContentType = "application/json";
req.ProtocolVersion = HttpVersion.Version11;
req.ClientCertificates = clientCertificates;
req.ServerCertificateValidationCallback += (o, certificate, chain, errors) =>
{
return true;
};
using (var stream = req.GetRequestStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
}
var response = req.GetResponse();
I fail on the req.GetResponse line with
System.Net.WebException: 'The request was aborted: Could not create
SSL/TLS secure channel.'
But if I instead load the client certificate from file, (the same file that I had previously installed in the store) with
var certificatePath = #"C:\temp\file.p12";
var clientCertificate = new X509Certificate2(certificatePath, "pwd",
X509KeyStorageFlags.Exportable);
and
req.ClientCertificates.Add(clientCertificate);
I will be able to run the https query successfully.
This requires both that I keep a file in the file system and that I put a password in the source code.
How do I use the store instead of the file system?
Why do I have to use validOnly: false to get the client certificates?
edit
The preferrable way of getting access to those certificates (client and server certificate) would be to have them in web.config as endpoints, but I have not succeeded doing that.
To solve the symptoms of the problem/many problems, I had to add the user Everyone to the ACL of the private key of the certificate.
Instead of changing the ACL of the private key, I found that the ClientCertificates property worked perfectly well if I only gave it public keys. Yes, the authentication won't work if you don't have the private key in the store, but converting to a public-key-only certificate appears to work for me every time.
var publicKeyOnly = new X509Certificate2(authenticationCert.Export((X509ContentType.Cert));

How to invoke a Web Service which requires a certificate in C#?

I need to communicate with a third party which has a .asmx web service. This web service is using https. I have the required certificate (.pfx).
When first trying to add this service using Add Service Reference in Visual Studio, I got an error. I got passed this error by importing the certificate into the Personal store. After I did that, I tried to add the Service Reference again and it works. So now I can create an instance of the web service. Nice.
But now I want to invoke the service. And when I do that I get this error:
302 Notification: Digital Certificate Missing
So how can I tell my service to use the right certificate?
I finally managed to fix my problem as follows:
var service = new Service1SoapClient();
service.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.TrustedPublisher, X509FindType.FindByIssuerName, "name_of_issuer");
((BasicHttpBinding)service.Endpoint.Binding).Security.Mode = BasicHttpSecurityMode.Transport;
((BasicHttpBinding)service.Endpoint.Binding).Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
Please use Certificate.pfx and install it with password.
Try adding this before getting the request stream:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
request.ProtocolVersion = HttpVersion.Version10;
request.ClientCertificates.Add(new X509Certificate2("YourPfxFile(full path).pfx", "password for your pfx file");
Depending on your security requirements and environment, you may need to use a different SecurityProrocolType value.
I was also facing "The request was aborted: Could not create SSL/TLS secure channel" while requesting a web service.
Fixed issue with below code, hope this will help someone and save time.
HttpWebRequest web_request = (HttpWebRequest)WebRequest.Create("https://yourservices/test.asmx");
web_request.ContentType = "text/xml;charset=\"utf-8\"";
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
web_request.ProtocolVersion = HttpVersion.Version10;
X509Certificate2Collection certificates = new X509Certificate2Collection();
certificates.Import(certName, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
web_request.ClientCertificates = certificates;
web_request.Accept = "text/xml";
web_request.Method = "POST";
using (Stream stm = web_request.GetRequestStream())
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(soap);
}
}
WebResponse web_response = null;
StreamReader reader = null;
try
{
web_response = web_request.GetResponse();
Stream responseStream = web_response.GetResponseStream();
XmlDocument xml = new XmlDocument();
reader = new StreamReader(responseStream);
xml.LoadXml(reader.ReadToEnd());
}
catch (Exception webExp) {
string exMessage = webExp.Message;
}

ASP.NET C# page with SSL and Mutual Auth from smartcard

I would like create a login page for user with smartcard authentication and redirect to third party service. I have verified in java and it's work (but dont'know how).
My Https Page have to read certificate with Request.ClientCertificate
after i need to create a webrequest (a Soap Envelope) to 3th party services.
When i execute this code on IIS Express locally , all works (private key of certificate is present)
when i publish on remote IIS this code don't work , the message i receive is
"Authorization Required" (private key of certificate is not present)
This the code is use:
public HttpWebRequest CreateWebRequest(string url)
{
Uri uri = new Uri(url);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
System.Net.ServicePointManager.ServerCertificateValidationCallback += mIgnoreBadCertificates;
webRequest.Proxy = null;
webRequest.Headers.Add("SOAP:Action");
webRequest.KeepAlive = true;
webRequest.ProtocolVersion = HttpVersion.Version10;
webRequest.Headers.Add("X-WASP-User", DataOnCertifcate);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
webRequest.AuthenticationLevel = AuthenticationLevel.MutualAuthRequired;
if (Request.ClientCertificate != null)
{
webRequest.ClientCertificates.Clear();
webRequest.ClientCertificates.Add(Request.ClientCertificate);
}
return webRequest;
}
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
HttpWebRequest request = CreateWebRequest(Url);
using (Stream stream = request.GetRequestStream())
{
envelope.Save(stream);
}
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
IAsyncResult asyncResult = request.BeginGetResponse(null, null);
asyncResult.AsyncWaitHandle.WaitOne();
string soapResult = "";
using (WebResponse webResponse = request.EndGetResponse(asyncResult))
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
1) on IIS there is SSL enabled
2) When i access to my https page , browser show me a list of certificate.
3) I choice the certificate present into smartcard, and i insert the Pin corretly
4) my https test page , show me the correct certificate and public key information, but no private key information (on remote Server, meanwhile on local server all works)
5) i Get this error
401 Authorization Required Authorization Required This server could not verify that you are authorized to access the document requested. Either you supplied the wrong credentials (e.g., bad password), or your browser doesn't understand how to supply the credentials required. Apache/2.2.3 (Red Hat) Server at server name Port 443
How can i fix this problem?

SSL HttpWebRequest Issues

I am attempting to access an api which they had me install a local cert via mmc I have done so on my local windows 7 machine so I could test out the service. I'm using a simple winforms app to test. I'm assuming this is a self signed cert server side so I'm hoping to bypass the exception for dev purposes.
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(postData);
req.Method = "POST";
req.ContentType = "application/x-www-form-uriencoded";
req.KeepAlive = true;
req.AllowAutoRedirect = false;
X509Store store = new X509Store(StoreName.Root,StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate cert = new X509Certificate();
for (int i = 0; i < store.Certificates.Count; i++)
{
if (store.Certificates[i].SerialNumber == "XXXX")
{
cert = store.Certificates[i];
}
}
req.ClientCertificates.Add(cert);
req.PreAuthenticate = true;
try
{
using (WebResponse resp = req.GetResponse())
{
Stream responseStream = resp.GetResponseStream();
using (StreamReader responseStreamReader = new
StreamReader(responseStream, new ASCIIEncoding()))
{
respString = responseStreamReader.ReadToEnd();
}
}
}
catch (Exception ex)
{
// there is a problem
}
I'm getting the following exception in the try catch:
The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.
I do have a certificate object in the variable "cert"
When I go to the api url in my browser I get the caution warning but then can proceed and get data.
I have tried the other fixes recommended on stackoverflow such as suppressing the exception.
ServicePointManager.ServerCertificateValidationCallback = new
RemoteCertificateValidationCallback
(
delegate { return true; }
);
I realize there are quite a few of these questions similar to this and trust me I have read through them all. Thanks for any suggestions they are appreciated.
Hey the following finally fixed it for me. I went to the api server address in my browser and exported their certificate to a file on my desktop. I then opened mmc and installed the certificate like in the following link:
http://support.esri.com/en/knowledgebase/techarticles/detail/38408
After I installed I had no issues calling the webservice and the exception went away.

Accessing ssl server (web service) from .net client

I’m tryng to access a ssl server (web service) from a .net client (c#). I have access to a java client code that can connect to the server. Included in the source code are 3 files (saPubKey.jks, WebServices.pfx and trustStore) and I think that only 2 of the 3 are used in the java example.
private void setSSLConnection(WSBindingProvider bp){
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(this.getClass().getClassLoader().getResourceAsStream("WebServices.pfx"), "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "password".toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyStore ts = KeyStore.getInstance("JKS");
ts.load(this.getClass().getClassLoader().getResourceAsStream("trustStore"), "pass".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ts);
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
bp.getRequestContext().put(JAXWSProperties.SSL_SOCKET_FACTORY, sslContext.getSocketFactory());
}
The code I have for the c# client is this
var clientCertificate = new X509Certificate2(#"C:\WebServices.pfx", "password");
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://blablabla.org:700/fws/ftrs");
req.ClientCertificates.Add(clientCertificate);
req.Headers.Add("SOAPAction", "\"https://blablabla.org:700/fws/ftrs/Rgdvice\"");
req.ContentType = "text/xml;charset=\"utf-8\"";
req.Accept = "text/xml";
req.Method = "POST";
using (Stream stm = req.GetRequestStream())
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(soap);
}
}
WebResponse response = req.GetResponse(); //(500) Internal Server Error.
Stream responseStream = response.GetResponseStream();
Method req.GetResponse() throws "(500) Internal Server Error."
With no client certificates added I get: "An unexpected error occurred on a send."
I also tried this line of code with no luck:
ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
I'm new to ssl and certificates, and really need help accessing the ssl server from c#.
This could be unrelated but make sure web service is not in the app_code folder.

Categories

Resources