Экспорт сертификата в формате BASE-64. – c# |

Содержание
  1. Запрос ssl сертификата в linux
  2. Конвертировать der-кодированный сертификат в pem
  3. Конвертировать сертификат pem в der
  4. Конфигурирование openssl
  5. Настройка дополнительных полей ssl сертификата в linux
  6. Общие преобразования pem
  7. Подпись ssl сертификата linux в доменном центре сертификации
  8. Поиск подключенных устройств
  9. Полезные ссылки
  10. Получение информации об устройстве
  11. Преобразовать сертификат в кодировке der с цепочкой доверия и закрытым ключом в pkcs # 12
  12. Просмотр содержимого файла сертификата pem
  13. Просмотр содержимого файла сертификата в кодировке der
  14. Работа с ключевыми парами гост р 34.10-2001
  15. Работа с сертификатами
  16. Расширения имени файла der
  17. Расшифрование данных, полученных с сервера, на клиенте
  18. Сертификат выдается при регистрации в системе
  19. Сертификат уже имеется на токене, выдан внешним уц
  20. Смена pin-кода
  21. Строгая аутентификация на портале
  22. Чтение ssl-сертификата из строки в base64 der формате
  23. Шифрование данных на клиенте для сервера
  24. Экспорт сертификата в формате base-64. – c# |

Запрос ssl сертификата в linux

После того как отредактировали файл создаем ключ и запрос в одной команде:

openssl req -newkey rsa:2048 -nodes -keyout domain.key -out domain.csr

Эта команда создаст файл закрытого ключа типа rsa длиной 2048 бит. Вы можете изменить эти параметры по своему усмотрению. Далее последует диалог, в котором необходимо указать основные поля сертификата.

Создание запроса ssl сертификата в Linux
Поле Common Name должно совпадать с именем хоста к которому вы выпускаете сертификат

Обратите внимание на поле Common Name такое же имя стоит прописать в конфиге выше в качестве одного из полей в alt_names.

Если пришло время и вы обновляете сертификат, то выпустить запрос можно получив информацию из существующего сертификата:

openssl x509 -in domain.crt -signkey domain.key -x509toreq -out domain.csr

Конвертировать der-кодированный сертификат в pem

openssl x509 -inform der -in CERTIFICATE.der -out CERTIFICATE.pem

Конвертировать сертификат pem в der

openssl x509 -outform der -in CERTIFICATE.pem -out CERTIFICATE.der

Конфигурирование openssl

Openssl поддерживает российские криптоалгоритмы, начиная с версии 1.0. Для того, чтобы их использовать, в openssl требуется подгружать engine gost. В большинстве дистрибутивов openssl эта библиотека присутствует. Чтобы engine подгружалась, можно прописать ее в конфигурационном файле openssl:

[openssl_def]
engines = engine_section

[engine_section]
gost  = gost_section

[gost_section]
engine_id  = gost
default_algorithms = ALL

Если конфигурационный файл openssl не расположен в стандартном месте, то путь к нему можно задать через переменную окружения OPENSSL_CONF.

Другим вариантом подгрузки engine gost является ее передача в параметрах командной строки утилиты openssl.

Если engine gost не расположена в стандартном месте, то через переменную окружения OPENSSL_ENGINES можно задать путь к директории, в которой openssl будет ее искать.

Для получения информации о том, успешен ли был вызов утилиты openssl или нет, с возможностью уточнения ошибки, требуется парсить stdout и stderror. В конце статьи приведена ссылка на PHP-скрипт, который использует данную утилиту.

Теперь перейдем к реализации законченных пользовательских сценариев.

Настройка дополнительных полей ssl сертификата в linux

Первым делом необходимо настроить список и значения дополнительных полей в сертификате, а именно Subject Alternative Names. Указывать их необходимо, чтобы избежать ошибки [missing_subjectAltName] и NET::ERR_CERT_COMMON_NAME_INVALID в Google Chrome и других браузерах. В данных полях необходимо перечислить все dns имена и ip адреса, по которым может быть открыт сайт.

Задаются параметры через файл /etc/ssl/openssl.cnf. Если у вас данный конфигурационный файл не изменялся то необходимо внести следующие изменения:

  1. В разделе [req] добавить строку: req_extensions = v3_req
  2. В разделе [v3_req] добавить строку: subjectAltName = @alt_names
  3. Создать раздел [ alt_names ] и добавить в него все альтернативные имена в формате:

Общие преобразования pem

В приведенных ниже командах OpenSSL замените имена файлов ВСЕМИ ЗАГЛАВНЫМИ буквами фактическими путями и именами файлов, с которыми вы работаете.

