Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.81/58: Рейтинг темы: голосов - 58, средняя оценка - 4.81
0 / 0 / 1
Регистрация: 01.09.2007
Сообщений: 5

HttpSendRequest ERROR_INTERNET_SECURITY_CHANNEL_ERROR 12157

05.11.2009, 18:20. Показов 12619. Ответов 1
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток

Согласно ТЗ необходимо обеспечить полнофункциональный диалог с сервером. Причем сервер использует "закрытый" сертификат. Сертификат был получен и установлен. При работе через браузер соединение проходит успешно.
При установке соединения SSL сервер выдает дополнительный запрос для авторизации. Ответ на который должен быть POST определенных данных.

Примечание: В ТЗ указано, что должна быть возможность посылать через указанный порт, поэтому не используем стандартный INTERNET_DEFAULT_HTTPS_PORT

Код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// используем модуль
# include <windows.h>
...
    // инициализируем WinInet
    m_hInternet = InternetOpen( m_lpszAgent,
                                        INTERNET_OPEN_TYPE_PRECONFIG,
                                        m_lpszHost,
                                        NULL,
                                        0);
 
    if (m_hInternet != NULL)
    {
 
        /// открываем HTTP сессию
        HINTERNET m_hConnect = InternetConnect(m_hInternet,
                                            m_lpszHost,
                                            m_lpszPort,
                                            NULL,NULL,
                                            INTERNET_SERVICE_HTTP,
                                            0,
                                            0);
 
        if (m_hConnect != NULL)
        {
            // открываем запрос
            HINTERNET m_hRequest = HttpOpenRequest(m_hConnect,
                                                  m_lpszMethod,
                                                  lpszAction,
                                                  NULL,
                                                  NULL,
                                                  0,
                                                  INTERNET_FLAG_KEEP_CONNECTION |
                                                  INTERNET_FLAG_DONT_CACHE |
                                                  INTERNET_FLAG_SECURE |
                                                  INTERNET_FLAG_IGNORE_CERT_CN_INVALID  |
                                                  INTERNET_FLAG_IGNORE_CERT_DATE_INVALID |
                                                  INTERNET_FLAG_NO_COOKIES,
 
        // добавленная метка изначально ее не было
        lAgain:
        ;
 
            if (m_hRequest != NULL) {
            // установка флагов игнорирования сертификатов
            DWORD dwSeqFlags = 0;
            DWORD dwBuffLen = sizeof(dwSeqFlags);
            InternetQueryOption (m_hRequest, INTERNET_OPTION_SECURITY_FLAGS, (LPVOID)&dwSeqFlags, &dwBuffLen);
 
            dwSeqFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA |
                                 INTERNET_FLAG_IGNORE_CERT_CN_INVALID  | 
                                 INTERNET_FLAG_IGNORE_CERT_DATE_INVALID;
 
            InternetSetOption (m_hRequest, INTERNET_OPTION_SECURITY_FLAGS, &dwSeqFlags, sizeof (dwSeqFlags) );
 
                     
             // выполним запрос
         if (::HttpSendRequest(
                    m_hRequest,
                    m_lpszDefaultHeader,
                    -1,
                    (LPVOID)lpszData,
                    lpszData? _tcslen(lpszData): 0) ) {
             // запрос в норме получи данные
 
              } else {
                  // здесь вылетает ошибка
                  DWORD dwError = GetLastError();
 
                  // закроем Request
                  InternetCloseHandle(m_hRequest);
                  m_hRequest = NULL;
 
                  // вернем неудачу
                  return false;
              }
 
// закрываем соединение
...
В большинстве случаев такой код подходит
Но при соединении с сервером с "закрытым" сертификатом вылетает ошибка ERROR_INTERNET_CLIENT_AUTH_CERT_NEE DED 12044

сертификат получен и установлен

Добавлено через 2 минуты
Два способа решения ошибки ERROR_INTERNET_CLIENT_AUTH_CERT_NEE DED 12044

Первый: Выведением окна с выбором сертификата

Код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
              // здесь вылетает ошибка
              DWORD dwError = GetLastError();
 
              // определим нужную ошибку
              if ( dwError == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED ){
 
                   if( InternetErrorDlg( GetDesktopWindow(), 
                             hReq,
                             ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED,
                             FLAGS_ERROR_UI_FILTER_FOR_ERRORS       |
                             FLAGS_ERROR_UI_FLAGS_GENERATE_DATA     |
                             FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, 
                             NULL) == ERROR_SUCCESS ){
                   // вывели окно повторим запрос немного криво не хотелось goto но пока так :(
                   goto lAgain ;
                   }
              }
 
              // закроем Request
              InternetCloseHandle(m_hRequest);
              m_hRequest = NULL;
 
              // вернем неудачу
              return false;
...
Второй: установим InternetSetOption INTERNET_OPTION_SECURITY_SELECT_CLI ENT_CERT
Код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
              // здесь вылетает ошибка
              DWORD dwError = GetLastError();
 
              // определим нужную ошибку
              if ( dwError == ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED ){
 
                        DWORD dwCert = 0;
                        InternetSetOption(m_hRequest, INTERNET_OPTION_SECURITY_SELECT_CLIENT_CERT, &dwCert, sizeof(dwCert));
 
                   // повторим запрос
                   goto lAgain ;
 
              }
 
              // закроем Request
              InternetCloseHandle(m_hRequest);
              m_hRequest = NULL;
 
              // вернем неудачу
              return false;
...
Примечание: Пока установила метку lAgain извините исправлю

Добавлено через 3 минуты
После всего этого мы получаем данные для повторной авторизации.
Отправляем данные сформированные из полученных с сервера методом POST. Опять вылетает ошибка ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED 12044. Снова вылетает окно с выбором сертификата, или не вылетает (если вторым способом) и опять данные авторизации.

Попробовала установить сертификат принудительно перед запросом HttpSendRequest
Код:
C++
1
2
3
4
5
6
7
8
// используем wincrypt.h crypt32.dll
# include <wincrypt.h>
...
                        // Установка сертификата перед запросом
                        PCCERT_CONTEXT pCert = NULL;
                        pCert = CertEnumCertificatesInStore(m_hSystemStore, pCert);
                        InternetSetOption(m_hRequest,INTERNET_OPTION_CLIENT_CERT_CONTEXT,(LPVOID)pCert,sizeof(CERT_CONTEXT));
...
m_hSystemStore получаем так
Код:
C++
1
2
3
4
...
    HCERTSTORE  m_hSystemStore;
    m_hSystemStore = CertOpenSystemStore(NULL, "My");
...
после запросов удаляем
Код:
C++
1
CertCloseStore(hSystemStore, 0);
Вылетает ошибка 12157 ERROR_INTERNET_SECURITY_CHANNEL_ERROR

Судя по данным pCert->pCertInfo выбирается нужный сертификат
Кто может подсказать решение проблемы?

Дополнительно сообщу, что m_hConnect и m_hInternet создается только при первом запросе, потом используется поэтому потеря сессии и создание новой не является причиной ошибки.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
05.11.2009, 18:20
Ответы с готовыми решениями:

Visual Studio 2017 C++ WinInet HTTPS. Ошибка 12157 на WinXP при вызове HttpSendRequest
Консольное приложение для получения страницы по HTTPS. exe-файл создан под VS-2017 C++ на Win7 64. Работает правильно, страницу по HTTPS...

Wininet, ошибка 12157 при попытке получить веб страницу
Доброго времени, посмотрел простенькие реализации получения кода веб странички, нашел подходящую. Когда попробовал все работает со многими...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
0 / 0 / 1
Регистрация: 01.09.2007
Сообщений: 5
08.11.2009, 11:11  [ТС]
Для решения проблемы ERROR_INTERNET_SECURITY_CHANNEL_ERR OR 12157 нужно воспользоваться CertFindCertificateInStore Function (Windows).

Код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
bool THttp::OpenSystemStore(){
    bool okOpenSystemStore = false;
    if(m_hSystemStore){
        // уже открыт
        okOpenSystemStore = true;
    }else{
        // пытаемся открыть
        okOpenSystemStore = (m_hSystemStore = CertOpenStore(
                                                            CERT_STORE_PROV_SYSTEM,
                                                            0,
                                                            NULL,
                                                            CERT_SYSTEM_STORE_CURRENT_USER,
                                                            L"MY"
                                                            ));
    }
    return okOpenSystemStore;
}
 
void THttp::FreeCert(){
    if(m_pCert){
        ::CertFreeCertificateContext(m_pCert);
        m_pCert = NULL;
    }
}
 
bool THttp::SetCert(const String _certSubject){
    bool okSetCert = false;
    if (OpenSystemStore()){
        // перенести
        WideString wstr(_certSubject);
        wchar_t*pCertSubject=wstr.c_bstr();
 
        FreeCert();
        okSetCert =
            (m_pCert = ::CertFindCertificateInStore(
                                                    m_hSystemStore,
                                                    PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
                                                    0,
                                                    CERT_FIND_SUBJECT_STR,
                                                    pCertSubject,
                                                    NULL));
        delete pCertSubject;
 
    }
    return okSetCert;
}
Перед поиском сертификата необходимо получить m_hSystemStore CertOpenStore.
m_pCert - глобальная переменная класса, в случае если она установлена перед запросом устанавливается сертификат.

Код:
C++
1
2
3
4
5
6
            // установить сертификат
            if (m_pCert)
                InternetSetOption(hRequest,INTERNET_OPTION_CLIENT_CERT_CONTEXT,(LPVOID)m_pCert,sizeof(CERT_CONTEXT));
 
                // дальше отправим запрос
                okSendRequest = ::HttpSendRequest(...
Перед запросом CertFindCertificateInStore необходимо, чтобы m_pCert был NULL. Дополнительная FreeCert() функция освобождает сертификат. Перед вызовом функции _certSubject приводится к уникоду. Это необходимо если CERT_FIND_SUBJECT_STR CertFindCertificateInStore не возвращает результат (и проект не уникод).

В конце работы необходимо очистить m_hSystemStore

Код:
C++
1
2
3
4
5
6
7
8
9
10
11
bool THttp::CloseSystemStore(){
    bool okCloseSystemStore = false;
    if(m_hSystemStore){
        // удалим сертификат
        FreeCert();
 
        okCloseSystemStore = ::CertCloseStore(m_hSystemStore, CERT_CLOSE_STORE_CHECK_FLAG);
        if (okCloseSystemStore) m_hSystemStore = NULL;
    }
    return okCloseSystemStore;
}
Функция возвращает true, если удаление прошло успешно и false, если ресурсы SystemStore заняты и их нельзя очистить.

Добавлено через 4 минуты
К сожаление так и не найден ответ. Теперь страницы получаем минуя этап ERROR_INTERNET_CLIENT_AUTH_CERT_NEE DED 12044. Сервер сразу выдает страницу авторизации. После отправки на него POST, тот же самый результат. Данные авторизации хранятся в сессии SSL, как их сохранят и получить так и не разобралась.

Может подскажете где копать?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Основы отладки веб-приложений на SDL3 по USB и Wi-Fi, запущенных в браузере мобильных устройств
8Observer8 07.02.2026
Содержание блога Браузер Chrome имеет средства для отладки мобильных веб-приложений по USB. В этой пошаговой инструкции ограничимся работой с консолью. Вывод в консоль - это часть процесса. . .
SDL3 для Web (WebAssembly): Обработчик клика мыши в браузере ПК и касания экрана в браузере на мобильном устройстве
8Observer8 02.02.2026
Содержание блога Для начала пошагово создадим рабочий пример для подготовки к экспериментам в браузере ПК и в браузере мобильного устройства. Потом напишем обработчик клика мыши и обработчик. . .
Философия технологии
iceja 01.02.2026
На мой взгляд у человека в технических проектах остается роль генерального директора. Все остальное нейронки делают уже лучше человека. Они не могут нести предпринимательские риски, не могут. . .
SDL3 для Web (WebAssembly): Вывод текста со шрифтом TTF с помощью SDL3_ttf
8Observer8 01.02.2026
Содержание блога В этой пошаговой инструкции создадим с нуля веб-приложение, которое выводит текст в окне браузера. Запустим на Android на локальном сервере. Загрузим Release на бесплатный. . .
SDL3 для Web (WebAssembly): Сборка C/C++ проекта из консоли
8Observer8 30.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
SDL3 для Web (WebAssembly): Установка Emscripten SDK (emsdk) и CMake для сборки C и C++ приложений в Wasm
8Observer8 30.01.2026
Содержание блога Для того чтобы скачать Emscripten SDK (emsdk) необходимо сначало скачать и уставить Git: Install for Windows. Следуйте стандартной процедуре установки Git через установщик. . . .
SDL3 для Android: Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 29.01.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами. Версия v3 была полностью переписана на Си, в. . .
Инструменты COM: Сохранение данный из VARIANT в файл и загрузка из файла в VARIANT
bedvit 28.01.2026
Сохранение базовых типов COM и массивов (одномерных или двухмерных) любой вложенности (деревья) в файл, с возможностью выбора алгоритмов сжатия и шифрования. Часть библиотеки BedvitCOM Использованы. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru