Strange issue happening intermittently whereby my HTTPS call to another service results in an exception being thrown (Underlying channel closed, remote certificate invalid according to callback...etc).
I'm hosting .net core (461) inside an azure app service.
My SSL certificate on the service being consumed is a public CA (GeoTrust/Digicert) certificate, and the same calls work almost all of the time, but I get periods when they routinely fail without any code change or deployments.
The strange part is, I supplied my own delegate (ServerCertificateValidationCallback) to skim the details of the certificate being returned, its chain, policy errors, etc - and when I get the error, the SSLPolicyError is set to RemoteCertificateChainErrors, yet when iterating over the ChainElements of the X509Chain, it returns a single element (my certificate) - and the ChainElementStatus is empty, with no corresponding deep-dive detail as to why the remote chain was considered invalid, it just states that it is.
I have compared this to an automated test using badssl.com as a test bed and I correctly get full chain details, including the reason as to why one of the elements was considered bad.
What possible reason could cause a RemoteCertificateChainErrors SSLPolicyError without having any corresponding chain information? Could it be a piece of networking kit has failed to call the CA itself to assess validity of the certificate?
Most strange error, appreciate any input!
We finally resolved this, by having to include the intermediate certificate alongside our ssl certificate on the service end. We still think the issue is in the failure to verify the intermediate certificate remotely in good time when not included in the bundle, but have yet to verify this.
Related
Here's the gist of my issue. I have a C# program that is calling several PowerShell cmdlets.
All the calls work, except when I get to "Connect-AzureAD -TenantId XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
But the way it "fails" is odd. It only lets me enter my Microsoft Account, but not the password. IF I RUN IT AGAIN, I can log in correctly and it works.
I thought I was hitting a timeout of some kind, but each call bellow results in a Null Reference Exception. You can see my comments of frustration.
// All of these are set to null...so what gives?
// all generate NRE's
//Debug.Print("MaxIdle Timeout is |{0}|", runspace.ConnectionInfo.MaxIdleTimeout.ToString());
//Debug.Print("Current Idle Timeout is |{0}|", runspace.ConnectionInfo.IdleTimeout.ToString());
//Debug.Print("Operation Timeout is |{0}|", runspace.ConnectionInfo.OperationTimeout.ToString());
Thoughts, ideas, comments?
I can post more of the code, if needed, but everything else works all the time.
Per a comment, I added a CR, but it appeared to do nothing (I will try a CR+LF, because I have no idea what's actually broken here, so there's no harm in trying).
So...after the PowerShell invoke call, I collect the results as follows:
foreach (PSObject outputObject in results)
and my results collection has these four errors in it:
{One or more errors occurred.: The browser based authentication dialog failed to complete. Reason: The server or proxy was not found.}
{One or more errors occurred.}
{ The browser based authentication dialog failed to complete. Reason: The server or proxy was not found.}
{One or more errors occurred.: The browser based authentication dialog failed to complete. Reason: The server or proxy was not found.}
It's telling me what I already know (that auth didn't work), but I'm still clueless as to what the actual issue is.
Adding some more detail
So...I've tried a few things. I added my Microsoft account to the connect. The result was even more odd -- a long delay, no password screen, and failure to log in.
Then I pivoted to setting up an application principal as detailed here: "Using a Service Principal to connect to a directory in PowerShell" https://learn.microsoft.com/en-us/powershell/azure/active-directory/signing-in-service-principal?view=azureadps-2.0
I got it all set up and verified in PowerShell that I can connect, then I placed the exact same (I copied and pasted it) Connect-AzureAD with the tenant, application ID, and certificate thumbprint that I used in PowerShell. It failed with these "new" errors -- still four somehow:
One or more errors occurred.
An error occurred while sending the request.
The remote name could not be resolved: 'login.microsoftonline.com'
One or more errors occurred.
Tomorrow, I'll fire up Wireshark. I'm getting the feeling that these errors are all misleading, although the fact that it works on the second try is just mind boggling.
In a UWP application, I can set something like this to enable self-signed certificates when connecting StreamSocket to an SSL-enabled host:
streamSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
streamSocket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
await streamSocket.ConnectAsync(new HostName("localhost"), "993", SocketProtectionLevel.Tls12);
However, I would like to make it possible for the application to examine which errors actually occurred during the connection. I thought I'd use this:
streamSocket.Information.ServerCertificateErrors
However, this collection is empty in my tests. It only gets populated in case when streamSocket.Control.IgnorableServerCertificateErrors is empty and thus the connection is aborted with an exception. I would like to have the connection established (i.e. SSL errors ignored) but still have these errors recorded and available for the application (like I did before with SslStream and .NET Framework). Is it possible?
In my opinion, if we add ChainValidationResult.InvalidName and ChainValidationResult.Untrusted to the StreamSocketControl.IgnorableServerCertificateErrors before we run the StreamSocket.ConnectAsync method, it will ignore the SSL server errors. That we can not get any ChainValidationResult in StreamSocketInformation.ServerCertificateErrors.
We should be able to use the StreamSocket.ConnectAsync method without adding the ChainValidationResult.InvalidName and ChainValidationResult.Untrusted.
There is an official sample about StreamSocket, please refer the Certificates in Scenario5.
We should be able to use try-catch to catch the exception of the StreamSocket.ConnectAsync method. Then we can get the ChainValidationResult in StreamSocketInformation.ServerCertificateErrors and we can add the ChainValidationResult to the StreamSocketControl.IgnorableServerCertificateErrors. Also we should be able to use the StreamSocket.ConnectAsync again.
I'm grabbing a self-signed piv auth X509certificate from a smart card inserted in a USB reader and am attaching it to the HttpWebRequest via the code below:
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(uriInfo);
Request.ClientCertificates.Add(theCert);
Request.Method = "POST";
//get the response back (the mini driver will prompt for a PIN at this point)
HttpWebResponse Response = (HttpWebResponse)Request.GetResponse();
Here is the thing that is confusing me, this code works on some machines but not on others. It's worked on Win7 on one machine and not on Win7 on another, it works in Win8. I've even tried running it in a Virtual Machine of Win8 which works, which is a guest of a Win7 host machine that doesn't work.
I've read a lot of articles on stack overflow, and tried many different things to get this to work, but nothing seems to. Since my certificate doesn't contain the private key info, that seems to be why it is not included in the request? Which is similar to this question: HttpWebRequest doesn't seem to be sending a client SSL certificate
Since it works on some machines and not others is this something I need to configure differently on the machines where it is not working?
I know the cert is not being attached because of some wireshark investigating. The certificate I'm using has been set up on the server, so it should trust it (and does in some cases).
Some things I'm doing different than other posts is I'm getting the cert from a piv smart card and simply attaching it to the request. When I call GetResponse, the microsoft minidriver steps in a prompts for a PIN to be entered. But since the certificate is not being attached to the request, I never get the prompt for the PIN and the server returns a 403 Forbidden error.
Any ideas?
(This is my first post here, so please forgive any sins which I've committed)
Ok, I finally found out what the problem was. I noticed that the when the smart card was inserted into the reader, the certificate was not propagated to the personal store. Then I found that the thing responsible for doing this was the a service called "Certificate Propagation".
I noticed that service was not running and when I tried starting it, it would stop right away giving the message,
"The Certificate Propagation service on Local Computer has started
then stopped. Some services stop automatically if they are not in use
by other services or programs."
After some digging on why this service would start but not stay running I found it was due to a Group Policy setting stashed in the registry. Changing the following registry setting from 0 to 1 fixed the issue for me:
HKLM\Software\Policies\Microsoft\Windows\Certprop\CertPropEnabled = 1
I know there are several threads about this, but I think my case might be different.
Our application needs to send requests to 2 HTTPS URL's: one of them is the ReCaptcha service, and another is some government service from Brazil (if you are from Brazil, probably you know what SEFAZ and NF-e means :D)
Sometimes, both just stops working. The exception, as the title says, is "Could not establish trust relationship for the SSL/TLS secure channel". When one of them starts throwing the exception, the other starts throwing it too, and vice versa: while one of them works, the other works too.
Everything was running just fine until some days ago when this exception started throwing randomly. This exception throws in our production server and also in our internal development server.
So, there are 2 services (ReCaptcha and this governement service) that just stops working apparently at the same time in both servers, apparently randomly. They stop working and then start working again.
The CA root is different in both cases. One uses GeoTrust Global CA and the other uses ICP-Brasil.
Based on this thread, we thought that maybe the clock is wrong, but it apparently isn't. We check it constantly.
I know about this solution:
ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
But it doesn't look very safe for me. Is there a problem using those solutions?
We could also use this:
ServicePointManager.ServerCertificateValidationCallback =
((sender, cert, chain, errors) => cert.Subject.Contains("ServerName"));
But we are really curious about why this exception throws apparently randomly. We might use it if we don't solve it in a "proper" fashion.
So, we ran out of ideas. Our service runs on Windows Server 2008R2 and IIS 7.5. What else should I look for?
ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
But it doesn't look very safe for me. Is there a problem using those solutions?
Uhm, yes! With this, you're allowing every server with any certificate to be the server you think you're speaking with.
Same goes for this:
ServicePointManager.ServerCertificateValidationCallback =
((sender, cert, chain, errors) => cert.Subject.Contains("ServerName"));
Only validating the Subject won't be enough here. You should at least apply more criteria here, e.g. GetSerialNumberString(), GetPublicKeyString() and GetCertHashString() to verify the correctness of the certificate.
But IMHO: don't do this in live environment - never ever! - only for development and testing purposes.
Regarding the main error - a part of this answer you already linked might be the cause of the issue:
When both certificates stop working at the same time, it's most likely to be an issue with the certificate chain. One part in the chain, that both certificates use might be unavailable, due to this the chain of trust is broken, and the secure channel cannot be established.
As far as I know, you should be able to override the ServerCertificateValidationCallback, log the certificate chain, and still return the basic validation afterwards. This would get you closer to the errors source.
I'm having problems creating a test X509Certificate in my store that I can use in WCF. All of the certificates I create have the same result when I try to use it in the WCF channel factory - "The private key is not present in the X.509 certificate".
channelFactory.Credentials.ClientCertificate.SetCertificate(StoreLocation.CurrentUser, StoreName.TrustedPeople, X509FindType.FindBySubjectName, "MyClientCert");
I've tried putting the certificate in LocalMachine, having it self-signed vs. a test CA. Nothing helps, the certificate always has the property HasPrivateKey equal to false.
UPDATES:
I've gotten past the above problem, by following the instructions at http://msdn.microsoft.com/en-us/library/ff650751.aspx. However, I'm onto a new problem with the certificate now generating a new error when I try to send the message to the queue. The error is:
An error occurred while sending to the queue: A cryptographic function failed. (-1072824272, 0xc00e0030).Ensure that MSMQ is installed and running. If you are sending to a local queue, ensure the queue exists with the required access mode and authorization.
Again, the process works if I use a real cert instead of a test one, so it seems like it has to be something related to the certificate.