Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2010/01/13/how-to-change-ownership-and-give-full-permissions-to-a-user-on-a-folder-vbscript/
Post name: How to change ownership and give full permissions to a user on a folder (VBScript)
Original author: Alejandro Campos Magencio
Posting date: 2010-01-13T02:21:00+00:00


Hi all,


Some time ago we faced an issue where a customer renamed users in their domain, but their profile folders didn't get renamed.So they wanted to automate the following process which worked for them when doing it manually: take ownership of a user's profile folder with an administrator, give full permissions to that admin on the folder, rename it, and give full permissions back to that user.


The following VBScript sample shows how to give ownership to a user on a folder, how to give full permissions to a user on a folder, and how to rename the folder. For that it will use WMIto manipulate the Security Descriptor of the folder:

'=======================================================================
' PARAMETERS
'-----------------------------------------------------------------------
'
' Documents and settings path
strDocsSetsPath = "C:\Documents and Settings\"

' Original user name
strOriginalUserName = "OriginalNameOfUser"

' Original user domain
strOriginalDomainName = "DomainOfUser"

' Target user name
strTargetUserName = "NewNameOfUser"

'=======================================================================
' CONSTANTS
'-----------------------------------------------------------------------
'
' Rights granted or denied to a trustee.
'
const FILE_READ_DATA = &H000001
const FILE_LIST_DIRECTORY = &H000001
const FILE_WRITE_DATA = &H000002
const FILE_ADD_FILE = &H000002
const FILE_APPEND_DATA = &H000004
const FILE_ADD_SUBDIRECTORY = &H000004
const FILE_READ_EA = &H000008
const FILE_WRITE_EA = &H000010
const FILE_EXECUTE = &H000020
const FILE_TRAVERSE = &H000020
const FILE_DELETE_CHILD = &H000040
const FILE_READ_ATTRIBUTES = &H000080
const FILE_WRITE_ATTRIBUTES = &H000100
const DELETE = &H010000
const READ_CONTROL = &H020000
const WRITE_DAC = &H040000
const WRITE_OWNER = &H080000
const SYNCHRONIZE = &H100000

' Win32_ACE.AccessMask (the following values are the sum of several
' values in the "Rights granted or denied to a trustee" list).
'
const ACCESS_MASK_FULL = &H1F01FF
const ACCESS_MASK_CHANGE = &H1301BF
const ACCESS_MASK_READ = &H1200A9

' Inheritance of the ACE.
'
const OBJECT_INHERIT_ACE = &H1
const CONTAINER_INHERIT_ACE = &H2

' Win32_ACE.AceFlags (the following values are the sum of several
' values in the "Inheritance of the ACE" list).
'
const ACE_FLAGS_INHERIT = &H3

' Win32_ACE.AceType.
'
const ACE_TYPE_ALLOW = &H0
const ACE_TYPE_DENY = &H1

' Win32_SecurityDescriptor.ControlFlags.
'
const SE_DACL_PRESENT = &H4
const SE_DACL_AUTO_INHERITED = &H400

'=======================================================================
' MAIN
'-----------------------------------------------------------------------
'

wscript.Echo _
"----------------------------------------------------------------------"

' Get computer info
'
Set objNet = CreateObject("WScript.NetWork")

strComputerName = objNet.ComputerName
wscript.Echo "Machine : '" & strComputerName & "'."
wscript.Echo

' Get info from admin user and machine running the script
'
wscript.Echo _
"----------------------------------------------------------------------"
wscript.Echo "INFO OF THE ADMIN USER RUNNING THE SCRIPT"
wscript.Echo _
"----------------------------------------------------------------------"
strAdminName = objNet.UserName
strAdminDomain = objNet.UserDomain
strAdmin = strAdminDomain & "\" & strAdminName
wscript.Echo "Admin user name : '" & strAdmin & "'"
wscript.Echo

Set objNet = Nothing

