How Can I Get XSockets to Work With HTTPS and WSS? - c#

My XSockets.Net code works fine when I use a "ws://" URL, but when I try to implement a secure version, I can't get it to work.
I used the following C# example code as my guide:
//Sample 1 - Certificate from store public class ChuckNorrisConfig :
ConfigurationSetting {
public MyCustomConfig1() : base(new Uri("wss://my.server.ip.address:4502"))
{
this.CertificateLocation = StoreLocation.LocalMachine;
this.CertificateSubjectDistinguishedName = "cn=localmachine";
}
}
//Sample 2 - X509Certificate2
public class MyCustomConfig2 : ConfigurationSetting {
public ChuckNorrisConfig() : base(new Uri("wss://my.server.ip.address:4502"))
{
this.Certificate = new X509Certificate2("file.name", "password");// line 369
}
}
I get the following error:
ERROR 2014/09/07-19:50:16 Could not start XSockets server.
System.Reflection.TargetInvocationException: Exception has been thrown
by the target of an invocation. --->
System.Security.Cryptography.CryptographicException: The system cannot
find the file specifed.
at
System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32
hr) at
System.Security.Cryptography.X509Certificates.X509Utils._QueryCertFileType(String
fileName) at
System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromFile(String
fileName, Object password, X509KeyStorageFlags keyStorageFlags) at
System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String
fileName, String password) at NET.Server.MyCustomConfig2..ctor() in
C:\MyProjects\NET.Server\Program.cs:line 369 --- End of
inner exception stack trace ---
It errors out on the line 369 which I've tagged with the comment.
I don't know what "file.name" is supposed to be. How do I get the "file.name" of an SSL certificate? I've been using a self-signed test certificate I made, but I don't know where to get its "file.name"
I wish there was an actual example of runnable code which I could reference, rather than having to look at generic stuff.
Does anyone have a full example of a working XSockets WSS implementation? I am using XSockets.Net version 3.0.6, thanks.

If you have the cert installed on the machine you need you use Sample1 (sounds like this is what you are looking for).
You can find the certificate in your computer using certmanager certmgr.msc and find it by name.
Sample 1 is in case you have the actual file certificate and dont want to import it.

Related

The remote certificate was rejected by the provided RemoteCertificateValidationCallback - how to get more details?

I have prepared a test case for my problem - a very simple .NET 6 Console app:
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
namespace CheckCert
{
internal class Program
{
public const string jsonUrl = "https://wordsbyfarber.com/de/top-5";
static void Main(string[] args)
{
Console.WriteLine($"jsonUrl = {jsonUrl}");
HttpClientHandler handler = new()
{
ServerCertificateCustomValidationCallback = BackendCaValidation,
CheckCertificateRevocationList = true,
};
HttpClient httpClient = new(handler);
string jsonStr = httpClient.GetStringAsync(new Uri(jsonUrl)).Result;
Console.WriteLine($"jsonStr = {jsonStr}");
}
private static bool BackendCaValidation(HttpRequestMessage message,
X509Certificate2? certificate,
X509Chain? chain,
SslPolicyErrors sslPolicyErrors)
{
Console.WriteLine($"sslPolicyErrors = {sslPolicyErrors}");
return SslPolicyErrors.None == sslPolicyErrors;
}
}
}
When I run it, it works as expected, will print SslPolicyErrors.None and the JSON content from my private website, which uses a Let's Encrypt certificate.
However when I change the jsonUrl to the URL of my work server, which I am better not sharing in public, then I end up with SslPolicyErrors.RemoteCertificateChainErrors and a System.AggregateException.
The exception says "look at the inner exception".
So inspect the inner exception and it says:
The remote certificate was rejected by the provided RemoteCertificateValidationCallback
So I keep looking at the certificate and the chain displayed by the Microsoft Edge browser - both for my private website and for the work server.
The work server uses a certificate issued by a self-signed work CA (and there is an intermediate certificate inbetween). All 3 certificates are not expired yet.
My question is: how to get more information here?
Why exactly do I get a SslPolicyErrors.RemoteCertificateChainErrors? is it because of that self-signed corporate CA or maybe because of some signing algorithm?
And also - similar code works for us in another project (an Azure Service Fabric application) without failing. I wonder, what could be the difference?
UPDATE:
I have followed the suggestion by Mr. Spiller (thank you!) and have added the code:
Console.WriteLine("-----------------------------------");
foreach (X509ChainStatus status in chain.ChainStatus)
{
Console.WriteLine($"status = {status.Status}");
}
Now my private Let's Encrypt secured URL looks like this (why is there no chain printed? I can see the chain in the web browser):
And the "faulty" corporate URL looks like this:
My main question is: how to make my app work against the corporate URL, without making it insecure?
I.e. I would probably have to accept the returned SslPolicyErrors.RemoteCertificateChainErrors in my app, but can I still perform some checks?
The parameter X509Chain? chain has a property ChainStatus which you can use to get the status for each element of the certification chain.
Each element in turn has a property Status of type System.Security.Cryptography.X509Certificates.X509ChainStatusFlags (cf. documentation) that should give you the status of each particular element of the certification chain.
In your case one (the only?) element most likely has the status UntrustedRoot.
If you want to connect to your corporate server even though the certificate is not trusted, you can simply return true from the callback. I.e. in BackendCaValidation check whether you are talking to the corporate server and return true even though sslPolicyErrors is not None.
The other (preferred?) way is to trust your corporate CA system-wide. I.e. add the CA to the cert store of your operating system and mark it as trusted.

