/**
  * Finalize signature to desired level
  *
  * @param sdoc SignedDoc object
  * @param sig Signature object
  * @param sigVal signature value
  * @param profile profile. Use null for default (e.g. profile in signed doc)
  * @return finalized signature
  */
 public static Signature finalizeSignature(
     SignedDoc sdoc, Signature sig, byte[] sigVal, String profile) throws DigiDocException {
   String prf = profile;
   if (prf == null) prf = sdoc.getProfile();
   if (m_logger.isDebugEnabled())
     m_logger.debug(
         "Finalize sig: "
             + sig.getId()
             + " profile: "
             + prf
             + " sdoc: "
             + sdoc.getFormat()
             + "/"
             + sdoc.getVersion());
   // xades-bes
   finalizeXadesBES(sig, sigVal);
   if (prf != null) {
     // T
     if (prf.equals(SignedDoc.BDOC_PROFILE_T)
         || prf.equals(SignedDoc.BDOC_PROFILE_CL)
         || prf.equals(SignedDoc.BDOC_PROFILE_TS)) finalizeXadesT(sdoc, sig);
     // C-L
     if (prf.equals(SignedDoc.BDOC_PROFILE_CL)
         || prf.equals(SignedDoc.BDOC_PROFILE_TM)
         || prf.equals(SignedDoc.BDOC_PROFILE_TS)) finalizeXadesC(sdoc, sig);
     // TM
     if (prf.equals(SignedDoc.BDOC_PROFILE_TM)) finalizeXadesXL_TM(sdoc, sig);
     // TS
     if (prf.equals(SignedDoc.BDOC_PROFILE_TS)) finalizeXadesXL_TS(sdoc, sig);
   }
   return sig;
 }
 public static Signature finalizeXadesXL_TS(SignedDoc sdoc, Signature sig)
     throws DigiDocException {
   if (m_logger.isDebugEnabled())
     m_logger.debug("Finalize XAdES-TS: " + sig.getId() + " profile: " + sig.getProfile());
   if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
     DigiDocXmlGenFactory genFac = new DigiDocXmlGenFactory(sdoc);
     TimestampFactory tsFac = ConfigManager.instance().getTimestampFactory();
     String sTsaCert = ConfigManager.instance().getStringProperty("DIGIDOC_TSA_CRT", null);
     if (sTsaCert != null) {
       if (m_logger.isDebugEnabled()) m_logger.debug("TSA cert: " + sTsaCert);
       X509Certificate tsaCrt = SignedDoc.readCertificate(sTsaCert);
       if (tsaCrt != null) {
         if (m_logger.isDebugEnabled())
           m_logger.debug("Add tsa cert: " + tsaCrt.getSubjectDN().getName());
         registerCert(tsaCrt, CertID.CERTID_TYPE_TSA, sig.getId() + "-TSA", sig);
       }
     }
     sig.setProfile(SignedDoc.BDOC_PROFILE_TS);
     // get <SigAndRefsTimeStamp>
     /* SignAndRefsTimestam not used in bdoc 2.0 any more
     StringBuffer sb = new StringBuffer();
     String tsaUrl = ConfigManager.instance().getProperty("DIGIDOC_TSA_URL");
     genFac.signatureValue2xml(sb, sig.getSignatureValue(), true);
     //String sSigValXml = sb.toString().trim();
     genFac.completeCertificateRefs2xml(sb, sig.getUnsignedProperties().getCompleteCertificateRefs(), sig, true);
     genFac.completeRevocationRefs2xml(sb, sig.getUnsignedProperties().getCompleteRevocationRefs(), sig, true);
     String sSigAndRefsDat = sb.toString().trim();
     byte[] hash = SignedDoc.digestOfType(sSigAndRefsDat.getBytes(),
     		(sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC) ? SignedDoc.SHA256_DIGEST_TYPE : SignedDoc.SHA1_DIGEST_TYPE));
     if(m_logger.isDebugEnabled())
     	m_logger.debug("Get sig-val-ts for: " + Base64Util.encode(hash) + " uri: " + tsaUrl +
     			" DATA:\n---\n" + sSigAndRefsDat + "\n---\n");
     TimeStampResponse tresp = tsFac.requestTimestamp(TSPAlgorithms.SHA1.getId(), hash, tsaUrl);
     if(tresp != null) {
       TimestampInfo ti = new TimestampInfo(sig.getId() + "-T1", sig, TimestampInfo.TIMESTAMP_TYPE_SIG_AND_REFS, hash, tresp);
       ti.addIncludeInfo(new IncludeInfo("#" + sig.getId() + "-SIG"));
       ti.addIncludeInfo(new IncludeInfo("#" + sig.getId() + "-T0"));
       ti.addIncludeInfo(new IncludeInfo("#" + sig.getId() + "-CERTREFS"));
       ti.addIncludeInfo(new IncludeInfo("#" + sig.getId() + "-REVOCREFS"));
       sig.addTimestampInfo(ti);
       sig.setProfile(SignedDoc.BDOC_PROFILE_TS);
     }*/
   }
   return sig;
 }
  public static Signature finalizeXadesT(SignedDoc sdoc, Signature sig) throws DigiDocException {
    if (m_logger.isDebugEnabled())
      m_logger.debug("Finalize XAdES-T: " + sig.getId() + " profile: " + sig.getProfile());
    UnsignedProperties usp = new UnsignedProperties(sig);
    sig.setUnsignedProperties(usp);
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
      DigiDocXmlGenFactory genFac = new DigiDocXmlGenFactory(sdoc);
      TimestampFactory tsFac = ConfigManager.instance().getTimestampFactory();
      // get <SignatureValueTimeStamp>
      StringBuffer sb = new StringBuffer();
      String tsaUrl = ConfigManager.instance().getProperty("DIGIDOC_TSA_URL");
      genFac.signatureValue2xml(sb, sig.getSignatureValue(), true);
      String sSigValXml = sb.toString().trim();
      byte[] hash =
          SignedDoc.digestOfType(
              sSigValXml.getBytes(),
              (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
                  ? SignedDoc.SHA256_DIGEST_TYPE
                  : SignedDoc.SHA1_DIGEST_TYPE));
      if (m_logger.isDebugEnabled())
        m_logger.debug(
            "Get sig-val-ts for: "
                + Base64Util.encode(hash)
                + " uri: "
                + tsaUrl
                + " DATA:\n---\n"
                + sSigValXml
                + "\n---\n");
      TimeStampResponse tresp = tsFac.requestTimestamp(TSPAlgorithms.SHA1.getId(), hash, tsaUrl);
      if (tresp != null) {
        TimestampInfo ti =
            new TimestampInfo(
                sig.getId() + "-T0", sig, TimestampInfo.TIMESTAMP_TYPE_SIGNATURE, hash, tresp);
        ti.addIncludeInfo(new IncludeInfo("#" + sig.getId() + "-SIG"));
        sig.addTimestampInfo(ti);
        try {
          if (m_logger.isDebugEnabled())
            m_logger.debug("Timestamp: " + Base64Util.encode(tresp.getEncoded()));
        } catch (Exception ex) {
        }
        // sb = new StringBuffer();
        // genFac.timestampInfo2xml(sb, ti, true);
        // String sToXml = sb.toString();
        // TODO: add TSA refs and certs ? Not in TSL yet!
        sig.setProfile(SignedDoc.BDOC_PROFILE_T);
        try {
          X509Certificate cert =
              SignedDoc.readCertificate(
                  new java.io.File("/Users/veiko/workspace/jdigidoc/trunk/iaik-tsa.crt"));

          /*Store st = tresp.getTimeStampToken().getCertificates();
          if(st  != null) {
           SignerInformationStore  signers = st.getSignerInfos();
           Collection              c = signers.getSigners();
           Iterator                it = c.iterator();

           while (it.hasNext())
           {
               SignerInformation   signer = (SignerInformation)it.next();
               Collection          certCollection = certStore.getMatches(signer.getSID());

               Iterator              certIt = certCollection.iterator();
               X509CertificateHolder cert = (X509CertificateHolder)certIt.next();


           }
          }*/
        } catch (Exception ex) {
          m_logger.error("Error ts: " + ex);
        }
      }
    }
    return sig;
  }
 public static Signature finalizeXadesXL_TM(SignedDoc sdoc, Signature sig)
     throws DigiDocException {
   if (m_logger.isDebugEnabled())
     m_logger.debug("Finalize XAdES-TM: " + sig.getId() + " profile: " + sig.getProfile());
   NotaryFactory notFac = ConfigManager.instance().getNotaryFactory();
   X509Certificate cert = sig.getKeyInfo().getSignersCertificate();
   boolean bUseLocal = ConfigManager.instance().getBooleanProperty("DIGIDOC_USE_LOCAL_TSL", false);
   TrustServiceFactory tslFac = ConfigManager.instance().getTslFactory();
   String ocspUrl = tslFac.findOcspUrlForCert(cert, 0, bUseLocal);
   if (ocspUrl == null)
     ocspUrl = ConfigManager.instance().getProperty("DIGIDOC_OCSP_RESPONDER_URL");
   X509Certificate caCert = tslFac.findCaForCert(cert, bUseLocal, null);
   if (m_logger.isDebugEnabled())
     m_logger.debug(
         "Get confirmation for cert: "
             + ((cert != null)
                 ? ConvertUtils.getCommonName(cert.getSubjectDN().getName())
                 : "NULL")
             + " CA: "
             + ((caCert != null)
                 ? ConvertUtils.getCommonName(caCert.getSubjectDN().getName())
                 : "NULL")
             + " URL: "
             + ((ocspUrl != null) ? ocspUrl : "NONE"));
   System.out.println("Get conf: " + sig.getId());
   Notary not = notFac.getConfirmation(sig, cert, caCert, null, ocspUrl);
   if (m_logger.isDebugEnabled()) m_logger.debug("Resp-id: " + not.getResponderId());
   String sRespId = ConvertUtils.getCommonName(not.getResponderId());
   // if(sRespId != null && sRespId.startsWith("byName: ")) sRespId = sRespId.substring("byName:
   // ".length());
   // if(sRespId != null && sRespId.startsWith("byKey: ")) sRespId = sRespId.substring("byKey:
   // ".length());
   X509Certificate rcert = notFac.getNotaryCert(sRespId, not.getCertNr());
   if (m_logger.isDebugEnabled())
     m_logger.debug(
         "Find responder cert by: "
             + sRespId
             + " and nr: "
             + not.getCertNr()
             + " found: "
             + ((rcert != null) ? "OK" : "NO")
             + " format: "
             + sdoc.getFormat());
   // if the request was successful then
   // create new data memebers
   if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC) && (rcert != null)) {
     X509Certificate rcacert = tslFac.findCaForCert(rcert, bUseLocal, null);
     if (m_logger.isDebugEnabled())
       m_logger.debug(
           "Register responders CA: "
               + ((rcacert != null) ? rcacert.getSubjectDN().getName() : "NULL"));
     String caId =
         not.getId() + "-" + ConvertUtils.getCommonName(rcacert.getSubjectDN().getName());
     registerCert(rcacert, CertID.CERTID_TYPE_RESPONDER_CA, caId, sig);
   }
   // add notary to list
   // sig.getUnsignedProperties().addNotary(not);
   // add ocsp ref for this notary
   OcspRef orf =
       new OcspRef(
           "#" + not.getId(),
           not.getResponderId(),
           not.getProducedAt(),
           (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
               ? SignedDoc.SHA256_DIGEST_ALGORITHM_1
               : SignedDoc.SHA1_DIGEST_ALGORITHM),
           SignedDoc.digestOfType(
               not.getOcspResponseData(),
               (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
                   ? SignedDoc.SHA256_DIGEST_TYPE
                   : SignedDoc.SHA1_DIGEST_TYPE)));
   sig.getUnsignedProperties().getCompleteRevocationRefs().addOcspRef(orf);
   // mark status
   sig.setProfile(SignedDoc.BDOC_PROFILE_TM);
   // change profile
   if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC) && sig.getPath() != null) {
     if (m_logger.isDebugEnabled()) m_logger.debug("Find signature: " + sig.getPath());
     ManifestFileEntry mfe = sdoc.findManifestEntryByPath(sig.getPath());
     if (mfe != null) {
       mfe.setMediaType(
           SignedDoc.MIME_SIGNATURE_BDOC_ + sdoc.getVersion() + "/" + sig.getProfile());
       if (m_logger.isDebugEnabled())
         m_logger.debug("Change signature: " + sig.getPath() + " type: " + mfe.getMediaType());
     }
   }
   // TODO: update certs and refs
   return sig;
 }
  /**
   * Adds a new uncomplete signature to signed doc
   *
   * @param sdoc SignedDoc object
   * @param profile new signature profile. Use NULL for default
   * @param cert signers certificate
   * @param claimedRoles signers claimed roles
   * @param adr signers address
   * @param sId new signature id, Use NULL for default value
   * @param sSigMethod signature method uri - ddoc: SignedDoc.RSA_SHA1_SIGNATURE_METHOD, bdoc:
   *     depends on card type. Use null for default value
   * @param sDigType digest type (all other hashes but SignedInfo). Use null for default type
   * @return new Signature object
   */
  public static Signature prepareXadesBES(
      SignedDoc sdoc,
      String profile,
      X509Certificate cert,
      String[] claimedRoles,
      SignatureProductionPlace adr,
      String sId,
      String sSigMethod,
      String sDigType)
      throws DigiDocException {
    if (m_logger.isDebugEnabled())
      m_logger.debug(
          "Prepare signature in sdoc: "
              + sdoc.getFormat()
              + "/"
              + sdoc.getVersion()
              + "/"
              + sdoc.getProfile()
              + " profile: "
              + profile
              + " signer: "
              + ((cert != null)
                  ? SignedDoc.getCommonName(cert.getSubjectDN().getName())
                  : "unknown")
              + " id "
              + sId);
    boolean bWeakSig = false;
    for (int i = 0; i < sdoc.countSignatures(); i++) {
      Signature sig = sdoc.getSignature(i);
      if (sig.getAltDigestMatch()) bWeakSig = true;
    }
    if (bWeakSig) {
      m_logger.error(
          "One or more signatures has wrong DataFile hash even if alternative hash matches!");
      throw new DigiDocException(
          DigiDocException.ERR_VERIFY,
          "One or more signatures has wrong DataFile hash even if alternative hash matches!",
          null);
    }
    // count roles
    if (claimedRoles != null && claimedRoles.length > 1) {
      m_logger.error("Currently supports no more than 1 ClaimedRole");
      throw new DigiDocException(
          DigiDocException.ERR_UNSUPPORTED, "Currently supports no more than 1 ClaimedRole", null);
    }
    // cannot proceed if cert has not been read
    if (cert == null) {
      m_logger.error("Signers certificate missing during signature preparation!");
      throw new DigiDocException(
          DigiDocException.ERR_SIGNERS_CERT,
          "Signers certificate missing during signature preparation!",
          null);
    }
    boolean bCheckNonRepu = ConfigManager.instance().getBooleanProperty("KEY_USAGE_CHECK", true);
    if (bCheckNonRepu && !ConfigManager.isSignatureKey(cert)) {
      if (m_logger.isDebugEnabled())
        m_logger.debug("Signers cert does not have non-repudiation bit set!");
      throw new DigiDocException(
          DigiDocException.ERR_SIGNERS_CERT_NONREPUD,
          "Signers cert does not have non-repudiation bit set!",
          null);
    }
    Signature sig = new Signature(sdoc);
    sig.setId(sId != null ? sId : sdoc.getNewSignatureId());
    if (profile != null) { // use new profile for this signature
      sig.setProfile(profile);
      if (sdoc.getProfile() == null || sdoc.getProfile().equals(SignedDoc.BDOC_PROFILE_BES))
        sdoc.setProfile(profile); // change also container to new profile
    } else // use default profile
    sig.setProfile(sdoc.getProfile());

    // create SignedInfo block
    SignedInfo si =
        new SignedInfo(
            sig,
            ((sSigMethod != null) ? sSigMethod : SignedDoc.RSA_SHA1_SIGNATURE_METHOD),
            SignedDoc.CANONICALIZATION_METHOD_20010315);
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
        && sdoc.getVersion().equals(SignedDoc.BDOC_VERSION_2_1)) {
      si.setCanonicalizationMethod(SignedDoc.CANONICALIZATION_METHOD_1_1);
      sdoc.setDefaultNsPref(SignedDoc.FORMAT_BDOC);
    }
    if (m_logger.isDebugEnabled())
      m_logger.debug(
          "Signer: "
              + cert.getSubjectDN().getName()
              + " EC key: "
              + isEcPubKey(cert)
              + " pre-2011: "
              + isPre2011IdCard(cert)
              + " digi-id: "
              + isDigiIdCard(cert)
              + " 2011: "
              + is2011Card(cert));
    if (sSigMethod == null) { // default values
      if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
        if (isPre2011IdCard(cert)) {
          if (m_logger.isDebugEnabled())
            m_logger.debug("Generating rsa-sha224 signature for pre-2011 card");
          si.setSignatureMethod(SignedDoc.RSA_SHA224_SIGNATURE_METHOD);
        } else {
          String dType =
              ConfigManager.instance().getStringProperty("DIGIDOC_DIGEST_TYPE", "SHA-256");
          String sSigMeth = ConfigManager.digType2SigMeth(dType, isEcPubKey(cert));
          if (m_logger.isDebugEnabled())
            m_logger.debug("Generating digest: " + dType + " and signature: " + sSigMeth);
          if (sSigMeth != null) si.setSignatureMethod(sSigMeth);
          else
            throw new DigiDocException(
                DigiDocException.ERR_DIGEST_ALGORITHM, "Invalid digest type: " + dType, null);
        }
      }
    }
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_XADES)
        || sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) si.setId(sig.getId() + "-SignedInfo");
    // SignedDataObjectProperties
    SignedDataObjectProperties sdop = new SignedDataObjectProperties();
    // add DataFile references
    for (int i = 0; i < sdoc.countDataFiles(); i++) {
      DataFile df = sdoc.getDataFile(i);
      if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
        if (!df.isDigestsCalculated()) {
          try {
            InputStream is = null;
            if (df.getDfCacheFile() != null) is = df.getBodyAsStream();
            if (is == null) is = sdoc.findDataFileAsStream(df.getFileName());
            if (is == null) is = new java.io.FileInputStream(df.getFileName());
            df.calcHashes(is);
          } catch (java.io.FileNotFoundException ex) {
            throw new DigiDocException(
                DigiDocException.ERR_READ_FILE, "Cannot read file: " + df.getFileName(), null);
          }
        }
      } else {
        if (!df.isDigestsCalculated()) df.calculateFileSizeAndDigest(null);
      }
      if (m_logger.isDebugEnabled()) m_logger.debug("Add ref for df: " + df.getId());
      Reference ref = new Reference(si, df, sDigType);
      if (sdoc.getFormat().equals(SignedDoc.FORMAT_XADES)
          || sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) ref.setId(sig.getId() + "-ref-" + i);
      si.addReference(ref);
      if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
          && sdoc.getVersion().equals(SignedDoc.BDOC_VERSION_2_1)) {
        DataObjectFormat dof = new DataObjectFormat("#" + ref.getId());
        dof.setMimeType(df.getMimeType());
        sdop.addDataObjectFormat(dof);
      }
    }
    // manifest.xml reference - bdoc 2.1-s ei allkirjasta manifest.xml-i
    // create key info
    KeyInfo ki = new KeyInfo(cert);
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_XADES)
        || sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) ki.setId(sig.getId() + "-KeyInfo");
    sig.setKeyInfo(ki);
    ki.setSignature(sig);
    registerCert(cert, CertValue.CERTVAL_TYPE_SIGNER, null, sig);
    if (m_logger.isDebugEnabled()) m_logger.debug("Signer cert: " + cert.getSubjectDN().getName());
    boolean bUseLocal = ConfigManager.instance().getBooleanProperty("DIGIDOC_USE_LOCAL_TSL", false);

    if (sdoc.getFormat().equals(SignedDoc.FORMAT_XADES)
        || sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) {
      TrustServiceFactory tslFac = ConfigManager.instance().getTslFactory();
      // first lookup in TSL-s
      X509Certificate ca = tslFac.findCaForCert(cert, bUseLocal, null);
      if (ca != null) {
        String caId = sig.getId() + "-" + ConvertUtils.getCommonName(ca.getSubjectDN().getName());
        registerCert(ca, CertValue.CERTVAL_TYPE_CA, caId, sig);
      }
      // TODO: maybe copy local CA certs to signature until the first ca that is in TSL?
    }
    // create signed properties
    SignedProperties sp = new SignedProperties(sig, cert, claimedRoles, adr);
    sig.setSignedProperties(sp);
    // bdoc 2.0 nonce policy
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)
        && sdoc.getVersion().equals(SignedDoc.BDOC_VERSION_2_1)
        && (sig.getProfile().equals(SignedDoc.BDOC_PROFILE_TM)
            || sig.getProfile().equals(SignedDoc.BDOC_PROFILE_BES)
            || sig.getProfile().equals(SignedDoc.BDOC_PROFILE_CL)
            || sig.getProfile().equals(SignedDoc.BDOC_PROFILE_TMA))) {
      sp.setSignedDataObjectProperties(sdop);
      Identifier id1 = new Identifier(Identifier.OIDAsURN);
      id1.setUri(BDOC_210_OID);
      ObjectIdentifier oid1 = new ObjectIdentifier(id1);
      SignaturePolicyId spi1 = new SignaturePolicyId(oid1);
      spi1.setDigestAlgorithm(BDOC_210_DIGEST_METHOD);
      spi1.setDigestValue(ConvertUtils.hex2bin(BDOC_210_DIGEST_HEX));
      // System.out.println("Spec hash: " + BDOC_210_DIGEST_HEX + " b64: " +
      // Base64Util.encode(ConvertUtils.hex2bin(BDOC_210_DIGEST_HEX)));
      spi1.addSigPolicyQualifier(new SpUri(BDOC_210_SPURI));
      SignaturePolicyIdentifier spid1 = new SignaturePolicyIdentifier(spi1);
      sp.setSignaturePolicyIdentifier(spid1);
    } else {
      SignaturePolicyIdentifier spid1 = new SignaturePolicyIdentifier(null);
      sp.setSignaturePolicyIdentifier(spid1);
    }
    Reference ref = new Reference(si, sp, sDigType);
    if (sdoc.getFormat().equals(SignedDoc.FORMAT_XADES)
        || sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC)) ref.setId(sig.getId() + "-ref-sp");
    ref.setType(SignedDoc.SIGNEDPROPERTIES_TYPE);
    si.addReference(ref);
    sig.setSignedInfo(si);
    sdoc.addSignature(sig);
    if (m_logger.isDebugEnabled())
      m_logger.debug("Prepared signature: " + sig.getId() + "/" + sig.getProfile());

    return sig;
  }