Skip to content

EnvelopedCms.ContentEncryptionAlgorithm.Parameters is empty after call to Decode on Windows #113668

Open
@Charlieface

Description

@Charlieface

Description

After calling EnvelopedCms.Decode all its properties are supposed to be loaded up with the info from the byte-array CMS data passed in. But the ContentEncryptionAlgorithm.Parameters is empty (zero-length array).

The issue was noted in this StackOverflow question.

Reproduction Steps

Below is a minimal repro of an AES-encrypted EnvelopedCMS.

var encryptedMessage = new byte[] {
	// Offset 0x00000000 to 0x00000393
	0x30, 0x82, 0x03, 0x90, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
    0x01, 0x07, 0x03, 0xA0, 0x82, 0x03, 0x81, 0x30, 0x82, 0x03, 0x7D, 0x02,
    0x01, 0x00, 0x31, 0x82, 0x01, 0x94, 0x30, 0x82, 0x01, 0x90, 0x02, 0x01,
    0x00, 0x30, 0x78, 0x30, 0x60, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55,
    0x04, 0x06, 0x13, 0x02, 0x49, 0x4E, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03,
    0x55, 0x04, 0x08, 0x0C, 0x02, 0x4D, 0x48, 0x31, 0x0D, 0x30, 0x0B, 0x06,
    0x03, 0x55, 0x04, 0x07, 0x0C, 0x04, 0x50, 0x55, 0x4E, 0x45, 0x31, 0x21,
    0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x0C, 0x18, 0x49, 0x6E, 0x74,
    0x65, 0x72, 0x6E, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74,
    0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4C, 0x74, 0x64, 0x31, 0x12, 0x30,
    0x10, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x09, 0x6C, 0x6F, 0x63, 0x61,
    0x6C, 0x68, 0x6F, 0x73, 0x74, 0x02, 0x14, 0x51, 0xB1, 0xB6, 0xA5, 0x42,
    0x6A, 0xCE, 0x91, 0x3F, 0x57, 0x1F, 0xC5, 0xF1, 0x18, 0x14, 0xBE, 0x46,
    0x89, 0x40, 0x87, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
    0x0D, 0x01, 0x01, 0x07, 0x30, 0x00, 0x04, 0x82, 0x01, 0x00, 0x80, 0x45,
    0xC3, 0x56, 0x3B, 0x28, 0x62, 0xAF, 0xDA, 0xAF, 0xD1, 0xC7, 0x09, 0xD1,
    0x47, 0xB1, 0x1C, 0x56, 0xE6, 0x53, 0x24, 0x4D, 0xF0, 0x1F, 0x75, 0x21,
    0xDD, 0x63, 0x0F, 0x86, 0xBC, 0xBB, 0xF2, 0xC0, 0x77, 0x8E, 0x2F, 0xEF,
    0x21, 0x35, 0x2A, 0x2F, 0xC4, 0xBE, 0x4B, 0xEB, 0x88, 0x5E, 0x82, 0x1A,
    0xDA, 0x71, 0xF2, 0x4F, 0x9B, 0x68, 0x4E, 0x64, 0x0D, 0x20, 0x31, 0x70,
    0x3C, 0xF6, 0x42, 0x00, 0x9B, 0xB8, 0x24, 0xB4, 0xEF, 0x08, 0x61, 0x2A,
    0x55, 0xCA, 0x0D, 0xE7, 0x45, 0x4D, 0xC0, 0x3B, 0x35, 0x6D, 0x50, 0x5A,
    0x88, 0xEB, 0x73, 0x35, 0x86, 0x85, 0x23, 0xAF, 0x97, 0x5F, 0xB0, 0x62,
    0xD2, 0x54, 0x29, 0x95, 0xC1, 0x5A, 0x42, 0xA3, 0x9C, 0x0A, 0x37, 0x2F,
    0x42, 0x51, 0x24, 0x7F, 0xD4, 0xB2, 0x92, 0x3E, 0xAB, 0x9E, 0x7E, 0x79,
    0x1D, 0xA5, 0x42, 0xC4, 0x2F, 0xB3, 0x68, 0x48, 0x7F, 0x0E, 0x49, 0xE0,
    0xEF, 0xDC, 0x76, 0xB2, 0x86, 0x3B, 0x47, 0x73, 0x49, 0x0C, 0x98, 0xBA,
    0x47, 0x24, 0x4B, 0xF0, 0x2A, 0xCE, 0xEF, 0xDD, 0x92, 0x61, 0x88, 0xE4,
    0x81, 0xFE, 0x32, 0xBE, 0x08, 0x53, 0x25, 0xF7, 0xA5, 0x0C, 0xFC, 0xC9,
    0x66, 0x77, 0xB1, 0x69, 0x57, 0x05, 0xE1, 0xD6, 0x3A, 0x0B, 0xA0, 0x6E,
    0x6B, 0x90, 0x86, 0x5B, 0x48, 0x58, 0xD3, 0x28, 0xDA, 0x28, 0x0C, 0x5B,
    0x7D, 0x86, 0xFF, 0x62, 0xE2, 0x84, 0xBA, 0x90, 0xBA, 0x43, 0x66, 0xF7,
    0xAB, 0x83, 0xF0, 0xC8, 0xAF, 0xDE, 0x15, 0x03, 0xFB, 0x05, 0xA1, 0xD1,
    0xDA, 0x2E, 0x04, 0x37, 0x33, 0x37, 0x14, 0x15, 0xBD, 0x75, 0x4F, 0x26,
    0x3C, 0xF3, 0x6A, 0x1F, 0x7D, 0x8E, 0x23, 0xC4, 0xEB, 0xF3, 0xD8, 0x35,
    0x25, 0x44, 0xE8, 0x1C, 0x5C, 0x5C, 0x14, 0x94, 0xAE, 0x2E, 0xDB, 0x52,
    0xFB, 0xFC, 0x30, 0x82, 0x01, 0xDE, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
    0xF7, 0x0D, 0x01, 0x07, 0x01, 0x30, 0x1D, 0x06, 0x09, 0x60, 0x86, 0x48,
    0x01, 0x65, 0x03, 0x04, 0x01, 0x2A, 0x04, 0x10, 0xA9, 0xAF, 0xB3, 0x34,
    0xA7, 0x07, 0x4A, 0xBB, 0x58, 0xD5, 0xCF, 0xD3, 0xFF, 0xB4, 0xDE, 0x7E,
    0x80, 0x82, 0x01, 0xB0, 0x46, 0x20, 0x3B, 0x68, 0x55, 0xEB, 0x5C, 0xDA,
    0x67, 0xEE, 0x41, 0xAA, 0x06, 0x88, 0xD7, 0x95, 0x83, 0x12, 0xF4, 0x47,
    0x17, 0x81, 0x08, 0xF7, 0x1B, 0x55, 0xEC, 0xF6, 0x12, 0xE2, 0x27, 0x05,
    0x1D, 0x6A, 0xFA, 0x6C, 0x45, 0x43, 0x75, 0xE9, 0xFA, 0xF6, 0xA9, 0x14,
    0x3E, 0x82, 0x3A, 0x29, 0xE8, 0xC7, 0xF8, 0x91, 0x2B, 0xD8, 0x42, 0x24,
    0xEE, 0x8A, 0x4D, 0x06, 0xD0, 0x61, 0xA3, 0xF7, 0x2D, 0xF6, 0x81, 0xD2,
    0xF1, 0x92, 0x95, 0xDD, 0x77, 0x01, 0xEB, 0xE4, 0x39, 0xBD, 0x84, 0x93,
    0x10, 0xAB, 0x7D, 0xB9, 0xB6, 0x62, 0x51, 0x2F, 0xCE, 0x71, 0xE2, 0x2A,
    0x23, 0x12, 0x6A, 0x36, 0xEF, 0x06, 0x2A, 0x89, 0x68, 0x22, 0x0B, 0x39,
    0x23, 0x22, 0x6A, 0xF0, 0xBB, 0x3F, 0xA6, 0x25, 0xAA, 0xFE, 0xCD, 0x0F,
    0x59, 0xF9, 0xD4, 0x48, 0x93, 0x03, 0x9E, 0xC4, 0xB8, 0xA3, 0x4D, 0x39,
    0x78, 0x2E, 0xF8, 0xB8, 0x9D, 0x90, 0xA4, 0xB2, 0x5E, 0x24, 0x90, 0x48,
    0x72, 0xD4, 0xB7, 0x51, 0x24, 0x61, 0x57, 0x72, 0x0F, 0xA4, 0xB3, 0x8F,
    0x09, 0x48, 0xD4, 0xD5, 0x0F, 0x65, 0x9E, 0x8B, 0x2B, 0x8B, 0x3A, 0xDA,
    0x52, 0xD0, 0xE3, 0x0E, 0x2B, 0x63, 0x31, 0xFC, 0xB5, 0x7B, 0xE2, 0x18,
    0x3A, 0xB5, 0x0B, 0xD2, 0x90, 0x20, 0x53, 0x72, 0xCE, 0x05, 0xFA, 0x9B,
    0xF2, 0xDC, 0xF6, 0x54, 0x7D, 0xD2, 0x80, 0x6F, 0xF0, 0x89, 0xF1, 0x33,
    0x8F, 0x4D, 0x13, 0xDF, 0xAE, 0xA1, 0xC0, 0xC1, 0x9C, 0x23, 0x8A, 0x7D,
    0xA2, 0x01, 0xB3, 0xDD, 0xE2, 0x45, 0xB3, 0x2C, 0xC8, 0x5F, 0xCF, 0xD4,
    0x7C, 0x0E, 0xA2, 0x22, 0xF1, 0x1D, 0x7B, 0xA8, 0x84, 0x55, 0xBE, 0x5C,
    0xCB, 0x61, 0x21, 0x97, 0xA0, 0x2C, 0x16, 0xE3, 0x26, 0x6A, 0x57, 0xA7,
    0x44, 0x41, 0xA9, 0x4B, 0x18, 0xBE, 0x41, 0x94, 0x80, 0xF6, 0xCE, 0x0F,
    0x6A, 0xD9, 0x07, 0x4E, 0xB6, 0x9A, 0xFA, 0x8E, 0x78, 0x95, 0x85, 0x3B,
    0x53, 0x8D, 0xF4, 0x13, 0x11, 0x3A, 0x9B, 0x26, 0x99, 0xA9, 0xD5, 0x1F,
    0x8C, 0x0B, 0xC0, 0x1F, 0xD1, 0xF0, 0xCA, 0xB4, 0x59, 0x5A, 0xE1, 0x5F,
    0xCE, 0x80, 0x45, 0x28, 0x3D, 0xD1, 0xFD, 0x84, 0xF8, 0xE1, 0x02, 0x5C,
    0xD4, 0x01, 0x7E, 0x63, 0x20, 0x3A, 0x4C, 0x0C, 0x2D, 0x25, 0x12, 0xCA,
    0x51, 0xF0, 0x51, 0x1C, 0x0F, 0x65, 0x97, 0xCA, 0xD1, 0xF4, 0xCD, 0x01,
    0x99, 0x65, 0xBA, 0x6A, 0x21, 0x16, 0xC1, 0xC6, 0xCB, 0x5D, 0x8F, 0xA1,
    0x59, 0x89, 0x82, 0xD6, 0x2A, 0x75, 0x9B, 0xDF, 0x6F, 0xA9, 0x2A, 0x9E,
    0xC7, 0x2A, 0x0D, 0xD9, 0x1B, 0x54, 0x21, 0x9E, 0xD6, 0xE2, 0xB2, 0x16,
    0xE9, 0x4E, 0xAF, 0x57, 0x0F, 0xE3, 0x13, 0x5D, 0xD8, 0x64, 0x64, 0xA7,
    0x5C, 0xAE, 0x5C, 0x04, 0x86, 0x6A, 0x2D, 0x52, 0x0D, 0xD2, 0x72, 0x8B,
    0xF9, 0x8E, 0xBC, 0xEA, 0x0C, 0xA9, 0xEE, 0xCB, 0x23, 0x1A, 0xA6, 0x0C,
    0x95, 0xDD, 0xFF, 0x70, 0xC6, 0xEC, 0xDA, 0x69, 0x8D, 0xC6, 0x51, 0x1A,
    0x71, 0x2F, 0x97, 0x97, 0xF9, 0xB1, 0x1C, 0x9D, 0x1D, 0x06, 0xDB, 0x0C,
    0x3F, 0x0D, 0xBF, 0xC2
};

