All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.digidoc4j.ddoc.factory.DigiDocXmlGenFactory Maven / Gradle / Ivy

Go to download

DDoc4J is Java Library for validating DDOC documents. It's not recommended to use it directly but rather through DigiDoc4J's API.

The newest version!
package org.digidoc4j.ddoc.factory;

import org.digidoc4j.ddoc.utils.ConvertUtils;
import org.digidoc4j.ddoc.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Factory class to handle all digidoc format xml generation issues
 * @author Veiko Sinivee
 */
public class DigiDocXmlGenFactory {
    private SignedDoc m_sdoc;

    private static final int NS_XMLDSIG = 1;
    private static final int NS_XADES = 2;
    private static final int NS_ASIC = 3;
    private Logger m_logger = LoggerFactory.getLogger(DigiDocXmlGenFactory.class);



    public DigiDocXmlGenFactory(SignedDoc sdoc)
    {
        m_sdoc = sdoc;
    }


    private void xmlElemTagStart(StringBuffer sb, int nNs, String tag, boolean bEnd, boolean bLf)
    {
        sb.append("<");
        if(nNs == NS_XMLDSIG && m_sdoc.getXmlDsigNs() != null && m_sdoc.getXmlDsigNs().length() > 0) {
            sb.append(m_sdoc.getXmlDsigNs());
            sb.append(":");
        }
        if(nNs == NS_XADES && m_sdoc.getXadesNs() != null && m_sdoc.getXadesNs().length() > 0) {
            sb.append(m_sdoc.getXadesNs());
            sb.append(":");
        }
        if(nNs == NS_ASIC && m_sdoc.getAsicNs() != null && m_sdoc.getAsicNs().length() > 0) {
            sb.append(m_sdoc.getAsicNs());
            sb.append(":");
        }
        sb.append(tag);
        if(bEnd)
            sb.append(">");
        if(bLf)
            sb.append("\n");
    }

    private void xmlElemTagEnd(StringBuffer sb, boolean bLf)
    {
        sb.append(">");
        if(bLf)
            sb.append("\n");
    }

    private void xmlElemEnd(StringBuffer sb, int nNs, String tag, boolean bLf)
    {
        sb.append(" 0) {
            sb.append(m_sdoc.getXmlDsigNs());
            sb.append(":");
        }
        if(nNs == NS_XADES && m_sdoc.getXadesNs() != null && m_sdoc.getXadesNs().length() > 0) {
            sb.append(m_sdoc.getXadesNs());
            sb.append(":");
        }
        if(nNs == NS_ASIC && m_sdoc.getAsicNs() != null && m_sdoc.getAsicNs().length() > 0) {
            sb.append(m_sdoc.getAsicNs());
            sb.append(":");
        }
        sb.append(tag);
        sb.append(">");
        if(bLf)
            sb.append("\n");
    }

    private void xmlElemAttr(StringBuffer sb, String name, String value)
    {
        sb.append(" ");
        sb.append(name);
        sb.append("=\"");
        sb.append(value);
        sb.append("\"");
    }

    private void xmlElemNsAttr(StringBuffer sb, int nNs)
    {
        sb.append(" ");
        sb.append("xmlns");
        if(nNs == NS_XMLDSIG && m_sdoc.getXmlDsigNs() != null && m_sdoc.getXmlDsigNs().length() > 0) {
            sb.append(":");
            sb.append(m_sdoc.getXmlDsigNs());
        }
        if(nNs == NS_XADES && m_sdoc.getXadesNs() != null && m_sdoc.getXadesNs().length() > 0) {
            sb.append(":");
            sb.append(m_sdoc.getXadesNs());
        }
        if(nNs == NS_ASIC && m_sdoc.getAsicNs() != null && m_sdoc.getAsicNs().length() > 0) {
            sb.append(":");
            sb.append(m_sdoc.getAsicNs());
        }
        sb.append("=\"");
        if(nNs == NS_XMLDSIG)
            sb.append(SignedDoc.xmlns_xmldsig);
        if(nNs == NS_XADES)
            sb.append(SignedDoc.xmlns_xades_123);
        sb.append("\"");
    }

