Validate endpoint with .p12 - c#

I have an endpoint that I need to hit and validate.
I have a generated .p12 file and a chain of certificates (Root and Intermediate) that I can use to validate.
Here is the code I currently am using which gives me this error:
System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
var handler = new HttpClientHandler();
var p12 = new X509Certificate2(
Path.Combine(Environment.CurrentDirectory, "Assets/Certs/p12filename.p12"),
"TheRealPassword");
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(p12);
handler.ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, chain, sslPolicyErrors) =>
{
var root = new X509Certificate2(
Path.Combine(Environment.CurrentDirectory, "Assets/Certs/Root.cer"));
X509Chain CertificateChain = chain;
CertificateChain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
return CertificateChain.Build( root );
};
var client = new HttpClient(handler);
var url = "https://urlHere"
var request = new HttpRequestMessage()
{
RequestUri = new Uri(url),
Method = HttpMethod.Get,
};
var response = await client.SendAsync(request);
I'm not super well versed in using certs so it is perhaps something quite elementary. Of note if inside the ServerCertificateCustomValidationCallback I return true I have no issues.
Update:
To clarify, how can I validate the end point I am hitting using my .p12 and the corresponding root and intermediate certificates. My assumption based on returning true in the call back giving me what I want is that I need to do these checks here.

Related

Get access token back from Onelogin using Authorization Code Flow with PKCe in step 2

I'm Trying to get the access token form OneLogin using the Authorization Code with PKCE. I'm able to go through step1 for PKCe and getting the authorization code back from OneLogin. But when i try to get the token using the authorization code sent by one login i keep getting 400 bad request error. I'm not sure what is wrong. I followed the info provided by oneLogin website to all required parameters in the request for Step 2. below the code i'm using. I will appreciate if some one can help on this
public async Task GetAccessToken(string redirecturl, string authCode) { HttpClientHandler clientHandler = new HttpClientHandler(); clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
var client = new HttpClient(clientHandler);
var body = JsonConvert.SerializeObject(new
{
grant_type = "authorization_code",
code = authCode, //The code returned from OneLogin in step 1
client_id="XXXXXXXXXXXXXXXXXX386d707215718",
redirect_uri=redirecturl,//The redirect URL registered in onelogin account
code_verifier=GetCacheEntry(CodeKey)// The code verifier used in step one
});
var req = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://MySubdomain.onelogin.com/oidc/2/token"),
Content = new StringContent(body)
};
req.Content.Headers.ContentType= new MediaTypeHeaderValue(#"application/x-www-form-urlencoded");
var response = await client.SendAsync(req);
if (response.StatusCode == HttpStatusCode.OK)
{
var responseBody =await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<OAuthTokenResponse>(responseBody);
memoryCache.Remove(CodeKey);
return Ok(json);
}
return BadRequest(response);
}

Could not create SSL/TLS secure channel when using client certificate from local machine

I am calling an API that requires a client certificate. With the client certificate installed into the Personal store of Current User, the API call is successful. But when the client certificate is installed into the Personal store of Local Machine, the call fails with:
The request was aborted: Could not create SSL/TLS secure channel.
Here is the setup code:
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { return true; };
const StoreName storeName = StoreName.My;
const X509FindType findType = X509FindType.FindByThumbprint;
const string findValue = "9ce5b57fe576b9a0933b426347e74e5583da59dd";
var certCurrentUser = GetCertificate(storeName, StoreLocation.CurrentUser, findType, findValue);
var certLocalMachine = GetCertificate(storeName, StoreLocation.LocalMachine, findType, findValue);
Both calls to GetCertificate() succeed and the certificates appear to be identical. (They were installed from the same .pfx)
When this call is made with certCurrentUser, it succeeds:
WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(certCurrentUser);
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("https://preprod.xconnectcollection.ce.corp.com/odata");
}
But when the call is made using certLocalMachine, it fails:
WebRequestHandler handler = new WebRequestHandler();
handler.ClientCertificates.Add(certLocalMachine);
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("https://preprod.xconnectcollection.ce.corp.com/odata");
}
Error:
The request was aborted: Could not create SSL/TLS secure channel.
What could be causing the request to fail when using the client certificate from local machine?
Ensure that the account running the application has full permissions to the certificate's private key.

Client send cert but GetClientCertificate always receives as null

Web api always receive GetClientCertificate as null. Its using with IISExpress and no need to host certificate on IISExpress or IIS. Certificate exists on certificate Store on server. Just want to validate manually like, client send cert file and web api code validate cert manually by looking into cert store on server (no iis validation).
went through couple of post on same issue but it needs to host cert on IIS/IISExpress.
Tried:
client send the certificate as below, And expected to receive on server side.
client send certificate:
var handler = new HttpClientHandler();
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certifcates = store.Certificates.Find(X509FindType.FindByThumbprint, "07a49ef049795a07be786512359be34d234e4548", false);
var cert = certifcates[0];
handler.ClientCertificates.Add(cert);
var client = new HttpClient(handler);
var s ="xml content to post";
var data = new StringContent(s, Encoding.UTF8, "application/xml");
var result = client.PostAsync("http://localhost:51567/api/PostContent", data).GetAwaiter().GetResult();
web api expecting to receive client cert on GetClientCertificate as below but, its always getting null.
web api:
var cert = httpActionContext.Request.GetClientCertificate();
if (cert == null)
...
else
..

Bypass certificate using .Net HttpClient

I'm trying to post a REST message to a website that has a certificate problem. Until our IT guy can resolve it, I need to bypass this when executing the
PostAsync call.
For some reason the ServerCertificateCustomValidationCallback is no longer part of the HttpClientHandler. Is there a another approach to resolve
this to avoid the permissions error? Thanks.
Here's a sample of what I'm doing.
string json = JsonConvert.SerializeObject(new
{
Message = new
{
TestID = "1",
}
});
var spHandler = new HttpClientHandler()
{
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
return true;
}
};
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient(spHandler,true);
client.BaseAddress = new System.Uri("https://test.com");
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage msg = client.PostAsync(#"/Test", content).Result;
Edited: (Fix '/' delimiter issue)
From
client.BaseAddress = new System.Uri("https://test.com");
HttpResponseMessage msg = client.PostAsync(#"/Test", content).Result;
To
client.BaseAddress = new System.Uri("https://test.com/");
HttpResponseMessage msg = client.PostAsync("Test", content).Result;
I actually found the problem and edited the question above. Turns out you cant use a leading '/' on the uri PostAsync query. This was causing the problem. The handler was actually fine.
I was successfully bypassed certificate validation by the following steps:
Get the certificate
X509Certificate2 clientCert = GetClientCertificate();
Create request handler and pass the certificate
WebRequestHandler requestHandler = new WebRequestHandler();
requestHandler.ClientCertificates.Add(clientCert);
Call the handler
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate { return true; };
Create HttpClient object passing the handler and call the service.
HttpClient client = new HttpClient(requestHandler)
I hope this is useful for you.

get ssl certificate in .net

i am looking to get the data from any given domain names SSL certificate. For example I want to put in any website address e.g. "http://stackoverflow.com" and my code would firstly check if an SSL certificate exists. If it does then I want it to pull out the expiry date of the certificate. [ i am reading Domainnames from DB ]
Example :http://www.digicert.com/help/
i need to create a web service to check expiry date. how can i implement it?? - I have looked up loads of different things such as RequestCertificateValidationCallback and ClientCertificates etc.
I could be completely wrong (hence why I need help) but would I create a HTTPWebRequest and then somehow request the client certificate and specific elements that way?
i tried the example provided #SSL certificate pre-fetch .NET , but i am getting forbitten 403 error.
For this to work your project will need a reference to System.Security:
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
//Do webrequest to get info on secure site
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://mail.google.com");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
//retrieve the ssl cert and assign it to an X509Certificate object
X509Certificate cert = request.ServicePoint.Certificate;
//convert the X509Certificate to an X509Certificate2 object by passing it into the constructor
X509Certificate2 cert2 = new X509Certificate2(cert);
string cn = cert2.GetIssuerName();
string cedate = cert2.GetExpirationDateString();
string cpub = cert2.GetPublicKeyString();
//display the cert dialog box
X509Certificate2UI.DisplayCertificate(cert2);
.NET Core 2.1 - .NET 5
You can use HttpClientHandler and ServerCertificateCustomValidationCallback Property. (This class is available in .net 4.7.1 and above also).
var handler = new HttpClientHandler
{
UseDefaultCredentials = true,
ServerCertificateCustomValidationCallback = (sender, cert, chain, error) =>
{
/// Access cert object.
return true;
}
};
using (HttpClient client = new HttpClient(handler))
{
using (HttpResponseMessage response = await client.GetAsync("https://mail.google.com"))
{
using (HttpContent content = response.Content)
{
}
}
}
#cdev's solution didn't work for me on .NET Core 2.1. It seems HttpWebRequest is not completely supported on .NET Core.
Here is the function I'm using on .NET Core to get any server's X509 certificate:
// using System;
// using System.Net.Http;
// using System.Security.Cryptography.X509Certificates;
// using System.Threading.Tasks;
static async Task<X509Certificate2> GetServerCertificateAsync(string url)
{
X509Certificate2 certificate = null;
var httpClientHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (_, cert, __, ___) =>
{
certificate = new X509Certificate2(cert.GetRawCertData());
return true;
}
};
var httpClient = new HttpClient(httpClientHandler);
await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));
return certificate ?? throw new NullReferenceException();
}
One thing to note is that you might need to set request.AllowAutoRedirect = False. Otherwise, if the server redirects HTTPS to HTTP, you won't be able to get the certificate from the HttpWebRequest object.
Recreating the HttpClient each time you want to make a request is very ineffective and may cause performance issues. Better to create a single readonly client for all the methods. More informations can be found here.
private readonly HttpClientHandler _handler;
private readonly HttpClient _client;
And this is my solution to getting certificate info:
Code inside constructor:
_handler = new HttpClientHandler {
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
sender.Properties.Add("Valid", sslPolicyErrors == System.Net.Security.SslPolicyErrors.None);
sender.Properties.Add("Errors", sslPolicyErrors);
return true;
}
};
_client = new HttpClient(_handler);
Then you can read all the variables by:
using var request = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com/");
var response = await _client.SendAsync(request);
var isCertificateValid = (bool)request.Properties["Valid"];

Categories