如何从签名文件 p7m/Enveloped 和 p7s/Enveloping 中提取使用 java Bouncycastle 签名的原始文件

How extract from signed file p7m/Enveloped and p7s/Enveloping the original file signed with java Bouncycastle

我需要从使用信封模式 (p7m) 或信封模式 (p7s) 的签名文件中提取已签名的原始文件。

我很难弄清楚如何使用 bouncycastle 库来执行此操作。

我同时使用了 BouncyCastle 1.5 和 BouncyCastle 1.4

private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(GetOriginalContentFromFileSigned.class);

protected static CMSSignedData extractContent(InputStream buffer) throws IOException, CMSException {        
    CMSSignedData cms = null;
    CMSSignedData signature = new CMSSignedData(buffer);        
    Store cs = signature.getCertificates();
    SignerInformationStore signers = signature.getSignerInfos();
    Collection c = signers.getSigners();
    Iterator it = c.iterator();

    //the following array will contain the content of xml document
    byte[] data = null;

    while (it.hasNext()) {
        SignerInformation signer = (SignerInformation) it.next();
        Collection certCollection = cs.getMatches(signer.getSID());
        Iterator certIt = certCollection.iterator();
        X509CertificateHolder cert = (X509CertificateHolder) certIt.next();

        CMSProcessable sc = signature.getSignedContent();
        data = (byte[]) sc.getContent();
        cms = signature;
    }
    return cms;
}   

protected static byte[] getOriginalDocumentBinaries(InputStream signedDocument) {
    try (InputStream is = getOriginalDocumentStream(signedDocument)) {
        return IOUtils.toByteArray(is);
    } catch (Exception e) {
        logger.warn("Unable to retrieve original document binaries", e);
        return null;
    }
}

protected static InputStream getOriginalDocumentStream(InputStream signedDocument) throws Exception {
    final CMSSignedData cmsSignedData = getCmsSignedData(signedDocument);
    CMSTypedData signedContent = null;
    try{
        signedContent = (CMSTypedData) cmsSignedData.getSignedContent();
    }catch(Throwable t){        
        Object content = cmsSignedData.getSignedContent().getContent();
        if(content!=null){
            return new ByteArrayInputStream((byte[]) content);
        }
    }
    if (signedContent != null) {
        return new ByteArrayInputStream(getSignedContent(signedContent));
    }else{
        throw new Exception("Only enveloping and detached signatures are supported");
    }
}

protected static CMSSignedData getCmsSignedData(final InputStream dssDocument) throws CMSException, IOException {
    CMSSignedData cmsSignedData = null;
    if (isASN1SequenceTag(readFirstByte(dssDocument))) {
        try {
            cmsSignedData = new CMSSignedData(Base64.encodeBase64(IOUtils.toByteArray(dssDocument)));
        } catch (CMSException e) {
            logger.error("Can't get the CmisSigneData from P7M",e);
        }
    }else{
        logger.warn("Can't get the CmisSigneData from P7M with standard way");
        try {
            cmsSignedData = new CMSSignedData(Base64.encodeBase64(IOUtils.toByteArray(dssDocument)));
        } catch (CMSException e) {
            logger.error("Can't get the CmisSigneData from P7M with no standard way",e);                    
        }
    }           
    return cmsSignedData;
}

protected static boolean isASN1SequenceTag(byte tagByte) {
    // BERTags.SEQUENCE | BERTags.CONSTRUCTED = 0x30
    return (BERTags.SEQUENCE | BERTags.CONSTRUCTED) == tagByte;
}

protected static byte readFirstByte(final InputStream dssDocument) throws IOException{
    byte[] result = new byte[1];
    try (InputStream inputStream = dssDocument) {
        inputStream.read(result, 0, 1);
    } catch (IOException e) {
        throw new IOException(e);
    }
    return result[0];
}

protected static byte[] getSignedContent(final CMSTypedData cmsTypedData) throws Exception {
    if (cmsTypedData == null) {
        throw new Exception("CMSTypedData is null (should be a detached signature)");
    }
    try (ByteArrayOutputStream originalDocumentData = new ByteArrayOutputStream()) {
        cmsTypedData.write(originalDocumentData);
        return originalDocumentData.toByteArray();
    } catch (CMSException | IOException e) {
        throw new Exception(e);
    }
}

