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

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline Alisa  
#1 Оставлено : 26 августа 2018 г. 10:09:38(UTC)
Alisa

Статус: Новичок

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

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 4 раз в 2 постах
Добрый день.
Подскажите, пожалуйста.

Реализую схему подписи на клиенте через КриптоПро Browser Plugin.

На сервере использую itextpdf.
Создаю pdf с пустым контейнером для подписи. Отдаю клиенту на подпись данные в Base64.

Код:
            
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            byte[] b = bytesByFile(is);
            PdfReader reader = new PdfReader(b);
            PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setVisibleSignature(new com.itextpdf.text.Rectangle(36, 748, 144, 780), 1, signatureFieldNam);
            ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
            MakeSignature.signExternalContainer(appearance, external,  8192);
            byte[] data = IOUtils.toByteArray(appearance.getRangeStream());
            return Base64.getEncoder().encodeToString(data);


На клиенте вычисляю хэш и подписываю его:
Код:

function createSign(dataToSign, selectedCertID){
        
        // Получаю нужный сертификат
        var thumbprint = e.options[selectedCertID].value.split(" ").reverse().join("").replace(/\s/g, "").toUpperCase();
        try {
            var oStore = yield cadesplugin.CreateObjectAsync("CAdESCOM.Store");
            yield oStore.Open();

            var all_certs = yield oStore.Certificates;
            var oCerts = yield all_certs.Find(cadesplugin.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, thumbprint);
            if ((yield oCerts.Count) == 0) {
              alert("Certificate not found");
              return;
            }
            var certificate = yield oCerts.Item(1);
        } catch (err) {
              alert('Certificate not found');
            return;
        }
        
        // Хэшируем. Используем CADESCOM_BASE64_TO_BINARY, поэтому оставляем пришедший base64
        try {
                var oHashedData = yield cadesplugin.CreateObjectAsync('CAdESCOM.HashedData');
                yield oHashedData.propset_Algorithm(cadesplugin.CADESCOM_HASH_ALGORITHM_CP_GOST_3411);
                yield oHashedData.propset_DataEncoding = cadesplugin.CADESCOM_BASE64_TO_BINARY;
                yield oHashedData.Hash(dataToSign);
            } catch (err) {
                throw "Failed to create CAdESCOM.HashedData: " + err.number;
            } 
         
         // подписчик
         try {
                var oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
                yield oSigner.propset_Certificate(certificate);
            } catch (err) {
                throw "Failed to create CAdESCOM.CPSigner: " + err.number;
            }

          // Подписываю хэш. Получаю base64 - отдаю его на сервер для дальнейшей вставки
            var oSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
            if (dataToSign) {
                try {
                   yield oSignedData.propset_DataEncoding = cadesplugin.CADESCOM_BASE64_TO_BINARY;
                   var Signature = yield oSignedData.SignHash(oHashedData, oSigner, cadesplugin.CADESCOM_CADES_BES);
                   return Signature;
                } catch (err) {
                    throw "Не удалось создать подпись из-за ошибки: " + cadesplugin.getLastError(err);
                }
            } 
}

Если проверить через yield oSignedData.VerifyHash - все норм.
С клиента приходит Base64. На сервере вставляю подпись в пустой ранее контейнер:

Код:

public byte[] sign(FileId fileId, byte[] signature, String signatureFieldNam) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            byte[] file = getContent(fileId).orElseThrow(() -> new FileNotFoundException(fileId));
            PdfReader reader = new PdfReader(file);
            ExternalSignatureContainer container = new BrowserSignatureContainer(signature);
            MakeSignature.signDeferred(reader, signatureFieldNam, outputStream, container);
            return outputStream.toByteArray();
        } catch (IOException | GeneralSecurityException | DocumentException e) {
            log.error("while sign pdf file by external signature", e);
            throw new Exception("");
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                // Ignore
            }
        }
    }

 class BrowserSignatureContainer implements ExternalSignatureContainer {
        private byte[] sinedData;
        public BrowserSignatureContainer(byte[] signature) {
            this.sinedData = Base64.getDecoder().decode(signature);
        }
        public byte[] sign(InputStream is) {
            return sinedData;
        }
        public void modifySigningDictionary(PdfDictionary pdfDictionary) {
        }
    }


Но подпись в Adobe Acrobat XI Pro не распознается.
Пишет "Ошибка при подтверждении подписи.
Ошибка при проверке:
Неподдерживаемый алгоритм"
Хотя если подписать прямо в Adobe Acrobat XI Pro этим же сертификатом- все нормально, подпись распознается.
Что-то делаю не так?
Судя по сравнению моего файла pdf (подписанного через браузер) и файла, подписанного через Adobe Acrobat XI Pro - они отличаются.