Active Directory: MSAL (UWP) PublicClientApplication.AcquireTokenAsync(...) returns exception

I am trying to implement a sign in / login function using Active Directory. I am basing myself in on this b2c-xamarin sample.
Below is the relevant code that I am having issues with. I have made modifications here to simplify readability. I have inserted comments for anything noteworty, particularly AcquireTokenAsync:
string ClientID = "<application_id_of_b2c_application>"
string Authority = "https://login.microsoftonline.com/tfp/<b2c_tenant_name>/<signin_policy_name>/oauth2/v2.0/authorize"
PublicClientApplication PCA = new PublicClientApplication(ClientID, Authority);
// The application says to override this which I do not as I am not sure if its required for actual sign in
PCA.RedirectUri = $"msal{ClientID}://auth";
// UWP SIGN IN CODE
string Scopes = { "User.Read" };
string PolicySignUpSignIn = "<signin_policy_name>";
// Arguments #2 and #3 both return null. This happens also with the unmodified sample that works.
// I do not know what to put in for argument #1 (scopes) - I have tried numerous combinations to no avail. currently I have { "User.Read" }
AuthenticationResult ar = await PCA.AcquireTokenAsync(Scopes, GetUserByPolicy(PCA.Users, PolicySignUpSignIn), PCA.UiParent);
The excpetion I get when calling AcquireTokenAsync is the following (truncated for readability purposes - I inserted the beginning and the end)
{Microsoft.Identity.Client.MsalException: WAB authentication failed
---> System.IO.FileNotFoundException: The specified protocol is unknown. (Exception from HRESULT: 0x800C000D) at
System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task) ...(TRUNCATION)...
--- End of stack trace from previous location where exception was thrown --- at
UserDetailsClient.MainPage.d__2.MoveNext()
ErrorCode: authentication_ui_failed}
The way I see it the problem could be any of the following:
PublicClientApplication (PCA) was initialized with incorrect parameters (client id / authority)
I am using the wrong Scopes argument for AcquireTokenAsync - currently its: { "User.Read" }
I need to specify the proper redirect URI and assign it to PCA before calling AcquireTokenAsync in UWP
I am missing something on the Azure end
I have tried many combinations of arguments based on the values I have in Azure AD to no avail. I could really use some help.

Amazon Glacier KeyNotFoundException