var envelopedCms = new EnvelopedCms();
envelopedCms.Decode(encryptedMessage);
var parameters = envelopedCms.ContentEncryptionAlgorithm.Parameters;
Console.WriteLine($"envelopedCms.ContentEncryptionAlgorithm.Parameters: {parameters.Length}");
var decryptor = envelopedCms.GetType().GetField("_decryptorPal", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
    .GetValue(envelopedCms);
var contentEncryption = decryptor!.GetType().GetField("_contentEncryptionAlgorithm", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
    .GetValue(decryptor);
var parametersInternal = contentEncryption!.GetType().GetField("Parameters", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)!
    .GetValue(contentEncryption);
Console.WriteLine($"envelopedCms._decryptorPal._contentEncryptionAlgorithm.Parameters.Length: {((ReadOnlyMemory<byte>)parametersInternal).Length}");

Expected behavior

The ContentEncryptionAlgorithm.Parameters should return the encoded algorithm parameters.

Actual behavior

The ContentEncryptionAlgorithm.Parameters can be seen as empty.

Known Workarounds

The CMS envelope can be manually read using AsnReader using the code in the answer of that StackOverflow post.

Configuration

Windows 10 19045.5487
.NET 8.0.13 and .NET 9.0.2
x64

Other information

After some debugging, it seems the issue is that ToAlgorithmIdentifier is not decoding the Parameters unless the algorithm is RSA-OAEP. Why this is the case is unclear: the RFCs specify that any algorithm can have Parameters.

public static AlgorithmIdentifier ToAlgorithmIdentifier(this CRYPT_ALGORITHM_IDENTIFIER cryptAlgorithmIdentifier)
{
.......
    AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Oid.FromOidValue(oidValue, OidGroup.All), keyLength);
    switch (oidValue)
    {
        case Oids.RsaOaep:
            algorithmIdentifier.Parameters = cryptAlgorithmIdentifier.Parameters.ToByteArray();
            break;
    }
    return algorithmIdentifier;
}

Weirdly, the code in DecryptorPalWindows.Decode appears to partially compensate for this bug, by manually calling Parameters.ToByteArray. But it only stores it in the internal _decryptorPal, not in the returned AlgorithmIdentifier.

AlgorithmIdentifierAsn contentEncryptionAlgorithmAsn;
using (SafeHandle sh = hCryptMsg.GetMsgParamAsMemory(CryptMsgParamType.CMSG_ENVELOPE_ALGORITHM_PARAM))
{
    unsafe
    {
        CRYPT_ALGORITHM_IDENTIFIER* pCryptAlgorithmIdentifier = (CRYPT_ALGORITHM_IDENTIFIER*)(sh.DangerousGetHandle());
        contentEncryptionAlgorithm = (*pCryptAlgorithmIdentifier).ToAlgorithmIdentifier();
        contentEncryptionAlgorithmAsn.Algorithm = contentEncryptionAlgorithm.Oid.Value!;
        contentEncryptionAlgorithmAsn.Parameters = (*pCryptAlgorithmIdentifier).Parameters.ToByteArray();
    }
}

The fix:

It seems all that is needed is to change the code in ToAlgorithmIdentifier to remove the switch and unconditionally retrieve the Parameters.

    AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(Oid.FromOidValue(oidValue, OidGroup.All), keyLength);
    algorithmIdentifier.Parameters = cryptAlgorithmIdentifier.Parameters.ToByteArray();
    return algorithmIdentifier;
}

The Decode can then retrieve it from there:

        CRYPT_ALGORITHM_IDENTIFIER* pCryptAlgorithmIdentifier = (CRYPT_ALGORITHM_IDENTIFIER*)(sh.DangerousGetHandle());
        contentEncryptionAlgorithm = (*pCryptAlgorithmIdentifier).ToAlgorithmIdentifier();
        contentEncryptionAlgorithmAsn.Algorithm = contentEncryptionAlgorithm.Oid.Value!;
        contentEncryptionAlgorithmAsn.Parameters = contentEncryptionAlgorithm.Parameters;

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions