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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Семён  
#1 Оставлено : 26 апреля 2013 г. 10:09:15(UTC)
Семён

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

Группы: Участники
Зарегистрирован: 31.07.2012(UTC)
Сообщений: 15

Сказал(а) «Спасибо»: 2 раз
Здравствуйте!

Появилась проблема с привязыванием сертификата к контейнеру закрытого ключа в vb6. Контейнер создается ранее, направляется запрос в УЦ на обновление сертификата, по которому получаю сертификат и привязываю его к контейнеру.

Ранее для привязки использовал библиотеку capicom, вот выдержка из кода:

Call oPrivateKeyNew.Open(containerName, PROVIDER_NAME, PROV_GOST_2001_DH, CAPICOM_KEY_SPEC_SIGNATURE, CAPICOM_CURRENT_USER_STORE, False)
oCertificateNew.PrivateKey = oPrivateKeyNew

Все прекрасно работало, но недавно свойство PrivateKey (CAPICOM.PrivateKey) объекта oCertificateNew (CAPICOM.certificate) стало недоступным: <Объект или свойство не найдено>

Пытаюсь сделать то же самое средствами crypto api:

Код:

' Объявляю структуры и функцию
Private Declare Function CertSetCertificateContextProperty Lib "crypt32" (ByRef pCertContext As Long, ByVal dwPropId As Long, ByVal dwFlags As Long, pvData As Any) As Long

Private Type CRYPT_KEY_PROV_PARAM
 dwParam As Long
 pbData As Long
 cbData As Long
 dwFlags As Long
End Type

Private Type CRYPT_KEY_PROV_INFO
    pwstringContainerName As String * 200
    pwstringProvName As String * 200
    longProvType As Long
    longFlags As Long
    longProvParam As Long
    rgProvParam As CRYPT_KEY_PROV_PARAM
    longKeySpec As Long
End Type

'Затем пробегаю по сертификатам, нахожу тех, которые без закрытого ключа, пытаюсь привязать ключ:
...
hCert = CertOpenSystemStore(0, "MY")
pCert = 0
    Do
        pCert = CertEnumCertificatesInStore(hCert, pCert)
        If (pCert <> 0) Then
            fResult = CertGetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, pcbData)
            If (fResult = 0) Then
                pvData = LocalAlloc(LPTR, pcbData)
                ProvInfo.pwstringContainerName = containerName
                ProvInfo.pwstringProvName = PROVIDER_NAME
                ProvInfo.longProvType = PROV_GOST_2001_DH
                ProvInfo.longFlags = 0
                ProvInfo.longProvParam = 0
                ProvInfo.longKeySpec = AT_KEYEXCHANGE
                If CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, ProvInfo) <> 0 Then GoTo Hook
                MsgBox Err.LastDllError
            End If
        End If
    Loop While pCert <> 0
...

На вызове CertSetCertificateContextProperty программа падает.

Мне кажется, проблема либо в заполнении структуры CRYPT_KEY_PROV_INFO, либо перед вызовом CertSetCertificateContextProperty необходимо найти или открыть контейнер. К тому же, проход по всем сертификатам и вызов CertSetCertificateContextProperty для любого сертификата с отсутствующей ссылкой на закрытый ключ - плохой подход.

Подскажите, пожалуйста, какие функции и в какой последовательности необходимо вызвать, чтобы связать конкретный сертификат с конкретным контейнером?
И почему могли появиться проблемы с capicom?
Offline Boris@Serezhkin.com  
#2 Оставлено : 26 апреля 2013 г. 12:02:56(UTC)
Boris@Serezhkin.com

Статус: Активный участник

Группы: Участники
Зарегистрирован: 26.08.2010(UTC)
Сообщений: 259
Откуда: Moscow

Сказал(а) «Спасибо»: 4 раз
Поблагодарили: 11 раз в 10 постах
Урра, любимый VB6 Drool

Автор: Семён Перейти к цитате
Здравствуйте!
Появилась проблема с привязыванием сертификата к контейнеру закрытого ключа в vb6. Контейнер создается ранее, направляется запрос в УЦ на обновление сертификата, по которому получаю сертификат и привязываю его к контейнеру.
Ранее для привязки использовал библиотеку capicom, вот выдержка из кода:
Call oPrivateKeyNew.Open(containerName, PROVIDER_NAME, PROV_GOST_2001_DH, CAPICOM_KEY_SPEC_SIGNATURE, CAPICOM_CURRENT_USER_STORE, False)
oCertificateNew.PrivateKey = oPrivateKeyNew