Про сертификаты:  Помощь в оформлении сертификата на установку гбо– услуги сертификации

Подпись ssl сертификата linux в доменном центре сертификации

Копируем содержимое csr файла в буфер, затем идем на веб сайт доменного центра сертификации.

Первый шаг подписи сертификата доменным центром сертификации
Кликаем ссылку запрос сертификата

В поле шаблон сертификата выбираем Веб-сервер и кликаем по кнопке «Выдать».

Скачивание ssl сертификата с сайта доменного центра сертификации
Переключаем формат сертификата в Base64

Кликаем по ссылке «Загрузить сертификат» и сохраняем файл сертификата. После этого его можно загрузить на сервер и настроить на использование вебсервером.

Поскольку доменный центр сертификации по умолчанию распространяет свой корневой сертификат на все машины в домене Active Directory, либо вы сделали это с помощью GPO, то все подписанные им сертификаты на машинах в домене будут валидными. Таким образом и SSL сертификат в Linux подписанный доменным центром сертификации прикрученный к внутрикорпоративному веб-серверу тоже не вызовет ошибок в браузере на рабочей машине пользователя.

Данная инструкция пригодится при выпуске сертификата например для установки на Proxmox Mail Gateway или любой другой веб-сервер.

Поиск подключенных устройств

Любой клиентский сценарий начинается с поиска подключенных к компьютеру USB-устройств Рутокен. В контексте данной статьи акцент делается на устройство Рутокен ЭЦП.

var devices = Array();

try 
{
    devices = plugin.enumerateDevices();
}
catch (error) 
{
    console.log(error);
}

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

Рутокен Плагин определяет все подключенные к компьютеру USВ-устройства Рутокен ЭЦП, Рутокен PINPad, Рутокен WEB. Поэтому следующим шагом следует определить тип устройства.

Полезные ссылки

Данные ссылки могут быть полезны разработчикам инфосистем с поддержкой ЭЦП на базе Рутокен Плагин и openssl:

Демосистема Рутокен ПлагинWEB-сервис генерации ключей, формирования запросов, управления сертификатами, формирования шаблонов запросов на сертификаты Документация на Рутокен ПлагинДокументация по использованию утилиты openssl с российскими крипталгоритмамиПример скрипта на PHP, использующего утилиту openssl

Получение информации об устройстве

Для определения типа устройства следует использовать функцию

с параметром TOKEN_INFO_DEVICE_TYPE. Значение этой константы содержится в объекте плагина.

var type;

try
{  
  type = plugin.getDeviceInfo(deviceId, plugin.TOKEN_INFO_DEVICE_TYPE);
}
catch (error) 
{
    console.log(error);
}

switch (type) 
{
    case plugin.TOKEN_TYPE_UNKNOWN:
        message = "Неизвестное устройство";
        break;
    case plugin.TOKEN_TYPE_RUTOKEN_ECP:
        message = "Рутокен ЭЦП";
        break;
    case plugin.TOKEN_TYPE_RUTOKEN_WEB:
        message = "Рутокен Web";
        break;
    case plugin.TOKEN_TYPE_RUTOKEN_PINPAD_2:
        message = "Рутокен PINPad";
        break;
}

Также с помощью функции getDeviceInfo можно получить:

Преобразовать сертификат в кодировке der с цепочкой доверия и закрытым ключом в pkcs # 12

Чтобы преобразовать сертификат DER в PKCS # 12, его следует сначала преобразовать в PEM, а затем объединить с любыми дополнительными сертификатами и / или закрытым ключом, как показано выше. Для более подробного описания преобразования DER в PKCS # 12, пожалуйста, смотрите это как.

Просмотр содержимого файла сертификата pem

openssl x509 -в CERTIFICATE.pem -text -noout 

Просмотр содержимого файла сертификата в кодировке der

openssl x509 -inform der -in CERTIFICATE.der -text -noout

Работа с ключевыми парами гост р 34.10-2001

1. Для получения декрипторов ключевых пар, хранящихся на устройстве, требуется ввод PIN-кода. Следует понимать, что само значение закрытого ключ получено быть не может, так как ключ является неизвлекаемым.

var keys = Array();

try
{   
    plugin.login(deviceId, "12345678");
    keys = plugin.enumerateKeys(deviceId, null);
}
catch (error) 
{
    console.log(error);
}

2. Для генерации ключевой пары требуется ввод PIN-кода. При генерации ключа параметры могут быть выбраны из набора:

Пример генерации ключевой пары ГОСТ Р 34.10-2001:

var options = {};
var keyId;

try 
{
    keyId = plugin.generateKeyPair(deviceId, "A",  null, options);
}
catch (error) 
{
    console.log(error);
}

3. С помощью функции deleteKeyPair ключевая пара может быть удалена с токена.

Работа с сертификатами

1. На токене могут храниться 3 категории сертификатов:

Про сертификаты:  ВОЗРОЖДЕНИЕ ТЕМЫ ! Тех Паспорта и Сертификаты для любой пневматики !

Расширения имени файла der

DER-кодированные файлы обычно находятся с расширениями .der и .cer.

Расшифрование данных, полученных с сервера, на клиенте

Для расшифрования данных, полученных с сервера, предназначена функция cmsDecrypt. Так как сервер шифрует для клиента, используя его сертификат, то в качестве keyId должен быть передан дескриптор закрытого ключа клиента, соответствующий открытому ключу в сертификате.

Этот дескриптор является уникальным и неизменным и потому может быть сохранен в учетной записи пользователя на сервере. Кроме того, дескриптор ключа пользователя может быть получен явным образом, путем вызова функции getKeyByCertificate.

Шифрование данных на сервере для клиента:

Сертификат выдается при регистрации в системе

Последовательность вызовов в клиентском скрипте будет следующей:

Далее запрос отправляется на сервер, где на его основе выдается сертификат.Для этого на сервере должен быть установлен и правильно сконфигурирован openssl версии от 1.0 и развернут функционал УЦ.

1. Генерация улюча УЦ:

openssl genpkey -engine gost -algorithm GOST2001 -pkeyopt paramset:A -out ca.key


После этого в файле ca.key будет создан закрытый ключ

2. Создание самоподписанного сертификата УЦ:

openssl req -engine gost -x509 -new -key ca.key -out ca.crt

После ввода необходимой информации об издателе в файле ca.crt будет создан сертификат УЦ.

Сертификат уже имеется на токене, выдан внешним уц

Ключевая пара при этом должна быть создана в формате, совместимом с библиотекой rtPKCS11ECP для Рутокен ЭЦП.

Последовательность вызовов на клиенте:
Экспорт сертификата в формате BASE-64. - c# |

Подпись получается в base64-формате. При проверке ее на сервере с помощью openssl подпись следует обрамить заголовками, чтобы сделать из нее PEM. Выглядеть подобная подпись будет примерно так:

-----BEGIN CMS-----
MIIDUQYJKoZIhvcNAQcCoIIDQjCCAz4CAQExDDAKBgYqhQMCAgkFADCBygYJKoZI
hvcNAQcBoIG8BIG5PCFQSU5QQURGSUxFIFVURjg PFY 0JLRi9C/0L7Qu9C90LjR
gtGMINCw0YPRgtC10L3RgtC40YTQuNC60LDRhtC40Y4/PCE c2VydmVyLXJhbmRv
bS1kYXRhZTI6ZGE6MmM6MDU6MGI6MzY6MjU6MzQ6YzM6NDk6Nzk6Mzk6YmI6MmY6
YzU6Mzc6ZGI6MzA6MTQ6NDQ6ODM6NjY6Njk6NmI6OWY6YTU6MDk6MzQ6YmY6YzQ6
NzY6YzmgggGeMIIBmjCCAUegAwIBAgIBATAKBgYqhQMCAgMFADBUMQswCQYDVQQG
EwJSVTEPMA0GA1UEBxMGTW9zY293MSIwIAYDVQQKFBlPT08gIkdhcmFudC1QYXJr
LVRlbGVjb20iMRAwDgYDVQQDEwdUZXN0IENBMB4XDTE0MTIyMjE2NTEyNVoXDTE1
MTIyMjE2NTEyNVowEDEOMAwGA1UEAxMFZmZmZmYwYzAcBgYqhQMCAhMwEgYHKoUD
AgIjAQYHKoUDAgIeAQNDAARADKA/O1Zw50PzMpcNkWnW39mAJcTehAhkQ2Vg7bHk
IwIdf7zPe2PxHyAr6lH stqdACK6sFYmkZ58cBjzL0WBwaNEMEIwJQYDVR0lBB4w
HAYIKwYBBQUHAwIGCCsGAQUFBwMEBgYpAQEBAQIwCwYDVR0PBAQDAgKkMAwGA1Ud
EwEB/wQCMAAwCgYGKoUDAgIDBQADQQD5TY55KbwADGKJRK bwCGZw24sdIyayIX5
dn9hrKkNrZsWdetWY3KJFylSulykS/dfJ871IT 8dXPU5A7WqG4 MYG7MIG4AgEB
MFkwVDELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEiMCAGA1UEChQZT09P
ICJHYXJhbnQtUGFyay1UZWxlY29tIjEQMA4GA1UEAxMHVGVzdCBDQQIBATAKBgYq
hQMCAgkFADAKBgYqhQMCAhMFAARAco5PumEfUYVcLMb1cnzETNOuWC8Goda8pdUL
W5ASK tztCwM7wpXgAy Y6/sLtClO9sh8dKnAaEY2Yavg3altQ==
-----END CMS-----