Подпись, что получаю через плагин:
MIIFxwYJKoZIhvcNAQcCoIIFuDCCBbQCAQExDDAKBgYqhQMCAgkFADALBgkqhkiG9w0BBwGgggMu
MIIDKjCCAtmgAwIBAgITEgAsOFQWlMsYXkwr7gAAACw4VDAIBgYqhQMCAgMwfzEjMCEGCSqGSIb3
DQEJARYUc3VwcG9ydEBjcnlwdG9wcm8ucnUxCzAJBgNVBAYTAlJVMQ8wDQYDVQQHEwZNb3Njb3cx
FzAVBgNVBAoTDkNSWVBUTy1QUk8gTExDMSEwHwYDVQQDExhDUllQVE8tUFJPIFRlc3QgQ2VudGVy
IDIwHhcNMTgwODIyMTM1NjE2WhcNMTgxMTIyMTQwNjE2WjA5MR8wHQYJKoZIhvcNAQkBFhBtYXNr
X2JlbEBtYWlsLnJ1MQowCAYDVQQDDAFNMQowCAYDVQQKDAFNMGMwHAYGKoUDAgITMBIGByqFAwIC
JAAGByqFAwICHgEDQwAEQGbbKsLP1NizExIOFnIM1BpRymkWDkAGLGjLMuhIDi598clA/xWSnRCC
5OU7e/3t2FRf2l9heNEs+HvFNRjhTy+jggFwMIIBbDAOBgNVHQ8BAf8EBAMCBPAwEwYDVR0lBAww
CgYIKwYBBQUHAwIwHQYDVR0OBBYEFDPZYK4dienvocZVEnL5RSOXAyx3MB8GA1UdIwQYMBaAFBUx
fLCNGt5m1xWcSVKXFyS5AXqDMFkGA1UdHwRSMFAwTqBMoEqGSGh0dHA6Ly90ZXN0Y2EuY3J5cHRv
cHJvLnJ1L0NlcnRFbnJvbGwvQ1JZUFRPLVBSTyUyMFRlc3QlMjBDZW50ZXIlMjAyLmNybDCBqQYI
KwYBBQUHAQEEgZwwgZkwYQYIKwYBBQUHMAKGVWh0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L0Nl
cnRFbnJvbGwvdGVzdC1jYS0yMDE0X0NSWVBUTy1QUk8lMjBUZXN0JTIwQ2VudGVyJTIwMi5jcnQw
NAYIKwYBBQUHMAGGKGh0dHA6Ly90ZXN0Y2EuY3J5cHRvcHJvLnJ1L29jc3Avb2NzcC5zcmYwCAYG
KoUDAgIDA0EA/A/uNOkkJRaATjSRGLyYAoepiVaDO2MbMd74kiyj6t+VLxJS561lgnHbQxXdp0PK
YwTrBemCAOcZ8w99HMon/TGCAmAwggJcAgEBMIGWMH8xIzAhBgkqhkiG9w0BCQEWFHN1cHBvcnRA
Y3J5cHRvcHJvLnJ1MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5DUllQ
VE8tUFJPIExMQzEhMB8GA1UEAxMYQ1JZUFRPLVBSTyBUZXN0IENlbnRlciAyAhMSACw4VBaUyxhe
TCvuAAAALDhUMAoGBiqFAwICCQUAoIIBUDAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqG
SIb3DQEJBTEPFw0xODA4MjYxNzAxMDJaMC8GCSqGSIb3DQEJBDEiBCBDTphHq50wH+WVLxw0BQ7q
n9t2Vt5oa/UQm3XGmm/HpDCB5AYLKoZIhvcNAQkQAi8xgdQwgdEwgc4wgcswCAYGKoUDAgIJBCC0
qDGWTfR/tASWHFUZSOnI6AA0GEZnYQ5R4jH2mEdmTTCBnDCBhKSBgTB/MSMwIQYJKoZIhvcNAQkB
FhRzdXBwb3J0QGNyeXB0b3Byby5ydTELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUG
A1UEChMOQ1JZUFRPLVBSTyBMTEMxITAfBgNVBAMTGENSWVBUTy1QUk8gVGVzdCBDZW50ZXIgMgIT
EgAsOFQWlMsYXkwr7gAAACw4VDAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQRAVMZaave5
IW7zfeYgTDr9IwxcYcCwbumNBAMe1Gk2N8Wh3Mm2YDg/qRC7frQOGJonHR1hy1ouQ7PBmMS+weIU
sQ==

