Getting Access Denied when trying to protect data with DPAPI - c#

I am developing a c# .net 3.5 application on Windows 8.
I need to encrypt data using DPAPI. it works ok on all of my machine except from one machine where I get the following exception: System.Security.Cryptography.CryptographicException Message: Access is denied.
byte[] bytes;
bytes = ProtectedData.Protect(Encoding.UTF8.GetBytes(argsStr.ToString()), null, DataProtectionScope.CurrentUser);
when I change the DataProtectionScope.CurrentUser to DataProtectionScope.LocalMachine it works ok.
It seems that someone has denied the access of the current user to preform DAPI encryption
What can i do to fix this issue?
The application that fails is a console application running under the current logged in user.
When running the application using elevated privileges it still failed with access denied.
I tried to reset the login password and it solved the issue.
How can something like that happen?

This happened because the MasterKey of DPAPI was not in sync.
Typical causes are :
password changed administratively (without providing the old one and not in a domain - net user administrator password)
third party authentication package
You can manually sync the MasterKey in code using CryptProtectData(CRYPTPROTECT_CRED_SYNC)
regards,
vincent

I had the very same problem in a case when the user did not have a password defined on Windows 7. The solution was to set a password for the user.

Related

Write files to network drive from IIS using Managed Service Account

I have an ASP.NET MVC 5 app hosted in IIS 10 on Windows 2016. Our sys admins have created a Managed Service Account (MSA) that is tied to this server and has read/write permissions to a folder on the network. I need to write PDFs to that folder from the web application using the MSA.
Currently, I'm simply trying to write a simple text file to the folder:
System.IO.File.WriteAllText(#"\\SomeUncPath\Reports\test.txt", "sample text");
The above produces this error, which is to be expected,
System.UnauthorizedAccessException: Access to the path '\SomeUncPath\Reports\test.txt' is denied.
I followed this video: https://www.youtube.com/watch?v=lBv81lwZgIo to no avail. It just caused the site to generate a 503 error.
Is it possible to write the files using C# impersonation, such as described in this article? But how do you impersonate an MSA, which has a password set by the system?
I tried the following code using the SimpleImpersonation:
var cred = new UserCredentials("myDomain", "someMsa$", "");
Impersonation.RunAsUser(cred, LogonType.Batch, () =>
{
System.IO.File.WriteAllText(#"\\SomeUncPath\Reports", "sample text");
}
);
The above throws this:
System.ArgumentException: Password cannot be empty or consist solely of whitespace characters. Parameter name: password
Update 1: The server is throwing the following error into the System log:
Application pool SomePool has been disabled. Windows Process Activation Service (WAS) encountered a failure when it started a worker process to serve the application pool.
And these two warnings:
Application pool SomePool has been disabled. Windows Process Activation Service (WAS) did not create a worker process to serve the application pool because the application pool identity is invalid.
and
The identity of application pool SomePool is invalid. The user name or password that is specified for the identity may be incorrect, or the user may not have batch logon rights. If the identity is not corrected, the application pool will be disabled when the application pool receives its first request. If batch logon rights are causing the problem, the identity in the IIS configuration store must be changed after rights have been granted before Windows Process Activation Service (WAS) can retry the logon. If the identity remains invalid after the first request for the application pool is processed, the application pool will be disabled. The data field contains the error number.
I tried this and rebooted the server but the issue persists.
Update 2: If I give the app pool my credentials, the app loads without any issues. It's only on the MSA that it fails with the above error/warnings. What could be wrong with the MSA?
Update 3: The issue was how I was adding the MSA to the app pool. I needed to include my domain in the username: myDomain\someMsa$. Once I had that in, it worked like a charm!
The issue had to do with missing the domain when setting the MSA as the app pool identity. When adding it, I needed to set it as myDomain\someMsa$ instead of simply someMsa$. What's strange is how IIS didn't give an error, perhaps because the MSA account was considered both a local and domain account.
Also, in our case, we didn't need the "Log on as a batch" permission for the MSA. It worked fine without it.

Error loading Private Keys in .net core on remote machine

I have a .net core web API project to process JWT tokens which uses the Eliptic Curve ES256 (secp256r1) certificates.
The certificates are cipher encrypted into a database.
I can retrieve and verify incoming tokens however I am having an issue while trying to retrieve the private key for signing new tokens.
The function I am using is:
private static ECDsa LoadPrivateKey(string privateKey)
{
var ecDsaCng = new ECDsaCng(CngKey.Import(Convert.FromBase64String(privateKey), CngKeyBlobFormat.Pkcs8PrivateBlob));
ecDsaCng.HashAlgorithm = CngAlgorithm.ECDsaP256;
return ecDsaCng;
}
The problem I am facing is that while this works fine on my local development machine, when I deploy it to the test server it fails with the message
An internal error occurred
I enables logging and can confirm the value retrieved is same in both the remote server as well as my development machine.
How to solve this?
So I finally managed to understand what the issue is here.
When I deployed it to the test server running under IIS, it seems that the user under which the APP Pool is running was not a local administrator on the test box.
it seems that to create a private key on the machine we need the user (in this case the APP Pool) to be a local administrator
I refered to this URL while trying to debug this and it did point me in the right direction:
https://blogs.msdn.microsoft.com/dsnotes/2012/08/17/cngkey-import-throws-an-exception-saying-an-internal-error-occurred-when-importing-a-key-blob-under-a-non-admin-user-from-a-wcf-web-service/

The LDAP Server is Unavailable using PrincipalContext and ADLDS

We are making use of ADLDS for our user management and authentication. We can successfully query the instance without problems. However, trying to perform an operation such as SetPassword will fail or even trying to create a new user if a password is not set, it fails. I can successfully update a user as long as its not password I'm trying to update. I've been reading a lot of different articles relating to this but not finding a resolution. Posting to see if I can get some fresh perspective on this issue, thanks for any input.
EXAMPLE
ContextType ctxType = ContextType.ApplicationDirectory;
string server = "myadldsserver.com";
string usersCN = "CN=Users,..."; // container where users reside
ContextOptions ctxOpts = ContextOptions.SimpleBind;
string uname = "myuser";
string pswrd = "mypass";
using(var ctx = new PrincipalContext(ctxType, server, usersCN, ctxOpts, uname, pswrd)
using(var newUser = new UserPrincipal(ctx)) {
newUser.Name = "newusername";
newUser.Enabled = true;
newUser.UserPrincipalName = "newusername";
newUser.Save();
newUser.SetPassword("newuserpassword");
}
ERROR 1
The first problem I encounter if I try to create a new UserPrincipal and call Save without having set the password like in Example above I get the exception A constraint violation occurred. with an InnerException extend message of 0000052D: AtrErr: DSID-033807D7, #1:0: 0000052D: DSID-033807D7, problem 1005 (CONSTRAINT_ATT_TYPE), data 2246, Att 9005a (unicodePwd)
Because of this error I tried moving the SetPassword before calling Save along with other approaches I found online such as getting the DirectoryEntry from the UserPrincipal and trying to call SetPassword but got a different error.
ERROR 2
Calling SetPassword before calling UserPrincipal.Save, when save is called, results in the error The directory property cannot be found in the cache.
Note that the same error will occur if I trying calling ResetPassword or getting a DirectoryEntry and calling Invoke("SetPassword"... as well
ERROR 3
From my research most seem to indicate this could have to do with needing to access AD LDS using a Secure connection. So, I changed my server to include the port of 636 string server = "myadldsserver.com:636" and I changed the ContextOptions to be ContextOptions.SimpleBind | ContextOptions.SecureSocketLayer.
Making these changes when the PrincipalContext is being constructed I get the following exception The server could not be contacted. with an inner exception of The LDAP server is unavailable., HResult is -2146233087
JAVA and LDP
To add some background to this, we do have similar code written in an older Java application. We are trying to port some of this logic over to .NET side in C#. The code in Java makes use of a Java keystore that contains the certificate that was generated on the AD LDS server. The Java application of course has no issues using the SSL port. We know the server seems to be configured correctly, it's just an issue of how to access it from .NET side.
Is there an equivalent on the .NET side such as the keystore in Java? We know that an SSL connection can be made to server. We have verified this using LDP as well.
GOALS
Be able to create a new user and set their password during creation
Be able to ResetPassword or ChangePassword for a user
Connect to our AD LDS instance from .NET securely
Have you tried using Microsoft Management Console to import the certificate?
Two ways to install the certificate
Either
Open a cmd.exe console and type "MMC"
File > Add/Remove Snap-In...
Select Certificates, click Add
Choose Computer Account and Local Computer when prompted, then OK...
Certificates should now be showing under Console Root
Certificates > Trusted Root Certification Authorities > Certificates > (right-click) > All Tasks > Import Certificate...
Find the certificate you want to import, click Next and choose defaults (Trusted Root Certification Authorities should already be
selected)
Click Next, Finish
(or)
Simply double-click on the .cer file for the certificate in Windows
Explorer, click Install Certificate... > Next > select the option to
"Place all certificates in following store" > Browse... > Select
Trusted Root Certification Authorities. Continue with next until done.
At this point your certificate is installed, and you should be able to communicate securely with your ADLDS server.

Help with SAML error: "Keyset does not exist"

We have two environments that should be identical but one of them raises an error when we try to generate a SAML message signature. I haven't looked at SAML before and I am not exactly sure what it tries to do
Part of the code:
X509Certificate2 x509Certificate = (X509Certificate2)Application[ASP.global_asax.IdPX509Certificate];
try
{
SAMLMessageSignature.Generate(samlResponse, x509Certificate.PrivateKey, x509Certificate);
}
catch (Exception ex)
{
app = File.AppendText(#"C:\SAML.txt");
app.WriteLine(ex.Message.ToString());
app.Flush();
app.Close();
}
The exception message is
Keyset does not exist
Does anyone have any idea of what I should be looking at?
Thanks in advance.
Hi please check the following on your setup.
Set the correct access control entries, ACLs, to the certificate you installed.
Add Modify access role for NETWORK SERVICE to the certificate.
If you are using Windows 2008 and Windows 7, you can access the private key from the certificate
snap-in in the MMC.
If it still did not work, add Modify access role also for IIS_IUSRS.
Hope it will help you.
Thank you!
Check to see if the certificate stored in the HttpApplicationState object's key ASP.global_asax.IdPX509Certificate was loaded successfully. If the certificate is being loaded from a PFX file, ensure that it is present on the disk and accessible by the account your web app is running under. If the certificate is being loaded from a certificate store, ensure that it is installed in the correct store and that the account your web app is running under can access the certificate.
You can use winhttpcertcfg.exe to install certificates into system keystores and manage certificate ACLs. The KB article http://support.microsoft.com/kb/901183 contains some additional info.

Why does X509Certificate2 sometimes fail to create from a blob?

I have an ASP.NET web service which is receiving a byte array representing the contents of a .pfx file containing an X.509 certificate. The server-side code is using the System.Security.Cryptography.X509Certificate2 constructor to load the certificate from the bytes:
X509Certificate2 native_cert = new X509Certificate2(
pkcs12_buf /*byte array*/,
password,
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.Exportable
);
Depending on who my service process is running as, this call will either succeed, or fail with an "internal error" exception. The last call on the exception stack is to X509Utils._LoadCertFromBlob, which is unmanaged code in mscore.dll.
This code succeeds when run from a console application in an interactive login using the service account's credentials. It fails when running under w3wp.exe in an application pool that uses the service account's credentials. Changing the app pool identity to an administrator fixes the problem, so it must be a privilege issue, but I have no idea what privilege could be necessary for this. The code does not touch either the filesystem or the Windows certificate stores.
[UPDATE: More Info]
This error appears in the Windows Event Log:
*Cryptographic Parameters:*
**Provider Name:** Microsoft Software Key Storage Provider
**Algorithm Name:** Not Available.
**Key Name:** {E182E13B-166D-472A-A24A-CBEF0808E9ED}
**Key Type:** User key.
*Cryptographic Operation:*
**Operation:** Open Key.
**Return Code:** 0x2
Any ideas?
I just found the solution to this one myself:
X509KeyStorageFlags flags = X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet;
X509Certificate2 cert = new X509Certificate2(pkcs12_buf, password, flags);
The trick here is to use the local key store MachineKeySet flag instead of the user profile key store, which is the default if you don't specify an alternative location. Because the ASP.NET process identity doesn't load the user profile store, you can't access the store when importing a certificate programmatically, but you can access the machine store.
I think PersistKeySet just keeps the private key loaded, but I'm not sure exactly what it does - it's required if you need to access the private key for some reason though.
Try granting the ASP.NET account permissions to the following folder: C:\Documents And Settings\All Users\Microsoft\Crypto\RSA\MachineKeys\ (may vary according to your environment)

Categories

Resources