SChannel, SEC_E_ALGORITHM_MISMATCH (0x80090331)
Дни устранения неполадок, поиска решений и перечитывания документации Microsoft по необходимым функциям. Изменение переменных, повторная попытка снова и снова. Помощь очень ценится, я уверен, что это не только я столкнулся с этим.
Я работаю над реализацией сетевых клиентских и серверных приложений, которые взаимодействуют со слоем SSL/TLS с использованием SChannel (и позже я также получу эту работу с OpenSSL для перекрестной совместимости). У меня есть клиент, который, как известно, работает, поэтому мы можем сосредоточиться на стороне сервера.
На данный момент цель состоит в том, чтобы заставить его работать без предоставления сертификата с обеих сторон (они должны просто генерироваться на лету при необходимости). Я выполняю AcquireCredentialsHandle, загружаю исходный токен с клиента (работающего на том же хосте) и вызываю AcceptSecurityContext.
Кажется, что независимо от того, какую переменную я изменяю, я всегда получаю ту же ошибку 0x80090331 при первом вызове AcceptSecurityContext. Протестировано на Windows 7 и Windows Server 2012.
Мне кажется, что вне моего кода должно быть что-то, параметр ОС, который мне нужно исправить. Я нахожу противоречивую информацию в Интернете. TLS 1.1 и TLS 1.2 были добавлены в реестр по адресу SecurityProviders\SCHANNEL\Protocols* и установлены с данными DisabledByDefault=0. Также добавлено ", schannel.dll" в "SecurityProviders".
Код выглядит следующим образом:
... snip... (код для вызова AcquireCredentialsHandle)
PCCERT_CONTEXT serverCerts[1] = {0};
SCHANNEL_CRED sc = {0};
sc.dwVersion = SCHANNEL_CRED_VERSION;
//sc.grbitEnabledProtocols = SP_PROT_SSL3_SERVER | SP_PROT_TLS1_SERVER | SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER;
sc.grbitEnabledProtocols = SP_PROT_TLS1_1_SERVER | SP_PROT_TLS1_2_SERVER;
sc.dwFlags = 0;
sc.cCreds = 0; // Let Crypto API find the appropriate certificate for us
sc.paCred = serverCerts;
TimeStamp tsExpiry;
SECURITY_STATUS status = AcquireCredentialsHandle(
NULL,
UNISP_NAME,
SECPKG_CRED_INBOUND,
NULL,
&sc,
NULL,
NULL,
&hCredential,
&tsExpiry);
std::cout << "AcquireCredentialsHandle result = 0x" << std::hex << status << std::endl;
... snip... (код для вызова AcceptSecurityContext)
// TOKEN is received from client into m_receivedData
//std::vector<char> m_receivedData;
m_ctxtFlags = ASC_REQ_ALLOCATE_MEMORY | ASC_REQ_STREAM;
SecBuffer inBuffers[2];
// Provide Schannel with the remote host's handshake data
inBuffers[0].pvBuffer = (char*)(&m_receivedData[0]);
inBuffers[0].cbBuffer = (unsigned long)m_receivedData.size();
inBuffers[0].BufferType = SECBUFFER_TOKEN;
inBuffers[1].pvBuffer = NULL;
inBuffers[1].cbBuffer = 0;
inBuffers[1].BufferType = SECBUFFER_EMPTY;
SecBufferDesc inBufferDesc = {0};
inBufferDesc.cBuffers = 2;
inBufferDesc.pBuffers = inBuffers;
inBufferDesc.ulVersion = SECBUFFER_VERSION;
SecBuffer outBuffers[2];
// We let Schannel allocate the output buffer for us
outBuffers[0].pvBuffer = NULL;
outBuffers[0].cbBuffer = 0;
outBuffers[0].BufferType = SECBUFFER_TOKEN;
// Contains alert data if an alert is generated
outBuffers[1].pvBuffer = NULL;
outBuffers[1].cbBuffer = 0;
outBuffers[1].BufferType = SECBUFFER_ALERT;
SecBufferDesc outBufferDesc = {0};
outBufferDesc.cBuffers = 2;
outBufferDesc.pBuffers = outBuffers;
outBufferDesc.ulVersion = SECBUFFER_VERSION;
unsigned long fContextAttr;
TimeStamp tsTimeStamp;
SECURITY_STATUS status = NULL;
if (isFirstCall) {
status = AcceptSecurityContext(
&hCredential,
NULL,
&inBufferDesc,
m_ctxtFlags,
0,
&hNewContext,
&outBufferDesc,
&fContextAttr,
NULL);
std::cout << "AcceptSecurityContext (isFirstCall) result = 0x" << std::hex << status << std::endl;
}
1 ответ
SSL/TLS требует сертификат на стороне сервера. Отсутствующий сертификат на стороне сервера генерирует ошибку 0x80090331. Следующим шагом является создание самозаверяющего сертификата по мере необходимости. См. CertCreateSelfSignCertificate. Пример A C с использованием CryptoAPI можно найти здесь.