Все прекрасно работало, но недавно свойство PrivateKey (CAPICOM.PrivateKey) объекта oCertificateNew (CAPICOM.certificate) стало недоступным: <Объект или свойство не найдено>


>Пытаюсь сделать то же самое средствами crypto api:
>Мне кажется, проблема либо в заполнении структуры CRYPT_KEY_PROV_INFO
Я бы сказал в объявлении, работать с указателями на VB6 можно, но сложно.
Поищите "Динамические массивы VB6" Была такая статья. Найду ссылку -свистну.
Там хорошо рассказано про указатели.
Private Type CRYPT_KEY_PROV_INFO
pwstringContainerName As long 'String * 200
pwstringProvName As long 'String * 200
longProvType As Long
longFlags As Long
longProvParam As Long
rgProvParam as long 'As CRYPT_KEY_PROV_PARAM
longKeySpec As Long
End Type

Далее про широкие строки. Если надо передать именно wstring, то
Dim b() as byte
b = "NewContainerName"
provinfo.pwstringContainerName = varptr(b(0))
А если нужна простая строка
b = strconv("NewContainerName", vbfromunicode)

Конечно цикл по всем сертификатам - плохая идея.
Находим нужный, по имени или как вам нравится.
Есть ли закрытый ключ? Что может быть проще:
if pcert.HasPrivateKey then

>Подскажите, пожалуйста, какие функции и в какой последовательности необходимо вызвать,
>чтобы связать конкретный сертификат с конкретным контейнером?
Тут я могу наврать, пусть меня поправят. d'oh!
Если сертификат помещен в хранилище, то подложить ему другой контейнер нельзя, криминал получается.
Вроде надо поступать так:
Найти ранее созданный контейнер, взять из него ссылку на закрытый ключ.
взять контейнер из сертификата, прописать в него полученную ссылку.
Как я понял из MSDN контейнеры и ключи это базы, а не структуры.

Цитата:
И почему могли появиться проблемы с capicom?

А когда и что предшествовало? Сам capicom вроде уж лет пять неизменен.
Если была установка новой версии криптопро, то ответ очевиден.

Борис

thanks 1 пользователь поблагодарил Boris@Serezhkin.com за этот пост.
Семён оставлено 08.05.2013(UTC)
Offline Семён  
#3 Оставлено : 29 апреля 2013 г. 11:23:28(UTC)
Семён

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

Группы: Участники
Зарегистрирован: 31.07.2012(UTC)
Сообщений: 15

Сказал(а) «Спасибо»: 2 раз
Автор: Boris@Serezhkin.com Перейти к цитате

Урра, любимый VB6 Drool

Спасибо за быстрый и позитивный ответ)

Цитата:
>И почему могли появиться проблемы с capicom?
А когда и что предшествовало? Сам capicom вроде уж лет пять неизменен.
Если была установка новой версии криптопро, то ответ очевиден.

В том то и дело, что csp не изменялся, на других машинах аналогично, не работает свойство privatekey объекта capicom.certificate.

Сертификат приходит с сервера в формате base64, ранее созданный контейнер с закрытым ключом доступен. Сертификат надо правильно установить и привязать к контейнеру. На выходных поковырялся, вроде как последовательность такая:
1. CertCreateCertificateContext - получаем указатель на созданный контекст сертификата;
2. Заполняем структуру CRYPT_KEY_PROV_INFO;
3. CertSetCertificateContextProperty(CRYPT_KEY_PROV_INFO) - привязываем сертификат к контейнеру;
4. CertOpenSystemStore - открываем хранилище;
5. CertAddCertificateContextToStore - импортируем сертификат в хранилище;
6. Освобождаем ресурсы и закрываем хранилище (CertFreeCertificateContext, CertCloseStore, CryptReleaseContext)

Отрабатывает без ошибок, сертификат привязывается к контейнеру и импортируется в хранилище, но возникла ошибка "При проверке отношений доверия произошла системная ошибка" при открытии сертификата. CSP при открытии контейнера выдает "В контейнере ХХХ отсутствуют сертификаты".
Читал, что после создания контектста сертификата нужно выполнить еще импорт ключей в хранилище.
Подскажите пожалуйста, что может быть не так и в какую сторону копать?

Отредактировано пользователем 29 апреля 2013 г. 16:09:24(UTC)  | Причина: Не указана

Offline MCR  
#4 Оставлено : 6 мая 2013 г. 12:24:18(UTC)
MCR

Статус: Активный участник

Группы: Участники
Зарегистрирован: 06.03.2012(UTC)
Сообщений: 177

Сказал(а) «Спасибо»: 57 раз
Поблагодарили: 11 раз в 8 постах
Автор: Семён Перейти к цитате
Автор: Boris@Serezhkin.com Перейти к цитате

Урра, любимый VB6 Drool

Спасибо за быстрый и позитивный ответ)

Цитата:
>И почему могли появиться проблемы с capicom?
А когда и что предшествовало? Сам capicom вроде уж лет пять неизменен.
Если была установка новой версии криптопро, то ответ очевиден.

В том то и дело, что csp не изменялся, на других машинах аналогично, не работает свойство privatekey объекта capicom.certificate.

Сертификат приходит с сервера в формате base64, ранее созданный контейнер с закрытым ключом доступен. Сертификат надо правильно установить и привязать к контейнеру. На выходных поковырялся, вроде как последовательность такая:
1. CertCreateCertificateContext - получаем указатель на созданный контекст сертификата;
2. Заполняем структуру CRYPT_KEY_PROV_INFO;
3. CertSetCertificateContextProperty(CRYPT_KEY_PROV_INFO) - привязываем сертификат к контейнеру;
4. CertOpenSystemStore - открываем хранилище;
5. CertAddCertificateContextToStore - импортируем сертификат в хранилище;
6. Освобождаем ресурсы и закрываем хранилище (CertFreeCertificateContext, CertCloseStore, CryptReleaseContext)

Отрабатывает без ошибок, сертификат привязывается к контейнеру и импортируется в хранилище, но возникла ошибка "При проверке отношений доверия произошла системная ошибка" при открытии сертификата. CSP при открытии контейнера выдает "В контейнере ХХХ отсутствуют сертификаты".
Читал, что после создания контектста сертификата нужно выполнить еще импорт ключей в хранилище.
Подскажите пожалуйста, что может быть не так и в какую сторону копать?

Если необходимо установить сертификат в контейнер, то смотрите CryptSetKeyParam(..,KP_Certificate,..)
И пользуйтесь поиском ;)

Ссылка на закрытый ключ устанавливается с помощью: CERT_KEY_PROV_INFO_PROP_ID
Offline Семён  
#5 Оставлено : 6 мая 2013 г. 14:29:51(UTC)
Семён

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

Группы: Участники
Зарегистрирован: 31.07.2012(UTC)
Сообщений: 15

Сказал(а) «Спасибо»: 2 раз
Автор: MCR Перейти к цитате

Если необходимо установить сертификат в контейнер, то смотрите CryptSetKeyParam(..,KP_Certificate,..)
И пользуйтесь поиском ;)

Ссылка на закрытый ключ устанавливается с помощью: CERT_KEY_PROV_INFO_PROP_ID


Благодарю за ответ!
Поиском очень активно пользуюсь, но иногда не помогает :)

Добавил CryptSetKeyParam(..,KP_Certificate,..), сертификат теперь устанавливается, но не совсем корректно. При использовании сертификата, установленного программно, при инициализации криптопровайдера появляется ошибка с кодом -2146893802 "Набор ключей не существует". Хотя при установке сертификата через виндовый мастер такой ошибки не наблюдается.

Прилагаю код, может что-то я все же упустил или допустил неточность:
Код:

Private Type CRYPT_KEY_PROV_INFO
    pwstringContainerName As Long
    pwstringProvName As Long
    longProvType As Long
    longFlags As Long
    longProvParam As Long
    rgProvParam As Long
    longKeySpec As Long
End Type

Private Type CERT_CONTEXT
    dwCertEncodingType As Long
    pbCertEncoded As Long
    cbCertEncoded As Long
    pCertInfo As Long
    hCertStore As Long
End Type

Private Function CertInstall(containerName As String, Certificate As String) As Boolean

