Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline MegaVasiliy  
#1 Оставлено : 12 июля 2023 г. 12:06:04(UTC)
MegaVasiliy

Статус: Участник

Группы: Участники
Зарегистрирован: 13.09.2022(UTC)
Сообщений: 20
Российская Федерация
Откуда: Волгоград

Сказал(а) «Спасибо»: 2 раз
Всем день добрый. Занимаюсь переносом некоторого кода с net core на net framework.

Там использовал флаг CspNoPersistKeySet для загрузки сертификата вот так:
Код:
var cert = new X509Certificate2(certBytes, certPassword, X509KeyStorageFlags.CspNoPersistKeySet);


А как сделать чтобы тоже самое на Net Framework 4.8?

Спасибо!
Offline Максим Коллегин  
#2 Оставлено : 12 июля 2023 г. 20:49:46(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,393
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 37 раз
Поблагодарили: 717 раз в 621 постах
В .NET не поддерживается этот флаг, здесь описан workaround:
https://cryptopro.ru/for...aspx?g=posts&t=10954
Знания в базе знаний, поддержка в техподдержке
Offline MegaVasiliy  
#3 Оставлено : 13 июля 2023 г. 14:15:06(UTC)
MegaVasiliy

Статус: Участник

Группы: Участники
Зарегистрирован: 13.09.2022(UTC)
Сообщений: 20
Российская Федерация
Откуда: Волгоград

Сказал(а) «Спасибо»: 2 раз
Автор: Максим Коллегин Перейти к цитате
В .NET не поддерживается этот флаг, здесь описан workaround:
https://cryptopro.ru/for...aspx?g=posts&t=10954


Спасибо за наводку, удалось набросать нечто похожее на работающий код:
Код:
        public static X509Certificate2 FromFile(string filename, string password)
        {
            var handle = default(GCHandle);
            var storePtr = IntPtr.Zero;
            try
            {   // Читаем файл сертификата
                byte[] buffer = File.ReadAllBytes(filename);

                handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);

                CRYPT_DATA_BLOB cryptdata = new CRYPT_DATA_BLOB
                {
                    cbData = buffer.Length,
                    pbData = handle.AddrOfPinnedObject()
                };

                // Открываем сертификат без хранения ключей.
                if ((storePtr = PFXImportCertStore(ref cryptdata, password, PKCS12_NO_PERSIST_KEY | CRYPT_EXPORTABLE)) == IntPtr.Zero)
                    return null;

                var certHandle = IntPtr.Zero;
                while ((certHandle = CertEnumCertificatesInStore(storePtr, certHandle)) != IntPtr.Zero)
                {
                    var size = 0;
                    // Получаем первый сертификат у которого есть приватный ключ (обычный или эфемерный).
                    if (CertGetCertificateContextProperty(certHandle, CERT_KEY_CONTEXT_PROP_ID, IntPtr.Zero, ref size)
                        || CertGetCertificateContextProperty(certHandle, CERT_KEY_PROV_INFO_PROP_ID, IntPtr.Zero, ref size))
                    {
                        var dup = CertDuplicateCertificateContext(certHandle);
                        var crt = new X509Certificate2(dup);
                        return crt;
                    }
                }

                return null;
            }
            finally
            {
                if (storePtr != IntPtr.Zero)
                    CertCloseStore(storePtr, 0);

                if (handle.IsAllocated)
                    handle.Free();
            }
        }
    }


Но, тут странная вещь: если использовать этот код в net Core - то полученный сертификат полностью идентичен загруженному с CspNoPersistKeySet - отлично работает подписание.
Но в net framework 4.8 НЕ работает, бросает исключение "Объект или свойство не найдено". Подпись получаю так:
Код:
        private static string Sign(string str, X509Certificate2 cert)
        {
            try
            {
                // Тестируем подпись.
                var file = string.IsNullOrEmpty(str)
                    ? new byte[] { 1, 2, 3, 5, 5, 6 }
                    : Encoding.UTF8.GetBytes(str);

                CmsSigner signer = new CmsSigner(cert);
                ContentInfo contentInfo = new ContentInfo(file);
                SignedCms signedCms = new SignedCms(contentInfo, detached: true);
                signedCms.ComputeSignature(signer); // Вот на этой строчке происходит падение

                return Convert.ToBase64String(signedCms.Encode());
            }
            catch (Exception exc)
            {
                return null;
            }
        }


Ну и в других операциях (например авторизации по сертификату) тоже сертификат не отрабатывает как надо. Что нужно улучшить здесь? Где может быть проблема?
Offline Максим Коллегин  
#4 Оставлено : 13 июля 2023 г. 14:26:59(UTC)
Максим Коллегин

Статус: Сотрудник

Группы: Администраторы
Зарегистрирован: 12.12.2007(UTC)
Сообщений: 6,393
Мужчина
Откуда: КРИПТО-ПРО

Сказал «Спасибо»: 37 раз
Поблагодарили: 717 раз в 621 постах
Проблема в ссылке на ключ скорее всего, попробуйте не закрывать хранилище.
Вообще кэш в .NET устроен очень странно, постараюсь вспомнить точнее, если не разберётесь.

Вспомнил, что лучше вообще не использовать SignedCms, он неверно работает со ссылками на криптопровайдер и при многопоточной работе гарантированы ошибки.

Отредактировано пользователем 13 июля 2023 г. 14:44:26(UTC)  | Причина: Не указана

Знания в базе знаний, поддержка в техподдержке
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest (2)
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.