I have been searching for quite a while now but i am unable to find the answer to the following. I am storing a key pair in Windows Store, and recently started receiving the "Keyset does not exist" error. Investigating a bit further i found out it could be two things, 1 - The private key is not stored with the persist key set attribute (X509KeyStorageFlags.PersistKeySet) and 2 - access rights to the key. I have tried both 1 and 2 with no success on one machine (in my machine it works apparently). The strange thing is that when i look into Microsoft\Crypto\RSA\MachineKeys (and S-1-5-18) the key remains there but only for a period of time then it is deleted which means that it is not persisting.
//If decoded then save as RSACryptoServiceProvider
newCert.PrivateKey = DecodePrivateKey(privateKeyFile, pkPassword)
if (newCert.PrivateKey == null)
throw new System.NullReferenceException("Decoded private key resulted in a null reference. Unable to store certificate.");
byte[] pfx = newCert.Export(X509ContentType.Pfx);
newCert = new X509Certificate2(pfx, string.Empty, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
I am running this code on a WCF Service hosted on IIS, and the certificate is deleted even if i give permissions to Network Service, the AppPoolIdentity, my account, etc through MMC-CertMgr. Would anyone know why this happens?
Thanks in advance!
UPDATE:
I have just found out today that since i am doing this through a WCF service, the application pool is deleting the private key when it reaches its idle time limit so i am completely sure that it is the application pool the one disposing of the private key which causes the key to be deleted from the Microsoft\Crypto\RSA\MachineKeys and S-1-5-18 folders. Today i left a test running where i disabled Idle time shut down from the application pool bu i am still not sure if the private key will stop persisting with a restart or something like that?
Would anybody know how to make the application pool stop deleting my private keys?
I'm not sure for this particular case, but at work we have had problems using the RSACryptoServiceProvider in a Web Application context as well.
What fixed the problem for us was that we set "Load User Profile" on the corresponding ApplicationPool to "true". In our case we actually got PermissionDenied errors though, so not sure it will work for you.
Probably not the best answer, but if anyone needs to know the way i worked around this back then was to set the AppPoolIdentity to an Administrator account and set the "Idle Time-out (minutes)" value in IIS to 0. Only this way the AppPool will not delete the certificate files.
Related
I'm new to using DPAPI so this is something I've messed up on my app because I've been redeploying between my work laptop and my personal desktop so now the key that DPAPI is using to protect my data has changed between environments.
Now I'm getting the error that the key isn't in the key ring.
I hit this answer where a link provided discusses configuring key storage so I've updated my code to persist keys to file system (while I wait for sysadmin to get back so he can set up blob storage on azure as an alternative) and this should work fine for dev anyway.
var path = this.Environment.ContentRootPath + "/Data/Keys/";
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(path));
I can see the key files being created, but the error persists because I don't have the key that the app is looking for.
So how can I get it to generate/use/look for a new key here?
Oddly enough, it seems like completely reinitializing the app's database solved the problem.
My guess is it has something to do with the encrypted values that I stored in there (the DPAPI IDataProtector.Protect() output values). Specifically the fact that those values were encrypted with what I assume to be the key that the app was reporting couldn't be found.
Having reinitialized the database with new data, everything now works as expected.
Right now i am using an web application with code to read from and write to the registry. While debugging in Visual studio everything went fine but on the online test server it didn't run. the error exception message i am getting is:
System.Security.SecurityException: Requested registry access is not
allowed.
This is the code i am using:
private RegistryKey GetWritableBaseRegistryKey(string extendedPath)
{
var path = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
return RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Default).OpenSubKey($"{path}\\{extendedPath}", true);
}
The sollutions i found where:
Solution 1
you will not be able to set AppPoolIdentity to a specific group, but
you can
create a local user (compmgmt.msc)
add the user to the administrator group (compmgmt.msc)
Set the application pool to run under that user, under Advanced Settings.
Obviously you know this is a very bad idea from a security
perspective, and should never ever ever be performed on a forward
facing server.
source
Solution 2
Create a separate console application to run the service in admin
modus so you could access the registry. This solution was performance
heavy because you need to run 2 separate applications.
Solution 3
Use this code to allow access to the registry.
RegistryPermission perm1 = new RegistryPermission(RegistryPermissionAccess.AllAccess, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall");
perm1.Demand();
Or this code
RegistrySecurity rs = new RegistrySecurity();
string currentUserStr = Environment.UserDomainName + "\\" + Environment.UserName;
RegistryAccessRule accessRule = new RegistryAccessRule(currentUserStr, RegistryRights.WriteKey | RegistryRights.ReadKey | RegistryRights.Delete | RegistryRights.FullControl, AccessControlType.Allow);
rs.AddAccessRule(accessRule);
But these didn't work on the server however while debugging in visual studio the code ran fine.
In order for the web application to access the registry it must have sufficient permission. Consequently Solution 1 is the only one likely to work. It describes setting the web sites application pool to a user in the local administrators group. Its misses the steps about actually setting your IIS web site to use the newly created App Pool, which is why it might not work for you.
The technical process of reading a restricted registry, especially the application Uninstall registry key, inside a web server is really unlikely to be useful to you. Of what possible use is allowing a web server to access the servers own Application uninstall list going to be ?
I suspect you intend to open that registry key on the client's PC (my speculation) which is not going to be possible.
I had some problems with using the authorization before so I got a brand new everything - new computer, new OS, fresh installation of VS, new app and DB in a new resource group on the Azure. The whole shabang.
I can confirm that I can log in to the Azure DB as the screenshots below show.
I can see the databases, tables, users etc.
The problem is that, although it works locally (using the default connection string provided automagically for me), it doesn't perform very well in the Azure (although I'm using the publish file from there). It said something about the file not being found and according to this answer, I needed to change the connection string.
After I've altered it, I get the following error. Please note that the firewall is open and that I can access the DB when I run the code of my applications. I feel that there's something that goes wrong when the authentication part is automatically configured. I'm out of ideas on how to trouble-shoot it, though.
[SqlException (0x80131904): Login failed for user 'Chamster'.
This session has been assigned a tracing ID of '09121235-87f3-4a92-a371-50bc475306ca'. Provide this tracing ID to customer support when you need assistance.]
The connection string I'm using is this.
Server=tcp:f8goq0bvq7.database.windows.net,1433;
Database=Squicker;
User ID=Chamster#f8goq0bvq7;
Password=Abc123();
Encrypt=True;
TrustServerCertificate=False;
Connection Timeout=10;
This issue's bothered me for a while and I'll be bounting it in two days. Any suggestion's warmly appreciated.
I believe I've managed to resolve this weird issue. It appears that the user I'm using, despite being admin with all bells and whistles isn't recognized as admin when used in the connection string and trying to create the tables (which is the case at the first registration).
My solution was to create two logins - one with db_owner role and one with db_datareader and db_datawriter. First, I've used the elevated user in my connection string and registered a single user. That created the tables in the database as shown below.
Then, while able to continue as admin, I realized that we should try the demoted user and tada!, it worked perfectly. Once the tables were there, the whole shabeling behaved as expected.
To be perfectly sure, I dropped the tables from the database and there it was - the same issues as before. When I changed to the elevated user, the tables were restored allowing me to get back to the demoted one.
I also tried dropping the tables, confirming the issues to re-appear and then creating the tables manually. That works too! So basically,the only gotcha that caused it all was the original admin who's not treated as admin.
It might have to do with the fact that my Azure account's getting a bit old, LiveID used there is ancient and that didn't have an updated version of DB in Azure (the pull-up to v12 was carried out the 18th of December, so it's possible that it also was a requirement to get it working). I'm too tired and lazy to check that out and I realize that I've no idea how to get an "old" type of account. Besides, the issue will decrease and gradually vanish because the old accounts get upgraded eventually.
I am trying to write some c# code that writes a new Performance Counter Category if it doesn't exist, and then adds a specific counter. When I run this code from the Visual Studio dev server, everything works fine. When I deploy it to IIS and try it, I get permission errors. I am running Windows 7 and using IIS 7.5.
What I have done so far, some of which is being done out of desperation:
Created a new App Pool that I will run as a specific user
Created a new user and added him to the Process Monitor and Administrator groups
Set the new user as the identity of the new App Pool
Pointed my web service to that App Pool.
Went in to regedit and gave the user full control over HKLM/System/CurrentControlSet (apparently there should be a permissions folder, but I don't see it anywhere).
I know these steps have worked partially, because I am now able to check whether or not a category exists (ASPNET user couldn't even do that). I can check if a category exists, I just cant add a new one.
The error that I get is
Cannot create or delete the Performance Category 'C:\Windows\TEMP\tmp1AA8.tmp' because access is denied.
The code to add the performance counter category is looks like this:
if (!PerformanceCounterCategory.Exists("APIService"))
{
CounterCreationDataCollection counters = new CounterCreationDataCollection();
CounterCreationData counter = new CounterCreationData();
counter.CounterName = "# of operations executed";
counter.CounterHelp = "Operations executed";
counter.CounterType = PerformanceCounterType.RateOfCountsPerSecond32;
counters.Add(counter);
PerformanceCounterCategory.Create("APIService", "Api Counter", PerformanceCounterCategoryType.SingleInstance, counters); // This code blows up
}
I have searched high and low and cant find anyone with the same problem. I have even tried giving Everyone Full Control over c:\windows\temp. Any idea what I might be missing here?
I think I figured out the solution (or rather someone else did, but I can find a link to that forum this morning). Instead of setting the App Pool to run as an admin, I switched it to the Local System user. That seems to have resolved everything, as the user has sufficient rights to write performance metrics and everything else that needs to be done.
I know (and it works) that in C#, this property tells me if the current session is a RDP one:
System.Windows.Forms.SystemInformation.TerminalServerSession
Now, I have a service that receives logon/logoff and lock/unlock events, and I need a way to tell this service if the session being started is rdp or local.
Problem: the service runs as SYSTEM user, and the property above always returns false (I think because SYSTEM is always considered a local connected user)
I've tried to search in the register for the Volatile Environment subkey to check if there is the subkey that identify the RDP Session Name: this works in lock/unlock handler, but in the logon handler the subkey doesn't exists yet (subkey is created after login completes).
Any idea about how to work around this problem?
While a wait for the key creation for a limited amount of time works, I would like a less "kludgy" way to do it.
You can detect whether a session is a local or remote session by calling WTSQuerySessionInformation with the WTSInfoClass parameter set to WTSClientProtocolType. If you'd prefer to avoid the P/Invokes, you can use the Cassia library: new TerminalServicesManager().GetLocalServer().GetSession(sessionId).ClientProtocolType.
Caveats: This won't help you when processing session logoff messages because you will not (reliably) be able to fetch information about the session, since it's in the process of being destroyed (but that seems relatively easy to work around). Also, the ClientProtocolType Cassia property mentioned above has not yet been released, but you can grab a trunk build from the build server by logging in as a guest and using the artifacts link.