【问题标题】:How to get CMS (PKCS#7) from PKCS#1 Zeal id integration如何从 PKCS#1 Zeal id 集成中获取 CMS (PKCS#7)
【发布时间】:2022-08-03 17:43:18
【问题描述】:

我正在集成 CSC2QR 热心 id 集成。我正在发送 Base64 URL 编码的 SHA256 哈希 (OGRlY2M4NTcxOTQ2ZDRjZDcwYTAyNDk0OWUwMzNhMmEyYTU0Mzc3ZmU5ZjFjMWI5NDRjMjBmOWVlMTFhOWU1MQ==) 进行签名,作为响应,我得到 PKCS#1 原始签名。我不知道如何使用这些信息对文档进行数字签名。我正在使用 itext7 。

\"signatures\": [
    \"uXPiaQOEToyju50OIMrNe5gTstUQhnufmlcxmI9mG5tPCCMDYdfEV4Y+gKkixdzD\\r\\nZqni1+QAfy8cabRzpq13Puz31qUJ5spDRLfY/VLgBvLZLWTDK0KnJPsPWb36vMY5\\r\\n8CAn3DSbB02QkOoAafJkcOL3StnXc/JnAszk0lICwIM4lC3IW/pv3tWetrIn6pAJ\\r\\n7XBSX/zw2tfW9czFFrBaLm7hSe2NlQ1JsMgyLWEBauvFHeyFLdf9rLMM+aCoagRU\\r\\nD7T4Z31LrxmHFKVelS5dRvZuj8GTYJ78lfYfigSiVMsD8NEY3+YDthAsw2Lmgqs5\\r\\nMgVmRaQrjSdUMNeDZduFR1IeC/DLmQoBa8oXmeVqgxM0nIplq9gze1FklbPgiZ7G\\r\\n5zmdD8lnAP9BLawu9P+hC2GZNkeqVep3QzmoO149Iyu0jK8nrhYmxcEEqzaZiklc\\r\\nIKK7t03Ypst93Kps0OLc0s09A2g2wU+KzuuM+s29VKaE/gua9DKHNtf1iIZDmLtv\\r\\nRUoQxV9odJvRZwa+UMPsRTVejKb9pbgodiUtieyLq8Kr/NjJl+wnuH8CIiXYWxpe\\r\\nFoQ+J1teMOok/`sbO2X90SNqg5jvsyFTCBrGSgGWSob1TFghgWgRNiDBienXWWY09`\\r\\noaii058RhlJDm5l1KhMurBUZsyAre9rs74qj5tntMyQ=\"
  ]

我也收到了签名者证书作为回应 回复 -:

{
  \"authMode\": \"oauth2code\",
  \"cert\": {},
  \"key\": {
    \"algo\": [
      \"1.2.840.113549.1.1.11\"
    ],
    \"len\": 4096,
    \"status\": \"enabled\"
  },
  \"lang\": \"en-US\",
  \"multisign\": 1
}
  • 顺便说一句,将ZealiD API reference 与您的凭据信息响应进行比较,看起来您使用的是 CSC API,而不是 CSC 2QR API。

标签: java itext digital-signature itext7 pkcs#7


【解决方案1】:

我不知道 CSC 2QR API,更不用说完成解决它的代码了。因此,在这个答案中,我将展示一个框架来集成任意远程签名 API。

将远程签名服务与 iText 7 签名 API 集成的最简单方法是相应地实现 IExternalSignature。这可能看起来像这样(特定于 CSC 2QR API 的代码,由伪代码表示):

public class CSC2QRSignature implements IExternalSignature {

    Certificate[] chain;
    String hashAlgorithm = "SHA256";
    String encryptionAlgorithm = "RSA";

    public CSC2QRSignature([... parameters you need for CSC 2QR communication ...]) {
        [... request your CSC 2QR Credentials Info and initialize      ...]
        [... chain, hashAlgorithm, and encryptionAlgorithm accordingly ...]
    }

    @Override
    public String getEncryptionAlgorithm() {
        return encryptionAlgorithm;
    }

    @Override
    public String getHashAlgorithm() {
        return hashAlgorithm;
    }

    public Certificate[] getChain() {
        return chain;
    }

    @Override
    public byte[] sign(byte[] message) throws GeneralSecurityException {
        byte[] digest = MessageDigest.getInstance(hashAlgorithm).digest(message);
        [... call CSC 2QR Sign Hash for the base64 encoded digest ...]
        [... and return the base64 decoded signature from the response ...]
    }
}

使用该类,您可以像这样签署 PDF:

PdfReader reader = new PdfReader(SOURCE_PDF);
OutputStream os = new FileOutputStream(RESULT_PDF);

CSC2QRSignature signature = new CSC2QRSignature(...);
IExternalDigest digest = new BouncyCastleDigest();

PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
signer.signDetached(digest, signature, signature.getChain() , null, null, null, 0, CryptoStandard.CMS);

【讨论】:

  • 嗨@mkl,我在这里面临一个问题,我需要在调用signHash api之前在第二个授权api中传递相同的哈希值......如果我在内部调用sign方法,哈希值将会改变。
  • 简单地做全部sign 方法中调用。
  • 谢谢您的帮助 ! ....实际上这里的第二个授权调用仅来自浏览器 ....但是 np 我找到了解决方案...非常感谢您的帮助
  • 嗨@mkl,pdf 已成功签名,但同时从ec.europa.eu/digital-building-blocks/DSS/webapp-demo/validation 验证。我得到签名格式:PDF-NOT-ETSI
  • “我收到签名格式:PDF-NOT-ETSI”- 的确。您没有提到您需要 PAdES 样式签名。作为第一步,您应该在signer.signDetached 行中使用CryptoStandard.CADES 而不是CryptoStandard.CMS。这应该允许 PAdES BASELINE-B。
【解决方案2】:

这是我从 zeal 获得签名后的代码。签名有效,但仍显示 PDF-NOT-ETSI。

public static  String  prepareSignature(InputStream in, ByteArrayOutputStream preparedArrayStream ) throws FileNotFoundException, IOException,GeneralSecurityException {
            PdfReader reader = new PdfReader(in);
             Rectangle rect = new Rectangle(36, 648, 200, 100);
            PdfSigner signer = new PdfSigner(reader, preparedArrayStream,  new StampingProperties().useAppendMode());
                
PdfSignatureAppearance appearance = signer.getSignatureAppearance();
                appearance.setPageRect(rect)
                .setPageNumber(1)
                .setLocation("EU")
                .setReason("Test");
               signer.setFieldName("testing");
                
                PreSignatureContainer external = new PreSignatureContainer(PdfName.Adobe_PPKLite,
                        PdfName.ETSI_CAdES_DETACHED);
                
                signer.signExternalContainer(external, 8192);
                String hash = Base64.encodeBase64String(external.getHash());
                return hash;
               // byte[] preSignedBytes = os.toByteArray();
              //  outputStream.close();
                
            
            //return outputStream;
        }
        static class PreSignatureContainer  implements IExternalSignatureContainer 
        {
            private PdfDictionary sigDic;
            private byte hash[];
    
            public PreSignatureContainer(PdfName filter, PdfName subFilter) {
                sigDic = new PdfDictionary();
                sigDic.put(PdfName.Filter, filter);
                sigDic.put(PdfName.SubFilter, subFilter);
            }
    
            @Override
            public byte[] sign(InputStream data) throws GeneralSecurityException {
                String hashAlgorithm = "SHA256";
                BouncyCastleDigest digest = new BouncyCastleDigest();
    
                try {
                    this.hash = DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));
                } catch (IOException e) {
                    throw new GeneralSecurityException("PreSignatureContainer signing exception", e);
                }
    
                return new byte[0];
            }
    
            @Override
            public void modifySigningDictionary(PdfDictionary signDic) {
                signDic.putAll(sigDic);
            }
    
            public byte[] getHash() {
                return hash;
            }
        }
    
    public static void createSignature(InputStream in, String signatures) throws Exception {
             byte[] decodeSignature = Base64.decodeBase64(signatures);
             PdfReader reader =  null;
                reader = new PdfReader(in);
                FileOutputStream outputStream = new FileOutputStream(new File("D:\\zealid\\test\\newZeal.pdf"));
                 PdfSigner signer = new PdfSigner(reader, outputStream,  new StampingProperties().useAppendMode());
                 signer.signDeferred(signer.getDocument(), "testing", outputStream, new ExternalPrecalculatedSignatureContainer(decodeSignature));
                
                
                    outputStream.close();
        }
    
    class ExternalPrecalculatedSignatureContainer extends ExternalBlankSignatureContainer
        {
            byte[] cmsSignatureContents;
            public ExternalPrecalculatedSignatureContainer(byte[] cmsSignatureContents) 
            {
                super(new PdfDictionary());
                this.cmsSignatureContents = cmsSignatureContents;
            }
            
            
            @Override
            public  byte[] sign(InputStream data) throws CertificateException, InvalidKeyException, NoSuchProviderException, NoSuchAlgorithmException
            {
              BouncyCastleDigest digest = new BouncyCastleDigest();
             PdfPKCS7 sgn = new PdfPKCS7(null, chain, DigestAlgorithms.SHA256, null, digest, false);
             sgn.setExternalDigest(cmsSignatureContents, null,"RSA");
             cmsSignatureContents = sgn.getEncodedPKCS7();
             
                return cmsSignatureContents;
            }
    
          
    
        
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-01-27
    • 2014-02-12
    • 2020-03-19
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-21
    相关资源
    最近更新 更多