' Show parameters info
'
wscript.Echo _
"----------------------------------------------------------------------"
wscript.Echo "PARAMETERS PASSED TO THE SCRIPT"
wscript.Echo _
"----------------------------------------------------------------------"
strOriginalUser = strOriginalDomainName & "\" & strOriginalUserName
wscript.Echo "Original user name: '" & strOriginalUser & "'"
strTargetUser = strOriginalDomainName & "\" & strTargetUserName
wscript.Echo "Target user name : '" & strOriginalDomainName & "\" & strTargetUserName & "'"
strOriginalPath = strDocsSetsPath & strOriginalUserName
wscript.Echo "Original path : '" & strOriginalPath & "'"
strTargetPath = strDocsSetsPath & strTargetUserName
wscript.Echo "Target path : '" & strTargetPath & "'"
wscript.Echo

wscript.Echo _
"----------------------------------------------------------------------"

' Connect to target machine.
'
wscript.Echo "Connecting to WMI..."

set objWMIService = GetObject( _
"winmgmts:{impersonationLevel=impersonate}!\\" _
& strComputerName & "\root\cimv2")

wscript.Echo "Connected!"
wscript.Echo

' Give Full Control to the folder and its contents to the ADMIN. Make
' her the owner, too.

wscript.Echo "Accessing security settings for '" & strOriginalPath & "'..."
set objRootSecSetting = objWMIService.Get( _
"Win32_LogicalFileSecuritySetting.path='" & strOriginalPath & "'")

wscript.Echo "Creating Full Trust ACE for '" & strAdmin & "'..."
set objAce = objWMIService.Get("Win32_Ace").SpawnInstance_()
objAce.AccessMask = ACCESS_MASK_FULL
objAce.AceFlags = ACE_FLAGS_INHERIT
objAce.AceType = ACE_TYPE_ALLOW
set objAdminTrustee = GetTrustee(strAdminDomain, strAdminName)
objAce.Trustee = objAdminTrustee

wscript.Echo "Creating new SD..."
set objSecurityDescriptor = objWMIService.Get( _
"Win32_SecurityDescriptor").SpawnInstance_()

wscript.Echo "Adding ACE to SD.DACL..."
objSecurityDescriptor.DACL = Array(objAce)
objSecurityDescriptor.ControlFlags = SE_DACL_PRESENT

wscript.Echo "Setting '" & strAdmin & "' as SD.Owner..."
objSecurityDescriptor.Owner = objAdminTrustee

wscript.Echo "Setting SD for '" & strOriginalPath & "'..."
RetVal = objRootSecSetting.SetSecurityDescriptor(objSecurityDescriptor)
wscript.Echo CStr(RetVal)

Set objAdminTrustee = Nothing
Set objAce = Nothing
set objSecurityDescriptor = Nothing
set objRootSecSetting = Nothing

wscript.Echo
wscript.Echo "'" & strAdmin & "' has FULL TRUST access now"
wscript.Echo "'" & strAdmin & "' is the OWNER now"
wscript.Echo

wscript.Echo _
"----------------------------------------------------------------------"

' Rename the folder.
'
wscript.Echo "Renaming '" & strOriginalPath & "' to '" & strTargetPath & "'..."
Set objFSO = CreateObject("Scripting.FileSystemObject")
objFSO.MoveFolder strOriginalPath, strTargetPath
wscript.Echo "Folder renamed!"
wscript.Echo

Set objFSO = Nothing

wscript.Echo _
"----------------------------------------------------------------------"

' Give Full Control to the folder and its contents to the USER. Make her
' the owner, too.

wscript.Echo "Accessing security settings for '" & strTargetPath & "'..."
set objRootSecSetting = objWMIService.Get( _
"Win32_LogicalFileSecuritySetting.path='" & strTargetPath & "'")

