'PDFBox signing document, empty certificate field and "At least one signature requires validating"

I am using PDFBox as a tool to sign my PDF, it is being created by the same library, and i am using CSP Crypto Pro as a sign tool (Bouncy castle is restricted in my company)

Here is the code that get complete on launch, it get certificate and other things for me

public SignUnloadService(String path) {
    String certificateAlias = "";
    String privateKeyAlias = "";
    String privateKeyPassword = "";

    try (FileInputStream fis = new FileInputStream(path)) {
        try {
            YamlToolConfiguration configuration = new YamlToolConfiguration(fis);

            for (SignerKeyConfiguration keyConfiguration : configuration.getSignerConfiguration().getInnerKeysConfiguration()) {
                if (keyConfiguration.getPrimary() != null && keyConfiguration.getPrimary()) {
                    certificateAlias = keyConfiguration.getCertificateAlias();
                    privateKeyAlias = keyConfiguration.getPrivateKeyAlias();
                    privateKeyPassword = keyConfiguration.getPrivateKeyPassword();
                }
            }

            if (StringUtils.isEmpty(certificateAlias)) {
                throw new SMEVSignatureException("Certificate init error: certificate alias: " + certificateAlias);
            } else if (StringUtils.isEmpty(privateKeyAlias)) {
                throw new SMEVSignatureException("Certificate init error: private key alias: " + privateKeyAlias);
            } else if (StringUtils.isEmpty(privateKeyPassword)) {
                throw new SMEVSignatureException("Certificate init error: private key password: " + privateKeyPassword);
            }

            System.out.println("Sign for attach:\ncertificateAlias: " + certificateAlias + "\nprivateKeyAlias: " + privateKeyAlias + "\nprivateKeyPassword: " + privateKeyPassword);

            DigitalSignatureFactory.init();

            KeyStoreWrapper keyStore = DigitalSignatureFactory.getKeyStoreWrapper();
            keyStoreSign = keyStore;
            privateKey = keyStore.getPrivateKey(privateKeyAlias, privateKeyPassword.toCharArray());
            certificate = keyStore.getX509Certificate(certificateAlias);
            signer = Factory.getSignerInstance(configuration.getSignerConfiguration());

        } catch (Exception e) {
            log.error("", e);
            throw new ExceptionInInitializerError("Crypto service initialization error: " + e.getMessage());
        }
    } catch (IOException e) {
        throw new IllegalArgumentException("Can not open configuration file " + path);
    }
}

Here is the code that gets the ByteArrayOutputStream of PDF and tries to sign it in my Documents directory.

public SignPdf signPdf(ByteArrayOutputStream pdf) {
    UUID uuid = UUID.randomUUID();
    String fileName = uuid + ".pdf";
    String fileNameSig = uuid + "_signed.pdf";
    File file = new File(dataDirectory + fileName);
    try (FileOutputStream fos = new FileOutputStream(file)) {
        pdf.writeTo(fos);
    } catch (IOException e) {
        log.error("Error on open pdf file");
    }
    try (FileOutputStream fos = new FileOutputStream(dataDirectory + "tmp/" + fileNameSig)) {
        PDDocument doc = PDDocument.load(file);
        int stampPage = doc.getNumberOfPages() - 1;
        PDSignature signature = new PDSignature();
        signature.setFilter(
                COSName.getPDFName("CryptoPro PDF")
                // PDSignature.FILTER_ADOBE_PPKLITE
        ); // <= using this Filter because "CryptoPro PDF" is a program that tries to verify my PDF
        signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
        signature.setName(getCommonName(certificate));
        signature.setSignDate(Calendar.getInstance());
        PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
        if (acroForm != null && acroForm.getNeedAppearances()) {
            if (acroForm.getFields().isEmpty()) {
                acroForm.getCOSObject().removeItem(COSName.NEED_APPEARANCES);
            } else {
                log.info("NeedAppearances is set, signature may be ignored by Adobe Reader");
            }
        }
        SignatureOptions signatureOptions = new SignatureOptions();
        GetCharLocationAndSize charLocationAndSize = new GetCharLocationAndSize(doc);
        charLocationAndSize.calculate();
        SignInfo signInfo = new SignInfo();
        
        signInfo.setCertNumber(certificate.getSerialNumber() != null ? certificate.getSerialNumber().toString() : "");
        signInfo.setStartDate(certificate.getNotBefore().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(DATE_FORMAT));
        signInfo.setEndDate(certificate.getNotAfter().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().format(DATE_FORMAT));
        signInfo.setSignerName(getCommonName(certificate));
        signatureOptions.setVisualSignature(createVisualSignatureTemplate(doc, 0, createSignatureRectangle(doc, new Rectangle2D.Float(50, charLocationAndSize.getLastPositionY(), 300, 85)), signInfo));
        signatureOptions.setPage(stampPage);
        
        doc.addSignature(signature, null, signatureOptions);
        ExternalSigningSupport externalSigning = doc.saveIncrementalForExternalSigning(fos);
        System.out.println(Base64.getEncoder().encodeToString(IOUtils.toByteArray(externalSigning.getContent())));

        byte[] cmsSignature = sign(new ByteArrayInputStream(Base64.getEncoder().encodeToString(IOUtils.toByteArray(externalSigning.getContent())).getBytes()));
        System.out.println(Base64.getEncoder().encodeToString(cmsSignature));
        externalSigning.setSignature(cmsSignature);

        File signedFile = new File(dataDirectory + "tmp/" + fileNameSig);
        File filePdf = new File(dataDirectory + "tmp/" + fileName);
        try(ByteArrayOutputStream baos = new ByteArrayOutputStream()){
            baos.write(FileUtils.readFileToByteArray(signedFile));
            try(OutputStream outputStream = new FileOutputStream("/home/ktulhu/Documents/111test.pdf")) {
                baos.writeTo(outputStream);
            }
            FileUtils.deleteQuietly(signedFile);
            FileUtils.deleteQuietly(filePdf);
        } catch (IOException e) {
            log.error("Error on read filePdf ", e);
        }
        IOUtils.closeQuietly(signatureOptions);
        IOUtils.closeQuietly(doc);
    } catch (Exception e) {
        log.error("ERROR", e);
    }
}

I am signing in this method - i first get the digest and sign the document with "GOST3410v12256" (PKCS7 detached)

    public byte[] sign(InputStream content){
    try {
        byte[] digest = signer.getDigest(signer.getDigestInputStream(content, signer.primaryDigestName()));
        return signer.signPKCS7Detached(digest);
    } catch (SMEVSignatureException | SMEVRuntimeException e) {
        log.error("Error sign", e);
        e.printStackTrace();
        return new byte[0];
    }
}

However, after seeing the pdf file, the adobe tells me that "At least one signature requires validating", however clicking the option to validate gives me nothing. The signature field itself appears to be missing the "Signed by" field, meaning i can not install any certificated from it, and it can not find any.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source