title: How extract from signed file p7m/Enveloped and p7s/Enveloping the original file signed with java Bouncycastle
body: <p>i need to extract from a signed file with the Enveloped mode (p7m) or the enveloping mode (p7s) the original file it's was signed.</p>
  
  <p>I have some hard time to figure out how use the bouncycastle library for doing this.</p>
  
  <p>I have use both BouncyCastle 1.5 and BouncyCastle 1.4</p>
  
  <pre><code>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
  }
  </code></pre>
  
  <p>Part of code is taken from the <a href="https://github.com/esig/dss" rel="nofollow noreferrer">https://github.com/esig/dss</a> project</p>
  
  <p>What i'm missing for make work the method "getOriginalDocumentBinaries"? 
  It's seem all right to me but i'm not expert of bouncycastle.</p>
  
  <p>Greetings.</p>