Верно ли я понимаю, что нужно выкинуть переносы строк и раскодировать из base64 на сервере?

Отредактировано пользователем 27 августа 2018 г. 14:46:00(UTC)  | Причина: Не указана

thanks 1 пользователь поблагодарил Alisa за этот пост.
Виталий.S оставлено 20.02.2020(UTC)
Offline two_oceans  
#2 Оставлено : 27 августа 2018 г. 6:49:57(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 1,602
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 110 раз
Поблагодарили: 397 раз в 367 постах
Подписью PDF не занимался, но могу подсказать по 2 пунктам: 1) указанный фрагмент base64 соответствует стандарту и включает переводы строк ровно после 77 символа в строке. Если декодер полностью поддерживает стандарт, то переводы строк будут автоматически проигнорированы при декодировании из Base64, удалять необязательно. Однако если удалите переводы строк предварительно, то ошибки не будет; 2) если речь идет о подписи по алгоритмам ГОСТ, то сравнивать 2 подписи побайтово и полностью бесполезно - одни и те же данные подписание одним и тем же сертификатом несколько раз дадут разные значения подписи - это нормально. В идеале совпасть должно все остальное за исключением самого поля значения подписи.
thanks 1 пользователь поблагодарил two_oceans за этот пост.
Alisa оставлено 27.08.2018(UTC)
Offline Alisa  
#3 Оставлено : 27 августа 2018 г. 10:09:24(UTC)
Alisa

Статус: Новичок

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

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 4 раз в 2 постах
two_oceans, спасибо большое.
Насчет второго, там же рандомное число в ГОСТ берется, вроде.
Про то,что они отличаются - я больше имела ввиду размер. Но, видимо, при подписи через КриптоПро PDF контейнер подписи сам просто больше.

Вообще настроила Adobe Acrobat так , чтобы при проверке подписи подхватывался сначала КриптоПро PDF.
Так вот сообщение по подписи поменялось.
Подпись начала распознаваться, НО теперь сообщение такое:
ПОДПИСЬ НЕДЕЙСТВИТЕЛЬНА
Подписан...
- Документ был изменен или поврежден после подписания
- Подпись сделана в формате CADES BES.
- Целостность документа повреждена
- Сертификат ненадежный
- Проблемы с проверкой сертификата и/или его цепочки.

Проверила - цепочка сертификатов такая же как и при обычной подписи (с корневым).
Осталось понять - где документ изменен.
Сравнивала документ до подписания (с пустой подписью) и документ после вставки подписи - кроме байтов подписи они вроде идентичны.

Отредактировано пользователем 27 августа 2018 г. 11:29:33(UTC)  | Причина: Не указана

Offline Alisa  
#4 Оставлено : 5 сентября 2018 г. 17:00:00(UTC)
Alisa

Статус: Новичок

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

Сказал(а) «Спасибо»: 1 раз
Поблагодарили: 4 раз в 2 постах
На сервере ничего не поменялось. Поменялось на клиенте.

Код:

function createSign(dataToSign, selectedCertID){
        
        // Получаю нужный сертификат
        ...
        //хэш не получаем

        // подписчик
         try {
                var oSigner = yield cadesplugin.CreateObjectAsync("CAdESCOM.CPSigner");
                yield oSigner.propset_Certificate(certificate);
            } catch (err) {
                throw "Failed to create CAdESCOM.CPSigner: " + err.number;
            }

          // Подписываю данные base64 с сервера. Получаю base64 - отдаю его на сервер для дальнейшей вставки
            var oSignedData = yield cadesplugin.CreateObjectAsync("CAdESCOM.CadesSignedData");
            if (dataToSign) {
                try {
                    yield oSignedData.propset_ContentEncoding(cadesplugin.CADESCOM_BASE64_TO_BINARY);
                    yield oSignedData.propset_Content(dataToSign);
                    var Signature = yield oSignedData.SignCades(oSigner, cadesplugin.CADESCOM_CADES_BES, true);
                } catch (err) {
                    throw "Не удалось создать подпись из-за ошибки: " + cadesplugin.getLastError(err);
                }
            } 
}


Теперь подпись распознается.
Теперь любопытно только, как добавить данные по подписанту на графическое поле подписи.
Интересно, такое возможно - при этом же должен поменяться range.
Или тогда придется делать дублирование подписи с уже "красивыми данными" на печати.
thanks 3 пользователей поблагодарили Alisa за этот пост.
Vadim_Pil оставлено 29.10.2019(UTC), Виталий.S оставлено 20.02.2020(UTC), kassfb оставлено 09.08.2022(UTC)
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.