wscript.Echo "Creating Full Trust ACE for '" & strTargetUser & "'..."
set objAce = objWMIService.Get("Win32_Ace").SpawnInstance_()
objAce.AccessMask = ACCESS_MASK_FULL
objAce.AceFlags = ACE_FLAGS_INHERIT
objAce.AceType = ACE_TYPE_ALLOW
set objTargetUserTrustee = GetTrustee(strOriginalDomainName, strTargetUserName)
objAce.Trustee = objTargetUserTrustee

wscript.Echo "Creating new SD..."
set objSecurityDescriptor = objWMIService.Get( _
"Win32_SecurityDescriptor").SpawnInstance_()

wscript.Echo "Adding ACE to SD.DACL..."
objSecurityDescriptor.DACL = Array(objAce)
objSecurityDescriptor.ControlFlags = SE_DACL_PRESENT

wscript.Echo "Setting '" & strTargetUser & "' as SD.Owner..."
objSecurityDescriptor.Owner = objTargetUserTrustee

wscript.Echo "Setting SD for '" & strTargetPath & "'..."
RetVal = objRootSecSetting.SetSecurityDescriptor(objSecurityDescriptor)
wscript.Echo CStr(RetVal)

set objTargetUserTrustee = Nothing
Set objAce = Nothing
set objSecurityDescriptor = Nothing
set objRootSecSetting = Nothing

wscript.Echo
wscript.Echo "'" & strTargetUser & "' has FULL TRUST access now"
wscript.Echo "'" & strTargetUser & "' is the OWNER now"
wscript.Echo

wscript.Echo _
"----------------------------------------------------------------------"

' We are done!
'
set objWMIService = Nothing
wscript.Echo "Done!"

'=======================================================================
' HELPER FUNCTIONS
'-----------------------------------------------------------------------

' Get trustee for "domain\name" account
'
function GetTrustee(strDomain, strName)

' Get account
'
set objAccount = objWMIService.Get( _
"Win32_Account.Name='" & strName & _
"',Domain='" & strDomain & "'")

' Get account's SID
'
Set objAccountSID = objWMIService.Get( _
"Win32_SID.SID='" & objAccount.SID &"'")

' Get account's trustee
'
set objTrustee = objWMIService.Get( _
"Win32_Trustee").SpawnInstance_()
objTrustee.Domain = strDomain
objTrustee.Name = strName
objTrustee.SID = objAccountSID.BinaryRepresentation

' Return trustee
'
set GetTrustee = objTrustee

end function



I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2010/01/13/do-cng-certificates-work-on-windows-xp/
Post name: Do CNG certificates work on Windows XP?
Original author: Alejandro Campos Magencio
Posting date: 2010-01-13T00:48:00+00:00


Hi all,

I posted some time ago about some issues that .NET2.0/3.0/3.5 had with CNG certificates: "Invalid provider type specified" error when accessing X509Certificate2.PrivateKey on CNG certificates. This issue happenedto us on Windows Vista/Server 2008 and later. But the weird thing is that if we tried the very same .NET code with the very same certificate on i.e.Windows XP, it worked. Why?

If we analyze the certificate with “certutil -dump mytestcert.pfx”, we can see something like this on i.e. Windows 2008:

"
Key Container = {...}
Unique container name: ...
Provider = Microsoft Software Key Storage Provider

"

Microsoft Software Key Storage Provider is a CNG KSP, and not a legacy CSP (Cryptographic Service Provider).

CNG Key Storage Providers
"
Unlike Cryptography API (CryptoAPI), Cryptography API: Next Generation (CNG) separates cryptographic providers from key storage providers (KSPs). KSPs can be used to create, delete, export, import, open and store keys. Depending on implementation, they can also be used for asymmetric encryption, secret agreement, and signing. Microsoft installs the following KSPs beginning with Windows Vista and Windows Server 2008.
"

As we saw, .NET doesn’t know how to work with CNG KSPs yet.

