客户端使用 SChannel 处理 DTLS 连接,服务器使用 OpenSSL。在客户端尝试关闭连接之前一切正常(我使用了本指南)。
这是客户端关闭例程:
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_ret;
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
DWORD dwshut = SCHANNEL_SHUTDOWN;
Buffer->BufferType = SECBUFFER_TOKEN;
Buffer->pvBuffer = &dwshut;
Buffer->cbBuffer = sizeof(dwshut);
init_sec_buffer_desc(&BuffDesc, &Buffer, 1);
sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);
if (sspi_ret != SEC_E_OK)
log(h, LOG_ERROR, "ApplyControlToken failed\n");
outbuf->BufferType = SECBUFFER_EMPTY;
outbuf->pvBuffer = NULL;
outbuf->cbBuffer = 0;
init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
&outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) {
ret = write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
FreeContextBuffer(outbuf.pvBuffer);
if (ret < 0 || ret != outbuf.cbBuffer)
log(h, LOG_ERROR, "Failed to send close message\n");
}
问题是 InitializeSecurityContext 返回 SEC_E_INVALID_TOKEN 并且不初始化输出缓冲区 - 所以我没有要发送到服务器的 close_notify 消息。
在这一点上,我不确定我是否做错了什么,或者我不能指望 SChannel 能够根据 OpenSSL 的关闭例程工作。任何帮助将不胜感激!
编辑
按照建议,我尝试使用不同的令牌类型 - SECBUFFER_TOKEN。因为我不使用 ISC_REQ_ALLOCATE_MEMORY 标志,所以我分配了一个缓冲区。我得到了 SEC_I_MESSAGE_FRAGMENT,所以我添加了一个循环。
现在它返回 SEC_I_MESSAGE_FRAGMENT 两次,第三次调用返回 SEC_E_INVALID_HANDLE。有任何想法吗?
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_ret;
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
DWORD dwshut = SCHANNEL_SHUTDOWN;
Buffer->BufferType = SECBUFFER_TOKEN;
Buffer->pvBuffer = &dwshut;
Buffer->cbBuffer = sizeof(dwshut);
init_sec_buffer_desc(&BuffDesc, &Buffer, 1);
sspi_ret = ApplyControlToken(&c->ctxt_handle, &BuffDesc);
if (sspi_ret != SEC_E_OK)
log(h, LOG_ERROR, "ApplyControlToken failed\n");
BYTE output_msg[MAX_MSG_SIZE];
memset(output_msg, 0, MAX_MSG_SIZE);
outbuf->BufferType = SECBUFFER_TOKEN;
outbuf->pvBuffer = output_msg;
outbuf->cbBuffer = MAX_MSG_SIZE;
init_sec_buffer_desc(&outbuf_desc, &outbuf, 1);
int size = 0;
do {
sspi_ret = InitializeSecurityContext(&c->cred_handle, &c->ctxt_handle, s->host,
c->request_flags, 0, 0, NULL, 0, &c->ctxt_handle,
&outbuf_desc, &c->context_flags, &c->ctxt_timestamp);
if (sspi_ret == SEC_I_MESSAGE_FRAGMENT) {
size += outbuf->cbBuffer;
outbuf.pvBuffer = output_msg + size;
outbuf.cbBuffer = MAX_MSG_SIZE;
}
} while (sspi_ret == SEC_I_MESSAGE_FRAGMENT);
if (sspi_ret == SEC_E_OK || sspi_ret == SEC_I_CONTEXT_EXPIRED) {
ret = write(s->tcp, outbuf.pvBuffer, outbuf.cbBuffer);
FreeContextBuffer(outbuf.pvBuffer);
if (ret < 0 || ret != outbuf.cbBuffer)
log(h, LOG_ERROR, "Failed to send close message\n");
}