मैं डीएसएस के साथ एक पीडीएफ दस्तावेज़ पर हस्ताक्षर करने की कोशिश कर रहा हूं, और मेरी समस्या यह है कि मैं सर्वर ए में दस्तावेज़ के हैश की गणना नहीं कर सकता और फिर इसे सर्वर बी में साइन कर सकता हूं।

यह जानते हुए कि सर्वर A में PDF दस्तावेज़ है और सर्वर B में हम हस्ताक्षर के लिए उपयोग किए गए प्रमाणपत्र को पुनः प्राप्त करते हैं

मेरा प्रश्न यह है कि मैं प्रमाण पत्र की आवश्यकता के बिना सर्वर ए में दस्तावेज़ के हैश की गणना कैसे कर सकता हूं। फिर इसे सर्वर बी में हस्ताक्षर के लिए भेजें?

अपडेट करें :

****** हैश की तैयारी और गणना ********

    IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
    PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();

    PAdESSignatureParameters parameters = new PAdESSignatureParameters();

    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    parameters.setReason("Preuve de signature");
    parameters.setLocation("MAROC");
    parameters.setGenerateTBSWithoutCertificate(true);

    SignatureImageParameters imageParameters = new SignatureImageParameters();

    imageParameters.setPage(1);
    FileDocument imageFile = new FileDocument("logo.png");
    RemoteDocument fileImage = RemoteDocumentConverter.toRemoteDocument(imageFile);
    DSSDocument image = RemoteDocumentConverter.toDSSDocument(fileImage);
    // set an image
    imageParameters.setImage(image);

    imageParameters.setxAxis(350);
    imageParameters.setyAxis(400);
    imageParameters.setWidth(200);
    imageParameters.setHeight(100);
    parameters.setImageParameters(imageParameters);
    SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
    DSSFont font = new DSSJavaFont(Font.SERIF);
    font.setSize(16); // Specifies the text size value (the default font size is 12pt)
    textParameters.setFont(font);
    textParameters.setTextColor(Color.BLUE);

    textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
    // Specifies a horizontal alignment of a text with respect to its area
    textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
    // Specifies a vertical alignment of a text block with respect to a signature field area
    textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
    imageParameters.setTextParameters(textParameters);

    FileDocument fileToSign = new FileDocument("file.pdf");
    RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
    DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);

    byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);

    DSSDocument signatureValue = SignHashDocument.signHash(hash);

    DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, DSSUtils.toByteArray(signatureValue), parameters);

    save(signedDocument);

****** हैश हस्ताक्षर ********

     // Create common certificate verifier
    CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
        // Create CAdESService for signature
    CAdESService service = new CAdESService(commonCertificateVerifier);

    CAdESSignatureParameters parameters = new CAdESSignatureParameters();
    DSSPrivateKeyEntry privateKey = getKey("certificate.p12","123456");


    // We choose the level of the signature (-B, -T, -LT, -LTA).
    parameters.setSignatureLevel(SignatureLevel.CAdES_BASELINE_B);
    parameters.setSignaturePackaging(SignaturePackaging.ENVELOPING);

    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    // We set the signing certificate
    parameters.setSigningCertificate(privateKey.getCertificate());
    // We set the certificate chain
    parameters.setCertificateChain(privateKey.getCertificateChain());


    SignatureTokenConnection signingToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()));


    convertByteArrayToFile(hashToSign,"filetosign.hash");
    FileDocument fileToSign = new FileDocument("filetosign.hash");
    RemoteDocument fileSign = RemoteDocumentConverter.toRemoteDocument(fileToSign);
    DSSDocument toSignDocument = RemoteDocumentConverter.toDSSDocument(fileSign);

    //ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

    ToBeSigned dataToSign = new ToBeSigned(hashToSign);

    DigestAlgorithm digestAlgorithm = parameters.getDigestAlgorithm();
    SignatureValue signatureValue = signingToken.sign(dataToSign, digestAlgorithm, privateKey);

    DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

    return  signedDocument;

********* पीडीएफ त्रुटि: *********

enter image description here

3
Mehdi 4 फरवरी 2021, 19:03

3 जवाब

सबसे बढ़िया उत्तर

सामान्य रूप में

यह आपके प्रश्न के मूल संशोधन के जवाब में लिखा गया था।

