diadoc / diadocapi-docs

HTTP API documentation - http://api-docs.diadoc.ru/
40 stars 92 forks source link

Подпись получить подпись строкой в Base64 для PostMessagePatch? #547

Closed elvirazakharova closed 4 years ago

elvirazakharova commented 4 years ago

Как с помощью КриптоПро выгрузить подпись для методов PostMessagePatch и GenerateUniversalTransferDocumentXmlForBuyer . Подпись в формате X509 Base64 не подходит для метода PostMessagePatch, ошибка "Invalid signature". Файл подписи в формате PKCS7 (.p7b) кодированный в Base64 дает ошибку "The server encountered an internal error or misconfiguration and was unable to complete your request"

ethaniel commented 4 years ago

Присоединяюсь к вопросу, у нас аналогичная проблема:

  1. Для авторизации мы используем содержимое "-----BEGIN CERTIFICATE-----", авторизация проходит успешно (так как там нет json, то отправляем сырые данные сертификата в POST).
  2. Когда передаем тот же сертификат в JSON в Signatures в PostMessagePatch, но уже в base64_encode, возвращается "Invalid Signature".
atytsky commented 4 years ago

@elvirazakharova Что вы и как пытаетесь подписать? У вас есть бинарное представление подписи?

@ethaniel Операция подписания происходит на клиентской стороне, поэтому нам в PostMessagePatch не нужно передавать сертификат, нужно передавать подпись.

ethaniel commented 4 years ago

@atytsky у нас есть "-----BEGIN CERTIFICATE-----" и "-----BEGIN ENCRYPTED PRIVATE KEY-----". Я так понимаю, что сам PRIVATE KEY мы передавать не должны. Как должна выглядеть подпись?

atytsky commented 4 years ago

@ethaniel конечно нет, Private Key — это ваш секрет, он как раз нужен для подписания/шифрования различного контента. Про подписи можно почитать например тут, или вот еще хорошая спека

Вообще, уже есть сертифицированные криптопровайдеры, которые умеют делать хорошие подписи, самый популярный — Крипто ПРо

ethaniel commented 4 years ago

@ethaniel конечно нет, Private Key — это ваш секрет, он как раз нужен для подписания/шифрования различного контента. Про подписи можно почитать например тут, или вот еще хорошая спека

Да вот только непонятно, что именно мы подписываем. Нужно заново скачать обратно XML по 820 приказу через GetMessage и заново его подписать как в SignedContent? Мы делаем все на PHP и JSON к примеру, поэтому нехватка документации и примеров смущает.

atytsky commented 4 years ago

Весь workflow описан здесь. Вам надо подписать XML-файл 1-го, либо 2-го титула (в зависимости от того, получаете или отправляете документ).

Если вы отправляете — подписывается 1-й титул УПД по №820, если получаете 2-й титул.

elvirazakharova commented 4 years ago

Частично разобралась. Надеюсь это поможет многим людям за неимением какого-либо мануала в доступе. Для подписания титула (PostMessagePatch) покупателем понадобятся:

  1. Непосредственно сам титул титул (использовать GenerateUniversalTransferDocumentXmlForBuyer)
  2. Файл открепленной подписи к этому файлу. То что подпись идет к файлу нигде не написано, ровно как и то, что она открепленная. Но это не точно. Создать такую подпись возможно например, программой КриптоАРМ или ViPNet CryptoFile. Если ваша среда разработки не особо позволяет пользоваться какими-либо библиотеками, то в коде этот файл открепленной подписи можно сгенерировать с помощью объекта (он же COM-компонент, он же ActiveXObject, он же AutoObject) с названием "CAdESCOM". Предварительно нужно будет:
  3. Установить криптопровайдер(=ПО, что понимает, что такое подпись и как на нее посмотреть) И именно тот, на котором вам подпись дали, скорее всего это КриптоПРо.
  4. Установить плагин КриптоПро ЭЦП Browser plug-in
  5. Установить сертификат на компьютер в хранилище “Личные”. У объекта "CAdESCOM" есть весьма гуглимый набор методов, который позволит получить подпись к файлу (который предварительно нужно кодировать в Base64 и подавать на вход строкой). А подойдет она или нет я узнаю только в понедельник. Открепленная подпись, созданная КриптоАРМом подошла. На выходе подпись уже в Base64, не нужно ее еще раз кодировать, это текстовый файл, можно блокнотом открыть, посмотреть что к чему там.
atytsky commented 4 years ago

@elvirazakharova в целом описано все верно, но есть следующие моменты:

ethaniel commented 4 years ago

Если кому-то нужно пример на php (linux), то вот наша функция для подписания документов:

function diadoc_sign($data) { 
    $descriptorspec = array(0 => array("pipe", "r"),1 => array("pipe", "w"),2 => array("pipe", "w"));

    $q = "/usr/local/openssl-gost/bin/openssl smime -sign -binary -noattr -gost89 -outform der -signer ".DIADOC_KEY." -inkey ".DIADOC_KEY." -passin pass:".DIADOC_KEYPASS; 

    $process = proc_open($q, $descriptorspec, $pipes);

    $token = "";
    if (is_resource($process)) {
        fwrite($pipes[0], $data);
        fclose($pipes[0]);
        $content = stream_get_contents($pipes[1]);
        $err = stream_get_contents($pipes[2]);
        fclose($pipes[1]);
        fclose($pipes[2]);

        $resCode = proc_close($process);
        if ($resCode != 0) {
            echo "Сбой на сервере. Пожалуйста, попробуйте позднее [1: $err].";
            return false;
        } else {
            //echo $content;
            //$content = join("\n",array_slice(array_filter(explode("\n",$content)),1,-1));
        }
    } else {
        echo "Сбой на сервере. Пожалуйста, попробуйте позднее [2].";
        return false;

    }

    return $content;
}

DIADOC_KEY - константа с местоположением PEM файла с ключом и сертификатом DIADOC_KEYPASS - константа с паролем от ключа /usr/local/openssl-gost/bin/openssl - наш локально собранный openssl с поддержкой ГОСТ-2012 (использовали вот эти примеры - https://github.com/kov-serg/get-cpcert) Экспортировали ключ и сертификат из КриптоПро при помощи лицензионной P12FromGostCSP (только она может экспортировать ключи ГОСТ-2012 в PFX файлы, http://soft.lissi.ru/ls_product/utils/p12fromcsp/) Конвертировали PFX в PEM при помощи /usr/local/openssl-gost/bin/openssl pkcs12 -passin pass: -in p12.pfx -clcerts -outfile certkey.pem (она же и предлагает указать пароль для ключа при его сохранении в PEM)