X509AsymmetricSecurityKey.GetAsymmetricAlgorithm returns null after .Net 4.7.2 upgrade - x509certificate

I have a problem with X509AsymmetricSecurityKey.GetAsymmetricAlgorithm running in a standard unit test. The test has been passing for years running on .Net Framework version 4.5.2 (C#), however since upgrading the project to version 4.7.2 it has ben failing as GetAsymmetricAlgorithm returns null. The exact same code runs perfect outside the test.
X509Certificate2 cert = null;
var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
// I'm actually using FindByThumbprint, just changing this here to protect keys
cert = store.Certificates[0];
// cert is valid X509, securityKey is valid
X509AsymmetricSecurityKey securityKey = new X509AsymmetricSecurityKey(cert);
// rsa is null
RSACryptoServiceProvider rsa = securityKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, true) as RSACryptoServiceProvider;
Same code, same certificate, running though test GetAsymmetricAlgorithm returns null, running on "live" code (class library called from WebAPI) it works perfect.
Any ideas why? I can't see anything in the docs for previous .Net version changes, nothing in the Microsoft docs.
https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.x509asymmetricsecuritykey.getasymmetricalgorithm?view=netframework-4.7.2
Thanks for any help on this.

As Crypt32 suggested in a comment, the problem is that after you upgraded from targeting <= 4.6.2 to targeting 4.7(+) you got a "retargeting change" which says that GetAsymmetricAlgorithm is allowed to return instances of RSACng, which is the better RSA class in .NET Framework.
The best action in your code is to change the line to
RSA rsa = securityKey.GetAsymmetricAlgorithm(SecurityAlgorithms.RsaSha256Signature, true) as RSA;
Then find the places that the code no longer compiles, and change from the RSACryptoServiceProvider variant method to the new RSA (base class) methods. (e.g. SignData(byte[], object) => SignData(byte[], RSASignaturePadding)).
You really want to avoid saying RSACng or RSACryptoServiceProvider if you can help it, since there are theoretical cases where RSACng won't work, and RSACryptoServiceProvider will be returned instead (older smartcards / HSMs which have a CAPI driver, but not a CNG driver).
This particular retargeting change is the System.IdentityModel version of https://learn.microsoft.com/en-us/dotnet/framework/migration-guide/retargeting/4.5-4.7.2#wcf-transport-security-supports-certificates-stored-using-cng, which seems to have not been written down. If you need to turn this off, the setting name is Switch.System.IdentityModel.DisableCngCertificates.

Related

Data Protection using Entity Framework Core

So I have followed microsoft's official guide (https://learn.microsoft.com/el-gr/aspnet/core/security/data-protection/implementation/key-storage-providers?view=aspnetcore-2.2&tabs=visual-studio) for encrypting data and storing them in database using Entity Framework Core, but I can't make it work accross multiple machines. So I used Entity Framework Core implementation because in the guide says "With this package, keys can be shared across multiple instances of a web app.". The app works perfectly when using it from the deployed version for example xyz.com, but It doesn't let me interfere from localhost. Will it be a problem afterwards when my virtual machine is maxed out and I want to add another one? If so how can I make it work in both the deployed site and different machines? There is no tutorial which implements that, I have searched everywhere. Thank you very much.
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256,
}
).PersistKeysToDbContext<DataContext>();
Update 12-6-2019
So I followed microsoft's documentation (https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/implementation/key-encryption-at-rest?view=aspnetcore-2.2)
and it states:
"If the app is spread across multiple machines, it may be convenient to distribute a shared X.509 certificate across the machines and configure the hosted apps to use the certificate for encryption of keys at rest"
I generated a x.509 certificate using this tutorial:
(https://www.youtube.com/watch?v=1xtBkukWiek)
My updated code:
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256,
}
)
// )
.ProtectKeysWithCertificate(new X509Certificate2("wibit-test-cert.pfx", "password"))
.PersistKeysToDbContext<DataContext>();
When testing on my local machine it works fine, but when I deploy it, I get this error:
error: "The system cannot find the file specified"
I have tried several ways to fix it including _hostingEnvironment.ContentRootPath or WebRootPath. Both these ways and the one I use in the updated code work in my machine but not in the deployed app.
Any clues?
I finally fixed it!
The problem was that I didn't set the application name:
.SetApplicationName("myapp")
And I changed the path of the certificate to this:
.ProtectKeysWithCertificate(new X509Certificate2(Path.Combine(_hostingEnvironment.ContentRootPath,"wibit-test-cert.pfx"), "password"))
Also it may be a permission problem, because when I hosted the app in A2Hosting it could't find the file specified(wibit-test-cert.pfx), but when I deployed in GCP Cloud it worked!
Now I can encrypt and decrypt data using the same database with different apps.
So my final code is this:
services.AddDataProtection()
.UseCryptographicAlgorithms(
new AuthenticatedEncryptorConfiguration()
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256,
}
)
.SetApplicationName("myapp")
.ProtectKeysWithCertificate(new X509Certificate2(Path.Combine(_hostingEnvironment.ContentRootPath,"wibit-test-cert.pfx"), "password"))
.PersistKeysToDbContext<DataContext>();

