2009-11-25 33 views
1

當使用具有有效上下文的win32 API中的EncryptMessage(SChannel)時,我按照正確的順序提供了四個緩衝區我得到SEC_E_INVALID_TOKEN響應,根據文檔找到的是SECBUFFER_DATA類型的緩衝區。我知道pvBuffers的集合應該從連續的內存中分配出來以提高速度,但爲了簡單起見,我已經明確了它是什麼。任何人都可以看到問題可能是什麼?EncryptMessage返回SEC_E_INVALID_TOKEN

謝謝, 布魯斯

的代碼是下面;

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; 

我用STRACE注入到可執行文件中,這行看起來很有趣;

12/07/2009 23:10:30:635 - SecBuffer #0 BufferType:0x00000007 cbBuffer:5 
12/07/2009 23:10:30:636 - SecBuffer #1 BufferType:0x00000001 cbBuffer:13 
12/07/2009 23:10:30:636 - SECBUFFER_DATA - 13 byte(s)/EncryptMessage - INPUT 
===================================================== 
     00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0fabcdef 

0000: 68 65 6c 6c 6f 20 77 6f 72 6c 64 21 00   hello world!. 
===================================================== 
12/07/2009 23:10:30:636 - SecBuffer #2 BufferType:0x00000006 cbBuffer:36 
12/07/2009 23:10:30:636 - SecBuffer #3 BufferType:0x00000000 cbBuffer:0 
12/07/2009 23:10:30:636 - 

*** WARNING : EncryptMessage failed (80090308) *** 

看起來好像OS正在獲取正確的信息。

我已經搜索了一下,發現80090308通常意味着證書有問題,因爲服務器的全名應該在主題CN = www.foobar.com中,但是這並沒有解決問題,證書和CA由OpenSSL生成。

+0

很高興見到你macking進步 – 2009-11-25 00:46:40

+0

你能否證實'FSecPkgSizes.cbHeader'值是5,'InDataLength'值介於1和16362和'FSecPkgSizes.cbTrailer'值是16? – 2009-11-25 01:04:00

+0

是的,正在取得進展:)。再次感謝您的幫助。在這種情況下,cbHeader是5,InDataLength是23(它說它會抱怨,如果它太小),但cbTrailer是36而不是16,我硬編碼到16,但仍然沒有喜悅。 – Bruce 2009-11-25 01:17:11

回答

2

這裏有一些猜測,因爲這似乎是人們在嘗試使用Windows上的非對稱加密進行任何操作時遇到的常見問題。

如果它是自簽名CA並且您的證書是使用自簽名CA簽名的,則需要將CA導入到您計算機的受信任CA存儲區中。如果你

  1. 文件 - >添加/刪除管理單元

  2. 添加「證書」管理單元中,選擇「計算機帳戶」:

    要做到這一點,運行MMC並執行以下操作希望它適用於計算機上的所有用戶。

  3. 打開「受信任的根證書頒發機構 - >證書」樹節點。

  4. 右鍵單擊「證書」並選擇導入。

  5. 導入CA證書文件。 (應該接受沒有問題,經編碼版本的PEM)

雖然CN需要將機器的名稱,在大多數情況下,你的機器的認證匹配,如果CA不是CA驗證將失敗導入Windows信任存儲。

我希望它有幫助。

+0

感謝您考慮它,但是我已經可以從商店獲得一個有效的證書並握手。您是否建議您可以在握手的雙方獲得SEC_E_OK,並且由於證書不是「正確的」,EncryptMessage仍會失敗? – Bruce 2009-12-13 22:46:06

+0

上下文的建立可能只是一個3路TCP握手,並且在發送第一條消息之前它不會通過TLS/SSL握手。你可以看看Wireshark之​​類的連接,並且在嘗試加密消息之前,看看是否建立了不僅僅是TCP連接。如果SChannel在第一條消息之前延遲了TLS/SSL握手,那麼即使上下文成功建立後,它也可能會失敗。運行Filemon或Regmon(sysinternals)可能會在您訪問本地CA商店時顯示。 – Nathan 2009-12-14 01:26:40

+0

我正在處理我自己的代碼中的握手,來回傳遞「令牌」,直到SEC_E_OK和最後一個令牌傳輸完畢,所以我非常肯定握手已經發生。我一直在使用系統事件查看器來查看證書已經建立。 – Bruce 2009-12-14 03:56:05

1

當您在客戶端和服務器上設置您的上下文使用;

InitializeSecurityContext // Schannel Client 
AcceptSecurityContext // Schannel Server 

工資非常特別注意你傳遞你想要爲這方面的類型標誌確定類型SecBuffer(S),你需要兩個EncryptMessage和DecryptMessage的。例如,我正在使用;

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 

並且對於DecryptMessage你還需要4個SecBuffers;

SECBUFFER_DATA 
SECBUFFER_EMPTY 
SECBUFFER_EMPTY 
SECBUFFER_EMPTY 

我的問題是,我有* _REQ_STREAM和* _REQ_CONNECTION其上的文件細讀基本上是不兼容的。這是最重要的,以確保您有一個有效的證書/信任等

我希望這可以幫助某人。

布魯斯