2009-11-25 5 views
1

При использовании EncryptMessage (SChannel) из API win32 с допустимым контекстом я поставляю четыре буфера в правильном порядке. Я получаю ответ 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) *** 

Как выглядит операционная система, получающая правильную информацию.

Я немного искал и обнаружил, что 80090308 обычно означает что-то неправильное с сертификатом, так как полное имя сервера должно быть в теме CN = www.foobar.com, но это не устраняет проблему либо , сертификат и CA создаются с помощью OpenSSL.

+0

Рад видеть, что вы Macking прогресс –

+0

Можете ли вы подтвердить, что 'значение FSecPkgSizes.cbHeader' 5,' значение InDataLength' между 1 и 16362 и 'значение FSecPkgSizes.cbTrailer' 16? –

+0

Да, достигнув прогресса :). Еще раз спасибо за вашу помощь. В этом случае cbHeader равен 5, InDataLength равно 23 (он говорит, что будет жаловаться, если он слишком мал), но cbTrailer 36 не 16, я жестко закодировал его до 16, но до сих пор не радует. – Bruce

ответ

2

В некоторой степени это предположение, так как это похоже на общую проблему, с которой сталкиваются люди при попытке сделать что-либо с асимметричным криптографическим кодом в Windows.

Если это самоподписанный ЦС, и ваш сертификат подписан с самоподписанным ЦС, вам необходимо импортировать ЦС в доверенное хранилище ЦС вашего компьютера.

Для этого запустите MMC и выполните следующие действия:

  1. Файл-> Добавить/Удалить оснастку в

  2. Добавить в "Сертификаты" защелкиваются и выберите "Computer Account", если вы хотите, чтобы он применялся для всех пользователей на компьютере.

  3. Открываем узел дерева доверенных корневых сертификатов-> сертификатов.

  4. Щелкните правой кнопкой мыши на «Сертификаты» и выберите импорт.

  5. Импортировать файл сертификата CA. (Он должен принять PEM кодированного версию без проблем.)

Хотя CN нужно будет совпадать с именем машины в вашем сертификате машины в большинстве случаев, проверка CA потерпит неудачу, если CA не импортированных в хранилище доверия Windows.

Надеюсь, это поможет.

+0

Спасибо за то, что подумал об этом, однако я уже могу получить действительный сертификат из магазина и рукопожатие. Вы предлагаете, чтобы вы могли получить SEC_E_OK для обеих сторон рукопожатия, и все же EncryptMessage потерпит неудачу из-за того, что сертификат не является «правильным»? – Bruce

+0

Возможно, что установление контекста - это всего лишь трехстороннее рукопожатие TCP и что оно не проходит через квитирование TLS/SSL до тех пор, пока не будет отправлено первое сообщение. Вы можете посмотреть соединение с чем-то вроде Wireshark и посмотреть, установлено ли больше, чем только TCP-соединение, прежде чем пытаться зашифровать сообщение. Если SChannel задерживает квитирование TLS/SSL до первого сообщения, возможно, что он действительно завершится неудачно даже после того, как контекст будет успешно установлен. Запуск Filemon или Regmon (sysinternals) может показать вам, когда он также обращается к локальному хранилищу CA. – Nathan

+0

Я обрабатываю рукопожатие в своем собственном коде, передавая «маркеры» туда и обратно, пока SEC_E_OK и последний токен не были переданы, поэтому я уверен, что произошло рукопожатие. Я использую средство просмотра событий системы, чтобы увидеть, что учетные данные были установлены. – Bruce

1

Когда вы настраиваете свой контекст как на клиенте, так и на сервере;

InitializeSecurityContext // Schannel Client 
AcceptSecurityContext // Schannel Server 

платят очень особое внимание на флаги, которые Вы передаете в для типа контекста вы хотите, как определяет типы SecBuffer (ы), что нужно для обоих 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 of;

SECBUFFER_STREAM_HEADER 
SECBUFFER_DATA 
SECBUFFER_STREAM_TRAILER 
SECBUFFER_EMPTY 

и для DecryptMessage вам также нужны четыре SecBuffers of;

SECBUFFER_DATA 
SECBUFFER_EMPTY 
SECBUFFER_EMPTY 
SECBUFFER_EMPTY 

Моя проблема заключалась в том, что у меня был * _REQ_STREAM и * _REQ_CONNECTION, который при внимательном чтении документации по существу несовместимы. Это относится к тому, что у вас есть действующий сертификат/доверенный и т. Д.

Надеюсь, это поможет кому-то.

Брюс

 Смежные вопросы

  • Нет связанных вопросов^_^