आपके कोड में PAdES का उल्लेख है। इस प्रकार, मुझे लगता है कि जब आप कहते हैं कि आप DSS के साथ एक PDF दस्तावेज़ पर हस्ताक्षर करने का प्रयास कर रहे हैं, तो आपका मतलब एकीकृत PAdES (अलग किए गए CAdES या XAdES) हस्ताक्षर नहीं हैं।

एकीकृत PDF हस्ताक्षर (जैसे PAdES) बनाने के लिए पहले एक एम्बेडेड हस्ताक्षर ले जाने में सक्षम होने के लिए PDF तैयार करने की आवश्यकता होती है, अर्थात किसी मौजूदा या नए हस्ताक्षर फ़ील्ड में एक हस्ताक्षर शब्दकोश जोड़ना। इस सिग्नेचर डिक्शनरी में कई जानकारी, हस्ताक्षर करने का समय, हस्ताक्षर करने का कारण, आदि और बाद में CMS हस्ताक्षर कंटेनर को एम्बेड करने के लिए एक प्लेसहोल्डर भी शामिल है। फिर यह तैयार पीडीएफ (प्लेसहोल्डर को छोड़कर) हैश किया जाता है।

इसके अलावा, आपके कोड में उल्लेख है कि आप हस्ताक्षर का स्तर चुनें (-B, -T, -LT, -LTA)

PAdES बेसलाइन LT और PAdES बेसलाइन LTA हस्ताक्षर बनाने के लिए PAdES बेसलाइन T हस्ताक्षर के साथ PDF तैयार करना और T हस्ताक्षर की प्रकृति के आधार पर अतिरिक्त वस्तुओं का संग्रह जोड़ना आवश्यक है।

ESig DSS आपके लिए यह सब तैयारी कर सकता है यदि उसके पास तैयार करने के लिए PDF है

इसलिए यदि आप सर्वर A से B तक केवल हैश मान भेजना चाहते हैं, तो आपको अधिकांश कार्य करने के लिए अपने सर्वर A पर eSig DSS का उपयोग करना होगा, और सर्वर B केवल एक हस्ताक्षरित हैश मान लौटाने वाली एक गूंगा हस्ताक्षर सेवा के रूप में कार्य करता है। PAdES के लिए प्रयोग करने योग्य अधिकांश CMS कंटेनर।

आप सर्वर ए के बिना ऐसा कर सकते हैं, प्रमाणपत्र के बारे में जानने के बाद, यह इस बात पर निर्भर करता है कि आप नए हस्ताक्षर के लिए एक हस्ताक्षर विजेट में प्रमाणपत्र विवरण दिखाना चाहते हैं या नहीं। विजेट उपस्थिति बनाना पीडीएफ तैयारी चरण का हिस्सा है, इसलिए यदि आप प्रमाणपत्र जानकारी के साथ ऐसा विजेट चाहते हैं, तो सर्वर ए को प्रमाणपत्र जानने की जरूरत है, आमतौर पर हस्ताक्षर का अनुरोध करने से पहले!

सर्वर ए और बी के बीच आप किस तरह का प्रोटोकॉल चलाते हैं, यह आप पर निर्भर है। आपको सर्वर B के साथ संचार करने के लिए eSig DSS में सर्वर A पर उपयोग करने के लिए केवल SignatureTokenConnection को तदनुसार लागू करना होगा।

आपके दृष्टिकोण के मामले में

अब आप दोनों सर्वरों से कोड दिखाने के बाद, कोई आपके विशिष्ट दृष्टिकोण पर चर्चा कर सकता है।

सर्वर A पर आप PAdES हस्ताक्षर तैयार करने के लिए eSig DSS का उपयोग करते हैं और SignatureValue अपने SignHashDocument.signHash कॉल रिटर्न के साथ एक CMS हस्ताक्षर कंटेनर एम्बेड करते हैं:

ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

SignatureValue signatureValue = SignHashDocument.signHash(dataToSign);

DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

अर्थात। सर्वर ए सीएमएस हस्ताक्षर कंटेनर बनाता है और सर्वर बी केवल हस्ताक्षरित हैश की आपूर्ति करता है।

यह तब तक काम नहीं कर सकता जब तक आप हस्ताक्षर करने के लिए उपयोग किए गए प्रमाणपत्र को नहीं जानते और इसे service.getDataToSign कॉल से पहले parameters में सेट नहीं करते।

इसका कारण यह है कि CMS कंटेनर में उस प्रमाणपत्र के संदर्भ अहस्ताक्षरित बाइट्स और (PAdES के लिए) कंटेनर के हस्ताक्षरित बाइट्स दोनों में होते हैं। अहस्ताक्षरित बाइट्स में संदर्भ के लिए यह सैद्धांतिक रूप से हस्ताक्षर बाइट्स के साथ प्रमाण पत्र को पुनः प्राप्त करने के लिए पर्याप्त होगा, लेकिन हस्ताक्षरित बाइट्स में संदर्भ के लिए इसे पहले से जानना होगा।

वैकल्पिक रूप से आप सर्वर बी पर सीएमएस कंटेनर की पूरी पीढ़ी को लागू करने का प्रयास कर सकते हैं।

हालाँकि, इसके लिए काफी बदलाव की आवश्यकता है, और आपको PAdESService स्रोतों में काफी गहराई तक उतरना होगा। सर्वर ए पर ऊपर उद्धृत तीन पंक्तियों के बजाय आपको यह करना होगा:

  • पहले एक पीडीएफ ऑब्जेक्ट लाइब्रेरी और पीडीएफ सिग्नेचर सर्विस प्राप्त करें

    IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
    PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
    
  • पहली बार हस्ताक्षर करने के लिए पीडीएफ तैयार करें और दस्तावेज़ डाइजेस्ट की गणना करें,

    byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);
    
  • इस दस्तावेज़ को डाइजेस्ट को बैकएंड (सर्वर बी) को भेजें, जिसे एक विशेष सीएडीईएस हस्ताक्षर कंटेनर बनाना और वापस करना होगा, न कि केवल नग्न हस्ताक्षर बाइट्स,

  • और इस हस्ताक्षर कंटेनर पर हस्ताक्षर करने और इंजेक्ट करने के लिए दूसरी बार पीडीएफ तैयार करें:

    DSSDocument signature = pdfSignatureService.sign(toSignDocument, encodedData, parameters);
    

अवधारणा का प्रमाण

यहाँ eSig DSS 5.8 का उपयोग करके अवधारणा का प्रमाण दिया गया है:

आपके सर्वर A पर हम अनिवार्य रूप से आपके मौजूदा कोड का उपयोग कर सकते हैं:

DSSDocument toSignDocument = PDF_DOCUMENT_TO_SIGN;
DSSDocument image = IMAGE_DOCUMENT;


PAdESSignatureParameters parameters = new PAdESSignatureParameters();
parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
parameters.setReason("Preuve de signature");
parameters.setLocation("MAROC");
parameters.setGenerateTBSWithoutCertificate(true);

SignatureImageParameters imageParameters = new SignatureImageParameters();
imageParameters.setPage(1);
imageParameters.setImage(image);
imageParameters.setxAxis(350);
imageParameters.setyAxis(400);
imageParameters.setWidth(200);
imageParameters.setHeight(100);
parameters.setImageParameters(imageParameters);

SignatureImageTextParameters textParameters = new SignatureImageTextParameters();
DSSFont font = new DSSJavaFont(Font.SERIF);
font.setSize(16);
textParameters.setFont(font);
textParameters.setTextColor(Color.BLUE);
textParameters.setSignerTextPosition(SignerTextPosition.RIGHT);
textParameters.setSignerTextHorizontalAlignment(SignerTextHorizontalAlignment.LEFT);
textParameters.setSignerTextVerticalAlignment(SignerTextVerticalAlignment.TOP);
textParameters.setText("TESTING");
imageParameters.setTextParameters(textParameters);


IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();

byte[] hash = pdfSignatureService.digest(toSignDocument, parameters);

byte[] signatureValue = signHash(hash);

DSSDocument signedDocument = pdfSignatureService.sign(toSignDocument, signatureValue, parameters);


signedDocument.save(PATH_TO_SAVE_THE_SIGNED_DOCUMENT_TO);

(SplitPAdESSigning परीक्षण testSplitPAdESGenerationForMehdi)

विधि signHash अब स्वतंत्र रूप से दिए गए दस्तावेज़ हैश के लिए एक CMS हस्ताक्षर कंटेनर बनाएगी, और यह कंटेनर PAdES आवश्यकताओं के अनुरूप होगा। eSig DSS में इस कार्यक्षमता को प्रदान करने वाली विधियां और कक्षाएं हैं लेकिन वे protected या उससे भी कम दिखाई देती हैं। इस प्रकार, हमारे POC के लिए हम बस उन्हें अपने कोड में कॉपी कर लेते हैं।

सादगी के लिए मैं हार्ड कोडित SHA512withRSA का उपयोग एल्गोरिथम पर हस्ताक्षर करने के रूप में करता हूं।

इस प्रकार:

byte[] signHash(byte[] hash) throws IOException {
    Pkcs12SignatureToken signingToken = new Pkcs12SignatureToken(YOUR_P12_DATA);
    DSSPrivateKeyEntry privateKey = signingToken.getKey(YOUR_ALIAS);

    CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();
    padesCMSSignedDataBuilder = new PadesCMSSignedDataBuilder(commonCertificateVerifier);

    PAdESSignatureParameters parameters = new PAdESSignatureParameters();
    parameters.setDigestAlgorithm(DigestAlgorithm.SHA512);
    parameters.setEncryptionAlgorithm(EncryptionAlgorithm.RSA);
    parameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    parameters.setSigningCertificate(privateKey.getCertificate());

    ToBeSigned dataToSign = getDataToSign(hash, parameters);
    SignatureValue signatureValue = signingToken.sign(dataToSign, DigestAlgorithm.SHA512, privateKey);
    return generateCMSSignedData(hash, parameters, signatureValue);
}

PadesCMSSignedDataBuilder padesCMSSignedDataBuilder;

(SplitPAdESSigning विधि)

सहायक विधियां getDataToSign और generateCMSSignedData अनिवार्य रूप से PAdESService से कॉपी की गई हैं; वे signHash द्वारा प्रदान किए गए padesCMSSignedDataBuilder का उपयोग करते हैं (सदस्य चर के बजाय आप इसे इन दो विधियों का एक और तर्क भी बना सकते हैं):

/** @see eu.europa.esig.dss.pades.signature.PAdESService#getDataToSign(DSSDocument, PAdESSignatureParameters) */
public ToBeSigned getDataToSign(byte[] messageDigest, final PAdESSignatureParameters parameters) throws DSSException {
    final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
    final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());

    SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(parameters, messageDigest);

    final CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(parameters, customContentSigner,
            signerInfoGeneratorBuilder, null);

    final CMSProcessableByteArray content = new CMSProcessableByteArray(messageDigest);

    CMSUtils.generateDetachedCMSSignedData(generator, content);

    final byte[] dataToSign = customContentSigner.getOutputStream().toByteArray();
    return new ToBeSigned(dataToSign);
}

/** @see eu.europa.esig.dss.pades.signature.PAdESService#generateCMSSignedData(DSSDocument, PAdESSignatureParameters, SignatureValue) */
protected byte[] generateCMSSignedData(byte[] messageDigest, final PAdESSignatureParameters parameters,
        final SignatureValue signatureValue) {
    final SignatureAlgorithm signatureAlgorithm = parameters.getSignatureAlgorithm();
    final SignatureLevel signatureLevel = parameters.getSignatureLevel();
    Objects.requireNonNull(signatureAlgorithm, "SignatureAlgorithm cannot be null!");
    Objects.requireNonNull(signatureLevel, "SignatureLevel must be defined!");
    
    final CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId(), signatureValue.getValue());
    
    final SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(parameters, messageDigest);
    
    final CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(parameters, customContentSigner,
    signerInfoGeneratorBuilder, null);
    
    final CMSProcessableByteArray content = new CMSProcessableByteArray(messageDigest);
    CMSSignedData data = CMSUtils.generateDetachedCMSSignedData(generator, content);

    return DSSASN1Utils.getDEREncoded(data);
}

(SplitPAdESSsigning तरीके)

सीमित दृश्यता के कारण PadesCMSSignedDataBuilder और PAdESLevelBaselineB कक्षाएं साथ में कॉपी की जाती हैं:

/** @see eu.europa.esig.dss.cades.signature.CMSSignedDataBuilder */
class PadesCMSSignedDataBuilder extends CMSSignedDataBuilder {
    public PadesCMSSignedDataBuilder(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected CMSSignedDataGenerator createCMSSignedDataGenerator(CAdESSignatureParameters parameters, ContentSigner contentSigner, SignerInfoGeneratorBuilder signerInfoGeneratorBuilder,
            CMSSignedData originalSignedData) throws DSSException {

        return super.createCMSSignedDataGenerator(parameters, contentSigner, signerInfoGeneratorBuilder, originalSignedData);
    }

    protected SignerInfoGeneratorBuilder getSignerInfoGeneratorBuilder(final PAdESSignatureParameters parameters, final byte[] messageDigest) {
        final CAdESLevelBaselineB cadesLevelBaselineB = new CAdESLevelBaselineB(true);
        final PAdESLevelBaselineB padesProfileB = new PAdESLevelBaselineB();

        final DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider();

        SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new SignerInfoGeneratorBuilder(digestCalculatorProvider);

        signerInfoGeneratorBuilder = signerInfoGeneratorBuilder.setSignedAttributeGenerator(new CMSAttributeTableGenerator() {
            @Override
            public AttributeTable getAttributes(@SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
                return padesProfileB.getSignedAttributes(params, cadesLevelBaselineB, parameters, messageDigest);
            }
        });

        signerInfoGeneratorBuilder = signerInfoGeneratorBuilder.setUnsignedAttributeGenerator(new CMSAttributeTableGenerator() {
            @Override
            public AttributeTable getAttributes(@SuppressWarnings("rawtypes") Map params) throws CMSAttributeTableGenerationException {
                return padesProfileB.getUnsignedAttributes();
            }
        });

        return signerInfoGeneratorBuilder;
    }
}

/** @see eu.europa.esig.dss.pades.signature.PAdESLevelBaselineB */
class PAdESLevelBaselineB {
    AttributeTable getSignedAttributes(@SuppressWarnings("rawtypes") Map params, 
            CAdESLevelBaselineB cadesProfile, PAdESSignatureParameters parameters, byte[] messageDigest) {
        AttributeTable signedAttributes = cadesProfile.getSignedAttributes(parameters);

        if (signedAttributes.get(CMSAttributes.contentType) == null) {
            ASN1ObjectIdentifier contentType = (ASN1ObjectIdentifier) params.get(CMSAttributeTableGenerator.CONTENT_TYPE);
            if (contentType != null) {
                signedAttributes = signedAttributes.add(CMSAttributes.contentType, contentType);
            }
        }

        if (signedAttributes.get(CMSAttributes.messageDigest) == null) {
            signedAttributes = signedAttributes.add(CMSAttributes.messageDigest, new DEROctetString(messageDigest));
        }

        return signedAttributes;
    }

    AttributeTable getUnsignedAttributes() {
        return null;
    }
}

(SplitPAdESSigning सहायक वर्ग)

signHash और उसके सहायक सर्वर ए कोड पर निर्भर नहीं होते हैं और इसलिए, सर्वर बी पर भी स्थित हो सकते हैं।

2
mkl 10 फरवरी 2021, 11:41

यह संभव है और एक खुला स्रोत पूर्ण कार्यान्वयन यहां देखा जा सकता है https:// github.com/eideasy/eideasy-external-pades-digital-signatures

आपको उसी प्रारूप में पीडीएफ बनाने की जरूरत है जैसा कि हस्ताक्षर होने के बाद होगा, सभी हस्ताक्षर बाइटरेंज को हटा दें और फिर हैश की गणना करें।

सीएडीईएस हस्ताक्षर प्राप्त करने के बाद बस इसे बाइटरेंज में जोड़ें। यह आपको बेसलाइन-टी सिग्नेचर तक देगा।

बेसलाइन एलटी के लिए आपको सभी उपयोग किए गए प्रमाणपत्रों, ओसीएसपी प्रतिक्रियाओं और सीआरएलएस के साथ डीएसएस भी जोड़ना होगा।

यदि अधिक प्रश्न हैं तो आप मेरी प्रोफ़ाइल में विवरण का उपयोग करके मुझसे संपर्क कर सकते हैं।

यहां पूर्ण आवेदन का सबसे महत्वपूर्ण हिस्सा है जो आपके लिए हस्ताक्षर किए जाने वाले डाइजेस्ट की गणना करेगा। डाइजेस्ट की गणना करते समय सिग्नेचरबाइट्स नया बाइट [0] हो सकता है।

    public byte[] signDetached(SignatureParameters parameters, PDDocument document, byte[] signatureBytes, OutputStream out)
        throws IOException, NoSuchAlgorithmException {

    if (document.getDocumentId() == null) {
        document.setDocumentId(parameters.getSignatureTime());
    }

    PDSignature signature = createSignatureDictionary(parameters);
    SignatureOptions options = new SignatureOptions();

    // Enough room for signature, timestamp and OCSP for baseline-LT profile.
    options.setPreferredSignatureSize(SignatureOptions.DEFAULT_SIGNATURE_SIZE * 2);
    document.addSignature(signature, options);
    ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(out);

    byte[] dataToSign = IOUtils.toByteArray(externalSigning.getContent());
    final MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] digestBytes = digest.digest(dataToSign);

