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.
EnvelopedCMS throws an "ASN1 out of memory" exception with files larger than 5 MB
Original author:
Alejandro Campos Magencio
Posting date:
2011-02-18T02:53:39+00:00
Hi all,
When using .NET's EnvelopedCMS to decode a file that is larger than 5 MB, you may get the following exception on Windows 7/Server 2008 R2:
Unhandled Exception: System.Security.Cryptography.CryptographicException: ASN1 out of memory.
at System.Security.Cryptography.Pkcs.EnvelopedCms.OpenToDecode(Byte[] encodedMessage)
at System.Security.Cryptography.Pkcs.EnvelopedCms.Decode(Byte[] encodedMessage)
Now, in the posts above, the error was similar but not the same: "ASN1 value too large". In this case the issue is a bit different, as the problematic files are not too big (only 5MB or so).It seems to berelated to the contents of the file itsef. In any case, the above sample worked on this scenario, too.
With the workaround at hand, I kept investigating and found that this issue is actually a bug on Windows! Fortunatelly we just released a fix for it:
Process created with CreateProcessAsUser won’t initialize properly
Original author:
Alejandro Campos Magencio
Posting date:
2011-01-12T01:04:19+00:00
Hi all
Some time ago a customer of mine had an issue with his client/server application when using CreateProcessAsUser. The process that they were creating was starting but closing immediately and unexpectedly without executing a single line of code in its "main" function. This was the scenario:
- The server side of their app was a Windows Service that accepted connections through a named pipe (with CreateNamedPipe, ConnectNamePipe APIs).
- The client connected to the server via named pipe.
This scenario was working fine on Windows XP and Server 2003, but not on Vista, Server 2008, Win7 & Server 2008 R2.
We tried to debug the launched process, without much success. When we tried to attach a debugger like cdb.exe or windbg.exe (Debugging Tools for Windows) when the process started, those debuggers failed to start too. When we tried to attach ntsd.exe debugger(Debugging Tools for Windows), the launched process worked just fine, so we couldn't repro the issue. Ntsd.exe made the issue to go away.
Then we verified with Process Monitor that the launched process was indeed starting, but closed before finishing its initialization, while it was loading dlls like kernelbase.dll.
It turned out that we were callingCreateProcessAsUser without any of these flags, so the child process was inheriting the console from the parentby default:
CREATE_NEW_CONSOLE 0x00000010 The new process has a new console, instead of inheriting its parent's console (the default). For more information, see Creation of a Console.
This flag cannot be used with DETACHED_PROCESS.
CREATE_NO_WINDOW 0x08000000 The process is a console application that is being run without a console window. Therefore, the console handle for the application is not set.
This flag is ignored if the application is not a console application, or if it is used with either CREATE_NEW_CONSOLE or DETACHED_PROCESS.
DETACHED_PROCESS 0x00000008 For console processes, the new process does not inherit its parent's console (the default). The new process can call the AllocConsole function at a later time to create a console. For more information, see Creation of a Console.
This value cannot be used with CREATE_NEW_CONSOLE.
Inheriting the console from the parent will fail since both processes, the windows service and the launched process, run in different sessions. The console cannot be shared between sessions.
Now, this used to work in versions of Windows older than Vista as there was no "session 0 isolation", so both the service and the launched process were running in the same session:
In Windows XP, Windows Server 2003, and earlier versions of Windows, all services run in Session 0 along with applications
We tried calling CreateProcessAsUser with each of these flags: CREATE_NEW_CONSOLE, CREATE_NO_WINDOW & DETACHED_PROCESS, and any of them made things work. You would have to choose one of those flags depending on your needs: Creation of a Console.
How to get the sAMAccountName of a foreign security principal (C#)
Original author:
Alejandro Campos Magencio
Posting date:
2011-01-11T02:33:17+00:00
Hi all,
The following sample shows a couple of ways to get the sAMAccountName of a foreign security principal in your Active Directory. Needless to say, the recommended approach is the one that uses .NET classes over the one that usesAdssecurity.dll:
using System;
using System.DirectoryServices;
using ADSSECURITYLib;
using System.Security.Principal;
namespace MySample
{
class Program
{
static void Main(string[] args)
{
string sAMAccountName = "";
// Get sAMAccountName with Adssecurity.dll. You will have to add to your project a reference to this COM dll
sAMAccountName = GetSamAccountNameWithADSSECURITYLib("LDAP://CN=S-1-5-21-100066778-12312342-412341235-513,CN=ForeignSecurityPrincipals,DC=domain,DC=com");
Console.WriteLine(sAMAccountName);
// Get sAMAccountName with .NET
sAMAccountName = GetSamAccountNameWithDotNET("LDAP://CN=S-1-5-21-100066778-12312342-412341235-513,CN=ForeignSecurityPrincipals,DC=domain,DC=com");
Console.WriteLine(sAMAccountName);
}
static string GetSamAccountNameWithADSSECURITYLib(string ldapPath)
{
const int ADS_SID_RAW = 0;
const int ADS_SID_SAM = 2;
string sAMAccountName = "";
try
{
DirectoryEntry user = new DirectoryEntry(ldapPath);
// Get the SID
object objectSid = user.InvokeGet("objectSid");
// Resolve the SID into its sAMAcountName.
ADsSIDClass sid = new ADsSIDClass();
sid.SetAs(ADS_SID_RAW, objectSid);
sAMAccountName = sid.GetAs(ADS_SID_SAM).ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return sAMAccountName;
}
static string GetSamAccountNameWithDotNET(string ldapPath)
{
string sAMAccountName = "";
try
{
DirectoryEntry user = new DirectoryEntry(ldapPath);
// Get the SID
object objectSid = user.InvokeGet("objectSid");
// Resolve the SID into its sAMAcountName.
SecurityIdentifier sid = new SecurityIdentifier((byte[])objectSid, 0);
NTAccount account = (NTAccount)sid.Translate(typeof(NTAccount));
sAMAccountName = account.ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return sAMAccountName;
}
}
}
An aborted process that reads from a smartcard causes a 2nd reader process to hang
Original author:
Alejandro Campos Magencio
Posting date:
2010-12-23T02:33:51+00:00
Hi all,
I'm currently working on the following issue on Windows Vista SP2 and Windows 7 RTM which doesn't happen on Windows XP SP3: if a process that reads from a smart card is aborted unexpectedly after a call toSCardBeginTransaction without callingSCardEndTransaction, other instances of the same application or any other application using the same card will hang when trying to connect to the card withSCardConnect.
After you repro the issue, you can restart the Smart Card service or just remove and re-insert the card in the reader to be able to use it again. Now, that workaround won't work in all scenarios, so we have just released a fix for the issue on Vista and Server 2008.
The fix for Windows 7 and Server 2008 R2 is on its way, but it won't be released before Service Pack 1 is publicly released next year (sorry, don't know the exact date).
So on XP we need a CSP of type PROV_RSA_AES like "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" (implemented in Rsaenh.dll) to work with SHA-2.
The other day a customer of mine was getting an“Invalid algorithm specified”when calling signedCms.CheckSignature to verify SHA256 signed files on Windows XP SP3.
Debugging the issue I saw that .NET ends up callingCryptMsgOpenToDecode APIbehind the sceneswith a NULL hCryptProv. That has the following implications:
Windows Server 2003, Windows XP, and Windows 2000: Specifies a handle for the cryptographic provider to use for hashing the message. For signed messages, hCryptProv is used for signature verification.This parameter's data type is HCRYPTPROV.
Unless there is a strong reason for passing in a specific cryptographic provider in hCryptProv, set this parameter to NULL. Passing in NULL causes the default RSA or DSS provider to be acquired before performing hash, signature verification, or recipient encryption operations.
And I could verify that we indeed end up getting the default CSP for the PROV_RSA_FULL provider type. So basically, with current .NET and Windows XP SP3 designs, we will never be able to use a provider of type PROV_RSA_AES with SignedCMS.
Summing up, current version of SignedCMS won’t support SHA-2 algorithms on Windows XP SP3.
So we took my LargeCMS sample as a base for a workaround:
The idea was to forget about SignedCMS by calling CryptMsg API directly. This way we could pass a validHCRYPTPROV handle of a CSP that works with SHA-2 (like our "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)") to CryptMsgOpenToDecode API.
My customer was able to use my sample with some minor modificationsto verify the signature in XP and Vista: he modified theOpenMessageToDecode and the CheckSignature methods to pass in a handle to the proper CSP that supports SHA-2.The SignedLargeCMS.VerifySignature method in the sample now becomes:
public void VerifySignature(FileStream dataFile, FileStream encodedFile, FileStream decodedFile)
{
SafeCSPHandle hCryptProv = SafeCSPHandle.Null;
try
{
hCryptProv = Win32.AcquireRsaEnhVerifyContext();
Decode(hCryptProv.DangerousGetHandle(), dataFile, encodedFile, decodedFile);
// Check all signature in the message
Win32.CheckSignatures2(hCryptProv.DangerousGetHandle(), m_hMsg);
}
finally
{
hCryptProv.Dispose();
}
// Check parameters
if (m_hMsg.IsInvalid)
{
throw new Exception("CheckSignature error: Decode method must be called first");
}
}
The AcquireRsaEnhVerifyContext method is in Win32Helper file:
public static SafeCSPHandle AcquireRsaEnhVerifyContext()
{
SafeCSPHandle hCryptProv = SafeCSPHandle.Null;
CryptAcquireContext(
out hCryptProv,
null,
"Microsoft Enhanced RSA and AES Cryptographic Provider",
PROV_RSA_ENH, // type 24, 0x00000018
CRYPT_VERIFYCONTEXT);
if ((hCryptProv == null) || (hCryptProv.IsInvalid))
{
throw new Exception("CryptAcquireContext error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error()));
}
return hCryptProv;
}
Note that inAcquireRsaEnhVerifyContext we will have to use "Microsoft Enhanced RSA and AES Cryptographic Provider" on Vista and later, and"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" on XP.