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/2011/02/18/envelopedcms-throws-an-asn1-out-of-memory-exception-with-files-larger-than-5-mb/
Post name: 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)

This simple code reproduces the issue:

byte[] encryptedContent = File.ReadAllBytes(@"c:\EncryptedFile.test");

EnvelopedCms cms = new EnvelopedCms();

cms.Decode(encryptedContent);

cms.Decrypt();

Issue won't happen with all files. Additionally, issue won't happen on e.g. Windows XP with the same code and file.

 

I’ve seen similar issues in the past when dealing with big CMS files, with both EnvelopedCMS and SignedCMS, and I solved them with this sample:

How to call CryptMsg API in streaming mode - LargeCMS full sample

More info:

"ASN1 value too large" error when calling SignedCms.ComputeSignature

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:

"ASN1 out of memory" error when the CryptMsgUpdate function decodes a message that is larger than 5 MB in Windows 7 or in Windows Server 2008 R2

Note that this fix goes on top of Windows 7 SP1.

I hope this helps.

Cheers,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2011/01/12/process-created-with-createprocessasuser-wont-initialize-properly/
Post name: 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.

- The server impersonated the client (with ImpersonateNamedPipeClient API).

- Then the server created a new process with client credentials (with GetCurrentThread, OpenThreadToken, DuplicateTokenEx and CreateProcessAsUser APIs).

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:

Process Creation Flags

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:

Impact of Session 0 Isolation on Services and Drivers in Windows

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.

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2011/01/11/how-to-get-the-samaccountname-of-a-foreign-security-principal-c/
Post name: 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;
        }

    }
}

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2010/12/23/an-aborted-process-that-reads-from-a-smartcard-causes-a-2nd-reader-process-to-hang/
Post name: 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).

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2010/12/21/more-on-net-cms-classes-and-sha-2-algorithms/
Post name: More on .NET CMS classes and SHA-2 algorithms
Original author: Alejandro Campos Magencio
Posting date: 2010-12-21T09:06:00+00:00


Hi all,

 

We don’t officially support the .NET CMS classes with SHA-2 algorithms. This won’t work on Vista and later with third-party CSPs, for instance:

"An internal error ocurred" when using SHA-2 algorithms with SignedCMS

"Invalid provider type specified" when using CNG providers with .NET CMS classes

But it will work on Vista and later with MS providers (e.g. with a cert associated to "Microsoft Enhanced RSA and AES Cryptographic Provider")

Now, in a Windows XP scenario we have no CNG, so the issue is a bit different. The support to SHA-2 itself on Windows XP is a bit limited:

SHA-2 support on Windows XP

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:

CryptMsgOpenToDecode Function

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:

How to call CryptMsg API in streaming mode - LargeCMS full sample

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.

I hope this helps.

Regards,

Alex (Alejandro Campos Magencio)