Проверка подписи на сервере:

Смена pin-кода

Пример смены PIN-кода на устройстве:

var options = {};

try
{   
    plugin.changePin(deviceId, "12345678", "12345671", options);
}
catch (error) 
{
    console.log(error);
}

Здесь первым параметром выступает старый PIN-код, а вторым новый PIN-код.

Строгая аутентификация на портале

Общая схема аутентификации, используемая в Рутокен Плагин, выглядит следующим образом:

Реализация данной схемы ничем принципиально не отличается от «Регистрация, сертификат уже имеется, выдан внешним УЦ».

Чтение ssl-сертификата из строки в base64 der формате

Судя по вашем ответу, cert у вас это base64 представление сертификата в DER кодировке (добавляя BEGIN/END CERTIFICATE строчки, вы превращаете это в PEM представление).

В таком случае, достаточно декодировать из base64, чтобы передать сертификат в функции, ожидающие DER формат, например, используя asn1crypto пакет (чистый Питон, не использует openssl):

import base64
from asn1crypto import x509  # $ pip install asn1crypto

cert = x509.Certificate.load(base64.b64decode(base64_der))
print(cert.serial_number)

где base64_der это ваш сертификат, «который представлен в виде типа buffer». Кроме asn1crypto вы ещё можете использовать и другие библиотеки, например: pyOpenSSL, M2Crypto, cryptography, pyasn1. См., пример кода и основные отличия.

Альтернативно, можно наоборот обернуть base64_der, чтобы получить PEM представление:

import ssl

pem_string = '-----BEGIN CERTIFICATE-----'   base64_der   '-----END CERTIFICATE-----'
der_bytes = ssl.PEM_cert_to_DER_cert(pem_string)
cert = x509.Certificate.load(der_bytes)
print(cert.serial_number)

См. также asn1crypto.pem.detect().

Для быстрого хака, достаточно стандартной библиотеки:

import ssl

p = ssl._ssl._test_decode_cert(tmp_certificate_path)
print(p['serialNumber'])

где tmp_certificate_path это путь к PEM файлу из вашего ответа и ssl._ssl._test_decode_cert() это неофициальная функция из _ssl.c, которая существует только для тестов (значит может исчезнуть, изменить поведение в любой момент).


Для сравнения (чтобы оценить удобство, предоставляемое библиотеками типа asn1crypto), вот код, который использует OpenSSL API напрямую через ctypes, чтобы получить серийный номер x509 сертификата из строки, содержащей DER представление, закодированное в base64 формат как одна строчка:

#!/usr/bin/env python3
import contextlib
import ctypes.util
from ssl import SSLError

_ssl = ctypes.cdll.LoadLibrary(ctypes.util.find_library('ssl'))
BIO_FLAGS_BASE64_NO_NL = 0x100 # bio.h

def get_serial_number_from_base64_der_oneline(base64_der):
    if isinstance(base64_der, str):
        base64_der = base64_der.encode('ascii', 'strict')
    with contextlib.ExitStack() as stack:
        bio = _ssl.BIO_new_mem_buf(base64_der, len(base64_der))
        stack.callback(_ssl.BIO_free, bio)
        b64 = _ssl.BIO_new(BIO_f_base64()) 
        stack.callback(_ssl.BIO_free, b64)
        _ssl.BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL) # oneline
        certificate = _ssl.d2i_X509_bio(_ssl.BIO_push(b64, bio), None)
        stack.callback(_ssl.X509_free, certificate)
        # get a memory buffer # from _ssl.c
        biobuf = _ssl.BIO_new(BIO_s_mem())
        stack.callback(_ssl.BIO_free_all, biobuf)
        serialNumber = _ssl.X509_get_serialNumber(certificate)
        _ssl.i2a_ASN1_INTEGER(biobuf, serialNumber)
        # should not exceed 20 octets, 160 bits, so buf is big enough
        buf = ctypes.create_string_buffer(21) # char[21]
        size = _ssl.BIO_gets(biobuf, buf, len(buf)-1)
        if size <= 0:
            raise SSLError
        return buf[:size].decode()

