Как подписать данные открепленной подписью для заказа КМ честного знака СУЗ?

Этот вопрос создан для того, что бы в интернете была хоть какая то запись как подписывать документы открепленной подписью для честного знака на python. На хабре есть статья как подписать прикрепленной подписью, но про открепленную я ничего не нашел. Буду рад если это кому то поможет, а еще лучше если кто то, распространит эту информацию в нужных местах.

Итак я разбираюсь с API честного знака СУЗ. Мне надо было создать заказ на эмиссию кодов. Для этого в заголовок запроса нужно добавить параметр X-Signature - Откреплённая подпись в кодировке Base64.
И тут начался геморой, каждый раз приходит ответ 200, после чего в статусе заказа приходит ответ "Подпись не прошла проверку". Но в итоге я сделал. Выложу сюда код как есть, можете ругаться на его красоту, мне всеравно, главное что это работает!

Код в ответе!
  • Вопрос задан
  • 76 просмотров
Решения вопроса 1
@Meller008 Автор вопроса
Код который у меня работает! Пользуйтесь на здоровье!

import win32com.client
import base64
import pythoncom
import json
import requests


def signed_data(_data):
    # Функция подписывает данные открепленной подписью
    # Возращает обратно данные которые подписаны, и открепленную подпись
    CADES_BES = 1
    CAPICOM_ENCODE_BASE64 = 0
    CAPICOM_CURRENT_USER_STORE = 2
    CAPICOM_MY_STORE = "My"
    CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED = 2
    sSerialNumber = "SERIAL_NUMBER"  # ID ключа, берется из крипто-про
    # Инструменты криптопро -> контейнеры -> Найти нужный ключ (не просроченный, видно при тестировании контейнера) -> Протестировать контейнер -> серийный номер

    # Ищем сертификат в хранилище
    oCert = None
    oStore = win32com.client.Dispatch("CAdESCOM.Store", pythoncom.CoInitialize())
    oStore.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, CAPICOM_STORE_OPEN_MAXIMUM_ALLOWED)
    for val in oStore.Certificates:
        if val.SerialNumber.upper() == sSerialNumber.upper():
            oCert = val
    oStore.Close
    if not oCert:
        print("Не найден сертификат в хранилище")
        return None

    oSigner = win32com.client.Dispatch("CAdESCOM.CPSigner", pythoncom.CoInitialize())
    oSigner.Certificate = oCert

    # Строка JSON БЕЗ ПРОБЕЛОВ
    message = _data
    message_bytes = message.encode()
    base64_bytes = base64.b64encode(message_bytes)
    base64_message = base64_bytes.decode()

    signedData = win32com.client.Dispatch("CAdESCOM.CadesSignedData", pythoncom.CoInitialize())
    signedData.ContentEncoding = 1
    signedData.Content = base64_message
    sSignedData = signedData.SignCades(oSigner, CADES_BES, True, CAPICOM_ENCODE_BASE64)

    # Удаляем из подписи символы переноса строки, иначе не вставить в заголовок запроса
    sSignedData = sSignedData.replace('\r', '')
    sSignedData = sSignedData.replace('\n', '')

    return _data, sSignedData


# token выдается при авторизации по URL <url стенда>/auth/simpleSignIn/{omsConnection}
# Статья есть на хабре.
headers = {"clientToken": "token", "Accept": "application/json", 'Content-type': 'application/json'}
# oms_id - Находим в личном кабинете - управление заказами - устройства - OMS ID:
query_params = {"omsId": "oms_id"}
# Заполнение поля products я пропущу, оно хорошо описано в документации к СУЗ
body = {
    "productGroup": "lp",
    "attributes": {
        "releaseMethodType": "PRODUCTION",
        "createMethodType": "SELF_MADE",
    },
    "products": [],
}

# Переводим словарь в JSON БЕЗ ПРОБЕЛОВ!
json_str = json.dumps(body, separators=(',', ':'))
sData, signed = signed_data(json_str)  # получаем подпись

headers["X-Signature"] = signed

# Так же в тело запроса отправляем этот JSON который подписывали без пробелов!
response = requests.post(f"https://suz.sandbox.crptech.ru/api/v3/order", params=query_params, headers=headers, data=sData)
if response.status_code == 200:
    response.json()
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы