Проблемы с валидацией отсоединенной подписи

Добрый день, использую рутокен ЭЦП 2.0. Подписываю некоторое сообщение на клиенте используя функцию sign(), опция detached - false, полученный CMS файл пересылаю на сервер и вытаскиваю из него "голую" подпись и подписанные данные. Пытаюсь проверить данную подпись (использую стандартный пакет java.security) открытым ключом, однако все время выносится решение false. В чем может быть проблема?

Re: Проблемы с валидацией отсоединенной подписи

Добрый день, Иван К..

К сожалению, этой информации недостаточно для помощи. Нужны ответы на вопросы:

  • Какой алгоритм и с каким размером ключа используется для подписи

  • Какое API используется на клиенте при подписи? Мы поддерживаем множество интерфейсов

  • Как\чем вытаскиваете "голую" подпись?

  • В идеале хорошо бы код подписи и код проверки видеть

Re: Проблемы с валидацией отсоединенной подписи

Добрый день, Владимир Салыкин,

Для подписи используется некоторая модификация предложенного на вашем сайте примера, в частности сама подпись происходит путем вызова функции sign():

         plugin.sign(rutokenHandle, certHandle, textToSign, false, {addSignTime: true}) ,

где textToSign - подписываемая строка.

Подпись и проверка происходит с использованием алгоритмов ГОСТ Р 34.11-2012/34.10-2012 512 бит.

Как уже писал ранее, полученное CMS сообщение пересылается на сервер и парсится используя средства bouncycastle:

     byte[] signerBytes = Base64.decodeBase64(data);
     CMSSignedData signedData = new CMSSignedData(signerBytes);
     content = (byte[]) signedData.getSignedContent().getContent();
     SignerInformation signerInformation = signedData.getSignerInfos().get(signer.getSID());
     AttributeTable signedAttributes = signerInformation.getSignedAttributes();

     byte[] sign = signerInformation.getSignature(); // вытаскиваем "голую" подпись

Данные записываются в БД.

Код проверки:

    KeyFactory keyFactory = KeyFactory.getInstance("GOST3410_2012_512");
    EncodedKeySpec spec = new X509EncodedKeySpec(bytesPublicKey);
    publicKey = keyFactory.generatePublic(spec);

    Signature signature = Signature.getInstance("GOST3411_2012_512withGOST3410_2012_512");
    signature.initVerify(publicKey);
    signature.update(content.getBytes(StandardCharsets.UTF_8));
    boolean flagVerified = signature.verify(signedBytes);

Метод verify() всегда возвращает false.

Re: Проблемы с валидацией отсоединенной подписи

Иван К., передали Вашу проблему разработчикам.

Но скорее всего проблема в открытом ключе - https://forum.rutoken.ru/topic/1917/

Re: Проблемы с валидацией отсоединенной подписи

Владимир Салыкин, думаю что дело не в открытом ключе, поскольку метод initVerify() имеет еще один конструктор, который принимает сертификат. Для тестирования я импортировал сертификат на котором происходила подпись, и метод verify() - аналогично, все время выносил решение false.

Re: Проблемы с валидацией отсоединенной подписи

Добрый день, Иван К..

Мы проверили на bouncy castle 1.61. Код:

            data = Files.readAllBytes(path);

            byte[] signerBytes = Base64.decode(data);
            CMSSignedData signedData = new CMSSignedData(signerBytes);

            InputStream in = new FileInputStream("C:\\cert.cer");
            CertificateFactory factory = new CertificateFactory();
            X509Certificate cert = (X509Certificate)factory.engineGenerateCertificate(in);

            Store certs = signedData.getCertificates();

            SignerInformationStore signers = signedData.getSignerInfos();
            Collection<SignerInformation> c = signers.getSigners();
            for (SignerInformation signer : c) {
                /*
                // можно взять сертификат из CMS-конверта

                SignerId signerId = signer.getSID();
                Collection certCollection = certs.getMatches(signerId);

                Iterator certIt = certCollection.iterator();
                X509CertificateHolder certificate = (X509CertificateHolder)certIt.next();
                X509Certificate certFromCms = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificate);
                */
                SignerInformationVerifier verifier =
                        new JcaSimpleSignerInfoVerifierBuilder()
                                .setProvider("BC").build(cert);
                //              .setProvider("BC").build(certFromCms);

                boolean result = signer.verify(verifier);
                System.out.write(result?1:0);

Проверка выполняется успешно.