private interface BERTags
{
    public static final int BOOLEAN             = 0x01;
    public static final int INTEGER             = 0x02;
    public static final int BIT_STRING          = 0x03;
    public static final int OCTET_STRING        = 0x04;
    public static final int NULL                = 0x05;
    public static final int OBJECT_IDENTIFIER   = 0x06;
    public static final int EXTERNAL            = 0x08;
    public static final int ENUMERATED          = 0x0a; // decimal 10
    public static final int SEQUENCE            = 0x10; // decimal 16
    public static final int SEQUENCE_OF         = 0x10; // for completeness - used to model a SEQUENCE of the same type.
    public static final int SET                 = 0x11; // decimal 17
    public static final int SET_OF              = 0x11; // for completeness - used to model a SET of the same type.


    public static final int NUMERIC_STRING      = 0x12; // decimal 18
    public static final int PRINTABLE_STRING    = 0x13; // decimal 19
    public static final int T61_STRING          = 0x14; // decimal 20
    public static final int VIDEOTEX_STRING     = 0x15; // decimal 21
    public static final int IA5_STRING          = 0x16; // decimal 22
    public static final int UTC_TIME            = 0x17; // decimal 23
    public static final int GENERALIZED_TIME    = 0x18; // decimal 24
    public static final int GRAPHIC_STRING      = 0x19; // decimal 25
    public static final int VISIBLE_STRING      = 0x1a; // decimal 26
    public static final int GENERAL_STRING      = 0x1b; // decimal 27
    public static final int UNIVERSAL_STRING    = 0x1c; // decimal 28
    public static final int BMP_STRING          = 0x1e; // decimal 30
    public static final int UTF8_STRING         = 0x0c; // decimal 12

    public static final int CONSTRUCTED         = 0x20; // decimal 32
    public static final int APPLICATION         = 0x40; // decimal 64
    public static final int TAGGED              = 0x80; // decimal 128
}

部分代码取自https://github.com/esig/dss项目

我缺少什么使方法 "getOriginalDocumentBinaries" 起作用? 这对我来说似乎没问题,但我不是 bouncycastle 的专家。

你好。

这个解决方案似乎有效:

/**
* Extract content from p7m file
*/
    private byte[] getOriginalDocumentBinaries(final byte[] signedDoc) throws SignerException {        
        ASN1InputStream asn1InputStream = null;
        try {
            asn1InputStream = new ASN1InputStream(new ByteArrayInputStream(signedDoc));
            DERObject signedContent;
            try {
                signedContent = asn1InputStream.readObject();
            }
            catch (IOException cause) {
                logger.error(cause.getMessage(), (Throwable)cause);
                throw new SignerException(cause.getMessage(), cause);
            }
            CMSSignedData cmsSignedData;
            try {
                cmsSignedData = new CMSSignedData(ContentInfo.getInstance(signedContent));
            }
            catch (IllegalArgumentException cause2) {
                logger.error(cause2.getMessage(), (Throwable)cause2);
                throw new SignerException(cause2.getMessage(), cause2);
            }catch (Throwable cause2) {
                throw new SignerException(cause2.getMessage(), cause2);
            }
            return (byte[])((CMSProcessableByteArray)cmsSignedData.getSignedContent()).getContent();
        }catch(Exception ex){
            logger.error(ex.getMessage(),ex);
            throw new SignerException(ex);
        }
        finally {
            try {
                asn1InputStream.close();
            }
            catch (IOException ex) {}
        }
    }

我刚刚遇到了同样的问题,我实现了这个。我相信这可能对其他人有所帮助。

/**
*Extract from .p7m file and write into new file  
*/

public void extractTxtFileFromP7M() throws Exception {
    File file = new File(".p7m FilePath");
    String fileName = FilenameUtils.removeExtension(file.getName());
    byte[] p7mFileByteArray = fromFileToByteArray(file);
    byte[] extractedFileByteArray = getData(p7mFileByteArray);
    File extractedFile = new File("..../fileName");
    FileUtils.writeByteArrayToFile(extractedFile, extractedFileByteArray);
}
private byte[] fromFileToByteArray(File file) {
    try {
        return FileUtils.readFileToByteArray(file);
    } catch (IOException e) {
        log.error("Error while reading .p7m file!", e);
    }
    return new byte[0];
}
private byte[] getData(final byte[] p7bytes) {
    CMSSignedData cms = null;
    try {
        cms = new CMSSignedData(p7bytes);
    } catch (CMSException e) {
        log.error("Error while converting bytes to CMSSignedData : " + e.getMessage(), e);
    }
    if( cms == null || cms.getSignedContent() == null) {
        return new byte[0];
    }
    return (byte[]) cms.getSignedContent().getContent();
}