BouncyCastle updated pgp key now getting checksum mismatch error

I have a utility that is using the BouncyCastle.Crypto dll (version 1.7.4, runtime version 1.1.4), in order to decrypt a file that is given to it by another system.
I just updated the pgp key (and provided the encryptor with the new public key). The new key uses 4096 bit RSA encryption and has a 24 character password, which are the only differences I can think of between the new key and the old key. The old key used I believe 2048 bit encryption with a 7 character password.
When I attempt to decrypt a file the process is now failing when calling the PgpSecretKey.ExtractPrivateKey(char[] passPhrase) function, provided by BouncyCastle. The error is "Checksum mismatch at 0 of 20."
The weird part is that the first time I tested it worked fine, then with no changes it began failing. I have tried with multiple encrypted files.
Since it's such an old version of BouncyCastle and this particular permutation of the ExtractPrivateKey function is no longer in use I am finding it difficult to locate relevant information. Any thoughts are appreciated.
I got that error once "Checksum mismatch at 0 of 20." . My issue was due to a wrong pass phrase. Hope this should help someone.

OData error: "A value without a type name was found and no expected type is available." when calling Azure Active Directory Graph API

Let's see if you experts have a clue of what's going on here.
Context
We have a web application running on Azure Web Sites. This WebApp uses OWIN + OpenID Connect to authenticate users against an Azure Active Directory tenant. Also the application uses the Azure AD Graph API to collect some data of the directory.
We based our code on this sample project provided in GitHub: https://github.com/AzureADSamples/WebApp-GraphAPI-DotNet
Issue
The WebApp was working perfectly some hours ago (authenticating to the AD and fetching data from the directory), but then the weirdest thing happened to us. Today we found that we could still authenticate against the AD but the Graph API was throwing errors almost randomly.
We traced the error down to a specific request, when trying to get a specific user by ObjectId in a synchronous way:
Claim claimObject = ClaimsPrincipal.Current.FindFirst(Helper.Constants.ADTenant.ObjectIdClaimType);
string userObjectID = claimObject == null ? string.Empty : claimObject.Value;
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
List<IUser> users = client.Users.Where(u => u.ObjectId == userObjectID).ExecuteAsync()
.Result.CurrentPage.ToList();
The thing is the last line throws an exception regarding the OData model:
"A value without a type name was found and no expected type is available. When the model is specified, each value in the payload must have a type which can be either specified in the payload, explicitly by the caller or implicitly inferred from the parent value."
We started slicing the last line of code into pieces as follows:
IReadOnlyQueryableSet<IUser> queryUsers = client.Users.Where(u => u.ObjectId == userObjectID);
IPagedCollection<IUser> pagedUserCollection = queryUsers.ExecuteAsync().Result;
List<IUser> users = pagedUserCollection.CurrentPage.ToList();
And found the exception was throwing in this line:
IPagedCollection<IUser> pagedUserCollection = queryUsers.ExecuteAsync().Result;
Weirdest thing is that this line was executing fine yesterday and today started failing without explanation.
Does anyone know what are we doing wrong? Why did it start failing today?
Remarks
We are using api-version=2013-11-8. We kept the Azure AD Graph API Client Library on version 1.0, as in the sample on GitHub.
Folks,
First of all - many apologies for introducing this problem. The underlying problem is that an entity (User entity in this case) was updated on the service side, with a new collection (AlternativeSignInNamesInfo). Typically adding new entities, properties, collections and complex types should not cause a breaking change for the client library. However due to an issue in ODatalib, unknown collections are not simply ignored.
I totally agree with the sentiment on this, and we absolutely do NOT want to have apps that take a dependency on the Graph Client Library be subject to ANY outages. We are working with the ODatalib team to get this issue rectified, so that this is no longer a problem with our Graph client library moving forward.
In the meantime we are in the process of rolling back our Graph service, so that 2.0.5 should start to work again. Version 2.0.6 should also work - as long as you don't try and post to the new collection on the User object (AlternativeSignInNamesInfo).
UPDATE: The Graph service has been rolled back. I’ve also verified that getting a user through Graph Client Library 2.0.5 AND 2.0.6 both work.
Hope this helps and again sorry for any issues caused here.
I had the same problem just now! I have an application which have been working for a couple of weeks and hasn't been changed. I've got it working by upgrading "Microsoft.Azure.ActiveDirectory.GraphClient" from version 2.0.5 to 2.0.6
Yes upgrading the graph client Nuget package to the latest 2.0.6 fixed this problem. I had a similar panic this morning too. It's an unbelievable fact that Microsoft rolled out a new version of the dll which breaks applications run on previous version!
My team had similar experience. After installing 2.06 our code started working again. Took the entire day with first discovering, fixing, and then testing the solution.