I keep getting the following exception when trying to upload a file to Amazon Glacier using the .NET sdk:
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at Amazon.Glacier.Model.Internal.MarshallTransformations.UploadArchiveResponseUnmarshaller.UnmarshallException(JsonUnmarshallerContext context, Exception innerException, HttpStatusCode statusCode)
at Amazon.Runtime.Internal.Transform.JsonResponseUnmarshaller.UnmarshallException(UnmarshallerContext input, Exception innerException, HttpStatusCode statusCode)
at Amazon.Runtime.AmazonWebServiceClient.handleHttpWebErrorResponse(AsyncResult asyncResult, WebException we)
at Amazon.Runtime.AmazonWebServiceClient.getResponseCallback(IAsyncResult result)
at Amazon.Runtime.AmazonWebServiceClient.endOperation[T](IAsyncResult result)
at Amazon.Glacier.Transfer.Internal.SinglepartUploadCommand.Execute()
at Amazon.Glacier.Transfer.ArchiveTransferManager.Upload(String vaultName, String archiveDescription, String filepath, UploadOptions options)
at UClaim.TaskRunner.Tasks.ArchiveDocuments.Execute() in c:\Projects\uclaim\src\UClaim.TaskRunner\Tasks\ArchiveDocuments.cs:line 55
I've got no idea why it's happening or what it means, and googling is turning up nothing. The code I'm using is nothing special, but here it is for completeness.
var document = GetDocumentToArchive();
var manager = new ArchiveTransferManager(Amazon.RegionEndpoint.EUWest1);
document.ArchiveId = manager.Upload(
"archivedDocs",
string.Format("#{0}: {1}", document.Claim.Id, document.Description),
document.GeneratePathOnServer()).ArchiveId;
Ok turns out this was a stupid mistake. I thought that the SDK would create the vault if it didn't exist but I guess it was attempting to look it up and failing. I logged in to the management console and created the "archivedDocs" vault and now it runs fine

LogonUserEx, DuplicateTokenEx for Impersonation with an ObjectContext in C#