Now, XP doesn’t know about CNG stuff. If we use certutil on the same pfx file on XP, we can see this:
"
Key Container = {...}
Provider = Microsoft Strong Cryptographic Provider
ProviderType = 1
Flags = 0
KeySpec = 1

"

So a CNG certificate will be associated to a legacy CSP (Microsoft Strong Cryptographic Provider in this case) on systems like XPwhere CNG is not supported.As.NET will work without problems with a certificate associated to a legacy CSP, that explains why our code works on XP.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2010/01/11/winhttpcertcfg-tool-cannot-access-private-key-of-a-certificate/
Post name: WinHttpCertCfg tool cannot access private key of a certificate
Original author: Alejandro Campos Magencio
Posting date: 2010-01-11T03:34:00+00:00


Hi all,


Ifaced thefollowing issue some time ago: a customer of mine got a certificate ina .p12 file (PKCS#12 format), and he tried to access its private key with a .NET code like the following:

X509Certificate2 clientCert = new X509Certificate2(certPath, certPassword, X509KeyStorageFlags.MachineKeySet);
... = clientCert.PrivateKey

This code worked fine on Vista or Windows 7, but failed to access the private keyon Windows XP. So he tried to load the certificate into the certificate store and set permissions on the private key with WinHttpCertCfg.exe. But this action failed with the following error:


Access was not successfully obtained for the private key. This can only done by the user who installed the certificate.


They tried to install the cetificate and run WinHttpCertCfg.exe with an administrator user, and they got the same error. The same actions on Vista or Win7 worked just fine.



So we verified the original .p12 file with Win7’s certutil.exe tool, and we could see the following error:

C:\>certutil -verify customer.p12
402.203.0: 0x80070057 (WIN32: 87): ..CertCli Version
LoadCert(Cert) returned ASN1 bad tag value met. 0x8009310b (ASN: 267)
CertUtil: -verify command FAILED: 0x8009310b (ASN: 267)
CertUtil: ASN1 bad tag value met.
301.3128.0: 0x8009310b (ASN: 267)


It turned out that the ASN1 encoding of the file was incorrect, and Windows XP didn't know how to extract the private key from the file. Still, Vista and Win7 were both able to extract the info properly. I tried the following workaround then: import the certificate on Win7, export the certificate to a new .p12 file, and use the new file on XP. It worked! I verified the new .p12 file with certutil.exe, and I could see that doing the import-export operation fixed the encoding of the file.


Customer applied a similar workaround, but using openssl tool instead: convert the .p12 file to .pem ("openssl pkcs12 -in file.p12 -out file.pem"), and back to .p12 ("openssl pkcs12 -in file.pem -export -out new_file.p12"). That fixed ASN1 enconding, too.


I hope this helps.


Regards



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/22/invalid-provider-type-specified-error-when-accessing-x509certificate2-privatekey-on-cng-certificates/
Post name: "Invalid provider type specified" error when accessing X509Certificate2.PrivateKey on CNG certificates
Original author: Alejandro Campos Magencio
Posting date: 2009-12-22T01:58:00+00:00


Hi all,

You may get the following exception when trying to access X509Certificate2.PrivateKey on a .NET 3.5 (or older) app:


"
System.Security.Cryptography.CryptographicException: Invalid provider type specified.

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()

"

When this happened to me, I used my CryptoAPI Tracer on the problematic app to find out which CryptoAPI was failingand causing that exception. This was the one:


"
CryptAcquireContextA (0x448)

IN
pszContainer
0078a948 "anycontainername"

pszProvider
00773fb8 "Microsoft Software Key Storage P"
00773fd8 "rovider"

dwProvType
0

dwFlags
0

OUT
hProv
NULL

RESULT
CryptAcquireContextA (0x448) FAILED
LastErrorValue: (HRESULT) 0x80090014 (2148073492) - Invalid provider type specified.
LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0

"

So the certificate I was using was associated to Microsoft Software Key Storage Provider, whichis not a CSP but a KSP:

CNG Key Storage Providers
"
Unlike Cryptography API (CryptoAPI), Cryptography API: Next Generation (CNG) separates cryptographic providers from key storage providers (KSPs). KSPs can be used to create, delete, export, import, open and store keys. Depending on implementation, they can also be used for asymmetric encryption, secret agreement, and signing. Microsoft installs the following KSPs beginning with Windows Vista and Windows Server 2008.
"

This is a CNG certificate! This is what CertUtil.exe returns on the private key of that certificate:

"
Key Container = ...
Unique container name: ...
Provider = Microsoft Software Key Storage Provider
Private key is NOT exportable
Encryption test passed

"

So certutil.exe knows how to deal with this kind of CNG certificates. I used my CryptoAPI Tracer on CertUtil, and this tool is using CryptAcquireCertificatePrivateKey instead of CryptAcquireContext to access the keys of the cert. CryptAcquireCertificatePrivateKey has specific flags to deal with CNG:

CryptAcquireCertificatePrivateKey Function
"
CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG
This function will attempt to obtain the key by using CryptoAPI. If that fails, this function will attempt to obtain the key by using the Cryptography API: Next Generation (CNG).
The pdwKeySpec variable receives the CERT_NCRYPT_KEY_SPEC flag if CNG is used to obtain the key.
...
pdwKeySpec [out]
CERT_NCRYPT_KEY_SPEC
The key is a CNG key.

"

.NET is not CNG aware yet (at least up to version 3.5 SP1). It uses CryptAcquireContext instead of CryptAcquireCertificatePrivateKey and CryptAcquireContext has no flags to deal with CNG.

A possible workaround to this may be to use CryptoAPI/CNG API directly to deal with CNG keys. That is what certutil.exe does. But ifwe wantan easier andpure .NET solution which understands CNG, this will help to implement it:

CLR Security
"
Security.Cryptography.dll provides a new set of algorithm implementations to augment the built in .NET framework supported algorithms. It also provides some APIs to extend the existing framework cryptography APIs. Within this project you will find:
§ A CNG implementation of the AES, RSA, and TripleDES encryption algorithms
§ A CNG implementation of a random number generator
§ A class that allows dynamically creating algorithms both from this library as well as all of the algorithms that ship with .NET 3.5
§ An enumerator over all of the installed CNG providers on the current machine
§ Extension methods that allow access to all of the keys installed in a CNG provider, as well as all of the algorithms the provider supports

"

If you want to use CNG with this dll, you have to do the following:

1) Change .NET version to 3.5. As far as I know the dll requires us to move at least to that version.

