0

客户端使用 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");
         }
4

0 回答 0