Dim hCP As Long
Dim hKey As Long
Dim pCert As Long
Dim provInfo As CRYPT_KEY_PROV_INFO
Dim a() As Byte
Dim b() As Byte
Dim c() As Byte
Dim hStore As Long
Dim Step As Integer

On Error GoTo Hook
    
    CertInstall = False
    Step = 0
    c = Certificate
    ' создать контекст сертификата
    Step = 1
    pCert = CertCreateCertificateContext(X509_ASN_ENCODING, VarPtr(c(0)), UBound(c) + 1)
    If pCert = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Exit Function
    End If
    ' заполнить инфу провайдера
    a = containerName
    b = PROVIDER_NAME
    provInfo.pwstringContainerName = VarPtr(a(0))
    provInfo.pwstringProvName = VarPtr(b(0))
    provInfo.longProvType = PROV_GOST_2001_DH
    provInfo.longFlags = 0
    provInfo.longProvParam = 0
    provInfo.longKeySpec = AT_KEYEXCHANGE
    ' ассоциировать сертификат с закрытым ключом
    Step = 2
    If CertSetCertificateContextProperty(pCert, CERT_KEY_PROV_INFO_PROP_ID, 0, provInfo) = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Call CertFreeCertificateContext(pCert)
        Exit Function
    End If
    ' запросить контекст контейнера закрытого ключа
    Step = 3
    If CryptAcquireContext(hCP, containerName, PROVIDER_NAME, PROV_GOST_2001_DH, 0) = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Call CertFreeCertificateContext(pCert)
        Call CryptReleaseContext(hCP, 0)
        Exit Function
    End If
    ' получить ссылку на пользовательский ключ
    Step = 4
    If CryptGetUserKey(hCP, AT_KEYEXCHANGE, hKey) = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Call CertFreeCertificateContext(pCert)
        Call CryptReleaseContext(hCP, 0)
        Exit Function
    End If
    ' записать сертификат в контейнер
    Step = 5
    If CryptSetKeyParam(hKey, KP_CERTIFICATE, VarPtr(c(0)), 0) = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Call CertFreeCertificateContext(pCert)
        Call CryptReleaseContext(hCP, 0)
        Exit Function
    End If
    ' добавить сертификат в личное хранилище
    Step = 6
    hStore = CertOpenSystemStore(0, "MY")
    Step = 7
    If CertAddCertificateContextToStore(hStore, pCert, CERT_STORE_ADD_ALWAYS, 0) = 0 Then
        LogError "frmKeyChange: CertInstall. step = " & Step & ". dll error id = " & Err.LastDllError
        Call CertFreeCertificateContext(pCert)
        Call CryptReleaseContext(hCP, 0)
        Call CertCloseStore(hStore, 0)
        Exit Function
    End If
    ' освободить ресурсы и уменьшить счетчик ссылок
    Step = 8
    Call CertCloseStore(hStore, 0)
    Call CertFreeCertificateContext(pCert)
    Call CryptReleaseContext(hCP, 0)
    CertInstall = True

Exit Function
Hook:
    LogError "frmKeyChange: CertInstall. step = " & Step & ". " & Err.description, eError
    CertInstall = False
End Function
Offline Семён  
#6 Оставлено : 8 мая 2013 г. 9:25:50(UTC)
Семён

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

Группы: Участники
Зарегистрирован: 31.07.2012(UTC)
Сообщений: 15

Сказал(а) «Спасибо»: 2 раз
Вопрос актуален.
Offline Kirill Sobolev  
#7 Оставлено : 8 мая 2013 г. 12:34:40(UTC)
Кирилл Соболев

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

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

Поблагодарили: 177 раз в 168 постах
Проверьте, что именно записывается в ссылку на ключ с помощью csptest -certprop.
Техническую поддержку оказываем тут
Наша база знаний
thanks 1 пользователь поблагодарил Кирилл Соболев за этот пост.
Семён оставлено 08.05.2013(UTC)
Offline Семён  
#8 Оставлено : 8 мая 2013 г. 13:50:19(UTC)
Семён

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

Группы: Участники
Зарегистрирован: 31.07.2012(UTC)
Сообщений: 15

Сказал(а) «Спасибо»: 2 раз
Кирилл, спасибо огромное за наводку!
В ссылке на ключ в имени контейнера присутствовали лишние символы, поэтому кейсет не мог найтись. В vb6 для получения указателя на широкую строку лучше пользоваться StrPtr(myString).
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.