332: Некорректный получатель сообщения.

Автор NPS, 30 Май 2012, 16:24:10

« предыдущая тема - следующая тема »

0 Пользователей и 1 Гость просматривают эту тему.

Вниз

NPS

Добрый день!

с ЦП разобрался, теперь к шифрованию...

Шифрую сообщение, складываю результат в файл, в другой процедуре открываю полученный файл пытаюсь расшифровать, в результате чего получаю сообщение об ошибке "332: Некорректный получатель сообщения.".

Сначала думал, что УЦ КЦМР возвращает из хранилища не один сертификат и переделал свои функции на загрузку сертификата из файла.. В конфигураторе  TumarCSP (4.2) экспортировал сертификаты в папку с ключами. Тот,что сиреневым шрифтом в списке ключей конфигуратора выделен назвал "certExch.cer", а тот что голубым "certSign.cer". Первый использую для функций шифрования\дешифрования, второй для функций формирования\проверки ЦП.

С ЦП, с тех пор как были исправлены некоторые ошибки в коде и после перехода на чтение сертификатов с локального диска, проблем как не было так и не возникло. А вот с шифрованием\дешифрованием проблемы остались..

код:
Шифрование:

function CryptStream(inData: TMemoryStream;
                     ProfileName, host, port: AnsiString;
                     var ErrMsg: string): TMemoryStream;
const
  DATA_OID   = '1.2.840.113549.1.7.2';
  CRYPT_OID  = '1.3.6.1.4.1.6801.1.2.4';
  DESCRIPTOR = 'DESCRIPTOR';
var
  hProv: HCRYPTPROV;
  hStore: Cardinal;
  hContext: hCERTCONTEXT;
  hCrypt: hCRYPTMSG;
  dataS, cmsBlob, cmcBlob: LPSTR;
  res: DWORD;
  i: integer;
  DName: LPSTR;
  crtSign, data, encryptBlob: pByte;
  DN: AnsiString;
  DNames: PAnsiChar;
  cmsSize, certSize, hCOLLECTION,
  sizeBlob, dataSize: ULONG;
  s: string;
  f: TFileStream;
  fln: integer;
