Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход. Новые регистрации запрещены.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Polox  
#1 Оставлено : 15 апреля 2009 г. 14:34:57(UTC)
Polox

Статус: Участник

Группы: Участники
Зарегистрирован: 15.04.2009(UTC)
Сообщений: 10

Коллеги,
возникла необходимость с помощью crypto api реализовать подпись и проверку xml дукумента
в соответствии со спецификацией http://tools.ietf.org/html/rfc3275 и с использованием российских гостов.
Порывшись в интернете нашел спецификацию http://tools.ietf.org/ht...v-cryptopro-cpxmldsig-05
разработанную сотрудниками crypto pro. Вот Xml документ, который приводится в спецификации
(я снял base64):

|1.xml|



1)Итак, следуя стандартам я применил C14N к документу, предварительно убрав поддерево содержащее
тэга signature.
Получился документ:
|2.xml|

2) Далее к документу на шаге один я применил хэш CALG_GR3411 с помощью кода(упрощенная версия кода):

Код:

::CryptAcquireContext(&cryptoProv, NULL, CP_GR3410_2001_PROV, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT);

HCRYPTHASH hHash;

::CryptCreateHash(cryptoProv,
                            CALG_GR3411,
                            NULL,
                            0,
                            &hHash);

::CryptHashData(hHash,
                         (BYTE*)buff,
                          buffSize,
                          0);
DWORD hash_size = 0;
DWORD paramSize;             

::CryptGetHashParam(hHash,
                                 HP_HASHSIZE,
                                 (BYTE*)(&hash_size),
                                 &paramSize,
                                 0);

                   
::CryptGetHashParam(hHash,
                                HP_HASHVAL,
                                (BYTE*)(hashValBuffer),
                                &hash_size,
                                 0);
::CryptDestroyHash(hHash);


3) полученный хэш я обернул в base64 и получил исходное /JwtQsvy5k/R0VeLzdm2IijPBtSJ5pJRjT9FUQHEyTg=. Что меня сильно порадовало ибо это то что нужно.

4) Далее я применил C14n к

|3.xml|

и получил:

|4.xml|

5) Затем я снял base64 с сертификата

|5.xml|

и импортировал его(см код проверки подписи ниже)

6) Затем я снял base64 со значения сигнатуры

|6.xml|

Я использую это значение для проверки подписи данных полученных на шаге 4 с помощью сертификата, полученного на шаге 5

Код, который проверяет сигнатуру документа фейлится на проверке подписи. Все остальные шаги выполняются без ошибок (упрощенная версия кода):

Код:

// сертификат с шага 5
static const unsigned char certBuffer[] = {0x30,0x82,0x1,0xd0,0x30,0x82,0x1,0x7f,0x2,0x10,0x2b,0xf5,0xc6,0x1e,0xc2,0x11,0xbd,0x17,0xc7,0xdc,0xd4,0x62,0x66,0xb4,0x2e,0x21,0x30,0x8,0x6,0x6,0x2a,0x85,0x3,0x2,0x2,0x3,0x30,0x6d,0x31,0x1f,0x30,0x1d,0x6,0x3,0x55,0x4,0x3,0xc,0x16,0x47,0x6f,0x73,0x74,0x52,0x33,0x34,0x31,0x30,0x2d,0x32,0x30,0x30,0x31,0x20,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x31,0x12,0x30,0x10,0x6,0x3,0x55,0x4,0xa,0xc,0x9,0x43,0x72,0x79,0x70,0x74,0x6f,0x50,0x72,0x6f,0x31,0xb,0x30,0x9,0x6,0x3,0x55,0x4,0x6,0x13,0x2,0x52,0x55,0x31,0x29,0x30,0x27,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x9,0x1,0x16,0x1a,0x47,0x6f,0x73,0x74,0x52,0x33,0x34,0x31,0x30,0x2d,0x32,0x30,0x30,0x31,0x40,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x1e,0x17,0xd,0x30,0x35,0x30,0x38,0x31,0x36,0x31,0x34,0x31,0x38,0x32,0x30,0x5a,0x17,0xd,0x31,0x35,0x30,0x38,0x31,0x36,0x31,0x34,0x31,0x38,0x32,0x30,0x5a,0x30,0x6d,0x31,0x1f,0x30,0x1d,0x6,0x3,0x55,0x4,0x3,0xc,0x16,0x47,0x6f,0x73,0x74,0x52,0x33,0x34,0x31,0x30,0x2d,0x32,0x30,0x30,0x31,0x20,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x31,0x12,0x30,0x10,0x6,0x3,0x55,0x4,0xa,0xc,0x9,0x43,0x72,0x79,0x70,0x74,0x6f,0x50,0x72,0x6f,0x31,0xb,0x30,0x9,0x6,0x3,0x55,0x4,0x6,0x13,0x2,0x52,0x55,0x31,0x29,0x30,0x27,0x6,0x9,0x2a,0x86,0x48,0x86,0xf7,0xd,0x1,0x9,0x1,0x16,0x1a,0x47,0x6f,0x73,0x74,0x52,0x33,0x34,0x31,0x30,0x2d,0x32,0x30,0x30,0x31,0x40,0x65,0x78,0x61,0x6d,0x70,0x6c,0x65,0x2e,0x63,0x6f,0x6d,0x30,0x63,0x30,0x1c,0x6,0x6,0x2a,0x85,0x3,0x2,0x2,0x13,0x30,0x12,0x6,0x7,0x2a,0x85,0x3,0x2,0x2,0x24,0,0x6,0x7,0x2a,0x85,0x3,0x2,0x2,0x1e,0x1,0x3,0x43,0,0x4,0x40,0x84,0x95,0x68,0x75,0x60,0x2,0x1a,0x40,0x75,0x8,0xcd,0x13,0x8c,0x31,0x89,0x2c,0xfd,0xe5,0x5,0x3,0x7a,0x43,0x5c,0xf4,0x6d,0x2b,0xf,0xe7,0x4f,0x32,0x7e,0x57,0x8f,0xeb,0xcc,0x16,0xb9,0x95,0x88,0x3,0xd0,0x9a,0x7c,0x85,0xae,0xf,0xe4,0x8d,0xea,0xa6,0xbb,0x7e,0x56,0xc7,0xcb,0xb0,0xdf,0xf,0x66,0xbc,0xca,0xea,0x1a,0x60,0x30,0x8,0x6,0x6,0x2a,0x85,0x3,0x2,0x2,0x3,0x3,0x41,0,0x3c,0x2f,0xc9,0x9,0x44,0xb7,0x27,0xa9,0xec,0xa7,0xd5,0xe9,0xfb,0x53,0x6d,0xd2,0xc3,0xaa,0x64,0x7c,0x44,0x2e,0xde,0xed,0x31,0x16,0x45,0x4f,0xbc,0x54,0x3f,0xdd,0xc1,0xde,0x17,0x6e,0x8d,0x1b,0xec,0x71,0xb5,0x93,0xf3,0xdd,0x36,0x93,0x55,0x77,0x68,0x89,0x89,0x17,0x62,0x20,0xf4,0xda,0xb1,0x31,0xd5,0xb5,0x1c,0x33,0xde,0xe2};
// документ полученный на шаге 4
static const unsigned char canonicalizedXml[] = {0x3c,0x53,0x69,0x67,0x6e,0x65,0x64,0x49,0x6e,0x66,0x6f,0x3e,0x3c,0x43,0x61,0x6e,0x6f,0x6e,0x69,0x63,0x61,0x6c,0x69,0x7a,0x61,0x74,0x69,0x6f,0x6e,0x4d,0x65,0x74,0x68,0x6f,0x64,0x20,0x41,0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77,0x33,0x2e,0x6f,0x72,0x67,0x2f,0x54,0x52,0x2f,0x32,0x30,0x30,0x31,0x2f,0x52,0x45,0x43,0x2d,0x78,0x6d,0x6c,0x2d,0x63,0x31,0x34,0x6e,0x2d,0x32,0x30,0x30,0x31,0x30,0x33,0x31,0x35,0x22,0x20,0x2f,0x3e,0x3c,0x53,0x69,0x67,0x6e,0x61,0x74,0x75,0x72,0x65,0x4d,0x65,0x74,0x68,0x6f,0x64,0x20,0x41,0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77,0x33,0x2e,0x6f,0x72,0x67,0x2f,0x32,0x30,0x30,0x31,0x2f,0x30,0x34,0x2f,0x78,0x6d,0x6c,0x64,0x73,0x69,0x67,0x2d,0x6d,0x6f,0x72,0x65,0x23,0x67,0x6f,0x73,0x74,0x72,0x33,0x34,0x31,0x30,0x32,0x30,0x30,0x31,0x2d,0x67,0x6f,0x73,0x74,0x72,0x33,0x34,0x31,0x31,0x22,0x20,0x2f,0x3e,0x3c,0x52,0x65,0x66,0x65,0x72,0x65,0x6e,0x63,0x65,0x20,0x55,0x52,0x49,0x3d,0x22,0x22,0x3e,0x3c,0x54,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x73,0x3e,0x3c,0x54,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x20,0x41,0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77,0x33,0x2e,0x6f,0x72,0x67,0x2f,0x32,0x30,0x30,0x30,0x2f,0x30,0x39,0x2f,0x78,0x6d,0x6c,0x64,0x73,0x69,0x67,0x23,0x65,0x6e,0x76,0x65,0x6c,0x6f,0x70,0x65,0x64,0x2d,0x73,0x69,0x67,0x6e,0x61,0x74,0x75,0x72,0x65,0x22,0x20,0x2f,0x3e,0x3c,0x2f,0x54,0x72,0x61,0x6e,0x73,0x66,0x6f,0x72,0x6d,0x73,0x3e,0x3c,0x44,0x69,0x67,0x65,0x73,0x74,0x4d,0x65,0x74,0x68,0x6f,0x64,0x20,0x41,0x6c,0x67,0x6f,0x72,0x69,0x74,0x68,0x6d,0x3d,0x22,0x68,0x74,0x74,0x70,0x3a,0x2f,0x2f,0x77,0x77,0x77,0x2e,0x77,0x33,0x2e,0x6f,0x72,0x67,0x2f,0x32,0x30,0x30,0x31,0x2f,0x30,0x34,0x2f,0x78,0x6d,0x6c,0x64,0x73,0x69,0x67,0x2d,0x6d,0x6f,0x72,0x65,0x23,0x67,0x6f,0x73,0x74,0x72,0x33,0x34,0x31,0x31,0x22,0x20,0x2f,0x3e,0x3c,0x44,0x69,0x67,0x65,0x73,0x74,0x56,0x61,0x6c,0x75,0x65,0x3e,0x2f,0x4a,0x77,0x74,0x51,0x73,0x76,0x79,0x35,0x6b,0x2f,0x52,0x30,0x56,0x65,0x4c,0x7a,0x64,0x6d,0x32,0x49,0x69,0x6a,0x50,0x42,0x74,0x53,0x4a,0x35,0x70,0x4a,0x52,0x6a,0x54,0x39,0x46,0x55,0x51,0x48,0x45,0x79,0x54,0x67,0x3d,0x3c,0x2f,0x44,0x69,0x67,0x65,0x73,0x74,0x56,0x61,0x6c,0x75,0x65,0x3e,0x3c,0x2f,0x52,0x65,0x66,0x65,0x72,0x65,0x6e,0x63,0x65,0x3e,0x3c,0x2f,0x53,0x69,0x67,0x6e,0x65,0x64,0x49,0x6e,0x66,0x6f,0x3e};
// сигнатура полученная на шаге 6
static unsigned char decodedSignedInfoSignature[] = {0x15,0xc6,0xf7,0xab,0x88,0x81,0xbd,0xd7,0xe0,0x62,0x8e,0xe7,0xf7,0x91,0x9a,0x40,0x2b,0x9d,0xf7,0x56,0xf,0xef,0xf,0x28,0x57,0x4d,0xd1,0xeb,0x39,0x11,0xd,0xd9,0x5c,0xf8,0x39,0xc2,0x73,0x4a,0xfd,0x32,0xc0,0x39,0x6b,0xf6,0xe1,0x60,0x2c,0x96,0x3d,0xdf,0xdc,0x11,0x4f,0x3e,0xa9,0x81,0x6b,0xc8,0x96,0xdc,0x8a,0xbc,0xb0,0x1c};

                    PCCERT_CONTEXT certContext = ::CertCreateCertificateContext(CERT_ENCODING_TYPE,
                                                                                (BYTE*)certBuffer,
                                                                                certSize);
                    if(certContext)
                    {
                        HCRYPTPROV cryptProv = NULL;
                        if(::CryptAcquireContext(&cryptProv, NULL, CP_GR3410_2001_PROV, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT))
                        {
                            HCRYPTKEY  hKey;
                            if(::CryptImportPublicKeyInfo(cryptProv,
                                                          CERT_ENCODING_TYPE,
                                                          &certContext->pCertInfo->SubjectPublicKeyInfo,
                                                          &hKey))
                            {
                                HCRYPTHASH hHash;

                                if(::CryptCreateHash(cryptProv,
                                                     CALG_GR3411,
                                                     NULL,
                                                     0,
                                                     &hHash))
                                {
                                    if(::CryptHashData(hHash,
                                                       (BYTE*)canonicalizedXml,
                                                       sizeof(canonicalizedXml),
                                                       0))
                                    {
                                        if(::CryptVerifySignature(hHash,
                                                                  (BYTE*)decodedSignedInfoSignature,
                                                                  sizeof(decodedSignedInfoSignature),
                                                                  hKey,
                                                                  NULL,
                                                                  0))
                                        {
                                            ret_val = true;
                                        }


Отсюда я делаю три предположения:
1) Я неверно понял рекомендацию и к 64-м байтам сигнатуры, которая берется из значения тэга SignatureValue
после снятия base64 применяется еще какое-то преобразование о котором явно не написано в рекомендации

2) Код которай проверяет сигнатуру неверен. Ну с другой стороны этот код нормально работет когда я даю ему
сигнатуру сгенерированную при помощи функций crypto api и своего тестового вектора и сертификата.
Так что тут возможен вариант, что я какие-то параметры не задал при проверке подписи.

3) Документ который приведен в рекомендации http://tools.ietf.org/ht...v-cryptopro-cpxmldsig-05
в качестве примера содержит неверную сигнатуру.

p.s
В основном интересуют комментарии людей писавших рекомендации или хорошо в ней разбирающихся.
По техническим причинам должен реализовать стандарт(точнее некоторое его подмножество) с помощью CryptoApi.
Буду очень благодарен за помощь.
Вложение(я):
1.xml (2kb) загружен 32 раз(а).
2.xml (1kb) загружен 24 раз(а).
3.xml (1kb) загружен 25 раз(а).
4.xml (1kb) загружен 21 раз(а).
5.xml (1kb) загружен 18 раз(а).
6.xml (1kb) загружен 20 раз(а).

У Вас нет прав для просмотра или загрузки вложений. Попробуйте зарегистрироваться.
Offline Polox  
#2 Оставлено : 15 апреля 2009 г. 18:53:41(UTC)
Polox

Статус: Участник

Группы: Участники
Зарегистрирован: 15.04.2009(UTC)
Сообщений: 10

В результате общения в привате с Коллегиным Максимом и выснилось два обстоятельства:
1) Тэг SignedInfo после канонизации C14c не содержал namespace xmlns="http://www.w3.org/2000/09/xmldsig#". Я использовал canonicalizer от apache
com.sun.org.apache.xml.internal.security.c14n.Canonicalizer cononicalizer = com.sun.org.apache.xml.internal.security.c14n.Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
Надо будет проверить в чем тут проблема.
2) Значение SignatureValue после снятия base64 должно подвергнуться I2OSP(RFC 2437) перед проверкой подсиси функцией SignatureVerify. Код приведенный в первоначальном после верен и вполне может использоваться для проверки.
Процедула преобразования I2OSP проста:

Код:

void I2OSP(unsigned char* original, unsigned char* result, int size)
{
    for(int i = 0; i < size; i++)
    {
        result[i] = original[size - i - 1];
    }
}


Еще раз огромное спасибо Максиму Коллегину
Offline Павел Смирнов  
#3 Оставлено : 15 мая 2009 г. 18:18:17(UTC)
Павел Смирнов

Статус: Вам и не снилось

Группы: Администраторы
Зарегистрирован: 24.12.2007(UTC)
Сообщений: 831
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 48 раз в 44 постах
Предположение о применении I2OSP к значению подписи перед её помещением в XML неверно.
В рассуждениях не учтена одна особенность CryptoAPI - на выходе функции CryptSignHash подпись представлена в обратном порядке байт. Об этом, например, явно написано в документации на КриптоПро CSP 3.6 (см. функцию CPSignHash). Соответственно, CryptVerifySignature также ждёт на вход "перевёрнутое" представление подписи.
Техническую поддержку оказываем тут.
Наша база знаний.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.