    private void reference2xml(StringBuffer sb, Reference ref)
    {
        xmlElemTagStart(sb, NS_XMLDSIG, "Reference", false, false);
        // @Id
        if(ref.getId() != null && ref.getId().length() > 0)
            xmlElemAttr(sb, "Id", ref.getId());
        // @URI
        if(ref.getUri().indexOf("SignedProperties") != -1) {
            if(m_sdoc.getVersion().equals(SignedDoc.VERSION_1_2) ||
                    m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3))
                xmlElemAttr(sb, "Type", "http://uri.etsi.org/01903/v1.1.1#SignedProperties");
            else
                xmlElemAttr(sb, "Type", SignedDoc.SIGNEDPROPERTIES_TYPE);
            String s = ref.getUri();
            if(s.startsWith("/") || s.startsWith("#"))
                s = s.charAt(0) + ConvertUtils.uriEncodePath(s.substring(1));
            else
                s = ConvertUtils.uriEncodePath(s);
            xmlElemAttr(sb, "URI", s);
        } else {
            String s = ref.getUri();
            if(s.startsWith("/") || s.startsWith("#"))
                s = s.charAt(0) + ConvertUtils.uriEncodePath(s.substring(1));
            else
                s = ConvertUtils.uriEncodePath(s);
            xmlElemAttr(sb, "URI", s);
        }
        xmlElemTagEnd(sb, true);
        // 
        if(ref.getTransformAlgorithm() != null && ref.getTransformAlgorithm().length() > 0) {
            xmlElemTagStart(sb, NS_XMLDSIG, "Transforms", true, false);
            xmlElemTagStart(sb, NS_XMLDSIG, "Transform", false, false);
            xmlElemAttr(sb, "Algorithm", ref.getTransformAlgorithm());
            xmlElemTagEnd(sb, true);
            xmlElemEnd(sb, NS_XMLDSIG, "Transform", true);
            xmlElemEnd(sb, NS_XMLDSIG, "Transforms", true);
        }
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestMethod", false, false);
        xmlElemAttr(sb, "Algorithm", ref.getDigestAlgorithm());
        xmlElemTagEnd(sb, true);
        xmlElemEnd(sb, NS_XMLDSIG, "DigestMethod", true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestValue", true, false);
        sb.append(Base64Util.encode(ref.getDigestValue(), 0));
        xmlElemEnd(sb, NS_XMLDSIG, "DigestValue", true);
        xmlElemEnd(sb, NS_XMLDSIG, "Reference", true);
    }

