Неверная подпись с PDFBox и Bouncycastle - PullRequest
0 голосов
/ 26 сентября 2019

Я пытаюсь подписать PDF, и мой код подписал PDF, но когда я открываю документ в Adobe, у меня есть такой ответ: enter image description here, и я не знаю, что происходит.

Генератор сертификатов

public static BigInteger generateSerial() {
        SecureRandom random = new SecureRandom();
        return BigInteger.valueOf(Math.abs(random.nextLong()));
    }

public static X509Certificate CeriticateGenerator(PublicKey publicKey, PrivateKey privateKey)  throws OperatorCreationException, CertificateException, CertIOException {
    Date startDate = new Date(System.currentTimeMillis());
    Date expiryDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);

    X500Name issuser=new X500Name("cn=Rubrica");
    X500Name subject=new X500Name("cn=Rubrica");
    X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuser,
            generateSerial(),
            startDate,
            expiryDate,
            subject,
            publicKey).addExtension(Extension.subjectKeyIdentifier, false, createSubjectKeyId(publicKey))
            .addExtension(Extension.authorityKeyIdentifier, false, createAuthorityKeyId(publicKey))
            .addExtension(Extension.basicConstraints, true, new BasicConstraints(true));

     ContentSigner sigGen = new JcaContentSignerBuilder("SHA512withRSA").setProvider("BC").build(privateKey);
     return new JcaX509CertificateConverter()
          .setProvider(new BouncyCastleProvider()).getCertificate(certGen.build(sigGen));


}
 private static SubjectKeyIdentifier createSubjectKeyId(final PublicKey publicKey) throws OperatorCreationException {
        final SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
        final DigestCalculator digCalc =
          new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));

        return new X509ExtensionUtils(digCalc).createSubjectKeyIdentifier(publicKeyInfo);
      }

      /**
       * Creates the hash value of the authority public key.
       *
       * @param publicKey of the authority certificate
       *
       * @return AuthorityKeyIdentifier hash
       *
       * @throws OperatorCreationException
       */
      private static AuthorityKeyIdentifier createAuthorityKeyId(final PublicKey publicKey)
        throws OperatorCreationException
      {
        final SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
        final DigestCalculator digCalc =
          new BcDigestCalculatorProvider().get(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1));

        return new X509ExtensionUtils(digCalc).createAuthorityKeyIdentifier(publicKeyInfo);
      }

это интерфейс Signature

public class PDBOXsignerManager implements SignatureInterface{
    private PrivateKey privateKey;
    private Certificate[] certificateChain;


    PDBOXsignerManager(KeyStore keyStore, String password, String appCertificateAlias)  {

        try {
            this.certificateChain = Optional.ofNullable(keyStore.getCertificateChain(appCertificateAlias))
                    .orElseThrow(() -> (new IOException("Could not find a proper certificate chain")));
            this.privateKey = (PrivateKey) keyStore.getKey(appCertificateAlias, password.toCharArray());

            Certificate certificate = this.certificateChain[0];

            if (certificate instanceof X509Certificate) {
                ((X509Certificate) certificate).checkValidity();
            }
        } catch (KeyStoreException | IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CertificateExpiredException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CertificateNotYetValidException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }

    @Override
    public byte[] sign(InputStream content) throws IOException {
        try {
            CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
            X509Certificate cert = (X509Certificate) this.certificateChain[0];
            ContentSigner ECDSASigner = new JcaContentSignerBuilder("SHA512withRSA").build(this.privateKey);
            gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(ECDSASigner, cert));
            gen.addCertificates(new JcaCertStore(Arrays.asList(this.certificateChain)));
            CMSProcessableInputStream msg = new CMSProcessableInputStream(content);
            CMSSignedData signedData = gen.generate(msg, false);



            return signedData.getEncoded();
        } catch (GeneralSecurityException | CMSException | OperatorCreationException e) {
            //throw new IOException cause a SignatureInterface, but keep the stacktrace
            throw new IOException(e);
        }
    }
}

этот подписывающий класс

public class PDBOXSigner extends PDBOXsignerManager
{
 PDBOXSigner(KeyStore keyStore, String password, String appCertificateAlias) {
    super(keyStore, password, appCertificateAlias);
        }

public void signDetached( PDDocument document, OutputStream output, String name, String reason) {
        PDSignature pdSignature = new PDSignature();
        pdSignature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
        pdSignature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_SHA1);
        pdSignature.setName(name);
        pdSignature.setReason(reason);

        // Se le agrega la fecha de firma necesaria para validar la misma
        pdSignature.setSignDate(Calendar.getInstance());

        // Registro del diccionario de firmas y y la interfaz de firma
        try {
             SignatureOptions signatureOptions = new SignatureOptions();
             // Size can vary, but should be enough for purpose.
             signatureOptions.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
             // register signature dictionary and sign interface
             document.addSignature(pdSignature, this, signatureOptions);

            // write incremental (only for signing purpose)
            document.saveIncremental(output);
            output.flush();
            output.close();

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }
}

Я создал сертификаты и пару ключейс Java и Bouncycastle, я не знаю, если это проблема или что я делаю не так?


1 Ответ

0 голосов
/ 26 сентября 2019

Ошибка заключалась в использовании SUBFILTER_ADBE_PKCS7_SHA1 вместо SUBFILTER_ADBE_PKCS7_DETACHED, который используется в официальном примере .SUBFILTER_ADBE_PKCS7_SHA1 не должен использоваться для подписи, он устарел в PDF 2.0.

...