/** Get the "issuer" from the TBSCertificate bytes that are passed in */
 private DERObject getIssuer(byte[] enc) {
   try {
     ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream(enc));
     ASN1Sequence seq = (ASN1Sequence) in.readObject();
     return (DERObject) seq.getObjectAt(seq.getObjectAt(0) instanceof DERTaggedObject ? 3 : 2);
   } catch (IOException e) {
     throw new Error("IOException reading from ByteArray: " + e);
   }
 }
  /** Read an existing PKCS#7 object from a DER encoded byte array */
  public PKCS7SignedData(byte[] in, String provider)
      throws SecurityException, CRLException, InvalidKeyException, NoSuchProviderException,
          NoSuchAlgorithmException {
    ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(in));

    //
    // Basic checks to make sure it's a PKCS#7 SignedData Object
    //
    DERObject pkcs;

    try {
      pkcs = din.readObject();
    } catch (IOException e) {
      throw new SecurityException("can't decode PKCS7SignedData object");
    }

    if (!(pkcs instanceof ASN1Sequence)) {
      throw new SecurityException("Not a valid PKCS#7 object - not a sequence");
    }

    ContentInfo content = ContentInfo.getInstance(pkcs);

    if (!content.getContentType().equals(signedData)) {
      throw new SecurityException(
          "Not a valid PKCS#7 signed-data object - wrong header "
              + content.getContentType().getId());
    }

    SignedData data = SignedData.getInstance(content.getContent());

    certs = new ArrayList();

    if (data.getCertificates() != null) {
      Enumeration ec = ASN1Set.getInstance(data.getCertificates()).getObjects();

      while (ec.hasMoreElements()) {
        try {
          certs.add(
              new X509CertificateObject(X509CertificateStructure.getInstance(ec.nextElement())));
        } catch (CertificateParsingException e) {
          throw new SecurityException(e.toString());
        }
      }
    }

    crls = new ArrayList();

    if (data.getCRLs() != null) {
      Enumeration ec = ASN1Set.getInstance(data.getCRLs()).getObjects();
      while (ec.hasMoreElements()) {
        crls.add(new X509CRLObject(CertificateList.getInstance(ec.nextElement())));
      }
    }

    version = data.getVersion().getValue().intValue();

    //
    // Get the digest algorithm
    //
    digestalgos = new HashSet();
    Enumeration e = data.getDigestAlgorithms().getObjects();

    while (e.hasMoreElements()) {
      ASN1Sequence s = (ASN1Sequence) e.nextElement();
      DERObjectIdentifier o = (DERObjectIdentifier) s.getObjectAt(0);
      digestalgos.add(o.getId());
    }

    //
    // Get the SignerInfo
    //
    ASN1Set signerinfos = data.getSignerInfos();
    if (signerinfos.size() != 1) {
      throw new SecurityException(
          "This PKCS#7 object has multiple SignerInfos - only one is supported at this time");
    }

    SignerInfo signerInfo = SignerInfo.getInstance(signerinfos.getObjectAt(0));

    signerversion = signerInfo.getVersion().getValue().intValue();

    IssuerAndSerialNumber isAnds = signerInfo.getIssuerAndSerialNumber();

    //
    // Get the signing certificate
    //
    BigInteger serialNumber = isAnds.getCertificateSerialNumber().getValue();
    X509Principal issuer = new X509Principal(isAnds.getName());

    for (Iterator i = certs.iterator(); i.hasNext(); ) {
      X509Certificate cert = (X509Certificate) i.next();
      if (serialNumber.equals(cert.getSerialNumber()) && issuer.equals(cert.getIssuerDN())) {
        signCert = cert;
        break;
      }
    }

    if (signCert == null) {
      throw new SecurityException(
          "Can't find signing certificate with serial " + serialNumber.toString(16));
    }

    digestAlgorithm = signerInfo.getDigestAlgorithm().getObjectId().getId();

    digest = signerInfo.getEncryptedDigest().getOctets();
    digestEncryptionAlgorithm = signerInfo.getDigestEncryptionAlgorithm().getObjectId().getId();

    sig = Signature.getInstance(getDigestAlgorithm(), provider);

    sig.initVerify(signCert.getPublicKey());
  }
  /** return the bytes for the PKCS7SignedData object. */
  public byte[] getEncoded() {
    try {

      digest = sig.sign();

      // Create the set of Hash algorithms. I've assumed this is the
      // set of all hash agorithms used to created the digest in the
      // "signerInfo" structure. I may be wrong.
      //
      ASN1EncodableVector v = new ASN1EncodableVector();
      for (Iterator i = digestalgos.iterator(); i.hasNext(); ) {
        AlgorithmIdentifier a =
            new AlgorithmIdentifier(new DERObjectIdentifier((String) i.next()), null);

        v.add(a);
      }

      DERSet algos = new DERSet(v);

      // Create the contentInfo. Empty, I didn't implement this bit
      //
      DERSequence contentinfo = new DERSequence(new DERObjectIdentifier(ID_PKCS7_DATA));

      // Get all the certificates
      //
      v = new ASN1EncodableVector();
      for (Iterator i = certs.iterator(); i.hasNext(); ) {
        ASN1InputStream tempstream =
            new ASN1InputStream(
                new ByteArrayInputStream(((X509Certificate) i.next()).getEncoded()));
        v.add(tempstream.readObject());
      }

      DERSet dercertificates = new DERSet(v);

      // Create signerinfo structure.
      //
      ASN1EncodableVector signerinfo = new ASN1EncodableVector();

      // Add the signerInfo version
      //
      signerinfo.add(new DERInteger(signerversion));

      IssuerAndSerialNumber isAnds =
          new IssuerAndSerialNumber(
              new X509Name((ASN1Sequence) getIssuer(signCert.getTBSCertificate())),
              new DERInteger(signCert.getSerialNumber()));
      signerinfo.add(isAnds);

      // Add the digestAlgorithm
      //
      signerinfo.add(
          new AlgorithmIdentifier(new DERObjectIdentifier(digestAlgorithm), new DERNull()));

      //
      // Add the digestEncryptionAlgorithm
      //
      signerinfo.add(
          new AlgorithmIdentifier(
              new DERObjectIdentifier(digestEncryptionAlgorithm), new DERNull()));

      //
      // Add the digest
      //
      signerinfo.add(new DEROctetString(digest));

      //
      // Finally build the body out of all the components above
      //
      ASN1EncodableVector body = new ASN1EncodableVector();
      body.add(new DERInteger(version));
      body.add(algos);
      body.add(contentinfo);
      body.add(new DERTaggedObject(false, 0, dercertificates));

      if (crls.size() > 0) {
        v = new ASN1EncodableVector();
        for (Iterator i = crls.iterator(); i.hasNext(); ) {
          ASN1InputStream t =
              new ASN1InputStream(new ByteArrayInputStream(((X509CRL) i.next()).getEncoded()));
          v.add(t.readObject());
        }
        DERSet dercrls = new DERSet(v);
        body.add(new DERTaggedObject(false, 1, dercrls));
      }

      // Only allow one signerInfo
      //
      body.add(new DERSet(new DERSequence(signerinfo)));

      // Now we have the body, wrap it in it's PKCS7Signed shell
      // and return it
      //
      ASN1EncodableVector whole = new ASN1EncodableVector();
      whole.add(new DERObjectIdentifier(ID_PKCS7_SIGNED_DATA));
      whole.add(new DERTaggedObject(0, new DERSequence(body)));

      ByteArrayOutputStream bOut = new ByteArrayOutputStream();

      DEROutputStream dout = new DEROutputStream(bOut);
      dout.writeObject(new DERSequence(whole));
      dout.close();

      return bOut.toByteArray();
    } catch (Exception e) {
      throw new RuntimeException(e.toString());
    }
  }