    private void signedInfo2xml(StringBuffer sb, SignedInfo si, boolean bHashCalc)
    {
        xmlElemTagStart(sb, NS_XMLDSIG, "SignedInfo", false, false);
        // @xmlns
        if(si.getSignature() != null && si.getSignature().getSignedDoc() != null &&
                si.getSignature().getSignedDoc().getFormat() != null &&
                (si.getSignature().getSignedDoc().getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) ||
                        si.getSignature().getSignedDoc().getFormat().equals(SignedDoc.FORMAT_SK_XML))) {
            xmlElemNsAttr(sb, NS_XMLDSIG);
        }
        // @Id
        if(si.getId() != null && si.getId().length() > 0)
            xmlElemAttr(sb, "Id", si.getId());
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "CanonicalizationMethod", false, false);
        xmlElemAttr(sb, "Algorithm", si.getCanonicalizationMethod());
        xmlElemTagEnd(sb, true);
        xmlElemEnd(sb, NS_XMLDSIG, "CanonicalizationMethod", true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "SignatureMethod", false, false);
        xmlElemAttr(sb, "Algorithm", si.getSignatureMethod());
        xmlElemTagEnd(sb, true);
        xmlElemEnd(sb, NS_XMLDSIG, "SignatureMethod", true);
        for(int i = 0; i < si.countReferences(); i++) {
            Reference ref = (Reference)si.getReference(i);
            reference2xml(sb, ref);
        }
        xmlElemEnd(sb, NS_XMLDSIG, "SignedInfo", false);
    }

    public void signatureValue2xml(StringBuffer sb, SignatureValue sv, boolean bWithNs)
    {
        xmlElemTagStart(sb, NS_XMLDSIG, "SignatureValue", false, false);
        if(bWithNs)
            xmlElemNsAttr(sb, NS_XMLDSIG);
        // @Id
        if(sv.getId() != null && sv.getId().length() > 0)
            xmlElemAttr(sb, "Id", sv.getId());
        xmlElemTagEnd(sb, true);
        sb.append(Base64Util.encode(sv.getValue(), 0));
        xmlElemEnd(sb, NS_XMLDSIG, "SignatureValue", true);
    }

    private void certValue2xml(StringBuffer sb, CertValue cval)
            throws DigiDocException
    {
        if(cval.getType() == CertValue.CERTVAL_TYPE_SIGNER) {
            xmlElemTagStart(sb, NS_XMLDSIG, "X509Certificate", true, false);
        } else {
            xmlElemTagStart(sb, NS_XADES, "EncapsulatedX509Certificate", false, false);
            // @Id
            if(cval.getId() != null && cval.getId().length() > 0)
                xmlElemAttr(sb, "Id", cval.getId());
            xmlElemTagEnd(sb, true);
        }
        try {
            sb.append(Base64Util.encode(cval.getCert().getEncoded(), 64));
        } catch(Exception ex) {
            DigiDocException.handleException(ex, DigiDocException.ERR_ENCODING);
        }
        if(cval.getType() == CertValue.CERTVAL_TYPE_SIGNER)
            xmlElemEnd(sb, NS_XMLDSIG, "X509Certificate", false);
        else
            xmlElemEnd(sb, NS_XADES, "EncapsulatedX509Certificate", true);
    }

    private void keyInfo2xml(StringBuffer sb, KeyInfo ki, Signature sig)
            throws DigiDocException
    {
        xmlElemTagStart(sb, NS_XMLDSIG, "KeyInfo", false, false);
        // @Id
        if(ki.getId() != null && ki.getId().length() > 0)
            xmlElemAttr(sb, "Id", ki.getId());
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "KeyValue", true, true);
        if(!sig.isEllipticCurveSiganture()) { // tegelikult ddoc-s meil EC allkirju ei olegi
            // 
            xmlElemTagStart(sb, NS_XMLDSIG, "RSAKeyValue", true, true);
            // 
            xmlElemTagStart(sb, NS_XMLDSIG, "Modulus", true, false);
            sb.append(Base64Util.encode(ki.getSignerKeyModulus().toByteArray(), 64));
            xmlElemEnd(sb, NS_XMLDSIG, "Modulus", true);
            // 
            xmlElemTagStart(sb, NS_XMLDSIG, "Exponent", true, false);
            sb.append(Base64Util.encode(ki.getSignerKeyExponent().toByteArray(), 64));
            xmlElemEnd(sb, NS_XMLDSIG, "Exponent", true);
            // 
            xmlElemEnd(sb, NS_XMLDSIG, "RSAKeyValue", true);
        }
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "KeyValue", true);
        // X509Data
        xmlElemTagStart(sb, NS_XMLDSIG, "X509Data", true, false);
        CertValue cval = sig.getCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
        if(cval != null)
            certValue2xml(sb, cval);
        xmlElemEnd(sb, NS_XMLDSIG, "X509Data", false);
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "KeyInfo", true);
    }

    private void certId2xml(StringBuffer sb, CertID ci, Signature sig)
    {
        xmlElemTagStart(sb, NS_XADES, "Cert", false, false);
        // in ddoc 1.1 and 1.2 we had forbidden Id atribute
        if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                (m_sdoc.getVersion().equals(SignedDoc.VERSION_1_1) ||
                        m_sdoc.getVersion().equals(SignedDoc.VERSION_1_2))) {
            // @Id
            if(ci.getId() != null && ci.getId().length() > 0)
                xmlElemAttr(sb, "Id", ci.getId());
        }
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "CertDigest", true, true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestMethod", false, false);
        xmlElemAttr(sb, "Algorithm", ci.getDigestAlgorithm());
        //if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC))
        //	xmlElemNsAttr(sb, NS_XMLDSIG);
        xmlElemTagEnd(sb, true);
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "DigestMethod", true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestValue", false, false);
        //if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC))
        //	xmlElemNsAttr(sb, NS_XMLDSIG);
        xmlElemTagEnd(sb, false);
        sb.append(Base64Util.encode(ci.getDigestValue()));
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "DigestValue", true);
        // 
        xmlElemEnd(sb, NS_XADES, "CertDigest", true);
        // 
        if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                (m_sdoc.getVersion().equals(SignedDoc.VERSION_1_1) ||
                        m_sdoc.getVersion().equals(SignedDoc.VERSION_1_2))) {
            xmlElemTagStart(sb, NS_XMLDSIG, "IssuerSerial", true, false);
            sb.append(ci.getSerial().toString());
            xmlElemEnd(sb, NS_XMLDSIG, "IssuerSerial", true);
        } else {
            xmlElemTagStart(sb, NS_XADES, "IssuerSerial", true, true);
            // 
            xmlElemTagStart(sb, NS_XMLDSIG, "X509IssuerName", false, false);
            xmlElemNsAttr(sb, NS_XMLDSIG);
            xmlElemTagEnd(sb, false);
            sb.append(ConvertUtils.escapeTextNode(ci.getIssuer()));
            // 
            xmlElemEnd(sb, NS_XMLDSIG, "X509IssuerName", true);
            // 
            xmlElemTagStart(sb, NS_XMLDSIG, "X509SerialNumber", false, false);
            xmlElemNsAttr(sb, NS_XMLDSIG);
            xmlElemTagEnd(sb, false);
            sb.append(ci.getSerial().toString());
            // 
            xmlElemEnd(sb, NS_XMLDSIG, "X509SerialNumber", true);
            // 
            xmlElemEnd(sb, NS_XADES, "IssuerSerial", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, "Cert", true);
    }

    private void signatureProductionPlace2xml(StringBuffer sb, SignatureProductionPlace adr)
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "SignatureProductionPlace", true, true);
        if(adr.getCity() != null && adr.getCity().trim().length() > 0) { // 
            xmlElemTagStart(sb, NS_XADES, "City", true, false);
            sb.append(ConvertUtils.escapeTextNode(adr.getCity()));
            xmlElemEnd(sb,  NS_XADES, "City", true);
        }
        if(adr.getStateOrProvince() != null && adr.getStateOrProvince().trim().length() > 0) { // 
            xmlElemTagStart(sb, NS_XADES, "StateOrProvince", true, false);
            sb.append(ConvertUtils.escapeTextNode(adr.getStateOrProvince()));
            xmlElemEnd(sb,  NS_XADES, "StateOrProvince", true);
        }
        if(adr.getPostalCode() != null && adr.getPostalCode().trim().length() > 0) { // 
            xmlElemTagStart(sb, NS_XADES, "PostalCode", true, false);
            sb.append(ConvertUtils.escapeTextNode(adr.getPostalCode()));
            xmlElemEnd(sb,  NS_XADES, "PostalCode", true);
        }
        if(adr.getCountryName() != null && adr.getCountryName().trim().length() > 0) { // 
            xmlElemTagStart(sb, NS_XADES, "CountryName", true, false);
            sb.append(ConvertUtils.escapeTextNode(adr.getCountryName()));
            xmlElemEnd(sb,  NS_XADES, "CountryName", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, "SignatureProductionPlace", true);
    }

    private void identifier2xml(StringBuffer sb, Identifier idf, Signature sig)
    {
        xmlElemTagStart(sb, NS_XADES, "Identifier", false, false);
        // @Qualifier
        if(idf.getQualifier() != null && idf.getQualifier().length() > 0)
            xmlElemAttr(sb, "Qualifier", idf.getQualifier());
        xmlElemTagEnd(sb, true);
        // oid or uri content
        if(idf.getUri() != null && idf.getUri().trim().length() > 0)
            sb.append(idf.getUri());
        // 
        xmlElemEnd(sb,  NS_XADES, "Identifier", true);
    }

    private void objectIdentifier2xml(StringBuffer sb, ObjectIdentifier odf, String tag, Signature sig)
    {
        xmlElemTagStart(sb, NS_XADES, tag, true, true);
        // 
        if(odf.getIdentifier() != null)
            identifier2xml(sb, odf.getIdentifier(), sig);
        // 
        if(odf.getDescription() != null) {
            xmlElemTagStart(sb, NS_XADES, "Description", true, false);
            sb.append(odf.getDescription());
            xmlElemEnd(sb,  NS_XADES, "Description", true);
        }
        // 
        if(odf.countDocumentationReferences() > 0) {
            xmlElemTagStart(sb, NS_XADES, "DocumentationReferences", true, true);
            for(int i = 0; i < odf.countDocumentationReferences(); i++) {
                xmlElemTagStart(sb, NS_XADES, "DocumentationReference", true, false);
                sb.append(odf.getDocumentationReference(i));
                xmlElemEnd(sb,  NS_XADES, "DocumentationReference", true);
            }
            xmlElemEnd(sb,  NS_XADES, "DocumentationReferences", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, tag, true);
    }

    private void noticeRef2xml(StringBuffer sb, NoticeRef nrf, Signature sig)
    {
        xmlElemTagStart(sb, NS_XADES, "NoticeRef", true, true);
        // Organization
        xmlElemTagStart(sb, NS_XADES, "Organization", true, true);
        sb.append(nrf.getOrganization());
        xmlElemEnd(sb,  NS_XADES, "Organization", true);
        // NoticeNumbers
        if(nrf.countNoticeNumbers() > 0) {
            xmlElemTagStart(sb, NS_XADES, "NoticeNumbers", true, true);
            for(int i = 0; i < nrf.countNoticeNumbers(); i++) {
                xmlElemTagStart(sb, NS_XADES, "int", true, false);
                sb.append(new Integer(nrf.getNoticeNumber(i)).toString());
                xmlElemEnd(sb,  NS_XADES, "int", true);
            }
            xmlElemEnd(sb,  NS_XADES, "NoticeNumbers", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, "NoticeRef", true);
    }

    private void spUserNotice2xml(StringBuffer sb, SpUserNotice not, Signature sig)
    {
        if(not != null && (not.getExplicitText() != null || not.getNoticeRef() != null)) {
            xmlElemTagStart(sb, NS_XADES, "SPUserNotice", true, true);
            // NoticeRef
            if(not.getNoticeRef() != null)
                noticeRef2xml(sb, not.getNoticeRef(), sig);
            // ExplicitText
            if(not.getExplicitText() != null) {
                xmlElemTagStart(sb, NS_XADES, "ExplicitText", true, true);
                sb.append(not.getExplicitText());
                xmlElemEnd(sb,  NS_XADES, "ExplicitText", true);
            }
            xmlElemEnd(sb,  NS_XADES, "SPUserNotice", true);
        }
    }

    private void spUri2xml(StringBuffer sb, SpUri uri, Signature sig)
    {
        if(uri != null && uri.getUri() != null) {
            xmlElemTagStart(sb, NS_XADES, "SPURI", true, true);
            sb.append(uri.getUri());
            xmlElemEnd(sb,  NS_XADES, "SPURI", true);
        }
    }

    private void sigPolicyQualifier2xml(StringBuffer sb, SigPolicyQualifier spq, Signature sig)
    {
        if(spq != null && (spq instanceof SpUserNotice || spq instanceof SpUri)) {
            xmlElemTagStart(sb, NS_XADES, "SigPolicyQualifier", true, true);
            // SPUserNotice
            if(spq instanceof SpUserNotice)
                spUserNotice2xml(sb, (SpUserNotice)spq, sig);
            // SPURI
            if(spq instanceof SpUri)
                spUri2xml(sb, (SpUri)spq, sig);
            xmlElemEnd(sb,  NS_XADES, "SigPolicyQualifier", true);
        }
    }

    private void signaturePolicyId2xml(StringBuffer sb, SignaturePolicyId spi, Signature sig)
    {
        if(spi != null) {
            xmlElemTagStart(sb, NS_XADES, "SignaturePolicyId", true, true);
            // Identifier
            if(spi.getSigPolicyId() != null)
                objectIdentifier2xml(sb,spi.getSigPolicyId(), "SigPolicyId", sig);
            // SigPolicyHash
            if(spi.getDigestAlgorithm() != null || spi.getDigestValue() != null) {
                xmlElemTagStart(sb, NS_XADES, "SigPolicyHash", true, true);
                // 
                xmlElemTagStart(sb, NS_XMLDSIG, "DigestMethod", false, false);
                xmlElemAttr(sb, "Algorithm", spi.getDigestAlgorithm());
                xmlElemTagEnd(sb, true);
                // 
                xmlElemEnd(sb, NS_XMLDSIG, "DigestMethod", true);
                // 
                xmlElemTagStart(sb, NS_XMLDSIG, "DigestValue", false, false);
                xmlElemTagEnd(sb, false);
                sb.append(Base64Util.encode(spi.getDigestValue()));
                // 
                xmlElemEnd(sb, NS_XMLDSIG, "DigestValue", true);
                xmlElemEnd(sb,  NS_XADES, "SigPolicyHash", true);
            }
            // SigPolicyQualifiers
            if(spi.countSigPolicyQualifiers() > 0) {
                xmlElemTagStart(sb, NS_XADES, "SigPolicyQualifiers", true, true);
                for(int i = 0; i < spi.countSigPolicyQualifiers(); i++) {
                    sigPolicyQualifier2xml(sb, spi.getSigPolicyQualifier(i), sig);
                }
                xmlElemEnd(sb,  NS_XADES, "SigPolicyQualifiers", true);
            }
            xmlElemEnd(sb,  NS_XADES, "SignaturePolicyId", true);
        }
    }

    private void signaturePolicyIdentifier2xml(StringBuffer sb, SignaturePolicyIdentifier spi, Signature sig)
    {
        xmlElemTagStart(sb, NS_XADES, "SignaturePolicyIdentifier", true, true);
        if(spi != null && spi.getSignaturePolicyId() != null) {
            signaturePolicyId2xml(sb, spi.getSignaturePolicyId(), sig);
        } else {
            xmlElemTagStart(sb, NS_XADES, "SignaturePolicyImplied", true, true);
            xmlElemEnd(sb, NS_XADES, "SignaturePolicyImplied", true);
        }
        xmlElemEnd(sb, NS_XADES, "SignaturePolicyIdentifier", true);
    }

    private void dataObjectFormat2xml(StringBuffer sb, DataObjectFormat dof, Signature sig)
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "DataObjectFormat", false, false);
        // @ObjectReference
        if(dof.getObjectReference() != null && dof.getObjectReference().length() > 0)
            xmlElemAttr(sb, "ObjectReference", dof.getObjectReference());
        xmlElemTagEnd(sb, true);
        // 
        if(dof.getDescription() != null && dof.getDescription().trim().length() > 0) {
            xmlElemTagStart(sb, NS_XADES, "Description", true, false);
            sb.append(dof.getDescription());
            xmlElemEnd(sb,  NS_XADES, "Description", true);
        }
        // 
        if(dof.getObjectIdentifier() != null) {
            objectIdentifier2xml(sb, dof.getObjectIdentifier(), "ObjectIdentifier", sig);
        }
        // 
        if(dof.getMimeType() != null && dof.getMimeType().trim().length() > 0) {
            xmlElemTagStart(sb, NS_XADES, "MimeType", true, false);
            sb.append(dof.getMimeType());
            xmlElemEnd(sb,  NS_XADES, "MimeType", true);
        }
        // 
        if(dof.getEncoding() != null && dof.getEncoding().trim().length() > 0) {
            xmlElemTagStart(sb, NS_XADES, "Encoding", true, false);
            sb.append(dof.getEncoding());
            xmlElemEnd(sb,  NS_XADES, "Encoding", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, "DataObjectFormat", true);
    }

    private void signedDataObjectProperties2xml(StringBuffer sb, SignedDataObjectProperties sdof, Signature sig)
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "SignedDataObjectProperties", true, true);
        // 
        for(int i = 0; (sdof != null) && (i < sdof.countDataObjectFormats()); i++) {
            DataObjectFormat dof = sdof.getDataObjectFormat(i);
            if(dof != null)
                dataObjectFormat2xml(sb, dof, sig);
        }
        // TODO: other structure elements not used

        // 
        xmlElemEnd(sb,  NS_XADES, "SignedDataObjectProperties", true);
    }

    private void signedProperties2xml(StringBuffer sb, SignedProperties sp, Signature sig, boolean bWithNs)
            throws DigiDocException
    {
        xmlElemTagStart(sb, NS_XADES, "SignedProperties", false, false);
        // in ddoc 1.1 and 1.2 we had wrong namespace and forbidden Target atribute
        if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                (m_sdoc.getVersion().equals(SignedDoc.VERSION_1_1) ||
                        m_sdoc.getVersion().equals(SignedDoc.VERSION_1_2))) {
            xmlElemAttr(sb, "Target", "#" + sig.getId());
            xmlElemAttr(sb, "xmlns", SignedDoc.xmlns_xmldsig);
        }
        // @Id
        if(sp.getId() != null && sp.getId().length() > 0)
            xmlElemAttr(sb, "Id", sp.getId());
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "SignedSignatureProperties", false, false);
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "SigningTime", true, false);
        sb.append(ConvertUtils.date2string(sp.getSigningTime(), m_sdoc));
        // 
        xmlElemEnd(sb,  NS_XADES, "SigningTime", true);
        // 
        xmlElemTagStart(sb, NS_XADES, "SigningCertificate", true, true);
        CertID cid = sig.getCertIdOfType(CertID.CERTID_TYPE_SIGNER);
        if(cid != null)
            certId2xml(sb, cid, sig);
        // 
        xmlElemEnd(sb,  NS_XADES, "SigningCertificate", true);
        // signature policy
        if(sig.getSignedProperties() != null && sig.getSignedProperties().getSignaturePolicyIdentifier() != null)
            signaturePolicyIdentifier2xml(sb, sig.getSignedProperties().getSignaturePolicyIdentifier(), sig);
        // 
        if(sp.getSignatureProductionPlace() != null) {
            sb.append("\n");
            signatureProductionPlace2xml(sb, sp.getSignatureProductionPlace());
        }
        // 
        if(sp.countClaimedRoles() > 0) {
            sb.append("\n");
            // 
            xmlElemTagStart(sb, NS_XADES, "SignerRole", true, true);
            // 
            xmlElemTagStart(sb, NS_XADES, "ClaimedRoles", true, true);
            for(int i = 0; i < sp.countClaimedRoles(); i++) {
                xmlElemTagStart(sb, NS_XADES, "ClaimedRole", true, false);
                sb.append(ConvertUtils.escapeTextNode(sp.getClaimedRole(i)));
                xmlElemEnd(sb,  NS_XADES, "ClaimedRole", true);
            }
            // 
            xmlElemEnd(sb,  NS_XADES, "ClaimedRoles", true);
            // 
            xmlElemEnd(sb,  NS_XADES, "SignerRole", true);
        }
        // 
        xmlElemEnd(sb,  NS_XADES, "SignedSignatureProperties", true);
        // 
        signedDataObjectProperties2xml(sb, sp.getSignedDataObjectProperties(), sig);
        // 
        xmlElemEnd(sb, NS_XADES, "SignedProperties", false);
    }

    public void completeCertificateRefs2xml(StringBuffer sb, CompleteCertificateRefs crefs, Signature sig, boolean bWithNs)
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "CompleteCertificateRefs", false, false);
        if(bWithNs) {
            xmlElemNsAttr(sb, NS_XMLDSIG);
            xmlElemNsAttr(sb, NS_XADES);
        }
        if(m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3))
            xmlElemAttr(sb, "Id", sig.getId() + "-CERTREFS");
        xmlElemTagEnd(sb, false);
        if(m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3))
            // 
            xmlElemTagStart(sb, NS_XADES, "CertRefs", true, true);
        for(int i = 0; i < crefs.countCertIDs(); i++) {
            CertID cid = crefs.getCertID(i);
            if(/*(m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC) && cid.getType() == CertID.CERTID_TYPE_RESPONDER_CA) ||
    		   (!m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC) &&*/ cid.getType() != CertID.CERTID_TYPE_SIGNER) {
                certId2xml(sb, cid, sig);
            }
        }
        if(m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3))
            // 
            xmlElemEnd(sb,  NS_XADES, "CertRefs", false);
        // 
        xmlElemEnd(sb,  NS_XADES, "CompleteCertificateRefs", false);
    }

    private void ocspRef2xml(StringBuffer sb, OcspRef orf)
            throws DigiDocException
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "OCSPRef", true, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "OCSPIdentifier", false, false);
        xmlElemAttr(sb, "URI", orf.getUri());
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "ResponderID", true, false);
        // 
        String s = orf.getResponderId();
        if(s.startsWith("byName: ")) s = s.substring("byName: ".length());
        if(s.startsWith("byKey: ")) s = s.substring("byKey: ".length());
        sb.append(ConvertUtils.escapeTextNode(s));
        // 
        // 
        xmlElemEnd(sb,  NS_XADES, "ResponderID", false);
        // 
        xmlElemTagStart(sb, NS_XADES, "ProducedAt", true, false);
        sb.append(ConvertUtils.date2string(orf.getProducedAt(), m_sdoc));
        xmlElemEnd(sb,  NS_XADES, "ProducedAt", true);
        // 
        xmlElemEnd(sb,  NS_XADES, "OCSPIdentifier", true);
        // 
        xmlElemTagStart(sb, NS_XADES, "DigestAlgAndValue", true, true);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestMethod", false, false);
        xmlElemAttr(sb, "Algorithm", orf.getDigestAlgorithm());
        //if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC))
        //	xmlElemNsAttr(sb, NS_XADES);
        xmlElemTagEnd(sb, true);
        xmlElemEnd(sb, NS_XMLDSIG, "DigestMethod", false);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "DigestValue", false, false);
        //if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_BDOC))
        //   xmlElemNsAttr(sb, NS_XADES);
        xmlElemTagEnd(sb, false);
        sb.append(Base64Util.encode(orf.getDigestValue(), 0));
        xmlElemEnd(sb, NS_XMLDSIG, "DigestValue", true);
        // 
        xmlElemEnd(sb, NS_XADES, "DigestAlgAndValue", true);
        // 
        xmlElemEnd(sb, NS_XADES, "OCSPRef", true);
    }

    public void completeRevocationRefs2xml(StringBuffer sb, CompleteRevocationRefs rrefs, Signature sig, boolean bWithNs)
            throws DigiDocException
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "CompleteRevocationRefs", false, false);
        if(bWithNs) {
            xmlElemNsAttr(sb, NS_XMLDSIG);
            xmlElemNsAttr(sb, NS_XADES);
        }
        // @Id
        xmlElemAttr(sb, "Id", sig.getId() + "-REVOCREFS");
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "OCSPRefs", true, true);

        for(int i = 0; i < rrefs.countOcspRefs(); i++) {
            OcspRef orf = rrefs.getOcspRefById(i);
            ocspRef2xml(sb, orf);
        }

        // 
        xmlElemEnd(sb, NS_XADES, "OCSPRefs", true);
        // 
        xmlElemEnd(sb, NS_XADES, "CompleteRevocationRefs", false);
    }

    private void unsignedProperties2xml(StringBuffer sb, UnsignedProperties sp, Signature sig) // , boolean bWithNs
            throws DigiDocException
    {
        // 
        xmlElemTagStart(sb, NS_XADES, "UnsignedProperties", false, false);
        // in ddoc 1.1 and 1.2 we had forbidden Target atribute
        if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                (m_sdoc.getVersion().equals(SignedDoc.VERSION_1_1) ||
                        m_sdoc.getVersion().equals(SignedDoc.VERSION_1_2))) {
            xmlElemAttr(sb, "Target", "#" + sig.getId());
        } else {
            xmlElemAttr(sb, "xmlns", SignedDoc.xmlns_etsi);
        }
        xmlElemTagEnd(sb, true);
        // 
        xmlElemTagStart(sb, NS_XADES, "UnsignedSignatureProperties", false, false);
        xmlElemTagEnd(sb, true);
        // profiles T/CL/TS/TSA/TM/TMA
        if(sig.getProfile().equals(SignedDoc.PROFILE_TM)) {
            // 
            completeCertificateRefs2xml(sb, sp.getCompleteCertificateRefs(), sig, false);
            // 
            completeRevocationRefs2xml(sb, sp.getCompleteRevocationRefs(), sig, false);
        }
        // profiles TM
        if(sig.getProfile().equals(SignedDoc.PROFILE_TM)) {
            // 
            int nCerts = 0;
            for(int i = 0; i < sig.countCertValues(); i++) {
                CertValue cval = sig.getCertValue(i);
                if(cval != null && cval.getType() != CertValue.CERTVAL_TYPE_SIGNER)
                    nCerts++;
            }
            if(nCerts > 0) {
                // 
                xmlElemTagStart(sb, NS_XADES, "CertificateValues", false, false);
                xmlElemTagEnd(sb, true);
                for(int i = 0; i < sig.countCertValues(); i++) {
                    CertValue cval = sig.getCertValue(i);
                    if(cval != null && cval.getType() != CertValue.CERTVAL_TYPE_SIGNER)
                        certValue2xml(sb, cval);
                }
                xmlElemEnd(sb, NS_XADES, "CertificateValues", true);
            }
            // 
            xmlElemTagStart(sb, NS_XADES, "RevocationValues", false, false);
            xmlElemTagEnd(sb, true);
            // 
            xmlElemTagStart(sb, NS_XADES, "OCSPValues", true, false);
            for(int i = 0; i < sp.countNotaries(); i++) {
                Notary not = sp.getNotaryById(i);
                // 
                xmlElemTagStart(sb, NS_XADES, "EncapsulatedOCSPValue", false, false);
                if(m_sdoc.getFormat().equals(SignedDoc.FORMAT_DIGIDOC_XML) &&
                                m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3))
                    xmlElemAttr(sb, "Id", not.getId());
                xmlElemTagEnd(sb, true);
                sb.append(Base64Util.encode(not.getOcspResponseData(), 64));
                // 
                xmlElemEnd(sb, NS_XADES, "EncapsulatedOCSPValue", true);
            }
            // 
            xmlElemEnd(sb, NS_XADES, "OCSPValues", false);
            // 
            xmlElemEnd(sb, NS_XADES, "RevocationValues", false);
        } // profiles TM/TMA/TS/TSA
        // 
        xmlElemEnd(sb, NS_XADES, "UnsignedSignatureProperties", true);
        // 
        xmlElemEnd(sb, NS_XADES, "UnsignedProperties", false);
    }

    /**
     * Formats signature in XML
     * @param sig Signature object
     * @return xml form of Signature
     */
    public String signature2xml(Signature sig)
            throws DigiDocException
    {
        StringBuffer sb = new StringBuffer();
        // @Id 0)
            xmlElemAttr(sb, "Id", sig.getId());
        xmlElemNsAttr(sb, NS_XMLDSIG);
        xmlElemTagEnd(sb, true);
        // 
        signedInfo2xml(sb, sig.getSignedInfo(), false);
        // 
        if(sig.getSignatureValue() != null)
            signatureValue2xml(sb, sig.getSignatureValue(), false);
        // 
        keyInfo2xml(sb, sig.getKeyInfo(), sig);
        // 
        xmlElemTagStart(sb, NS_XMLDSIG, "Object", true, false);
        // 
        xmlElemTagStart(sb, NS_XADES, "QualifyingProperties", false, false);
        if(m_sdoc.getVersion().equals(SignedDoc.VERSION_1_3)) {
            // @Target
            xmlElemAttr(sb, "Target", "#" + sig.getId());;
            xmlElemAttr(sb, "xmlns", SignedDoc.xmlns_etsi);
        }
        xmlElemTagEnd(sb, false);
        // 
        signedProperties2xml(sb, sig.getSignedProperties(), sig, false);
        // Profiles T / C / TM / TS
        if(sig.getUnsignedProperties() != null) {
            // 
            unsignedProperties2xml(sb, sig.getUnsignedProperties(), sig);
        } // Profiles: T/C/TM/TS
        // 
        xmlElemEnd(sb, NS_XADES, "QualifyingProperties", false);
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "Object", true);
        // 
        xmlElemEnd(sb, NS_XMLDSIG, "Signature", true);
        return sb.toString();
    }

    /**
     * Formats Signature object to XML
     * @param sig Signature object
     * @return XML form of signature
     * @throws DigiDocException
     */
    public byte[] signatureToXML(Signature sig)
            throws DigiDocException
    {
        if(sig.getOrigContent() != null) {
            return sig.getOrigContent();
        } else {
            String sXml = signature2xml(sig);
            try {
                return ConvertUtils.str2data(sXml);
            } catch(Exception ex) {
                DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
            }
            return null;
        }
    }

    /**
     * Formats Signature object to XML
     * @param sig Signature object
     * @return XML form of signature
     * @throws DigiDocException
     */
    public byte[] signedPropertiesToXML(Signature sig, SignedProperties sp)
            throws DigiDocException
    {
        StringBuffer sb = new StringBuffer();
        signedProperties2xml(sb, sp, sig, true);
        String sXml = sb.toString();
        try {
            return ConvertUtils.str2data(sXml);
        } catch(Exception ex) {
            DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
        }
        return null;
    }

    /**
     * Formats Signatore object to XML
     * @param sig Signature object
     * @return XML form of signature
     * @throws DigiDocException
     */
    public byte[] unsignedPropertiesToXML(Signature sig, UnsignedProperties usp)
            throws DigiDocException
    {
        StringBuffer sb = new StringBuffer();
        unsignedProperties2xml(sb, usp, sig);
        String sXml = sb.toString();
        try {
            return ConvertUtils.str2data(sXml);
        } catch(Exception ex) {
            DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
        }
        return null;
    }

    /**
     * Formats Signatore object to XML
     * @param sig Signature object
     * @return XML form of signature
     * @throws DigiDocException
     */
    public byte[] signedInfoToXML(Signature sig, SignedInfo si)
            throws DigiDocException
    {
        StringBuffer sb = new StringBuffer();
        signedInfo2xml(sb, si, true);
        String sXml = sb.toString();
        try {
            return ConvertUtils.str2data(sXml);
        } catch(Exception ex) {
            DigiDocException.handleException(ex, DigiDocException.ERR_XML_CONVERT);
        }
        return null;
    }

}