    if (signatureBytes != null) {
        externalSigning.setSignature(signatureBytes);
    }

    return digestBytes;
}

private PDSignature createSignatureDictionary(final SignatureParameters parameters) {
    PDSignature signature = new PDSignature();

    signature.setType(COSName.getPDFName("Sig"));
    signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
    signature.setSubFilter(PDSignature.SUBFILTER_ETSI_CADES_DETACHED);

    if (notEmpty(parameters.getSignerName())) {
        signature.setName(parameters.getSignerName());
    }

    if (notEmpty(parameters.getContactInfo())) {
        signature.setContactInfo(parameters.getContactInfo());
    }

    if (notEmpty(parameters.getLocation())) {
        signature.setLocation(parameters.getLocation());
    }

    if (notEmpty(parameters.getReason())) {
        signature.setReason(parameters.getReason());
    }

    // the signing date, needed for valid signature
    final Calendar cal = Calendar.getInstance();
    final Date signingDate = new Date(parameters.getSignatureTime());
    cal.setTime(signingDate);
    signature.setSignDate(cal);

    return signature;
}
0
Margus Pala 11 फरवरी 2021, 10:45

जीथब डीएसएस एसिग रिपोजिटरी पर कुछ शोध के बाद मैं एक समाधान खोजने में सक्षम था जो सही लग रहा था:

******* सर्वर ए पर *********

public class ServerA {
private static PAdESSignatureParameters signatureParameters;
private static DSSDocument documentToSign;
public static ExternalCMSPAdESService service;


public static void main(String[] args) throws Exception {
    documentToSign = new FileDocument(new File("file.pdf"));

    signatureParameters = new PAdESSignatureParameters();
    signatureParameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    signatureParameters.setLocation("Luxembourg");
    signatureParameters.setReason("DSS testing");
    signatureParameters.setContactInfo("Jira");
    signatureParameters.setGenerateTBSWithoutCertificate(true);

    service = new ExternalCMSPAdESService(getOfflineCertificateVerifier());
    byte[] documentDigest = computeDocumentDigest(documentToSign, signatureParameters);

    // Embedded CAdES is generated by a third party
    byte[] cmsSignedData = ServerB.getSignedCMSignedData(documentDigest);

    service.setCmsSignedData(cmsSignedData);
    DSSDocument finalDoc = service.signDocument(documentToSign, signatureParameters, null);

    save(finalDoc);
}

private static void save(DSSDocument signedDocument) {
    try (FileOutputStream fos = new FileOutputStream("DSS.pdf")) {
        Utils.copy(signedDocument.openStream(), fos);
    } catch (Exception e) {
        Alert alert = new Alert(Alert.AlertType.ERROR, "Unable to save file : " + e.getMessage(), ButtonType.CLOSE);
        alert.showAndWait();
        return;
    }
}

public static CertificateVerifier getOfflineCertificateVerifier() {
    CertificateVerifier cv = new CommonCertificateVerifier();
    cv.setDataLoader(new IgnoreDataLoader());
    return cv;
}

protected static byte[] computeDocumentDigest(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters) {
    IPdfObjFactory pdfObjFactory = new ServiceLoaderPdfObjFactory();
    final PDFSignatureService pdfSignatureService = pdfObjFactory.newPAdESSignatureService();
    return pdfSignatureService.digest(toSignDocument, parameters);
}

private static class ExternalCMSPAdESService extends PAdESService {

    private static final long serialVersionUID = -2003453716888412577L;

    private byte[] cmsSignedData;

