Itext подписывает pdf строковой подписью в базе 64 от клиента - PullRequest
1 голос
/ 17 марта 2020

Я пытаюсь подписать документ в формате pdf с подписью, исходящей от всего клиента в формате base 64.

  1. служба делает запрос для расчета га sh из документа
  2. Я беру содержимое из pdf документа, вычисляю из него га sh по алгоритму.
  3. Сервис берет полученное га sh и подписывает его, отправляет полученное подпись вместе с байтами документа для подписи
  4. Я получаю строку в базе 64 и pdf байты для подписи

Возможно ли это? Я даю пример кода

public byte[] insertSignature(byte[] document, String signature) {
    try (InputStream inputStream = new ByteArrayInputStream(document);
         ByteArrayOutputStream os = new ByteArrayOutputStream();
         ByteArrayOutputStream result = new ByteArrayOutputStream()) {
        byte[] decodeSignature = Base64.decodeBase64(signature);
        CAdESSignature cades = new CAdESSignature(decodeSignature, null, null);
        var certificate = cades.getCAdESSignerInfo(0).getSignerCertificate();
        var subject = new Subject(certificate.getSubjectX500Principal().getEncoded());
        List<String> names = getSignaturesFields(document);
        String sigFieldName = String.format("Signature %s", names.size() + 1);
        PdfName filter = PdfName.Adobe_PPKLite;
        PdfName subFilter = PdfName.ETSI_CAdES_DETACHED;
        int estimatedSize = 8192;

        PdfReader reader = new PdfReader(inputStream);
        StampingProperties stampingProperties = new StampingProperties();
        if (names.size() > 1) {
            stampingProperties.useAppendMode();
        }
        PdfSigner signer = new PdfSigner(reader, os, stampingProperties);
        signer.setCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);
        PdfSignatureAppearance appearance = signer.getSignatureAppearance();
        appearance
                .setContact(subject.email().orElse(""))
                .setSignatureCreator(subject.organizationName().orElse(""))
                .setLocation(subject.country())
                .setReuseAppearance(false)
                .setPageNumber(1);

        signer.setFieldName(sigFieldName);
        ContainerForPrepareSignedDocument external = new ContainerForPrepareSignedDocument(filter, subFilter);
        signer.signExternalContainer(external, estimatedSize);
        byte[] preSignedBytes = os.toByteArray();

        ContainerReadyToSignedDocument extSigContainer = new ContainerReadyToSignedDocument(decodeSignature);
        PdfDocument docToSign = new PdfDocument(new PdfReader(new ByteArrayInputStream(preSignedBytes)));
        PdfSigner.signDeferred(docToSign, sigFieldName, result, extSigContainer);
        docToSign.close();
        return result.toByteArray();
    }
    catch (IOException e) {
        throw new InternalException("IO exception by insert signature to document:", e);
    }
    catch (GeneralSecurityException e) {
        throw new InternalException("General security by insert signature to document:", e);
    }
    catch (CAdESException e) {
        throw new InternalException("CAdESException by insert signature to document:", e);
    }
}

private List<String> getSignaturesFields(byte[] document)
        throws IOException {
    try (InputStream inputStream = new ByteArrayInputStream(document);
         PdfReader reader = new PdfReader(inputStream);
         PdfDocument pdfDocument = new PdfDocument(reader)) {
        SignatureUtil signUtil = new SignatureUtil(pdfDocument);
        return signUtil.getSignatureNames();
    }
}

static class ContainerForPrepareSignedDocument implements IExternalSignatureContainer {
    private final PdfName filter;
    private final PdfName subFilter;

    public ContainerForPrepareSignedDocument(PdfName filter,
                                             PdfName subFilter) {
        this.filter = filter;
        this.subFilter = subFilter;
    }

    public byte[] sign(InputStream docBytes) {
        return new byte[0];
    }

    public void modifySigningDictionary(PdfDictionary signDic) {
        signDic.put(PdfName.Filter, filter);
        signDic.put(PdfName.SubFilter, subFilter);
    }
}


static class ContainerReadyToSignedDocument implements IExternalSignatureContainer {
    private byte[] cmsSignatureContents;

    public ContainerReadyToSignedDocument(byte[] cmsSignatureContents) {
        this.cmsSignatureContents = cmsSignatureContents;
    }


    public byte[] sign(InputStream docBytes) {
        return cmsSignatureContents;
    }

    public void modifySigningDictionary(PdfDictionary signDic) {
    }
}
...