begin
  try
    try
      ErrMsg := '';
      Result := TMemoryStream.Create;
      res := 0;
      hProv := 0;
      Dname := 'c=KZ;';
      DN := 'c=KZ;o=APLAT;cn=APLATTESTNPS;ou=NPS';
      hContext := 0;
      hCOLLECTION := 0;
      DNames := nil;
      hStore := 0;

      res := CSPOpenContext(@hProv, PAnsiChar(ProfileName), 25, 0, 0,
                            nil, 0, nil, nil, nil);
      if res <> 0 then
      begin
        s := ErrorString(res);
        raise Exception.Create('CSPOpenContext - ошибка ' + IntToStr(res) + ': ' + s);
      end;

      i := CrtOpenStore(CRT_STORE_PROV_FILE, hProv, 0, false, nil, @hStore);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrtOpenStore - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      i := CrtSetStorePropertyExt(hStore, 0, 't=L;', PAnsiChar(host),
                                  PAnsiChar(port), 300, nil, nil);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrtSetStorePropertyExt - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      try
        try
          f := TFileStream.Create('certExch.cer', fmShareDenyNone);
          certSize := f.Size;
          GetMem(crtSign, certSize);
          f.Position := 0;
          f.Read(crtSign^, certSize);
        except
          raise Exception.Create('ошибка отрытия файла сертификата');
        end;
      finally
        f.Free;
      end;

      i := GetCertificateContext(hStore, crtSign, certSize, @hContext);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('GetCertificateContext - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      i := CrptMsgOpen(hProv, 0, @hCrypt);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrptMsgOpen - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      GetMem(DNames, 2048);
      FillMemory(DNames, 2048, 0);
      CopyMemory(DNames, @DN[1], Length(DN));

      i := GetCertificateCollection(hStore, hContext, '', 1,
                                    @DNames, @hCOLLECTION);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('GetCertificateCollection - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      dataSize := inData.Size;
      GetMem(data, dataSize);
      inData.Position := 0;
      inData.Read(data^, dataSize);

      i := CryptMessage(hCrypt, hCollection, hContext,
                        PAnsiChar(CRYPT_OID),
                        PAnsiChar(DATA_OID),
                        true,
                        data,
                        dataSize,
                        PAnsiChar(DESCRIPTOR), 1, nil, @sizeBlob);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CryptMessage - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      GetMem(encryptBlob, sizeBlob);
      i := CryptMessage(hCrypt, hCollection,hContext,
                        PAnsiChar(CRYPT_OID),
                        PAnsiChar(DATA_OID),
                        true,
                        data,
                        dataSize,
                        PAnsiChar(DESCRIPTOR), 1, encryptBlob, @sizeBlob);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CryptMessage - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      Result.Write(encryptBlob^, sizeBlob);

    except on E: Exception do
      ErrMsg := E.Message
    end;
  finally
    if hStore <> 0 then
    begin
      ReleaseCertificateContext(hStore, @hContext);
      CrtCloseStore(hStore);
    end;
    if hProv > 0 then CSPCloseContext(@hProv);
    FreeMem(Data);
    FreeMem(cmcBlob);
    FreeMem(cmsBlob);
    FreeMem(crtSign);
    FreeMem(DNames);
    FreeMem(encryptBlob)
  end;
end;


Дешифрование:
function DecryptStream(inData: TMemoryStream;
                       ProfileName, host, port: AnsiString;
                       var ErrMsg: string): TMemoryStream;
const
  DATA_OID   = '1.2.840.113549.1.7.2';
  CRYPT_OID  = '1.3.6.1.4.1.6801.1.2.4';
  DESCRIPTOR = 'DESCRIPTOR';
var
  hProv: HCRYPTPROV;
  hStore: Cardinal;
  hContext: hCERTCONTEXT;
  hCrypt: hCRYPTMSG;
  dataS, cmsBlob, cmcBlob: LPSTR;
  res: DWORD;
  i: integer;
  DName, SenderName, timeToCrypted, dataDescriptor: LPSTR;
  crtSign, inBlob, OutData: pByte;
  DN: AnsiString;
  cmsSize, cmcSize, certSize, hCOLLECTION,
  sizeBlob, dataSize, OutSize: ULONG;
  s: string;
  f: TFileStream;
begin
  try
    try
      res := 0;
      hProv := 0;
      ErrMsg := '';
      Result := TMemoryStream.Create;
      Dname := 'c=KZ';
      DN := 'c=KZ;o=aplat.kz;cn=TEST;';
      hContext := 0;
      hCOLLECTION := 0;
      hStore := 0;

      res := CSPOpenContext(@hProv, PAnsiChar(ProfileName), 25, 0, 0,
                            nil, 0, nil, nil, nil);
      if res <> 0 then
      begin
        s := ErrorString(res);
        raise Exception.Create('CSPOpenContext - ошибка ' + IntToStr(res) + ': ' + s);
      end;

      i := CrtOpenStore(CRT_STORE_PROV_FILE, hProv, 0, false, nil, @hStore);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrtOpenStore - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      sizeBlob := inData.Size;
      GetMem(inBlob, sizeBlob);
      inData.Position := 0;
      inData.Read(inBlob^, sizeBlob);

      i := CrtSetStorePropertyExt(hStore, 0, 't=L;', PAnsiChar(host),
                                  PAnsiChar(port), 30, nil, nil);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrtSetStorePropertyExt - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      try
        try
          f := TFileStream.Create('certExch.cer', fmShareDenyNone);
          certSize := f.Size;
          GetMem(crtSign, certSize);
          f.Position := 0;
          f.Read(crtSign^, certSize);
        except
          raise Exception.Create('ошибка отрытия файла сертификата');
        end;
      finally
        f.Free;
      end;

      i := GetCertificateContext(hStore, crtSign, certSize, @hContext);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('GetCertificateContext - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      i := CrptMsgOpen(hProv, 0, @hCrypt);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('CrptMsgOpen - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      i := GetMessageCertificate(hStore, inBlob, sizeBlob, @hCOLLECTION);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('GetMessageCertificate - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      i := DECryptMessage(hCrypt, hCollection, hContext,
                          false,
                          inBlob,
                          sizeBlob,
                          SenderName,
                          timeToCrypted,
                          dataDescriptor,
                          nil, @outsize);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('DECryptMessage - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      GetMem(OutData, outsize);
      i := DeCryptMessage(hCrypt, hCollection,hContext,
                          true,
                          inBlob,
                          sizeBlob,
                          SenderName,
                          timeToCrypted,
                          dataDescriptor,
                          OutData, @outsize);
      if i <> 0 then
      begin
        s := ErrorString(i);
        raise Exception.Create('DECryptMessage - ошибка ' + IntToStr(i) + ': ' + s);
      end;

      Result.Write(OutData^, outsize);

    except on E: Exception do
      ErrMsg := E.Message
    end;
  finally
    if hStore <> 0 then
    begin
      ReleaseCertificateContext(hStore, @hContext);
      CrtCloseStore(hStore);
      //FreeMem(hStore);
    end;
    if hProv > 0 then CSPCloseContext(@hProv);
    FreeMem(cmcBlob);
    FreeMem(cmsBlob);
    FreeMem(crtSign);
  end;
end;


прототипы внешних функций:
  function CryptMessage(const hCrypt: hCRYPTMSG;
                        const hCollection: hCERTCOLLECTION;
                        const MYCert: hCERTCONTEXT;
                        const cryptOID: LPSTR;
                        const dataOID: LPSTR;
                        const bFinal: boolean;
                        dataToEncrypted: pByte;
                        dataSize: ULONG;
                        const dataDescriptor: LPSTR;
                        const Flags: ULONG;
                        encryptedBlob: pByte;
                        sizeBlob: pULONG): integer; cdecl;

  function DecryptMessage(const hCrypt: hCRYPTMSG;
                          const hCollection: hCERTCOLLECTION;
                          const MYCert: hCERTCONTEXT;
                          const bFinal: boolean;
                          const encryptedBlob: pByte;
                          const sizeBlob: ULONG;
                          SenderName: LPSTR;
                          timeToCrypted: LPSTR;
                          dataDescriptor: LPSTR;
                          dataToDecrypted: pByte;
                          dataSize: pULONG): integer; cdecl;

  function CryptMessage; external LIB name 'CryptMessage';
  function DecryptMessage; external LIB name 'DecryptMessage';


При этом сервер КЦМР тоже не может расшифровать подписанные и зашифрованные мною сообщения...

Где и что я сделал не так, подскажите, пожалуйста?

Прилагаю файл с зашифрованным сообщением (думаю, что сертификат, хоть он и тестовый, с помощью которого я шифровал сообщение, сюда выклатывать не строит - скину в личку или на почту специалистам "Гаммы" по запросу)

Sergey

Добрый день.
Схема шифрования сообщения должна быть такая:
1. Необходимо загрузить собственные ключи
res := CSPOpenContext(@hProv, PAnsiChar(ProfileName), 25, 0, 0, nil, 0, nil, nil, nil);
ProfileName - должен указывать на профайл со своими ключами.
2. Необходимо загрузить сертификат получателя т.е. на закрытом ключе данного пользователя будет расшифровываться сообщение.
f := TFileStream.Create('certExch.cer', fmShareDenyNone);
certExch.cer - сертификат получателя.
3. Зашифровать сообщение.

Схема расшифровки сообщения:
1. Загрузить ключи для расшифровывания
res := CSPOpenContext(@hProv, PAnsiChar(ProfileName), 25, 0, 0, nil, 0, nil, nil, nil);
ProfileName - должен указывать на ключ соответствующий сертификату загруженному на шаге 2 при шифровании.
2. Загрузить свой сертификат
f := TFileStream.Create('certExch.cer', fmShareDenyNone);
certExch.cer - должен указывать на сертификат соответствующий ключам загруженным на шаге 1 при шифровании.
3. Расшифровать сообщение.

ЦитироватьПри этом сервер КЦМР тоже не может расшифровать подписанные и зашифрованные мною сообщения...

Это происходит из-за того что для шифрования вы используете свой сертификат а не сертификат сервера КЦМР.

NPS

Позже специалисты КЦМР предоставили мне свой сертификат для зашифровывания сообщения...
с этим сертификатом я зашифровал сообщение и отправил на сервер КЦМР.. но результат тот-же - на сервере мое сообщение не расшифровывается..

Sergey

Добрый день.
В вашем коде есть небольшая неточность:
i := GetCertificateCollection(hStore, hContext, '', 1, @DNames, @hCOLLECTION);
а должно быть так:
i := GetCertificateCollection(hStore, hStore, '', 1, @DNames, @hCOLLECTION);

NPS

Спасибо! исправил.
но сервер КЦМР все равно выдает ошибку 332 при получении моего сообщения.
Теперь хочу выяснить следующее:

в документе, описывающем протокол взаимодействия с системой APlat говорится:

Цитировать1. Подписать сообщение закрытым ключом банка, с вложением открытого ключа банка. Полученный результат формируется в формате PKCS7.
2. Полученный пакет зашифровать открытым ключом системы Авангард Plat.
3. Результату шифрования добавить в конце строку «<EOPCP>» в двоичном виде и отправить на сервер Авангард Plat.


из чего не понятно:
1. Выгруженный мной cer-файл (certSign.cer) из конфигуратора Тумар не содержит закрытого ключа. Где его взять? И, если закрытый ключ для подписи будет находиться в отдельном cer-файле, то как выполнить вложение открытого ключа в функции SignMessage?
2. Да, так и делаю: шифрую сообщение, используя cer-файл, полученный от КЦМР.
3. Строку, как и указано, добавляю.

Возможно ли то, что мое сообщение на севере КЦМР расшифровывается верно, но проверка ЦП не проходит?
в логе сервера КЦМР, при получении моего сообщения пишется:
ЦитироватьDECRYPT:IDTerminal = 754 error(DecryptMessage(1)): 332

Sergey

Добрый день.
Цитироватьсервер КЦМР все равно выдает ошибку 332 при получении моего сообщения.

Ошибка 332 означает некорректный отправитель сообщения (VAR_BAD_RECIPIENT), возможно
это связано с тем что вкладывается неправильный сертификат в сообщение. На что можно обратить внимание:

  • Данный сертификат должен быть выпущен тем же УЦ что и сертификат сервера (скорее всего по информации из
       зашифрованного сообщения происходит поиск данного сертификата в хранилище сертификатов и он там не находится)

  • Вложен сертификат на подпись, т.е. его открытый ключ имеет в начале 06 02 00 00 3a aa должен быть 06 02 00 00 45 a0



Цитировать1. Выгруженный мной cer-файл (certSign.cer) из конфигуратора Тумар не содержит закрытого ключа. Где его взять? И, если закрытый ключ для подписи будет находиться в отдельном cer-файле, то как выполнить вложение открытого ключа в функции SignMessage?

В первом пункте необходимо сформировать подпись в формате PKCS#7 используя закрытый ключ банка (это означает что необходимо в коде загрузить нужный профайл с ключом подписать данные и вложить сертификат для проверки данной подписи).

Судя по ошибке не проходит операция расшифровывания сообщения.

NPS

ЦитироватьВложен сертификат на подпись, т.е. его открытый ключ имеет в начале 06 02 00 00 3a aa должен быть 06 02 00 00 45 a0


последовательность "06 02 00 00 45 a0" в моем пакете имеется (смещение D9)... значит остается вероятность того, что мне дали не тот сертификат..

имеет ли значение то, что у меня в системе не установлен корневой сертификат УЦ?

Sergey

06 Июнь 2012, 13:07:33 #7 Последнее редактирование: 06 Июнь 2012, 13:12:07 от Sergey
Цитироватьимеет ли значение то, что у меня в системе не установлен корневой сертификат УЦ?

Нет не имеет.
Цитироватьзначит остается вероятность того, что мне дали не тот сертификат

Проверить это можно сравнив поля сертификатов (своего и сервера) у них должен быть одинаковый издатель.

NPS

на закладке "Общие" свойств сертификата поля  "Кем выдан" совпадают, а "Кому выдан" отличаются.
на закладке "Состав" значение поля "Поставщик" у всех:

ЦитироватьC = KZ
O = KISC
CN = KISC Beta CA

Sergey

Для более детального разбора возможно будет зашифровать какое нибудь сообщение на нашем сертификате и выслать его нам?

NPS

06 Июнь 2012, 13:40:41 #10 Последнее редактирование: 06 Июнь 2012, 13:48:42 от NPS
может у меня неверно определены значения переменной DName в функции CryptStream?
в функции определено так:

DN := 'c=KZ;o=AGENT1;cn=NAME1'; // <<-- Передается в массив DNames функции GetCertificateCollection()

сертификат КЦМР в поле "Субъект" имеет следующие значения:

ЦитироватьCN = NAME1
O = AGENT1
C = KZ


мой серитификат в поле "Субъект" имеет следующие значения:

ЦитироватьCN = APLATTESTNPS
OU = NPS
O = APLAT
C = KZ


я ни чего не напутал?

ЦитироватьДля более детального разбора возможно будет зашифровать какое нибудь сообщение на нашем сертификате и выслать его нам?


стоит попробовать

Sergey

Цитироватья ни чего не напутал?

Скорее всего проблема именно в этом.
Я еще раз посмотрел пример и в нем есть еще неточность при вложении сертификата из файла не нужно вызывать функцию
GetCertificateCollection т.к. данная функция ищет сертификаты в хранилище сертификатов hStore по имени DNames, вместо этого
в случае чтения из фала нужно использовать функцию GetCertificateCollectionEx:
/*
*   GetCertificateCollectionEx - получить хендл на коллекцию сертификатов
*
*   Входные параметры   - hStore    - указатель (хендл) на хранилище
*                         certCount - кол-во сертификатов
*                         certBuf   - массив сертификатов
*                         certSize  - массив длин
*
*   Выходные параметры  - hCollection - хендл на коллекцию сертификатов
*
*   Результат           - 0 если все в порядке, иначе смотри myerror.h
*/
_WIN_DLL int GetCertificateCollectionEx
                                      (const hCERTSTORE hStore,
                                       const int certCount,
                                       unsigned char **certBuf,
                                       unsigned long *certSize,
                                       hCERTCOLLECTION *hCollection);

NPS


NPS

Шифрование, благодаря последним исправлениям, заработало...
теперь проблема с подписью:
север КЦМР в свои логи пишет

ЦитироватьPostTerminal.Work: DESIGN:IDTerminal = 754 error(MessageInfo): 311


я так понимаю, что 311 - это "Некорректный тип криптографического сообщения CMS"

NPS

Прикрепляю подписанное сообщение "Сообщение".
Посмотрите, пожалуйста, что в нем не так? (я, делая проверку подписи на своей стороне, ошибок не получаю. сообщение из подписи извлекается)

Вверх