# https://www.openssl.org/docs/manmaster/crypto/BIO_f_base64.html
# const BIO_METHOD *BIO_f_base64(void);
BIO_f_base64 = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_char))(("BIO_f_base64", _ssl))
BIO_s_mem = ctypes.CFUNCTYPE(ctypes.POINTER(ctypes.c_char))(("BIO_s_mem", _ssl))

def null_check(result, func, arguments):
    if not result:
        raise SSLError
    return result

for f in [BIO_f_base64, BIO_s_mem, _ssl.BIO_new_mem_buf, _ssl.BIO_new, _ssl.d2i_X509_bio]:
    f.errcheck = null_check

Алгоритм:

  1. декодируется base64 представление, используя BIO_f_base64(), получаем DER
  2. DER превращаем во внутреннее представление, используя d2i_X509_bio()
  3. X509_get_serialNumber() извлекает серийный номер как ASN1_INTEGER
  4. i2a_ASN1_INTEGER() даёт серийный номер как число в ascii строке
Про сертификаты:  Центр сертификации продукции по России, в Калининграде: СС, БАД, ТУ, ДС, паспорта безопасности - Эксперт Тест

Из-за отсутствия прототипов у некоторых функций (для краткости, пример и так длинный), код
вероятно может сломаться на платформах, где размеры указателя и целого
разные.

ExitStack() и null_check используются, чтобы ресурсы освободить в
случае ошибки. Так как используется C API, то приходится явно временем
жизни управлять.

Пример:

print(get_serial_number_from_base64_der_oneline(base64_der))

где base64_der та же строка что и в других примерах.

Шифрование данных на клиенте для сервера

Для того, чтобы обеспечить конфиденциальность обмена данными между клиентом и сервером в плагине предусмотрено шифрование/расшифрование данных. Данные шифруются в формате CMS. Для того, чтобы зашифровать данные в формате CMS, требуется сертификат открытого ключа «адресата».

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

Для этого следует использовать функцию importCertificate, при этом в качестве параметра category следует передать CERT_CATEGORY_OTHER. Для использования в функции cmsEncrypt нужно получить тело сертификата по его дескриптору с помощью функции getCertificate.

При этом дескриптор является уникальным и неизменным и может быть сохранен в учетной записи пользователя на сервере при импорте сертификата сервера. Для того, чтобы использовалось аппаратное шифрование по ГОСТ 28147-89, требуется установить опцию useHardwareEncryption в true. В противном случае будет использована быстрая программная реализация ГОСТ 28147-89.

Последовательность вызовов приведена на картинке:

Шифрование данных на клиенте:

try
{
    var recipientCert = plugin.getCertificate(deviceId, certRecId);        
}
catch (error) 
{
    console.log(error);
}

var options = {};
options.useHardwareEncryption = true;
var cms;

try
{
    cms = plugin.cmsEncrypt(deviceId, certSenderId, recipientCert, data, options);
}
catch (error) 
{
    console.log(error);
}

Расшифрование данных на сервере, перед расшифрованием сообщение нужно обрамить PEM-заголовками “—–BEGIN PKCS7—–” и “—–END PKCS7—–“:

openssl smime -engine gost -decrypt -in message.cms -inform PEM -recip recipient.crt -inkey recipient.key

recipient.crt — сертификат того, для кого зашифровано сообщение, recipient.key — ключ того, для кого зашифровано сообщение.

Экспорт сертификата в формате base-64. – c# |

Я пытаюсь экспортировать сертификат без закрытого ключа как файл с кодировкой BASE-64, так же как экспортировать его из окон. При экспорте из окон я могу открыть файл .cer в блокноте.

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

X509Certificate2 cert = new X509Certificate2("c:\myCert.pfx", "test", X509KeyStorageFlags.Exportable);

File.WriteAllBytes("c:\testcer.cer", cert.Export(X509ContentType.Cert));

Я попытался удалить “X509KeyStorageFlags.Exportable”, но это не работает. Я что-то пропустил?

Изменить – я попробовал

File.WriteAllText("c:\testcer.cer",Convert.ToBase64String(cert.Export(X509ContentType.Cert)))

и что, похоже, работает, однако, отсутствует “—– BEGIN CERTIFICATE —–” и “—– END CERTIFICATE —–”

Оцените статью
Мой сертификат
Добавить комментарий