Подпишите PDF с помощью HSM

Я пытаюсь реализовать подпись PDF-документа с помощью HSM, но не могу получить действительную подпись и больше не могу ошибаться. Я искал различные проблемы, которые существуют по этому поводу, но я не вижу проблемы с моим кодом.

Я использую следующие версии

<dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.9</version>
        </dependency>   
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.47</version>
        </dependency>
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15on</artifactId>
            <version>1.47</version>
        </dependency>

И мой код:

 public byte[] getHash() throws Exception {
     reader = new PdfReader(new ByteArrayInputStream(content));

     baos = new ByteArrayOutputStream();
     stamper = PdfStamper.createSignature(reader, baos, '\0');
     sap = stamper.getSignatureAppearance();

     sap.setReason("Test");
     sap.setLocation("On a server!");
     sap.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
     sap.setCertificate(x509Certificate);

     dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
     dic.setReason(sap.getReason());
     dic.setLocation(sap.getLocation());
     dic.setContact(sap.getContact());
     dic.setDate(new PdfDate(sap.getSignDate()));
     sap.setCryptoDictionary(dic);

     exc = new HashMap<PdfName, Integer>();
     exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
     sap.preClose(exc);

     externalDigest = new ExternalDigest() {
         @Override
         public MessageDigest getMessageDigest(String hashAlgorithm)
                 throws GeneralSecurityException {
             return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
         }
     };

     chain = new X509Certificate[1];
     chain[0] = x509Certificate;

     sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
     data = sap.getRangeStream();
     cal = Calendar.getInstance();
     hash = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
     sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
     sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
     return sh;
 }

 public void complateToSignature(byte[] signedHash) throws Exception {
    sgn.setExternalDigest(Base64.decode(signedHash), null, "RSA");
    encodedSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
    paddedSig = new byte[8192];
    System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);

    PdfDictionary dic2 = new PdfDictionary();
    dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));

    sap.close(dic2);

    byte[] pdf = baos.toByteArray();
    FileUtils.saveFileContent(pdf, Paths.get("pathFileDest.pdf"));
 }

Наконец, мой тестовый код:

private void signPdf(X509Certificate certificate){
    File pdf = new File("C:\\File8888.pdf");
    FileInputStream is;
    byte[] content = new byte[0];
    try {
        is = new FileInputStream(pdf);
        content = new byte[is.available()];
        is.read(content);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

    PDFSignature1 operation = new PDFSignature1(content, certificate);

    byte[] hash = new byte[0];
    String encodeData = "";
    try {
        hash = operation.getHash();
         //simule control for mobile signature.
        encodeData = com.itextpdf.text.pdf.codec.Base64.encodeBytes(hash);
        if (encodeData.length() != 44) {
            throw new Exception("Sign to data must be 44 characters");
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    final String hashHex = toHex(encodeData);
    final String hashSignat = signExternalService(hashHex);

    try {
        operation.complateToSignature(hashSignat.getBytes());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Нам не удалось увидеть, что мы ошибаемся в этом процессе.

Мы будем очень признательны за любую помощь или альтернативный способ выполнения процесса.

Спасибо.


person Kike MC    schedule 29.06.2016    source источник
comment
Я не понимаю ваш код. Где вы определяете свой KeyStore? Почему вы не используете PKCS#11? Вы вообще читали документацию? Это — это то, как должен выглядеть ваш код.   -  person Bruno Lowagie    schedule 29.06.2016
comment
Я закрыл вопрос, ссылаясь на вопрос о том, как подписать PDF-файл с помощью USB-токена. Ваш вопрос касается подписания с помощью HSM, и вы можете подумать, что это другой вопрос. Это не так: подписание с помощью USB-накопителя или с помощью HSM выполняется одинаково: с помощью PKCS#11. На самом деле ответ на USB-ключ объясняет, как подписать PDF-файл с помощью Luna SA из SafeNet (это конкретный HSM).   -  person Bruno Lowagie    schedule 29.06.2016
comment
Во-первых, я не понимаю, почему он закрыл вопрос, если он не понял. Во-вторых, закрытый ключ находится в HSM, поэтому у меня нет PKCS#11. Этот процесс состоит из создания подписываемого документа строки HASH, который отправляется через веб-службу в HSM и сам HSM с указанным сертификатом, подписью и возвращает эту строку. Наконец, эта строка вставляется в элемент подписи документа PDF.   -  person Kike MC    schedule 29.06.2016
comment
Я искал на форуме и не нашел решения этой проблемы. Спасибо вам большое за ваше внимание.   -  person Kike MC    schedule 29.06.2016
comment
Я написал книгу о цифровых подписях. Если бы вы написали: закрытый ключ хранится в HSM, поэтому я не могу использовать PKCS#12, вы были бы правы. Но если вы скажете: закрытый ключ хранится в HSM, поэтому я не могу использовать PKCS#11, вы совершенно не правы. PKCS#11 — это стандарт RSA, который объясняет, как использовать закрытые ключи, хранящиеся на устройствах. Вы не читали бесплатную электронную книгу о цифровых подписях. Вопрос закрыт, поскольку на StackOverflow уже был дан адекватный ответ.   -  person Bruno Lowagie    schedule 29.06.2016
comment
Если бы на него уже был дан ответ, я мог бы сказать, что тема есть? Поскольку вы упомянули в начале вопроса, это не имеет ничего общего с представленным здесь. Спасибо большое.   -  person Kike MC    schedule 29.06.2016
comment
Я пытался следовать теме: Подписать PDF с помощью внешней службы и iText, но я не могу получить действительную подпись, поэтому обратился за помощью сюда.   -  person Kike MC    schedule 29.06.2016
comment
Вы читали stackoverflow.com /вопросы/14831200/   -  person Bruno Lowagie    schedule 29.06.2016
comment
Большое спасибо и извините за беспокойство. Хорошего дня   -  person Kike MC    schedule 29.06.2016
comment
Здравствуйте, читая форум, вы увидели это в одном из ваших ответов: Однако с учетом того, как реализован iText, в настоящее время необходим сертификат клиента. Именно это и пытаются объяснить. Что мне нужно сделать, так это отправить HASH HASH и подписать только это, поскольку HSM позволяет мне делать только это. В теме stackoverflow.com/questions/29210451/ то же самое, что пытаться объяснить комментарии.   -  person Kike MC    schedule 29.06.2016
comment
Я понимаю вопрос. Жаль, что вы не понимаете ответов.   -  person Bruno Lowagie    schedule 29.06.2016
comment
Окей, большое спасибо. Ваши ответы очень полезны для тех, кто не обладает своими знаниями. Я надеюсь, что остальные участники форума им действительно помогут.   -  person Kike MC    schedule 30.06.2016
comment
Подводя итог: если вы хотите подписать PDF-файл на том же компьютере, что и HSM, вы используете PKCS#11, как описано в этот ответ. Если вы хотите подписать PDF-файл в любом месте и подписать хэш на HSM, вы должны использовать метод signDeferred(), как описано в этот ответ. Технически вы не можете подписать PDF-файл без общедоступного сертификата, но вы можете заранее составить хеш, который необходимо подписать, и отправить этот хэш в HSM для подписи.   -  person Bruno Lowagie    schedule 30.06.2016
comment
Прежде всего, большое спасибо за ответ. Я тестирую тему, которую вы мне показали с помощью signDeferred. Но это дает мне исключение nullPointerException для запуска signDeferred. Я понимаю, что это потому, что у меня есть PrivateKey. Извините за сомнения, я не могу понять, как мне это сделать. В настоящее время я резервирую место с помощью метода emptySignature, затем вычисляю HASH и отправляю его в HSM, который подписывает мою обратную цепочку, и, наконец, вызываю метод createSignature, но в этот момент выдает мне nullPointerException . Я читал на тему, что вы со мной случились, это PrivateKey.   -  person Kike MC    schedule 30.06.2016
comment
С signDeferred() вам не нужен PrivateKey в приложении, которое подписывает PDF. Вам просто нужно реализовать ExternalSignatureContainer. В вашем случае эта реализация также не нуждается в PrivateKey: ей просто нужно установить соединение с приложением, работающим на HSM, которое подписывает байты и возвращает подписанные байты. Я не понимаю, почему вы пишете Я читал на тему, что вы со мной столкнулись, это PrivateKey. Я уважаю людей, для которых английский язык не является родным (я не являюсь носителем английского языка либо), но это предложение не имеет для меня никакого смысла.   -  person Bruno Lowagie    schedule 30.06.2016
comment
Извините за мой английский, я пытаюсь объяснить, как могу. Я реализую решение, которое вы обсуждали со мной, с помощью signDeferred(); Спасибо большое.   -  person Kike MC    schedule 01.07.2016
comment
Привет, с решением, которое вы мне обсуждали (signDeferred()), теперь не указываете мне, что файл был изменен после подписания, теперь я получаю сообщение об ошибке, например Failed to decode BER. Мне остается только отбросить проблему с подписанной цепочкой. Кто-то может дать мне небольшое указание, что может быть причиной этой ошибки? Большое спасибо!   -  person Kike MC    schedule 04.07.2016