Winapi EncryptMessage返回SEC_E_无效\u令牌

Winapi EncryptMessage返回SEC_E_无效\u令牌,winapi,sspi,schannel,Winapi,Sspi,Schannel,在使用win32 API的EncryptMessage(SChannel)和有效上下文时,我按照正确的顺序提供了四个缓冲区。我得到了SEC_E_INVALID_令牌响应,根据文档,没有找到SECBUFFER_数据类型缓冲区。我知道,为了提高速度,应该从连续内存中分配pvBuffers集,但为了简单起见,我已经明确说明了这是什么。有人知道问题出在哪里吗 谢谢, 布鲁斯 代码如下: procedure TTCPSocket.SSPEncryptBuffer(SSPCtx: PCtxtHandle;

在使用win32 API的EncryptMessage(SChannel)和有效上下文时,我按照正确的顺序提供了四个缓冲区。我得到了SEC_E_INVALID_令牌响应,根据文档,没有找到SECBUFFER_数据类型缓冲区。我知道,为了提高速度,应该从连续内存中分配pvBuffers集,但为了简单起见,我已经明确说明了这是什么。有人知道问题出在哪里吗

谢谢, 布鲁斯

代码如下:

procedure TTCPSocket.SSPEncryptBuffer(SSPCtx: PCtxtHandle; InData: PAnsiChar; InDataLength: Cardinal);
var
  SecStatus: TSecurityStatus;

  SecBufDesc: TSecBufferDesc;
  SecBufs: packed array [0 .. 3] of TSecBuffer;
begin
  SecBufs[0].BufferType := SECBUFFER_STREAM_HEADER;
  SecBufs[0].cbBuffer := FSecPkgSizes.cbHeader;
  SecBufs[0].pvBuffer := AllocMem(FSecPkgSizes.cbHeader); 

  SecBufs[1].BufferType := SECBUFFER_DATA;
  SecBufs[1].cbBuffer := InDataLength; 
  SecBufs[1].pvBuffer := InData; 

  SecBufs[2].BufferType := SECBUFFER_STREAM_TRAILER;
  SecBufs[2].cbBuffer := FSecPkgSizes.cbTrailer;
  SecBufs[2].pvBuffer := AllocMem(FSecPkgSizes.cbTrailer);

  SecBufs[3].BufferType := SECBUFFER_EMPTY;
  SecBufs[3].cbBuffer := 0;
  SecBufs[3].pvBuffer := nil;

  SecBufDesc.ulVersion := SECBUFFER_VERSION;
  SecBufDesc.cBuffers := 4;
  SecBufDesc.pBuffers := @SecBufs[0];

  SecStatus := EncryptMessage(SSPCtx, 0, @SecBufDesc, 0);

  if SecStatus <> SEC_E_OK then
  begin
    // Error code..
  end;
end;
看起来操作系统获得了正确的信息


我搜索了一下,发现80090308通常意味着证书有问题,因为服务器的全名应该在主题中,CN=www.foobar.com,但这也没有解决问题,证书和CA是使用OpenSSL生成的。

这里有点猜测,因为这似乎是人们在Windows上尝试使用非对称加密时遇到的常见问题

如果是自签名CA,并且您的证书是使用自签名CA签名的,则需要将CA导入计算机的受信任CA存储

要执行此操作,请运行MMC并执行以下操作:

  • 文件->添加/删除管理单元

  • 添加“证书”管理单元,并选择“计算机帐户”,如果您希望它适用于计算机上的所有用户

  • 打开“受信任的根证书颁发机构->证书”树节点

  • 右键单击“证书”并选择导入

  • 导入CA证书文件。(它应该毫无问题地接受PEM编码的版本。)

  • 虽然在大多数情况下,CN需要与计算机证书中的计算机名称匹配,但如果未将CA导入Windows信任存储,CA验证将失败


    我希望它能有所帮助。

    当您在客户端和服务器上使用

    InitializeSecurityContext // Schannel Client
    AcceptSecurityContext // Schannel Server
    
    请特别注意为您想要的上下文类型传入的标志,因为它决定了EncryptMessage和DecryptMessage所需的SecBuffer类型。例如,我目前正在使用

      FClientContextFlags :=
        ISC_REQ_CONFIDENTIALITY or
        ISC_REQ_STREAM or
        ISC_REQ_ALLOCATE_MEMORY;
    
      FServerContextFlags :=
        ASC_REQ_CONFIDENTIALITY or
        ASC_REQ_STREAM or
        ASC_REQ_ALLOCATE_MEMORY;
    
    这意味着对于EncryptMessage,您需要四个SecBuffers

    SECBUFFER_STREAM_HEADER
    SECBUFFER_DATA
    SECBUFFER_STREAM_TRAILER
    SECBUFFER_EMPTY
    
    SECBUFFER_DATA
    SECBUFFER_EMPTY
    SECBUFFER_EMPTY
    SECBUFFER_EMPTY
    
    对于解密消息,您还需要四个SecBuffers

    SECBUFFER_STREAM_HEADER
    SECBUFFER_DATA
    SECBUFFER_STREAM_TRAILER
    SECBUFFER_EMPTY
    
    SECBUFFER_DATA
    SECBUFFER_EMPTY
    SECBUFFER_EMPTY
    SECBUFFER_EMPTY
    
    我的问题是我有*_-REQ_流和*_-REQ_连接,仔细阅读文档后发现它们基本上是不兼容的。这是在确保您拥有有效的证书/受信任的证书等的基础上进行的

    我希望这对某人有帮助


    Bruce

    很高兴看到您正在进行压缩。您能否确认
    FSecPkgSizes.cbHeader
    值为5,
    InDataLength
    值介于1和16362之间,
    FSecPkgSizes.cbTrailer
    值为16?是的,正在进行压缩:)。再次感谢你以前的帮助。在本例中,cbHeader是5,InDataLength是23(它说如果太小它会抱怨),但CBTraile是36而不是16,我硬编码为16,但仍然没有乐趣。我已经对您提到的关于“解决方案”的问题()添加了一条注释。感谢您的思考,但是,我已经可以从商店获得有效的证书,而且握手可以正常工作。您是否建议您可以在握手双方都获得SEC_E__OK,但由于证书不“正确”,EncryptMessage仍将失败?可能上下文的建立只是一个3向TCP握手,并且在发送第一条消息之前不会进行TLS/SSL握手。您可以使用Wireshark之类的工具查看连接,并在尝试加密消息之前查看是否建立了TCP连接以外的连接。如果SChannel将TLS/SSL握手延迟到第一条消息,那么即使在成功建立上下文之后,它也可能确实失败。运行Filemon或Regmon(sysinternals)可能也会显示它何时访问本地CA存储。我正在用自己的代码处理握手,来回传递“令牌”,直到secu__OK和最后一个令牌被传输,所以我非常确定握手已经发生。我一直在使用系统事件查看器查看凭据是否已建立。