We have a particular SQL Server which we need to access from a thick (.Net 4.0 WPF) client, and the only credentials available to us for that connection is a 'service' account which is effectively an Active Directory account with permission on the SQL Server.
I am using Entity Framework, and ObjectContext, throughout the project, so am continuing with it here. After looking around, I have implemented an impersonation routine based on LogonUserEx, and DuplicateTokenEx, which allows me, via Dependency Injection, to write the following:
using (container.Resolve<Impersonate>())
using (var context = container.Resolve<MyObjectContext>())
{
context.Connection.Open();
//Do some work with the data as the service account.
context.Connection.Close();
}
The constructor of the Impersonate class above calls LogonUserEx and so on. I am explicitly opening and closing the connection as part of a Unit Of Work pattern, which shouldn't be relevant.
Now, via debugging I have found that the token is successfully retrieved for the service account and the user is 'impersonated'. However, as soon as I try to instantiate the ObjectContext I get the following error:
System.TypeInitializationException: The type initializer for 'EntityBid' threw a
n exception. ---> System.IO.FileLoadException: Could not load file or assembly '
System.Data.Entity.dll' or one of its dependencies. Either a required impersonat
ion level was not provided, or the provided impersonation level is invalid. (Exc
eption from HRESULT: 0x80070542)
at System.Runtime.InteropServices.Marshal.GetHINSTANCE(RuntimeModule m)
at System.Runtime.InteropServices.Marshal.GetHINSTANCE(Module m)
at EntityBid.initEntryPoint()
at EntityBid.internalInitialize()
at EntityBid..cctor()
--- End of inner exception stack trace ---
at EntityBid.Trace(String fmtPrintfW, String a1)
at System.Data.EntityUtil.ProviderExceptionWithMessage(String message, Except
ion inner)
at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean op
enCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection
, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnection
OnFailure)
at System.Data.EntityClient.EntityConnection.Open()
at Core.Security.TestHarness._2.Class1..ctor()
Consequently, it would appear that the account I am impersonating no longer has access or sufficient privelage to load the DLL's from the GAC. The Fusion log is not giving any additional information.
I am not sure how to solve this. I wonder if I am not currently retrieving a token with sufficient privelage. Note that I am providing these paramteres to LogonUserEx: LOGON32_LOGON_NETWORK_CLEARTEXT and LOGON32_PROVIDER_DEFAULT.
Finally, note that this process works absolutely fine on a machine with administrative privelages for the logged on user. It breaks when I run it on a user with a 'normal' account, subject to the usual corporate GPO!
EDIT: Just to include the 'important' part of the impersonation. Notice that I have now swapped to LOGON32_LOGON_UNLOCK, as it is working better. Apologies for the slightly iffy formatting:
if (LogonUserEx(dUser, dDomain, dPassword, LOGON32_LOGON_UNLOCK,
LOGON32_PROVIDER_DEFAULT, out token, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero))
{
if (DuplicateTokenEx(token, MAXIMUM_ALLOWED, ref sa, SECURITY_IMPERSONATION_LEVEL.SecurityDelegation, TOKEN_TYPE.TokenPrimary, out tokenDuplicate))
{
m_ImpersonatedUser = new WindowsIdentity(token);
_windowsImpersonationContext = m_ImpersonatedUser.Impersonate();
Any help greatly appreciated.
Nick.

Loading the Jira Public Certificate in .Net from a string (how to convert ASN.1 encoded SubjectPublicKeyInfo to X509 Cert in .Net)

I am building an oauth 1.0a service that will be consumed by a gadget within Jira, it's a .Net 3.5 Application written in C#.
Jira makes requests to this service using the RSA-SHA1 signature method, which means to verify the signature of the request I need create an X509Certificate instance form their public cert.
Within the Jira application you can get the public cert by going to the consumer info screen (which also has the consumer key for Jira etc.) and it presents the public key in this format:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCObJRTGSZbAo
jRkvKmm0cwFXnKcPMfR4t/sghvLe/+QVs6TJOz5cUh5UokSqyz
VeMsL0jomP18ZcR3SPcIFT7xtOGQjLwLk7ghfYSsxjTGs9VxsC
/PQk5OQRP3v43IxFNF3M2SYhFWJZTOnqrab5AsMh2Kxdv+D69D
CINXCu5ltQIDAQAB
Looking at the Jira code which generates this key I can see it's (supposedly) PEM encoded without the BEGIN/END certificate header/footer.
RSAKeys.toPemEncoding(consumer.getPublicKey())
RSAKeys is an open source class found here:
https://studio.atlassian.com/source/browse/OAUTH/trunk/api/src/main/java/com/atlassian/oauth/util/RSAKeys.java?r=HEAD
I wish to load this public cert (key) into an X509Certificate instance within .Net, but my attempts so far have failed. Here's the code I have:
static readonly Regex stripRegex = new Regex("-----[A-Z ]*-----");
public string ConvertFromOpenSsl(string key)
{
return stripRegex.Replace(key, "").Replace("\r", "").Replace("\n", "");
}
public X509Certificate2 GetConsumerCertificate(IConsumer consumer)
{
string cert =
#"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCObJRTGSZbAo
jRkvKmm0cwFXnKcPMfR4t/sghvLe/+QVs6TJOz5cUh5UokSqyz
VeMsL0jomP18ZcR3SPcIFT7xtOGQjLwLk7ghfYSsxjTGs9VxsC
/PQk5OQRP3v43IxFNF3M2SYhFWJZTOnqrab5AsMh2Kxdv+D69D
CINXCu5ltQIDAQAB";
string converted = ConvertFromOpenSsl(cert);
var bytes = Convert.FromBase64String(converted);
var cert = new X509Certificate2(bytes); // throws here
But on the last line of code I have an exception thrown:
System.Security.Cryptography.CryptographicException: Cannot find the requested object.
at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._QueryCertBlobType(Byte[] rawData)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[] data)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData)
I'm pretty sure I am missing something elementary, but I can think what it is.
UPDATE
OK, on further investigation it appears that this is a SubjectPublicKeyInfo serialization of the public key, so it's ASN.1, base 64 encoded (162 bytes unencoded), which is the default output from Java using java.security.PublicKey.getEncoded().
So given all that - is there any easy way to create an X509Certificate2 instance wrapping this public key - or is additional metadata required beyond the public key to create an x509Certificate2 instance?
Jira should provide you with a Certificate (not just a public key).
Typically the Java world will give a base64 encoded or PEM certificate. X509Certificate2 from .Net can automatically .Load a base64, PEM or binary certificate.
you can generate your XML RSA certificate via .NET using RSACryptoServiceProvider. This will give you XML (FromXmlString method), the public key then needs to be encoded, for example by using this service:
https://superdry.apphb.com/tools/online-rsa-key-converter
and then used to create application link to JIRA.
The private key in XML form you got previously, can be used for signing .NET app requests directly.
I personally used DonNetAuth library for signing, exchannging tokens, etc and it works for me. The only bug I encountered was regarding jql queries, where the signing needed a bit of tweaking to work correctly. Here is the link:
http://samondotnet.blogspot.sk/2012/12/introduction-to-dotnetauth.html
Additionally see this link:
https://answers.atlassian.com/questions/172760/is-there-any-jira-oauth-implementation-example-in-net
Hope this helps.

Categories