2) Reference Security.Cryptography.dll in your project.

3) Include "using Security.Cryptography.X509Certificates;" statement (in C#, of course)to activate CNG extensions for standard X509Certificate2 class.

Then you may check whether the cert has a CNG key using the extension .HasCngKey() for X509Certificate2. If you have a CNG key, you can then instantiate an RSACng object using the extension .GetCngPrivateKey() for X509Certificate2. You can then i.e. decrypt with RSACng.DecryptValue().

 

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/12/14/does-signtool-work-on-windows-7/
Post name: Does SignTool work on Windows 7?
Original author: Alejandro Campos Magencio
Posting date: 2009-12-14T00:32:00+00:00


Hi all,

The answer to the question of the title is YES, OF COURSE!Why wouldn't it? Well, the reason of this question is the following: you may already know that CAPICOM has been deprecated on Windows 7 (CAPICOM support on Windows 7). It was going to be deprecated when Vista came out, but it didn't (CAPICOM support on Windows Vista). And why wasn't it deprecated on Vista? Because a tool like SignTool depended on CAPICOM.

So if SignTool depends on CAPICOM, will it work on Windows 7? Yes, because Signtool has been updated on Windows 7 and it does not use CAPICOM anymore.

Note: remember that Win7 version of SignTool comes with Microsoft Windows SDK for Windows 7 and .NET Framework 3.5 SP1.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)