COM Exception for client-side object called by Classic ASP page

I have tricky problem, which I'm struggling quite a bit with.
The current solution, consists of a Classic ASP site hosted on some Win2K3 server, that calls some Client-side DLL's on XP machines coded in VB6.
These client-side DLL's then again can call some other COM objects, in this particular case it calls IBM Louts Notes (Lotus Domino Objects 1.2).
Now for different reasons these DLL's has to be converted to .NET (still x86), at this stage, this is the only change to be done. This works quite well except for one piece of code which throws an error.
COMException when calling the Lotus Notes COM object
ASP script calling the DLL
Set objLotus = CreateObject("OpenLotusNotes_FU_v2.clsMain")
sRet = objLotus.OpenLotus_mail()
Client-side DLL
Dim session As NotesSession = New NotesSession() 'works well
Dim objNotesWrkSp As Object
objNotesWrkSp = Activator.CreateInstance(Type.GetTypeFromProgID("Notes.NotesUIWorkspace")) 'crashes
Exception
Retrieving the COM class factory for component with CLSID {29131502-2EED-1069-BF5D-
00DD011186B7} failed due to the following error: 80080005
Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).
When I try to run this code in console application on the same computer, it works. So it has to be some permissions(?), I have tried changing basically everything I can think of.
Any help would be much appreciated!
Updated 01.09.2014
What I see is when I trigger the code from ASP, is that it creates a new process of Notes everytime, but only in the background, no UI what so ever. When I trigger the code from a console application, I get the Notes UI, which asks me for password, if I don't already have notes running.
I believe that I'm getting the Exception because it eventually times out.
Have a read of this article , your dealing with an Out Of Process COM component which may not initialize properly for some reason.
Another possibility is that the COM threading model is not supported in a free threaded component which .NET is by default compiled with. You can compile you DLL with a STA attribute, but as far am I'm aware that only effects console applications. You might find some additional information in this article from MS, if you have not already read it of course. Hope something there helps you solve your problem.
Consult with your admins first, but for this scenario you can set no password for the ID the Lotus Notes uses.
I did resolve this, so if anyone else would run in to this…
First of all configure the “Notes Link” Component Service to run as a “The interactive user” and that the process owner has permissions in "Launch and Activation Permissions" and "Access permissions".
Then this should be possible
Dim objNotesWrkSp As Object
Dim objWorkspace As Type = Type.GetTypeFromProgID("Notes.NotesUIWorkspace")
objNotesWrkSp = Activator.CreateInstance(objWorkspace)
As it turned out in this particular case I could only get it to work with late-binding, when I tried to this it just opened a conhost.exe process and then never responed:
Dim session as New NotesSession
session.Initialize()
Among other similar issues... So then I only used late-binding for all communication with Notes.
Dim mailServerPath, mailFile As String
objWorkspace.InvokeMember("OpenDatabase", Reflection.BindingFlags.InvokeMethod, Nothing, objNotesWrkSp, New Object() {mailServerPath, mailFile})
And so on...

.netCART Credit Card Decryption - IIS 7 App Pool and Decryption issue

I've got a site using .netCART. It's running fine in production with Windows Server 2003 and .NET 2.0. On the new server (Windows Server 2008) everything is working except for credit card decryption in the store admin. No errors are being sent, no exceptions thrown, just the encrypted string being output to the screen instead of a decrypted credit card number.
Dim strCCEncrypt As String
strCCEncrypt = Trim(DataRow.Item("CreditCard"))
strCCEncrypt = tools.Decrypt(strCCEncrypt) 'tools is a .netCART utility
Has anyone had experience with .netCART, or seen this issue before?
EDIT:
After much investigating yesterday, it seems as though the problem is tied to the App Pool (which is running in classic pipeline mode on .NET 2.0), and Decryption. Can anyone tell me what the processes or services are that are tied to the default app pool which help handle decryption?
Don't know where your specific problem is, but that code snippet is equivalent to this:
Dim CCEncrypt As String = tools.Decrypt(DataRow("CreditCard").ToString().Trim())
To explain the changes:
You can skip the .Item part because it's an indexer for DataRow
But you should call .ToString(), in case of other types or DbNulls
Then use the string type's .Trim() method rather than the VB Trim() function. Trim() and other old string functions exist solely for backwards compatibility. You're better off becoming accustom to the methods attached to the string type.
In .Net, it's no big deal to declare a variable and assign to it on the same line
And in .Net, Microsoft's style guidelines specifically recommend against any hungarian-notation type warts on variable names.
The end result of this problem was that I used Reflector to get the method out, provide the key manually to perform the decryption, since the decrypt method shown above just provided a call to a method that took the key.
Check the machinekey element in your web.config. Is it possible the credit cards were encrypted with a different key than you are trying to decrypt them with?

Resources