    public ExternalCMSPAdESService(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected byte[] generateCMSSignedData(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters,
                                           final SignatureValue signatureValue) {
        if (this.cmsSignedData == null) {
            throw new NullPointerException("A CMS signed data must be provided");
        }
        return this.cmsSignedData;
    }

    public void setCmsSignedData(final byte[] cmsSignedData) {
        this.cmsSignedData = cmsSignedData;
    }

}
}

और परिकलित हैश पर हस्ताक्षर करने में सक्षम होने के लिए:

******* सर्वर बी पर *********

public class ServerB {

private static PAdESSignatureParameters signatureParameters;
private static DSSDocument documentToSign;
public static ExternalCMSPAdESService service;

/**
 * Computes a CAdES with specific things for PAdES
 */
public static byte[] getSignedCMSignedData(byte[] documentDigest) throws Exception {
    signatureParameters = new PAdESSignatureParameters();
    signatureParameters.setSigningCertificate(getSigningCert());
    signatureParameters.setCertificateChain(getCertificateChain());
    signatureParameters.setSignatureLevel(SignatureLevel.PAdES_BASELINE_B);
    signatureParameters.setLocation("Luxembourg");
    signatureParameters.setReason("DSS testing");
    signatureParameters.setContactInfo("Jira");

    CMSProcessableByteArray content = new CMSProcessableByteArray(documentDigest);

    PadesCMSSignedDataBuilder padesCMSSignedDataBuilder = new PadesCMSSignedDataBuilder(getOfflineCertificateVerifier());
    SignatureAlgorithm signatureAlgorithm = signatureParameters.getSignatureAlgorithm();

    CustomContentSigner customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId());
    SignerInfoGeneratorBuilder signerInfoGeneratorBuilder = padesCMSSignedDataBuilder.getSignerInfoGeneratorBuilder(signatureParameters, documentDigest);

    CMSSignedDataGenerator generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(signatureParameters, customContentSigner,
            signerInfoGeneratorBuilder, null);

    CMSUtils.generateDetachedCMSSignedData(generator, content);

    SignatureTokenConnection signingToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()));
    DSSPrivateKeyEntry privateKey = getKey("certificate.p12","123456");

    SignatureValue signatureValue = signingToken.sign(new ToBeSigned(customContentSigner.getOutputStream().toByteArray()),
            signatureParameters.getDigestAlgorithm(), privateKey);

    customContentSigner = new CustomContentSigner(signatureAlgorithm.getJCEId(), signatureValue.getValue());
    generator = padesCMSSignedDataBuilder.createCMSSignedDataGenerator(signatureParameters, customContentSigner, signerInfoGeneratorBuilder, null);

    CMSSignedData cmsSignedData = CMSUtils.generateDetachedCMSSignedData(generator, content);
    return DSSASN1Utils.getDEREncoded(cmsSignedData);
}

public static CertificateVerifier getOfflineCertificateVerifier() {
    CertificateVerifier cv = new CommonCertificateVerifier();
    cv.setDataLoader(new IgnoreDataLoader());
    return cv;
}

public static List<CertificateToken> getCertificateChain() throws Exception {
    List<CertificateToken> list = new ArrayList<>();
    CertificateToken[] l = getKey("certificate.p12","123456").getCertificateChain();
    for (int i = 0; i < l.length; i++) {
        list.add(l[i]);
    }
    return list;
}

public static CertificateToken getSigningCert() throws Exception {
    return getKey("certificate.p12","123456").getCertificate();
}

public static DSSPrivateKeyEntry getKey(String certificate, String pin) throws Exception {
    try (Pkcs12SignatureToken signatureToken = new Pkcs12SignatureToken("certificate.p12",
            new KeyStore.PasswordProtection("123456".toCharArray()))) {
        List<DSSPrivateKeyEntry> keys = signatureToken.getKeys();
        KSPrivateKeyEntry dssPrivateKeyEntry = (KSPrivateKeyEntry) keys.get(0);
        DSSPrivateKeyEntry entry = signatureToken.getKey(dssPrivateKeyEntry.getAlias(),
                new KeyStore.PasswordProtection("123456".toCharArray()));
        return entry;
    }
}
private static class ExternalCMSPAdESService extends PAdESService {

    private static final long serialVersionUID = -2003453716888412577L;

    private byte[] cmsSignedData;

    public ExternalCMSPAdESService(CertificateVerifier certificateVerifier) {
        super(certificateVerifier);
    }

    @Override
    protected byte[] generateCMSSignedData(final DSSDocument toSignDocument, final PAdESSignatureParameters parameters,
                                           final SignatureValue signatureValue) {
        if (this.cmsSignedData == null) {
            throw new NullPointerException("A CMS signed data must be provided");
        }
        return this.cmsSignedData;
    }

    public void setCmsSignedData(final byte[] cmsSignedData) {
        this.cmsSignedData = cmsSignedData;
    }

}
}
0
Mehdi 10 फरवरी 2021, 13:04