File: Internal\Cryptography\Pal\Windows\DecryptorPalWindows.DecodeRecipients.cs
Web Access
Project: src\src\runtime\src\libraries\System.Security.Cryptography.Pkcs\src\System.Security.Cryptography.Pkcs.csproj (System.Security.Cryptography.Pkcs)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Security.Cryptography.Pkcs;

using Microsoft.Win32.SafeHandles;

using static Interop.Crypt32;

namespace Internal.Cryptography.Pal.Windows
{
    internal sealed partial class DecryptorPalWindows : DecryptorPal
    {
        private static RecipientInfoCollection CreateRecipientInfos(SafeCryptMsgHandle hCryptMsg)
        {
            int numRecipients;
            int cbRecipientsCount = sizeof(int);
            if (!Interop.Crypt32.CryptMsgGetParam(hCryptMsg, CryptMsgParamType.CMSG_CMS_RECIPIENT_COUNT_PARAM, 0, out numRecipients, ref cbRecipientsCount))
                throw Marshal.GetLastPInvokeError().ToCryptographicException();

            List<RecipientInfo> recipientInfos = new List<RecipientInfo>(numRecipients);
            for (int index = 0; index < numRecipients; index++)
            {
                // Do not dispose this safehandle. The RecipientInfoPal objects we create hold on to these and they get freed through garbage collection.
                SafeHandle pCmsgCmsRecipientInfoMemory = hCryptMsg.GetMsgParamAsMemory(CryptMsgParamType.CMSG_CMS_RECIPIENT_INFO_PARAM, index);
                IEnumerable<RecipientInfo> recipientInfosForThisIndex = ToRecipientInfosForThisIndex(pCmsgCmsRecipientInfoMemory, index);
                recipientInfos.AddRange(recipientInfosForThisIndex);
            }

            return new RecipientInfoCollection(recipientInfos);
        }

        private static IEnumerable<RecipientInfo> ToRecipientInfosForThisIndex(SafeHandle pCmsgCmsRecipientInfoMemory, int index)
        {
            bool mustRelease = false;
            pCmsgCmsRecipientInfoMemory.DangerousAddRef(ref mustRelease);
            try
            {
                unsafe
                {
                    CMSG_CMS_RECIPIENT_INFO* pCMsgCmsRecipientInfo = (CMSG_CMS_RECIPIENT_INFO*)(pCmsgCmsRecipientInfoMemory.DangerousGetHandle());
                    switch (pCMsgCmsRecipientInfo->dwRecipientChoice)
                    {
                        case CMsgCmsRecipientChoice.CMSG_KEY_TRANS_RECIPIENT:
                            return new KeyTransRecipientInfo[] { new KeyTransRecipientInfo(new KeyTransRecipientInfoPalWindows(pCmsgCmsRecipientInfoMemory, index)) };

                        case CMsgCmsRecipientChoice.CMSG_KEY_AGREE_RECIPIENT:
                            {
                                CMSG_KEY_AGREE_RECIPIENT_INFO* pCmsKeyAgreeRecipientInfo = pCMsgCmsRecipientInfo->KeyAgree;
                                int numKeys = pCmsKeyAgreeRecipientInfo->cRecipientEncryptedKeys;
                                KeyAgreeRecipientInfo[] recipients = new KeyAgreeRecipientInfo[numKeys];
                                for (int subIndex = 0; subIndex < numKeys; subIndex++)
                                {
                                    recipients[subIndex] = new KeyAgreeRecipientInfo(new KeyAgreeRecipientInfoPalWindows(pCmsgCmsRecipientInfoMemory, index, subIndex));
                                }
                                return recipients;
                            }

                        default:
                            throw ErrorCode.E_NOTIMPL.ToCryptographicException();
                    }
                }
            }
            finally
            {
                if (mustRelease)
                {
                    pCmsgCmsRecipientInfoMemory.DangerousRelease();
                }
            }
        }
    }
}