/**
   * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from
   * the signer's associated certificate using the sha1DigestCalculator.
   *
   * @param sha1DigestCalculator calculator for SHA-1 of certificate.
   * @param signerInfoGen the generator for the signer we are using.
   * @param tsaPolicy tasPolicy to send.
   * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated
   *     certificate for the signer,
   * @throws TSPException if the signer certificate cannot be processed.
   */
  public TimeStampTokenGenerator(
      DigestCalculator sha1DigestCalculator,
      final SignerInfoGenerator signerInfoGen,
      ASN1ObjectIdentifier tsaPolicy)
      throws IllegalArgumentException, TSPException {
    this.signerInfoGen = signerInfoGen;
    this.tsaPolicyOID = tsaPolicy;

    if (!sha1DigestCalculator
        .getAlgorithmIdentifier()
        .getAlgorithm()
        .equals(OIWObjectIdentifiers.idSHA1)) {
      throw new IllegalArgumentException("Digest calculator must be for SHA-1");
    }

    if (!signerInfoGen.hasAssociatedCertificate()) {
      throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate");
    }

    TSPUtil.validateCertificate(signerInfoGen.getAssociatedCertificate());

    try {
      OutputStream dOut = sha1DigestCalculator.getOutputStream();

      dOut.write(signerInfoGen.getAssociatedCertificate().getEncoded());

      dOut.close();

      final ESSCertID essCertid = new ESSCertID(sha1DigestCalculator.getDigest());

      this.signerInfoGen =
          new SignerInfoGenerator(
              signerInfoGen,
              new CMSAttributeTableGenerator() {
                public AttributeTable getAttributes(Map parameters)
                    throws CMSAttributeTableGenerationException {
                  AttributeTable table =
                      signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);

                  return table.add(
                      PKCSObjectIdentifiers.id_aa_signingCertificate,
                      new SigningCertificate(essCertid));
                }
              },
              signerInfoGen.getUnsignedAttributeTableGenerator());

    } catch (IOException e) {
      throw new TSPException("Exception processing certificate.", e);
    }
  }
  public TimeStampTokenGenerator(
      final SignerInfoGenerator signerInfoGen, ASN1ObjectIdentifier tsaPolicy)
      throws IllegalArgumentException, TSPException {
    this.signerInfoGen = signerInfoGen;
    this.tsaPolicyOID = tsaPolicy.getId();

    if (!signerInfoGen.hasAssociatedCertificate()) {
      throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate");
    }

    TSPUtil.validateCertificate(signerInfoGen.getAssociatedCertificate());

    try {
      final ESSCertID essCertid =
          new ESSCertID(
              MessageDigest.getInstance("SHA-1")
                  .digest(signerInfoGen.getAssociatedCertificate().getEncoded()));

      this.signerInfoGen =
          new SignerInfoGenerator(
              signerInfoGen,
              new CMSAttributeTableGenerator() {
                public AttributeTable getAttributes(Map parameters)
                    throws CMSAttributeTableGenerationException {
                  AttributeTable table =
                      signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);

                  return table.add(
                      PKCSObjectIdentifiers.id_aa_signingCertificate,
                      new SigningCertificate(essCertid));
                }
              },
              signerInfoGen.getUnsignedAttributeTableGenerator());

    } catch (NoSuchAlgorithmException e) {
      throw new TSPException("Can't find a SHA-1 implementation.", e);
    } catch (IOException e) {
      throw new TSPException("Exception processing certificate.", e);
    }
  }
  /**
   * Basic Constructor - set up a calculator based on signerInfoGen with a ESSCertID calculated from
   * the signer's associated certificate using the sha1DigestCalculator. If alternate values are
   * required for id-aa-signingCertificate they should be added to the signerInfoGen object before
   * it is passed in, otherwise a standard digest based value will be added.
   *
   * @param signerInfoGen the generator for the signer we are using.
   * @param digestCalculator calculator for to use for digest of certificate.
   * @param tsaPolicy tasPolicy to send.
   * @param isIssuerSerialIncluded should issuerSerial be included in the ESSCertIDs, true if yes,
   *     by default false.
   * @throws IllegalArgumentException if calculator is not SHA-1 or there is no associated
   *     certificate for the signer,
   * @throws TSPException if the signer certificate cannot be processed.
   */
  public TimeStampTokenGenerator(
      final SignerInfoGenerator signerInfoGen,
      DigestCalculator digestCalculator,
      ASN1ObjectIdentifier tsaPolicy,
      boolean isIssuerSerialIncluded)
      throws IllegalArgumentException, TSPException {
    this.signerInfoGen = signerInfoGen;
    this.tsaPolicyOID = tsaPolicy;

    if (!signerInfoGen.hasAssociatedCertificate()) {
      throw new IllegalArgumentException("SignerInfoGenerator must have an associated certificate");
    }

    X509CertificateHolder assocCert = signerInfoGen.getAssociatedCertificate();
    TSPUtil.validateCertificate(assocCert);

    try {
      OutputStream dOut = digestCalculator.getOutputStream();

      dOut.write(assocCert.getEncoded());

      dOut.close();

      if (digestCalculator
          .getAlgorithmIdentifier()
          .getAlgorithm()
          .equals(OIWObjectIdentifiers.idSHA1)) {
        final ESSCertID essCertid =
            new ESSCertID(
                digestCalculator.getDigest(),
                isIssuerSerialIncluded
                    ? new IssuerSerial(
                        new GeneralNames(new GeneralName(assocCert.getIssuer())),
                        assocCert.getSerialNumber())
                    : null);

        this.signerInfoGen =
            new SignerInfoGenerator(
                signerInfoGen,
                new CMSAttributeTableGenerator() {
                  public AttributeTable getAttributes(Map parameters)
                      throws CMSAttributeTableGenerationException {
                    AttributeTable table =
                        signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);

                    if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificate) == null) {
                      return table.add(
                          PKCSObjectIdentifiers.id_aa_signingCertificate,
                          new SigningCertificate(essCertid));
                    }

                    return table;
                  }
                },
                signerInfoGen.getUnsignedAttributeTableGenerator());
      } else {
        AlgorithmIdentifier digAlgID =
            new AlgorithmIdentifier(digestCalculator.getAlgorithmIdentifier().getAlgorithm());
        final ESSCertIDv2 essCertid =
            new ESSCertIDv2(
                digAlgID,
                digestCalculator.getDigest(),
                isIssuerSerialIncluded
                    ? new IssuerSerial(
                        new GeneralNames(new GeneralName(assocCert.getIssuer())),
                        new ASN1Integer(assocCert.getSerialNumber()))
                    : null);

        this.signerInfoGen =
            new SignerInfoGenerator(
                signerInfoGen,
                new CMSAttributeTableGenerator() {
                  public AttributeTable getAttributes(Map parameters)
                      throws CMSAttributeTableGenerationException {
                    AttributeTable table =
                        signerInfoGen.getSignedAttributeTableGenerator().getAttributes(parameters);

                    if (table.get(PKCSObjectIdentifiers.id_aa_signingCertificateV2) == null) {
                      return table.add(
                          PKCSObjectIdentifiers.id_aa_signingCertificateV2,
                          new SigningCertificateV2(essCertid));
                    }

                    return table;
                  }
                },
                signerInfoGen.getUnsignedAttributeTableGenerator());
      }
    } catch (IOException e) {
      throw new TSPException("Exception processing certificate.", e);
    }
  }