feat: живой цикл M2M с НРД + мастер установки ключа на флешку
Инфраструктура M2M (живой обмен с НРД через ИШ): - обработка M2MTransferResponse: ERROR(M2Mxx) → заявка Отклонена, сохранение ответа; INFO → ждём Decision; идемпотентность поллера - fallback-корреляция ответов с нулевым GUID (M2M14/M2M17) по FIFO - сырой XML ответа НРД в карточке заявки (для пересылки в ТП) - тестовый пакет роботу приведён к эталону m2m_robot_samples (CostInfo=Yes, 4 бумаги, IsolationStatus, DocumentSeries=сценарий); override паспорта - редирект из теста сразу в карточку заявки Мастер установки ключа Валидаты на флешку (admin/setup/keywizard): - пошаговый: загрузка .7z+пароль → выбор флешки → запись → справочник сертификатов (CRL) → перезапуск+проверка ИШ → готово - привилегированный воркер (bj-keymedia) в host-namespace через файл-обмен, bj-server остаётся в песочнице - сохранение структуры профиля архива (spr<N>), перечисление съёмных USB Прочее: - пакет-доказательство для ТП НРД + форма регистрации участника M2M - эталонные образцы робота (DOC/m2m_robot_samples) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+219
-273
@@ -1,351 +1,297 @@
|
||||
// Package cryptocli — Go-клиент к СКЗИ через PKCS#11 (КриптоПро CSP,
|
||||
// Рутокен ЭЦП 2.0, ViPNet, Валидата). Загружает указанный .so модуль,
|
||||
// открывает сессию, перечисляет токены, читает сертификаты и
|
||||
// предоставляет операции Sign/Verify.
|
||||
// Package cryptocli — gRPC-клиент к crypto-service по Unix Domain
|
||||
// Socket. Сам Go-процесс не выполняет криптографию — всё делает
|
||||
// Java-сайдкар (services/crypto-service) поверх АПК «Валидата
|
||||
// Клиент L».
|
||||
//
|
||||
// На ВМ без установленного СКЗИ модуль не загрузится — клиент
|
||||
// возвращает понятную ошибку и помечает себя как «провайдер
|
||||
// недоступен». В этом случае lk-gateway переходит в режим stub:
|
||||
// XMLDSig-подписи проходят без реальной проверки (только для
|
||||
// дев-стендов и демо).
|
||||
// На дев-стендах без поднятого сайдкара (стандартный путь
|
||||
// /run/bj/crypto.sock не существует) клиент возвращает понятную
|
||||
// ошибку «провайдер недоступен» и lk-gateway работает в stub-режиме:
|
||||
// XMLDSig-подписи проходят без проверки (только для демо).
|
||||
package cryptocli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/pkcs11"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/cryptocli/cryptopb"
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/m2mcore"
|
||||
)
|
||||
|
||||
// Provider — тип СКЗИ-провайдера.
|
||||
// Provider — тип СКЗИ-провайдера (информативный — реальный выбор
|
||||
// делает crypto-service через переменную BJ_CRYPTO_PROVIDER).
|
||||
type Provider string
|
||||
|
||||
// Известные провайдеры.
|
||||
const (
|
||||
ProviderStub Provider = "stub"
|
||||
ProviderCryptoPro Provider = "cryptopro"
|
||||
ProviderRutoken Provider = "rutoken"
|
||||
ProviderValidata Provider = "validata"
|
||||
ProviderVipNet Provider = "vipnet"
|
||||
ProviderStub Provider = "stub"
|
||||
ProviderValidata Provider = "validata"
|
||||
)
|
||||
|
||||
// DefaultModulePath возвращает дефолтный путь до PKCS#11 .so модуля
|
||||
// для указанного провайдера. Используется в /admin/setup как placeholder.
|
||||
// DefaultModulePath сохранена для обратной совместимости с UI;
|
||||
// текущий путь интеграции — не PKCS#11-модуль, а UDS-сокет
|
||||
// crypto-service. Возвращаемое значение информативное.
|
||||
func DefaultModulePath(p Provider) string {
|
||||
switch p {
|
||||
case ProviderCryptoPro:
|
||||
return "/opt/cprocsp/lib/amd64/libcppkcs11.so"
|
||||
case ProviderRutoken:
|
||||
return "/usr/lib64/librtpkcs11ecp.so"
|
||||
case ProviderValidata:
|
||||
return "/opt/validata/lib/libvalidata-pkcs11.so"
|
||||
case ProviderVipNet:
|
||||
return "/opt/itcs/lib/libvipnet-pkcs11.so"
|
||||
if p == ProviderValidata {
|
||||
return "/opt/Validata/VDCSP/lib/amd64 (через сайдкар, не PKCS#11)"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Config — конфигурация клиента.
|
||||
type Config struct {
|
||||
Provider Provider
|
||||
ModulePath string // путь до PKCS#11 .so модуля (libcppkcs11.so и т.п.)
|
||||
PIN string // PIN для сессии (логин на токен)
|
||||
SlotID uint // 0 = первый доступный
|
||||
Timeout time.Duration
|
||||
// SocketPath — путь к UDS-сокету crypto-service.
|
||||
// Пустое значение = /run/bj/crypto.sock.
|
||||
SocketPath string
|
||||
// Provider — желаемый провайдер; информативно (см. выше).
|
||||
Provider Provider
|
||||
// ModulePath — сохраняется для UI; в gRPC-режиме не используется.
|
||||
ModulePath string
|
||||
// Timeout — таймаут одной gRPC-операции.
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// Client — PKCS#11-клиент к СКЗИ.
|
||||
// Client — gRPC-клиент к crypto-service.
|
||||
type Client struct {
|
||||
cfg Config
|
||||
mu sync.Mutex
|
||||
ctx *pkcs11.Ctx
|
||||
opened bool
|
||||
cfg Config
|
||||
mu sync.Mutex
|
||||
conn *grpc.ClientConn
|
||||
api cryptopb.CryptoServiceClient
|
||||
}
|
||||
|
||||
// New создаёт клиент. Сам Initialize() здесь не вызывается — это
|
||||
// делает Connect или явный Ping (Health-check на admin-странице).
|
||||
// New создаёт клиент. Само соединение поднимается лениво при первом
|
||||
// вызове.
|
||||
func New(cfg Config) *Client {
|
||||
if cfg.Timeout == 0 {
|
||||
cfg.Timeout = 5 * time.Second
|
||||
}
|
||||
if cfg.SocketPath == "" {
|
||||
cfg.SocketPath = "/run/bj/crypto.sock"
|
||||
}
|
||||
return &Client{cfg: cfg}
|
||||
}
|
||||
|
||||
// Health — лёгкая проверка готовности. Шаги:
|
||||
// 1. Сам файл .so существует?
|
||||
// 2. Initialize модуля?
|
||||
// 3. Есть ли хотя бы один доступный слот с токеном?
|
||||
// 4. Информация о токене (label, manufacturer, serial).
|
||||
func (c *Client) Health(_ context.Context) (HealthInfo, error) {
|
||||
if c.cfg.Provider == "" || c.cfg.Provider == ProviderStub {
|
||||
return HealthInfo{Provider: string(ProviderStub),
|
||||
Message: "Провайдер stub — реальная криптография не подключена."}, nil
|
||||
}
|
||||
if c.cfg.ModulePath == "" {
|
||||
return HealthInfo{}, errors.New("cryptocli: ModulePath не задан")
|
||||
}
|
||||
if _, err := os.Stat(c.cfg.ModulePath); err != nil {
|
||||
return HealthInfo{}, fmt.Errorf("cryptocli: модуль %s не найден: %w", c.cfg.ModulePath, err)
|
||||
}
|
||||
|
||||
// Close закрывает gRPC-соединение.
|
||||
func (c *Client) Close() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if err := c.ensureInitLocked(); err != nil {
|
||||
return HealthInfo{}, err
|
||||
if c.conn != nil {
|
||||
err := c.conn.Close()
|
||||
c.conn = nil
|
||||
c.api = nil
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := c.ctx.GetInfo()
|
||||
if err != nil {
|
||||
return HealthInfo{}, fmt.Errorf("cryptocli: GetInfo: %w", err)
|
||||
}
|
||||
|
||||
slots, err := c.ctx.GetSlotList(true) // только токены
|
||||
if err != nil {
|
||||
return HealthInfo{}, fmt.Errorf("cryptocli: GetSlotList: %w", err)
|
||||
}
|
||||
h := HealthInfo{
|
||||
Provider: string(c.cfg.Provider),
|
||||
ModulePath: c.cfg.ModulePath,
|
||||
CryptokiVersion: fmt.Sprintf("%d.%d", info.CryptokiVersion.Major, info.CryptokiVersion.Minor),
|
||||
ManufacturerID: info.ManufacturerID,
|
||||
LibraryVersion: fmt.Sprintf("%d.%d", info.LibraryVersion.Major, info.LibraryVersion.Minor),
|
||||
}
|
||||
for _, slot := range slots {
|
||||
tok, err := c.ctx.GetTokenInfo(slot)
|
||||
if err != nil {
|
||||
h.Tokens = append(h.Tokens, TokenInfo{SlotID: slot, Error: err.Error()})
|
||||
continue
|
||||
}
|
||||
h.Tokens = append(h.Tokens, TokenInfo{
|
||||
SlotID: slot,
|
||||
Label: tok.Label,
|
||||
Manufacturer: tok.ManufacturerID,
|
||||
Model: tok.Model,
|
||||
SerialNumber: tok.SerialNumber,
|
||||
})
|
||||
}
|
||||
if len(h.Tokens) == 0 {
|
||||
h.Message = "Модуль PKCS#11 загружен, но активных токенов не найдено. Подключите Рутокен или установите ключевой контейнер."
|
||||
} else {
|
||||
h.Message = fmt.Sprintf("Доступно токенов: %d. Криптография готова к работе.", len(h.Tokens))
|
||||
}
|
||||
return h, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Certificate — DER-сертификат с распарсенными атрибутами для UI.
|
||||
// ensureConn устанавливает gRPC-канал к UDS-сокету при первом
|
||||
// использовании. Используем встроенный в grpc-go резолвер unix:.
|
||||
func (c *Client) ensureConn() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.api != nil {
|
||||
return nil
|
||||
}
|
||||
target := "unix:" + c.cfg.SocketPath
|
||||
conn, err := grpc.NewClient(target,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cryptocli: dial %s: %w", c.cfg.SocketPath, err)
|
||||
}
|
||||
c.conn = conn
|
||||
c.api = cryptopb.NewCryptoServiceClient(conn)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Health — gRPC Health-вызов. Если сокет недоступен (сайдкар не
|
||||
// поднят) — вернёт «провайдер недоступен» с явной ошибкой.
|
||||
func (c *Client) Health(ctx context.Context) (HealthInfo, error) {
|
||||
if c.cfg.Provider == ProviderStub {
|
||||
return HealthInfo{
|
||||
Provider: string(ProviderStub),
|
||||
Message: "Провайдер stub — реальная криптография не подключена.",
|
||||
}, nil
|
||||
}
|
||||
if err := c.ensureConn(); err != nil {
|
||||
return HealthInfo{}, err
|
||||
}
|
||||
cctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
defer cancel()
|
||||
resp, err := c.api.Health(cctx, &cryptopb.HealthRequest{})
|
||||
if err != nil {
|
||||
return HealthInfo{}, fmt.Errorf("cryptocli: Health: %w", err)
|
||||
}
|
||||
return HealthInfo{
|
||||
Provider: resp.GetProvider(),
|
||||
Message: resp.GetVersion(),
|
||||
ModulePath: c.cfg.SocketPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Certificate — упрощённое описание сертификата (для совместимости с
|
||||
// прежним UI). В gRPC-режиме crypto-service возвращает информацию о
|
||||
// подписанте через VerifyResponse; полный список сертификатов
|
||||
// (FindCertificates) пока не реализован — для UI возвращаем пустой
|
||||
// список.
|
||||
type Certificate struct {
|
||||
SlotID uint
|
||||
TokenLabel string
|
||||
Label string // CKA_LABEL (объект на токене)
|
||||
Label string
|
||||
SubjectCN string
|
||||
IssuerCN string
|
||||
Serial string
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time
|
||||
INN string // если есть в OID 1.2.643.3.131.1.1
|
||||
INN string
|
||||
DER []byte
|
||||
HasPrivateKey bool // найден ли парный приватный ключ на токене
|
||||
HasPrivateKey bool
|
||||
}
|
||||
|
||||
// FindCertificates перечисляет сертификаты на всех подключенных
|
||||
// токенах. Не требует Login для публичных сертификатов; для контейнеров
|
||||
// CryptoPro/Rutoken достаточно открыть сессию (CKU_USER не выполняется).
|
||||
// FindCertificates пока возвращает пустой список — список ключей
|
||||
// управляется самой Валидатой через её собственный справочник (zcs),
|
||||
// а bj-server о конкретных сертификатах узнаёт по результатам
|
||||
// Verify/Sign-операций. Эту функцию переопределим позже отдельным
|
||||
// gRPC-методом ListCertificates если потребуется.
|
||||
func (c *Client) FindCertificates(_ context.Context) ([]Certificate, error) {
|
||||
if c.cfg.Provider == "" || c.cfg.Provider == ProviderStub {
|
||||
return nil, errors.New("cryptocli: провайдер stub — нет реальных сертификатов")
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if err := c.ensureInitLocked(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
slots, err := c.ctx.GetSlotList(true)
|
||||
// Shutdown — отправляет команду «выйти с exit-code 2» сайдкару.
|
||||
// systemd с Restart=on-failure поднимет его обратно. Возвращает
|
||||
// ошибку если соединение разорвалось (что нормально и означает что
|
||||
// сайдкар уже завершается).
|
||||
func (c *Client) Shutdown(ctx context.Context) error {
|
||||
if c.cfg.Provider == ProviderStub {
|
||||
return errors.New("provider=stub: некуда отправлять Shutdown")
|
||||
}
|
||||
if err := c.ensureConn(); err != nil {
|
||||
return err
|
||||
}
|
||||
cctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
defer cancel()
|
||||
_, err := c.api.Shutdown(cctx, &cryptopb.ShutdownRequest{})
|
||||
// Закрываем соединение, чтобы не держать ссылку на падающий процесс.
|
||||
_ = c.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// ActivateResult — результат переключения профиля Валидаты.
|
||||
type ActivateResult struct {
|
||||
OK bool
|
||||
Provider string
|
||||
Profile string
|
||||
Message string
|
||||
}
|
||||
|
||||
// Activate переключает crypto-service на указанный профиль pki1.conf.
|
||||
// Пустая строка = minimal mode (без профиля).
|
||||
func (c *Client) Activate(ctx context.Context, profile string) (ActivateResult, error) {
|
||||
if c.cfg.Provider == ProviderStub {
|
||||
return ActivateResult{
|
||||
OK: false,
|
||||
Provider: string(ProviderStub),
|
||||
Message: "Провайдер stub — переключение профиля недоступно.",
|
||||
}, nil
|
||||
}
|
||||
if err := c.ensureConn(); err != nil {
|
||||
return ActivateResult{}, err
|
||||
}
|
||||
cctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
defer cancel()
|
||||
resp, err := c.api.Activate(cctx, &cryptopb.ActivateRequest{Profile: profile})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cryptocli: GetSlotList: %w", err)
|
||||
return ActivateResult{}, fmt.Errorf("cryptocli: Activate: %w", err)
|
||||
}
|
||||
|
||||
var out []Certificate
|
||||
for _, slot := range slots {
|
||||
tokInfo, _ := c.ctx.GetTokenInfo(slot)
|
||||
certs, err := c.listSlotCertificates(slot, tokInfo.Label)
|
||||
if err != nil {
|
||||
// продолжаем — возможно один слот занят, другие доступны
|
||||
continue
|
||||
}
|
||||
out = append(out, certs...)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// listSlotCertificates открывает сессию на слоте, ищет CKO_CERTIFICATE,
|
||||
// читает DER и парсит x509.
|
||||
func (c *Client) listSlotCertificates(slot uint, tokenLabel string) ([]Certificate, error) {
|
||||
sess, err := c.ctx.OpenSession(slot, pkcs11.CKF_SERIAL_SESSION)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("OpenSession: %w", err)
|
||||
}
|
||||
defer func() { _ = c.ctx.CloseSession(sess) }()
|
||||
|
||||
template := []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_CERTIFICATE),
|
||||
}
|
||||
if err := c.ctx.FindObjectsInit(sess, template); err != nil {
|
||||
return nil, fmt.Errorf("FindObjectsInit: %w", err)
|
||||
}
|
||||
handles, _, err := c.ctx.FindObjects(sess, 32)
|
||||
_ = c.ctx.FindObjectsFinal(sess)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FindObjects: %w", err)
|
||||
}
|
||||
|
||||
out := make([]Certificate, 0, len(handles))
|
||||
for _, h := range handles {
|
||||
attrs, err := c.ctx.GetAttributeValue(sess, h, []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_VALUE, nil),
|
||||
pkcs11.NewAttribute(pkcs11.CKA_LABEL, nil),
|
||||
pkcs11.NewAttribute(pkcs11.CKA_ID, nil),
|
||||
})
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
cert := Certificate{
|
||||
SlotID: slot,
|
||||
TokenLabel: tokenLabel,
|
||||
}
|
||||
var idAttr []byte
|
||||
for _, a := range attrs {
|
||||
switch a.Type {
|
||||
case pkcs11.CKA_VALUE:
|
||||
cert.DER = a.Value
|
||||
case pkcs11.CKA_LABEL:
|
||||
cert.Label = string(a.Value)
|
||||
case pkcs11.CKA_ID:
|
||||
idAttr = a.Value
|
||||
}
|
||||
}
|
||||
// Парсим X.509 (ГОСТ-сертификаты тоже парсятся через crypto/x509
|
||||
// — Subject/Issuer/Serial/Validity не зависят от алгоритма подписи).
|
||||
parsed, err := x509.ParseCertificate(cert.DER)
|
||||
if err == nil {
|
||||
cert.SubjectCN = parsed.Subject.CommonName
|
||||
cert.IssuerCN = parsed.Issuer.CommonName
|
||||
cert.Serial = parsed.SerialNumber.Text(16)
|
||||
cert.NotBefore = parsed.NotBefore
|
||||
cert.NotAfter = parsed.NotAfter
|
||||
// ИНН в OID 1.2.643.3.131.1.1 — извлекаем из Subject.
|
||||
cert.INN = extractINN(parsed)
|
||||
}
|
||||
// Проверим есть ли парный приватный ключ.
|
||||
if len(idAttr) > 0 {
|
||||
cert.HasPrivateKey = c.hasPrivateKey(sess, idAttr)
|
||||
}
|
||||
out = append(out, cert)
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// hasPrivateKey ищет CKO_PRIVATE_KEY с тем же CKA_ID что и сертификат.
|
||||
func (c *Client) hasPrivateKey(sess pkcs11.SessionHandle, id []byte) bool {
|
||||
tmpl := []*pkcs11.Attribute{
|
||||
pkcs11.NewAttribute(pkcs11.CKA_CLASS, pkcs11.CKO_PRIVATE_KEY),
|
||||
pkcs11.NewAttribute(pkcs11.CKA_ID, id),
|
||||
}
|
||||
if err := c.ctx.FindObjectsInit(sess, tmpl); err != nil {
|
||||
return false
|
||||
}
|
||||
defer func() { _ = c.ctx.FindObjectsFinal(sess) }()
|
||||
handles, _, err := c.ctx.FindObjects(sess, 1)
|
||||
return err == nil && len(handles) > 0
|
||||
}
|
||||
|
||||
// extractINN ищет ИНН в Subject сертификата по OID НРД 1.2.643.3.131.1.1.
|
||||
func extractINN(c *x509.Certificate) string {
|
||||
innOID := asn1.ObjectIdentifier{1, 2, 643, 3, 131, 1, 1}
|
||||
for _, name := range c.Subject.Names {
|
||||
if name.Type.Equal(innOID) {
|
||||
if s, ok := name.Value.(string); ok {
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// VerifyXMLDSig — заглушка для интерфейса m2mcore.CryptoVerifier.
|
||||
// Реальная проверка XMLDSig потребует канонизации XML и parsing
|
||||
// сертификатов; пока возвращает CertInfo с подписанной полезной
|
||||
// нагрузкой как хеш SHA-256 и заглушку CN. На M3-M4 заменим на
|
||||
// полноценный verify через PKCS#11 + Apache Santuario-like канонизатор.
|
||||
func (c *Client) VerifyXMLDSig(ctx context.Context, payload []byte) (m2mcore.CertInfo, error) {
|
||||
if _, err := c.Health(ctx); err != nil {
|
||||
return m2mcore.CertInfo{}, err
|
||||
}
|
||||
sum := sha256.Sum256(payload)
|
||||
return m2mcore.CertInfo{
|
||||
SignerCN: "stub-verifier",
|
||||
SignerINN: "",
|
||||
Serial: hex.EncodeToString(sum[:8]),
|
||||
NotBefore: time.Now().Add(-365 * 24 * time.Hour),
|
||||
NotAfter: time.Now().Add(365 * 24 * time.Hour),
|
||||
return ActivateResult{
|
||||
OK: resp.GetOk(),
|
||||
Provider: resp.GetProvider(),
|
||||
Profile: resp.GetProfile(),
|
||||
Message: resp.GetMessage(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close завершает работу PKCS#11 модуля.
|
||||
func (c *Client) Close() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.ctx == nil {
|
||||
return nil
|
||||
// VerifyXMLDSig — проксирует в crypto-service.VerifyXMLDSig.
|
||||
// Реализует m2mcore.CryptoVerifier — поэтому возвращает CertInfo,
|
||||
// заполненный из gRPC-ответа.
|
||||
func (c *Client) VerifyXMLDSig(ctx context.Context, payload []byte) (m2mcore.CertInfo, error) {
|
||||
if c.cfg.Provider == ProviderStub {
|
||||
return m2mcore.CertInfo{
|
||||
SignerCN: "stub-verifier",
|
||||
}, nil
|
||||
}
|
||||
_ = c.ctx.Finalize()
|
||||
c.ctx.Destroy()
|
||||
c.ctx = nil
|
||||
c.opened = false
|
||||
return nil
|
||||
if err := c.ensureConn(); err != nil {
|
||||
return m2mcore.CertInfo{}, err
|
||||
}
|
||||
cctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
defer cancel()
|
||||
resp, err := c.api.VerifyXMLDSig(cctx, &cryptopb.VerifyRequest{
|
||||
Payload: payload,
|
||||
})
|
||||
if err != nil {
|
||||
return m2mcore.CertInfo{}, fmt.Errorf("cryptocli: VerifyXMLDSig: %w", err)
|
||||
}
|
||||
if !resp.GetValid() {
|
||||
var msg string
|
||||
if errs := resp.GetErrors(); len(errs) > 0 {
|
||||
msg = errs[0]
|
||||
} else {
|
||||
msg = "подпись недействительна"
|
||||
}
|
||||
return m2mcore.CertInfo{}, errors.New("cryptocli: " + msg)
|
||||
}
|
||||
return m2mcore.CertInfo{
|
||||
SignerCN: resp.GetSignerCn(),
|
||||
SignerINN: resp.GetSignerInn(),
|
||||
Serial: resp.GetSerial(),
|
||||
NotBefore: time.Unix(resp.GetNotBefore(), 0),
|
||||
NotAfter: time.Unix(resp.GetNotAfter(), 0),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ensureInitLocked инициализирует PKCS#11 модуль если ещё не.
|
||||
// Должен вызываться под c.mu.Lock.
|
||||
func (c *Client) ensureInitLocked() error {
|
||||
if c.opened {
|
||||
return nil
|
||||
// SignXMLDSig — проксирует в crypto-service.SignXMLDSig. Возвращает
|
||||
// DER-байты CMS detached signature (готовы к включению в XMLDSig-обёртку
|
||||
// или к самостоятельной отправке как .p7s).
|
||||
//
|
||||
// keyAlias — alias ключа из ПСП Валидаты (пустой = ключ по умолчанию
|
||||
// активного профиля). profile — имя профиля в pki1.conf, пустой = тот
|
||||
// что инициализирован.
|
||||
func (c *Client) SignXMLDSig(ctx context.Context, payload []byte, keyAlias, profile string) ([]byte, error) {
|
||||
if c.cfg.Provider == ProviderStub {
|
||||
return nil, errors.New("provider=stub: подпись недоступна")
|
||||
}
|
||||
c.ctx = pkcs11.New(c.cfg.ModulePath)
|
||||
if c.ctx == nil {
|
||||
return fmt.Errorf("cryptocli: не получилось загрузить модуль %s", c.cfg.ModulePath)
|
||||
if err := c.ensureConn(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.ctx.Initialize(); err != nil {
|
||||
c.ctx.Destroy()
|
||||
c.ctx = nil
|
||||
return fmt.Errorf("cryptocli: Initialize: %w", err)
|
||||
cctx, cancel := context.WithTimeout(ctx, c.cfg.Timeout)
|
||||
defer cancel()
|
||||
resp, err := c.api.SignXMLDSig(cctx, &cryptopb.SignRequest{
|
||||
Payload: payload,
|
||||
KeyAlias: keyAlias,
|
||||
Profile: profile,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cryptocli: SignXMLDSig: %w", err)
|
||||
}
|
||||
c.opened = true
|
||||
return nil
|
||||
return resp.GetSignedXml(), nil
|
||||
}
|
||||
|
||||
// HealthInfo — что показывает /admin/setup и /admin/status.
|
||||
// HealthInfo — что показывает /admin/setup → СКЗИ.
|
||||
type HealthInfo struct {
|
||||
Provider string
|
||||
ModulePath string
|
||||
CryptokiVersion string
|
||||
ManufacturerID string
|
||||
LibraryVersion string
|
||||
ModulePath string // в gRPC-режиме — UDS-сокет
|
||||
CryptokiVersion string // не используется
|
||||
ManufacturerID string // не используется
|
||||
LibraryVersion string // не используется
|
||||
Tokens []TokenInfo
|
||||
Message string
|
||||
}
|
||||
|
||||
// TokenInfo — описание подключённого токена/контейнера.
|
||||
// TokenInfo — для совместимости с UI; в gRPC-режиме пустой.
|
||||
type TokenInfo struct {
|
||||
SlotID uint
|
||||
Label string
|
||||
|
||||
@@ -8,55 +8,45 @@ import (
|
||||
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/cryptocli"
|
||||
)
|
||||
|
||||
// TestStubProviderHealthOK — провайдер stub не лезет в gRPC,
|
||||
// возвращает информативный Health без ошибки.
|
||||
func TestStubProviderHealthOK(t *testing.T) {
|
||||
cli := cryptocli.New(cryptocli.Config{Provider: cryptocli.ProviderStub})
|
||||
defer cli.Close()
|
||||
h, err := cli.Health(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("Health: %v", err)
|
||||
}
|
||||
if h.Provider != string(cryptocli.ProviderStub) {
|
||||
t.Errorf("Provider = %q", h.Provider)
|
||||
t.Errorf("Provider = %q, ожидался stub", h.Provider)
|
||||
}
|
||||
if !strings.Contains(h.Message, "stub") {
|
||||
t.Errorf("сообщение не содержит 'stub': %q", h.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func TestModulePathMissing(t *testing.T) {
|
||||
// TestValidataProviderNoSocket — провайдер validata пытается дойти до
|
||||
// сайдкара, но в тестах сокета нет. gRPC-клиент создаётся лениво
|
||||
// (NewClient не возвращает ошибку), а ошибка приходит при первом RPC.
|
||||
func TestValidataProviderNoSocket(t *testing.T) {
|
||||
cli := cryptocli.New(cryptocli.Config{
|
||||
Provider: cryptocli.ProviderCryptoPro,
|
||||
ModulePath: "/nonexistent/libcppkcs11.so",
|
||||
Provider: cryptocli.ProviderValidata,
|
||||
SocketPath: "/nonexistent/crypto.sock",
|
||||
})
|
||||
defer cli.Close()
|
||||
_, err := cli.Health(context.Background())
|
||||
if err == nil {
|
||||
t.Fatal("ожидалась ошибка о ненайденном модуле")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "не найден") {
|
||||
t.Errorf("неинформативная ошибка: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyModulePath(t *testing.T) {
|
||||
cli := cryptocli.New(cryptocli.Config{Provider: cryptocli.ProviderCryptoPro})
|
||||
_, err := cli.Health(context.Background())
|
||||
if err == nil {
|
||||
t.Fatal("ожидалась ошибка о пустом ModulePath")
|
||||
t.Fatal("ожидалась ошибка о недоступном сокете")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDefaultModulePath — информативный текст для UI.
|
||||
func TestDefaultModulePath(t *testing.T) {
|
||||
cases := []struct {
|
||||
p cryptocli.Provider
|
||||
want string
|
||||
}{
|
||||
{cryptocli.ProviderCryptoPro, "/opt/cprocsp/lib/amd64/libcppkcs11.so"},
|
||||
{cryptocli.ProviderRutoken, "/usr/lib64/librtpkcs11ecp.so"},
|
||||
{cryptocli.ProviderStub, ""},
|
||||
if cryptocli.DefaultModulePath(cryptocli.ProviderStub) != "" {
|
||||
t.Error("DefaultModulePath(stub) должен быть пустым")
|
||||
}
|
||||
for _, c := range cases {
|
||||
got := cryptocli.DefaultModulePath(c.p)
|
||||
if got != c.want {
|
||||
t.Errorf("DefaultModulePath(%s) = %q, ожидалось %q", c.p, got, c.want)
|
||||
}
|
||||
v := cryptocli.DefaultModulePath(cryptocli.ProviderValidata)
|
||||
if v == "" {
|
||||
t.Error("DefaultModulePath(validata) не должен быть пустым")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,694 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v3.12.4
|
||||
// source: crypto.proto
|
||||
|
||||
package cryptopb
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type ActivateRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Имя профиля в pki1.conf. Пустая строка = minimal mode.
|
||||
Profile string `protobuf:"bytes,1,opt,name=profile,proto3" json:"profile,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActivateRequest) Reset() {
|
||||
*x = ActivateRequest{}
|
||||
mi := &file_crypto_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ActivateRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ActivateRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ActivateRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActivateRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ActivateRequest) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *ActivateRequest) GetProfile() string {
|
||||
if x != nil {
|
||||
return x.Profile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ActivateResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// true если провайдер успешно (пере)инициализирован.
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
// Имя активного провайдера ("validata" / "stub").
|
||||
Provider string `protobuf:"bytes,2,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
// Имя активного профиля (пусто для minimal).
|
||||
Profile string `protobuf:"bytes,3,opt,name=profile,proto3" json:"profile,omitempty"`
|
||||
// Сообщение о результате (для UI).
|
||||
Message string `protobuf:"bytes,4,opt,name=message,proto3" json:"message,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) Reset() {
|
||||
*x = ActivateResponse{}
|
||||
mi := &file_crypto_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ActivateResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ActivateResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActivateResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ActivateResponse) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) GetProfile() string {
|
||||
if x != nil {
|
||||
return x.Profile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActivateResponse) GetMessage() string {
|
||||
if x != nil {
|
||||
return x.Message
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ShutdownRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ShutdownRequest) Reset() {
|
||||
*x = ShutdownRequest{}
|
||||
mi := &file_crypto_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ShutdownRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ShutdownRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ShutdownRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ShutdownRequest) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
type ShutdownResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// true означает «запрос принят, процесс завершится через ~500ms».
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ShutdownResponse) Reset() {
|
||||
*x = ShutdownResponse{}
|
||||
mi := &file_crypto_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ShutdownResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ShutdownResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ShutdownResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ShutdownResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ShutdownResponse) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *ShutdownResponse) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type VerifyRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Целиком подписанный XML.
|
||||
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
// Профиль ключей и сертификатов: "guest-gost" | "test3-gost" |
|
||||
// "prod-gost" | "guest-rsa" | ... — определяет хранилище и trust store.
|
||||
Profile string `protobuf:"bytes,2,opt,name=profile,proto3" json:"profile,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *VerifyRequest) Reset() {
|
||||
*x = VerifyRequest{}
|
||||
mi := &file_crypto_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *VerifyRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*VerifyRequest) ProtoMessage() {}
|
||||
|
||||
func (x *VerifyRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use VerifyRequest.ProtoReflect.Descriptor instead.
|
||||
func (*VerifyRequest) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *VerifyRequest) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *VerifyRequest) GetProfile() string {
|
||||
if x != nil {
|
||||
return x.Profile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type VerifyResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Прошла ли проверка.
|
||||
Valid bool `protobuf:"varint,1,opt,name=valid,proto3" json:"valid,omitempty"`
|
||||
// CN из сертификата подписанта.
|
||||
SignerCn string `protobuf:"bytes,2,opt,name=signer_cn,json=signerCn,proto3" json:"signer_cn,omitempty"`
|
||||
// ИНН из сертификата (если присутствует в OID 1.2.643.3.131.1.1).
|
||||
SignerInn string `protobuf:"bytes,3,opt,name=signer_inn,json=signerInn,proto3" json:"signer_inn,omitempty"`
|
||||
// Серийный номер сертификата (hex).
|
||||
Serial string `protobuf:"bytes,4,opt,name=serial,proto3" json:"serial,omitempty"`
|
||||
// Срок действия сертификата (unix epoch, секунды).
|
||||
NotBefore int64 `protobuf:"varint,5,opt,name=not_before,json=notBefore,proto3" json:"not_before,omitempty"`
|
||||
NotAfter int64 `protobuf:"varint,6,opt,name=not_after,json=notAfter,proto3" json:"not_after,omitempty"`
|
||||
// Тексты ошибок проверки (если valid=false).
|
||||
Errors []string `protobuf:"bytes,7,rep,name=errors,proto3" json:"errors,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) Reset() {
|
||||
*x = VerifyResponse{}
|
||||
mi := &file_crypto_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*VerifyResponse) ProtoMessage() {}
|
||||
|
||||
func (x *VerifyResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use VerifyResponse.ProtoReflect.Descriptor instead.
|
||||
func (*VerifyResponse) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetValid() bool {
|
||||
if x != nil {
|
||||
return x.Valid
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetSignerCn() string {
|
||||
if x != nil {
|
||||
return x.SignerCn
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetSignerInn() string {
|
||||
if x != nil {
|
||||
return x.SignerInn
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetSerial() string {
|
||||
if x != nil {
|
||||
return x.Serial
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetNotBefore() int64 {
|
||||
if x != nil {
|
||||
return x.NotBefore
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetNotAfter() int64 {
|
||||
if x != nil {
|
||||
return x.NotAfter
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *VerifyResponse) GetErrors() []string {
|
||||
if x != nil {
|
||||
return x.Errors
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SignRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Канонизированный XML, который нужно подписать.
|
||||
Payload []byte `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
// Алиас ключа в JCP-keystore.
|
||||
KeyAlias string `protobuf:"bytes,2,opt,name=key_alias,json=keyAlias,proto3" json:"key_alias,omitempty"`
|
||||
// Профиль (тот же что у Verify).
|
||||
Profile string `protobuf:"bytes,3,opt,name=profile,proto3" json:"profile,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SignRequest) Reset() {
|
||||
*x = SignRequest{}
|
||||
mi := &file_crypto_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SignRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SignRequest) ProtoMessage() {}
|
||||
|
||||
func (x *SignRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SignRequest.ProtoReflect.Descriptor instead.
|
||||
func (*SignRequest) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *SignRequest) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SignRequest) GetKeyAlias() string {
|
||||
if x != nil {
|
||||
return x.KeyAlias
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SignRequest) GetProfile() string {
|
||||
if x != nil {
|
||||
return x.Profile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SignResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Подписанный XML (с детачированной или встроенной подписью —
|
||||
// зависит от профиля).
|
||||
SignedXml []byte `protobuf:"bytes,1,opt,name=signed_xml,json=signedXml,proto3" json:"signed_xml,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SignResponse) Reset() {
|
||||
*x = SignResponse{}
|
||||
mi := &file_crypto_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SignResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SignResponse) ProtoMessage() {}
|
||||
|
||||
func (x *SignResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SignResponse.ProtoReflect.Descriptor instead.
|
||||
func (*SignResponse) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *SignResponse) GetSignedXml() []byte {
|
||||
if x != nil {
|
||||
return x.SignedXml
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type HealthRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *HealthRequest) Reset() {
|
||||
*x = HealthRequest{}
|
||||
mi := &file_crypto_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HealthRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HealthRequest) ProtoMessage() {}
|
||||
|
||||
func (x *HealthRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HealthRequest.ProtoReflect.Descriptor instead.
|
||||
func (*HealthRequest) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
type HealthResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
// Активный провайдер криптографии: "cryptopro" | "validata" | "vipnet" | "stub".
|
||||
Provider string `protobuf:"bytes,3,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *HealthResponse) Reset() {
|
||||
*x = HealthResponse{}
|
||||
mi := &file_crypto_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *HealthResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*HealthResponse) ProtoMessage() {}
|
||||
|
||||
func (x *HealthResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_crypto_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use HealthResponse.ProtoReflect.Descriptor instead.
|
||||
func (*HealthResponse) Descriptor() ([]byte, []int) {
|
||||
return file_crypto_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *HealthResponse) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *HealthResponse) GetVersion() string {
|
||||
if x != nil {
|
||||
return x.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *HealthResponse) GetProvider() string {
|
||||
if x != nil {
|
||||
return x.Provider
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_crypto_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_crypto_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\fcrypto.proto\x12\x1abridge_and_joins.crypto.v1\"+\n" +
|
||||
"\x0fActivateRequest\x12\x18\n" +
|
||||
"\aprofile\x18\x01 \x01(\tR\aprofile\"r\n" +
|
||||
"\x10ActivateResponse\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\x12\x1a\n" +
|
||||
"\bprovider\x18\x02 \x01(\tR\bprovider\x12\x18\n" +
|
||||
"\aprofile\x18\x03 \x01(\tR\aprofile\x12\x18\n" +
|
||||
"\amessage\x18\x04 \x01(\tR\amessage\"\x11\n" +
|
||||
"\x0fShutdownRequest\"\"\n" +
|
||||
"\x10ShutdownResponse\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\"C\n" +
|
||||
"\rVerifyRequest\x12\x18\n" +
|
||||
"\apayload\x18\x01 \x01(\fR\apayload\x12\x18\n" +
|
||||
"\aprofile\x18\x02 \x01(\tR\aprofile\"\xce\x01\n" +
|
||||
"\x0eVerifyResponse\x12\x14\n" +
|
||||
"\x05valid\x18\x01 \x01(\bR\x05valid\x12\x1b\n" +
|
||||
"\tsigner_cn\x18\x02 \x01(\tR\bsignerCn\x12\x1d\n" +
|
||||
"\n" +
|
||||
"signer_inn\x18\x03 \x01(\tR\tsignerInn\x12\x16\n" +
|
||||
"\x06serial\x18\x04 \x01(\tR\x06serial\x12\x1d\n" +
|
||||
"\n" +
|
||||
"not_before\x18\x05 \x01(\x03R\tnotBefore\x12\x1b\n" +
|
||||
"\tnot_after\x18\x06 \x01(\x03R\bnotAfter\x12\x16\n" +
|
||||
"\x06errors\x18\a \x03(\tR\x06errors\"^\n" +
|
||||
"\vSignRequest\x12\x18\n" +
|
||||
"\apayload\x18\x01 \x01(\fR\apayload\x12\x1b\n" +
|
||||
"\tkey_alias\x18\x02 \x01(\tR\bkeyAlias\x12\x18\n" +
|
||||
"\aprofile\x18\x03 \x01(\tR\aprofile\"-\n" +
|
||||
"\fSignResponse\x12\x1d\n" +
|
||||
"\n" +
|
||||
"signed_xml\x18\x01 \x01(\fR\tsignedXml\"\x0f\n" +
|
||||
"\rHealthRequest\"V\n" +
|
||||
"\x0eHealthResponse\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\x12\x18\n" +
|
||||
"\aversion\x18\x02 \x01(\tR\aversion\x12\x1a\n" +
|
||||
"\bprovider\x18\x03 \x01(\tR\bprovider2\x88\x04\n" +
|
||||
"\rCryptoService\x12f\n" +
|
||||
"\rVerifyXMLDSig\x12).bridge_and_joins.crypto.v1.VerifyRequest\x1a*.bridge_and_joins.crypto.v1.VerifyResponse\x12`\n" +
|
||||
"\vSignXMLDSig\x12'.bridge_and_joins.crypto.v1.SignRequest\x1a(.bridge_and_joins.crypto.v1.SignResponse\x12_\n" +
|
||||
"\x06Health\x12).bridge_and_joins.crypto.v1.HealthRequest\x1a*.bridge_and_joins.crypto.v1.HealthResponse\x12e\n" +
|
||||
"\bActivate\x12+.bridge_and_joins.crypto.v1.ActivateRequest\x1a,.bridge_and_joins.crypto.v1.ActivateResponse\x12e\n" +
|
||||
"\bShutdown\x12+.bridge_and_joins.crypto.v1.ShutdownRequest\x1a,.bridge_and_joins.crypto.v1.ShutdownResponseBq\n" +
|
||||
"!ru.zetit.bridgeandjoins.crypto.v1P\x01ZJgit.zetit.ru/zuevav/Bridge-and-Join-s/internal/cryptocli/cryptopb;cryptopbb\x06proto3"
|
||||
|
||||
var (
|
||||
file_crypto_proto_rawDescOnce sync.Once
|
||||
file_crypto_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_crypto_proto_rawDescGZIP() []byte {
|
||||
file_crypto_proto_rawDescOnce.Do(func() {
|
||||
file_crypto_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_crypto_proto_rawDesc), len(file_crypto_proto_rawDesc)))
|
||||
})
|
||||
return file_crypto_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_crypto_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_crypto_proto_goTypes = []any{
|
||||
(*ActivateRequest)(nil), // 0: bridge_and_joins.crypto.v1.ActivateRequest
|
||||
(*ActivateResponse)(nil), // 1: bridge_and_joins.crypto.v1.ActivateResponse
|
||||
(*ShutdownRequest)(nil), // 2: bridge_and_joins.crypto.v1.ShutdownRequest
|
||||
(*ShutdownResponse)(nil), // 3: bridge_and_joins.crypto.v1.ShutdownResponse
|
||||
(*VerifyRequest)(nil), // 4: bridge_and_joins.crypto.v1.VerifyRequest
|
||||
(*VerifyResponse)(nil), // 5: bridge_and_joins.crypto.v1.VerifyResponse
|
||||
(*SignRequest)(nil), // 6: bridge_and_joins.crypto.v1.SignRequest
|
||||
(*SignResponse)(nil), // 7: bridge_and_joins.crypto.v1.SignResponse
|
||||
(*HealthRequest)(nil), // 8: bridge_and_joins.crypto.v1.HealthRequest
|
||||
(*HealthResponse)(nil), // 9: bridge_and_joins.crypto.v1.HealthResponse
|
||||
}
|
||||
var file_crypto_proto_depIdxs = []int32{
|
||||
4, // 0: bridge_and_joins.crypto.v1.CryptoService.VerifyXMLDSig:input_type -> bridge_and_joins.crypto.v1.VerifyRequest
|
||||
6, // 1: bridge_and_joins.crypto.v1.CryptoService.SignXMLDSig:input_type -> bridge_and_joins.crypto.v1.SignRequest
|
||||
8, // 2: bridge_and_joins.crypto.v1.CryptoService.Health:input_type -> bridge_and_joins.crypto.v1.HealthRequest
|
||||
0, // 3: bridge_and_joins.crypto.v1.CryptoService.Activate:input_type -> bridge_and_joins.crypto.v1.ActivateRequest
|
||||
2, // 4: bridge_and_joins.crypto.v1.CryptoService.Shutdown:input_type -> bridge_and_joins.crypto.v1.ShutdownRequest
|
||||
5, // 5: bridge_and_joins.crypto.v1.CryptoService.VerifyXMLDSig:output_type -> bridge_and_joins.crypto.v1.VerifyResponse
|
||||
7, // 6: bridge_and_joins.crypto.v1.CryptoService.SignXMLDSig:output_type -> bridge_and_joins.crypto.v1.SignResponse
|
||||
9, // 7: bridge_and_joins.crypto.v1.CryptoService.Health:output_type -> bridge_and_joins.crypto.v1.HealthResponse
|
||||
1, // 8: bridge_and_joins.crypto.v1.CryptoService.Activate:output_type -> bridge_and_joins.crypto.v1.ActivateResponse
|
||||
3, // 9: bridge_and_joins.crypto.v1.CryptoService.Shutdown:output_type -> bridge_and_joins.crypto.v1.ShutdownResponse
|
||||
5, // [5:10] is the sub-list for method output_type
|
||||
0, // [0:5] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_crypto_proto_init() }
|
||||
func file_crypto_proto_init() {
|
||||
if File_crypto_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_crypto_proto_rawDesc), len(file_crypto_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_crypto_proto_goTypes,
|
||||
DependencyIndexes: file_crypto_proto_depIdxs,
|
||||
MessageInfos: file_crypto_proto_msgTypes,
|
||||
}.Build()
|
||||
File_crypto_proto = out.File
|
||||
file_crypto_proto_goTypes = nil
|
||||
file_crypto_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v3.12.4
|
||||
// source: crypto.proto
|
||||
|
||||
package cryptopb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
CryptoService_VerifyXMLDSig_FullMethodName = "/bridge_and_joins.crypto.v1.CryptoService/VerifyXMLDSig"
|
||||
CryptoService_SignXMLDSig_FullMethodName = "/bridge_and_joins.crypto.v1.CryptoService/SignXMLDSig"
|
||||
CryptoService_Health_FullMethodName = "/bridge_and_joins.crypto.v1.CryptoService/Health"
|
||||
CryptoService_Activate_FullMethodName = "/bridge_and_joins.crypto.v1.CryptoService/Activate"
|
||||
CryptoService_Shutdown_FullMethodName = "/bridge_and_joins.crypto.v1.CryptoService/Shutdown"
|
||||
)
|
||||
|
||||
// CryptoServiceClient is the client API for CryptoService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// CryptoService — серверная криптография по ГОСТ через КриптоПро JCP.
|
||||
// Слушает на Unix Domain Socket (по умолчанию /run/bj/crypto.sock).
|
||||
type CryptoServiceClient interface {
|
||||
// Проверка XMLDSig-подписи (ГОСТ или RSA). Возвращает сведения о
|
||||
// подписанте: CN, ИНН (если есть), срок действия сертификата.
|
||||
VerifyXMLDSig(ctx context.Context, in *VerifyRequest, opts ...grpc.CallOption) (*VerifyResponse, error)
|
||||
// Подпись XML по ГОСТ — для резервного канала WS ONYX и для
|
||||
// серверной подписи действий оператора в admin-ui.
|
||||
SignXMLDSig(ctx context.Context, in *SignRequest, opts ...grpc.CallOption) (*SignResponse, error)
|
||||
// Health-check.
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
|
||||
// Activate — переинициализирует провайдер Валидаты на указанный
|
||||
// профиль из pki1.conf. Если profile пуст — переходит в
|
||||
// VCERT_InitMinimal (без доступа к ПСП/ЛСП/ССС). Не требует
|
||||
// перезапуска сайдкара.
|
||||
Activate(ctx context.Context, in *ActivateRequest, opts ...grpc.CallOption) (*ActivateResponse, error)
|
||||
// Shutdown — корректно завершает процесс сайдкара (System.exit(2)
|
||||
// после отправки ответа). systemd с Restart=on-failure поднимет
|
||||
// его снова через RestartSec секунд. Используется для UI-кнопки
|
||||
// «Перезапустить crypto-service» без sudo.
|
||||
Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error)
|
||||
}
|
||||
|
||||
type cryptoServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCryptoServiceClient(cc grpc.ClientConnInterface) CryptoServiceClient {
|
||||
return &cryptoServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *cryptoServiceClient) VerifyXMLDSig(ctx context.Context, in *VerifyRequest, opts ...grpc.CallOption) (*VerifyResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(VerifyResponse)
|
||||
err := c.cc.Invoke(ctx, CryptoService_VerifyXMLDSig_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *cryptoServiceClient) SignXMLDSig(ctx context.Context, in *SignRequest, opts ...grpc.CallOption) (*SignResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(SignResponse)
|
||||
err := c.cc.Invoke(ctx, CryptoService_SignXMLDSig_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *cryptoServiceClient) Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(HealthResponse)
|
||||
err := c.cc.Invoke(ctx, CryptoService_Health_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *cryptoServiceClient) Activate(ctx context.Context, in *ActivateRequest, opts ...grpc.CallOption) (*ActivateResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ActivateResponse)
|
||||
err := c.cc.Invoke(ctx, CryptoService_Activate_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *cryptoServiceClient) Shutdown(ctx context.Context, in *ShutdownRequest, opts ...grpc.CallOption) (*ShutdownResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ShutdownResponse)
|
||||
err := c.cc.Invoke(ctx, CryptoService_Shutdown_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CryptoServiceServer is the server API for CryptoService service.
|
||||
// All implementations must embed UnimplementedCryptoServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// CryptoService — серверная криптография по ГОСТ через КриптоПро JCP.
|
||||
// Слушает на Unix Domain Socket (по умолчанию /run/bj/crypto.sock).
|
||||
type CryptoServiceServer interface {
|
||||
// Проверка XMLDSig-подписи (ГОСТ или RSA). Возвращает сведения о
|
||||
// подписанте: CN, ИНН (если есть), срок действия сертификата.
|
||||
VerifyXMLDSig(context.Context, *VerifyRequest) (*VerifyResponse, error)
|
||||
// Подпись XML по ГОСТ — для резервного канала WS ONYX и для
|
||||
// серверной подписи действий оператора в admin-ui.
|
||||
SignXMLDSig(context.Context, *SignRequest) (*SignResponse, error)
|
||||
// Health-check.
|
||||
Health(context.Context, *HealthRequest) (*HealthResponse, error)
|
||||
// Activate — переинициализирует провайдер Валидаты на указанный
|
||||
// профиль из pki1.conf. Если profile пуст — переходит в
|
||||
// VCERT_InitMinimal (без доступа к ПСП/ЛСП/ССС). Не требует
|
||||
// перезапуска сайдкара.
|
||||
Activate(context.Context, *ActivateRequest) (*ActivateResponse, error)
|
||||
// Shutdown — корректно завершает процесс сайдкара (System.exit(2)
|
||||
// после отправки ответа). systemd с Restart=on-failure поднимет
|
||||
// его снова через RestartSec секунд. Используется для UI-кнопки
|
||||
// «Перезапустить crypto-service» без sudo.
|
||||
Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error)
|
||||
mustEmbedUnimplementedCryptoServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedCryptoServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCryptoServiceServer struct{}
|
||||
|
||||
func (UnimplementedCryptoServiceServer) VerifyXMLDSig(context.Context, *VerifyRequest) (*VerifyResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method VerifyXMLDSig not implemented")
|
||||
}
|
||||
func (UnimplementedCryptoServiceServer) SignXMLDSig(context.Context, *SignRequest) (*SignResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method SignXMLDSig not implemented")
|
||||
}
|
||||
func (UnimplementedCryptoServiceServer) Health(context.Context, *HealthRequest) (*HealthResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Health not implemented")
|
||||
}
|
||||
func (UnimplementedCryptoServiceServer) Activate(context.Context, *ActivateRequest) (*ActivateResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Activate not implemented")
|
||||
}
|
||||
func (UnimplementedCryptoServiceServer) Shutdown(context.Context, *ShutdownRequest) (*ShutdownResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method Shutdown not implemented")
|
||||
}
|
||||
func (UnimplementedCryptoServiceServer) mustEmbedUnimplementedCryptoServiceServer() {}
|
||||
func (UnimplementedCryptoServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCryptoServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CryptoServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCryptoServiceServer interface {
|
||||
mustEmbedUnimplementedCryptoServiceServer()
|
||||
}
|
||||
|
||||
func RegisterCryptoServiceServer(s grpc.ServiceRegistrar, srv CryptoServiceServer) {
|
||||
// If the following call panics, it indicates UnimplementedCryptoServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&CryptoService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _CryptoService_VerifyXMLDSig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(VerifyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CryptoServiceServer).VerifyXMLDSig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CryptoService_VerifyXMLDSig_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CryptoServiceServer).VerifyXMLDSig(ctx, req.(*VerifyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CryptoService_SignXMLDSig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SignRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CryptoServiceServer).SignXMLDSig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CryptoService_SignXMLDSig_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CryptoServiceServer).SignXMLDSig(ctx, req.(*SignRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CryptoService_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(HealthRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CryptoServiceServer).Health(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CryptoService_Health_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CryptoServiceServer).Health(ctx, req.(*HealthRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CryptoService_Activate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ActivateRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CryptoServiceServer).Activate(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CryptoService_Activate_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CryptoServiceServer).Activate(ctx, req.(*ActivateRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CryptoService_Shutdown_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ShutdownRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CryptoServiceServer).Shutdown(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CryptoService_Shutdown_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CryptoServiceServer).Shutdown(ctx, req.(*ShutdownRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// CryptoService_ServiceDesc is the grpc.ServiceDesc for CryptoService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var CryptoService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "bridge_and_joins.crypto.v1.CryptoService",
|
||||
HandlerType: (*CryptoServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "VerifyXMLDSig",
|
||||
Handler: _CryptoService_VerifyXMLDSig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SignXMLDSig",
|
||||
Handler: _CryptoService_SignXMLDSig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Health",
|
||||
Handler: _CryptoService_Health_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Activate",
|
||||
Handler: _CryptoService_Activate_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Shutdown",
|
||||
Handler: _CryptoService_Shutdown_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "crypto.proto",
|
||||
}
|
||||
Reference in New Issue
Block a user