Sample code for 30+ languages & platforms
PureBasic

Sign Bolivia Invoice XML

See more XML Digital Signatures Examples

Demonstrates how to create an XML digital signature (XmlDSig) for a Bolivia invoice (factura).

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkCert.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkXmlDSigGen.pb"
IncludeFile "CkXmlDSig.pb"
IncludeFile "CkStringBuilder.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example assumes the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    success = 1

    ; Create the following XML to be signed:

    ; <?xml version="1.0" encoding="UTF-8"?>
    ; <facturaElectronicaCompraVenta xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="facturaElectronicaCompraVenta.xsd">
    ;     <cabecera>
    ;         <nitEmisor>99999999</nitEmisor>
    ;         <razonSocialEmisor>Abc Xyz</razonSocialEmisor>
    ;         <municipio>Cochabamba - Cochabamba</municipio>
    ;         <telefono>4444444</telefono>
    ;         <numeroFactura>417</numeroFactura>
    ;         <cuf>ABABABABABABABABABABABABABABABABABABABABABABABABABABABABA</cuf>
    ;         <cufd>xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx</cufd>
    ;         <codigoSucursal>0</codigoSucursal>
    ;         <direccion>aaa aaa aaa</direccion>
    ;         <codigoPuntoVenta>1</codigoPuntoVenta>
    ;         <fechaEmision>2023-04-13T22:43:22.417</fechaEmision>
    ;         <nombreRazonSocial>xyz</nombreRazonSocial>
    ;         <codigoTipoDocumentoIdentidad>1</codigoTipoDocumentoIdentidad>
    ;         <numeroDocumento>1234567</numeroDocumento>
    ;            <complemento xsi:nil="true"/>
    ;         <codigoCliente>1234567</codigoCliente>
    ;         <codigoMetodoPago>1</codigoMetodoPago>
    ;            <numeroTarjeta xsi:nil="true"/>
    ;         <montoTotal>22.00</montoTotal>
    ;         <montoTotalSujetoIva>22.00</montoTotalSujetoIva>
    ;         <codigoMoneda>1</codigoMoneda>
    ;         <tipoCambio>1.00</tipoCambio>
    ;         <montoTotalMoneda>22.00</montoTotalMoneda>
    ;            <montoGiftCard xsi:nil="true"/>
    ;         <descuentoAdicional>0.00</descuentoAdicional>
    ;            <codigoExcepcion>1</codigoExcepcion>
    ;            <cafc xsi:nil="true"/>
    ;         <leyenda>Ley N� 453: El proveedor de servicios debe habilitar medios e instrumentos para efectuar consultas y reclamaciones.</leyenda>
    ;         <usuario>nromero</usuario>
    ;         <codigoDocumentoSector>1</codigoDocumentoSector>
    ;     </cabecera>
    ;     <detalle>
    ;         <actividadEconomica>620100</actividadEconomica>
    ;         <codigoProductoSin>123456</codigoProductoSin>
    ;         <codigoProducto>1</codigoProducto>
    ;         <descripcion>Economicos</descripcion>
    ;         <cantidad>1.00</cantidad>
    ;         <unidadMedida>58</unidadMedida>
    ;         <precioUnitario>22.00</precioUnitario>
    ;         <montoDescuento>0.00</montoDescuento>
    ;         <subTotal>22.00</subTotal>
    ;            <numeroSerie xsi:nil="true"/>
    ;            <numeroImei xsi:nil="true"/>
    ;     </detalle>
    ; </facturaElectronicaCompraVenta>

    ; Use this online tool to generate code from sample XML: 
    ; Generate Code to Create XML

    xml.i = CkXml::ckCreate()
    If xml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xml, "facturaElectronicaCompraVenta")
    CkXml::ckAddAttribute(xml,"xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
    CkXml::ckAddAttribute(xml,"xsi:noNamespaceSchemaLocation","facturaElectronicaCompraVenta.xsd")
    CkXml::ckUpdateChildContent(xml,"cabecera|nitEmisor","99999999")
    CkXml::ckUpdateChildContent(xml,"cabecera|razonSocialEmisor","Abc Xyz")
    CkXml::ckUpdateChildContent(xml,"cabecera|municipio","Cochabamba - Cochabamba")
    CkXml::ckUpdateChildContent(xml,"cabecera|telefono","4444444")
    CkXml::ckUpdateChildContent(xml,"cabecera|numeroFactura","417")
    CkXml::ckUpdateChildContent(xml,"cabecera|cuf","ABABABABABABABABABABABABABABABABABABABABABABABABABABABABA")
    CkXml::ckUpdateChildContent(xml,"cabecera|cufd","xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoSucursal","0")
    CkXml::ckUpdateChildContent(xml,"cabecera|direccion","aaa aaa aaa")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoPuntoVenta","1")
    CkXml::ckUpdateChildContent(xml,"cabecera|fechaEmision","2023-04-13T22:43:22.417")
    CkXml::ckUpdateChildContent(xml,"cabecera|nombreRazonSocial","xyz")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoTipoDocumentoIdentidad","1")
    CkXml::ckUpdateChildContent(xml,"cabecera|numeroDocumento","1234567")
    CkXml::ckUpdateAttrAt(xml,"cabecera|complemento",1,"xsi:nil","true")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoCliente","1234567")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoMetodoPago","1")
    CkXml::ckUpdateAttrAt(xml,"cabecera|numeroTarjeta",1,"xsi:nil","true")
    CkXml::ckUpdateChildContent(xml,"cabecera|montoTotal","22.00")
    CkXml::ckUpdateChildContent(xml,"cabecera|montoTotalSujetoIva","22.00")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoMoneda","1")
    CkXml::ckUpdateChildContent(xml,"cabecera|tipoCambio","1.00")
    CkXml::ckUpdateChildContent(xml,"cabecera|montoTotalMoneda","22.00")
    CkXml::ckUpdateAttrAt(xml,"cabecera|montoGiftCard",1,"xsi:nil","true")
    CkXml::ckUpdateChildContent(xml,"cabecera|descuentoAdicional","0.00")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoExcepcion","1")
    CkXml::ckUpdateAttrAt(xml,"cabecera|cafc",1,"xsi:nil","true")
    CkXml::ckUpdateChildContent(xml,"cabecera|leyenda","Ley N� 453: El proveedor de servicios debe habilitar medios e instrumentos para efectuar consultas y reclamaciones.")
    CkXml::ckUpdateChildContent(xml,"cabecera|usuario","nromero")
    CkXml::ckUpdateChildContent(xml,"cabecera|codigoDocumentoSector","1")
    CkXml::ckUpdateChildContent(xml,"detalle|actividadEconomica","620100")
    CkXml::ckUpdateChildContent(xml,"detalle|codigoProductoSin","123456")
    CkXml::ckUpdateChildContent(xml,"detalle|codigoProducto","1")
    CkXml::ckUpdateChildContent(xml,"detalle|descripcion","Economicos")
    CkXml::ckUpdateChildContent(xml,"detalle|cantidad","1.00")
    CkXml::ckUpdateChildContent(xml,"detalle|unidadMedida","58")
    CkXml::ckUpdateChildContent(xml,"detalle|precioUnitario","22.00")
    CkXml::ckUpdateChildContent(xml,"detalle|montoDescuento","0.00")
    CkXml::ckUpdateChildContent(xml,"detalle|subTotal","22.00")
    CkXml::ckUpdateAttrAt(xml,"detalle|numeroSerie",1,"xsi:nil","true")
    CkXml::ckUpdateAttrAt(xml,"detalle|numeroImei",1,"xsi:nil","true")

    gen.i = CkXmlDSigGen::ckCreate()
    If gen.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXmlDSigGen::setCkSigLocation(gen, "facturaElectronicaCompraVenta")
    CkXmlDSigGen::setCkSigLocationMod(gen, 0)
    CkXmlDSigGen::setCkSigNamespacePrefix(gen, "")
    CkXmlDSigGen::setCkSigNamespaceUri(gen, "http://www.w3.org/2000/09/xmldsig#")
    CkXmlDSigGen::setCkSignedInfoCanonAlg(gen, "C14N")
    CkXmlDSigGen::setCkSignedInfoDigestMethod(gen, "sha256")

    CkXmlDSigGen::ckAddSameDocRef(gen,"","sha256","C14N_WithComments","","")

    ; Provide your certificate + private key. (PFX password is test123)
    cert.i = CkCert::ckCreate()
    If cert.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkCert::ckLoadPfxFile(cert,"qa_data/pfx/cert_test123.pfx","test123")
    If success <> 1
        Debug CkCert::ckLastErrorText(cert)
        CkXml::ckDispose(xml)
        CkXmlDSigGen::ckDispose(gen)
        CkCert::ckDispose(cert)
        ProcedureReturn
    EndIf

    CkXmlDSigGen::ckSetX509Cert(gen,cert,1)

    CkXmlDSigGen::setCkKeyInfoType(gen, "X509Data")
    CkXmlDSigGen::setCkX509Type(gen, "Certificate")

    CkXmlDSigGen::setCkBehaviors(gen, "EnvelopedTransformFirst")

    ; Load XML to be signed...
    sbXml.i = CkStringBuilder::ckCreate()
    If sbXml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkEmitCompact(xml, 1)
    CkXml::ckGetXmlSb(xml,sbXml)

    ; Sign the XML...
    success = CkXmlDSigGen::ckCreateXmlDSigSb(gen,sbXml)
    If success <> 1
        Debug CkXmlDSigGen::ckLastErrorText(gen)
        CkXml::ckDispose(xml)
        CkXmlDSigGen::ckDispose(gen)
        CkCert::ckDispose(cert)
        CkStringBuilder::ckDispose(sbXml)
        ProcedureReturn
    EndIf

    ; -----------------------------------------------

    ; Save the signed XML to a file.
    success = CkStringBuilder::ckWriteFile(sbXml,"qa_output/signedXml.xml","utf-8",1)

    Debug CkStringBuilder::ckGetAsString(sbXml)

    ; ----------------------------------------
    ; Verify the signatures we just produced...
    verifier.i = CkXmlDSig::ckCreate()
    If verifier.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkXmlDSig::ckLoadSignatureSb(verifier,sbXml)
    If success <> 1
        Debug CkXmlDSig::ckLastErrorText(verifier)
        CkXml::ckDispose(xml)
        CkXmlDSigGen::ckDispose(gen)
        CkCert::ckDispose(cert)
        CkStringBuilder::ckDispose(sbXml)
        CkXmlDSig::ckDispose(verifier)
        ProcedureReturn
    EndIf

    numSigs.i = CkXmlDSig::ckNumSignatures(verifier)
    verifyIdx.i = 0
    While verifyIdx < numSigs
        CkXmlDSig::setCkSelector(verifier, verifyIdx)
        verified.i = CkXmlDSig::ckVerifySignature(verifier,1)
        If verified <> 1
            Debug CkXmlDSig::ckLastErrorText(verifier)
            CkXml::ckDispose(xml)
            CkXmlDSigGen::ckDispose(gen)
            CkCert::ckDispose(cert)
            CkStringBuilder::ckDispose(sbXml)
            CkXmlDSig::ckDispose(verifier)
            ProcedureReturn
        EndIf

        verifyIdx = verifyIdx + 1
    Wend
    Debug "All signatures were successfully verified."


    CkXml::ckDispose(xml)
    CkXmlDSigGen::ckDispose(gen)
    CkCert::ckDispose(cert)
    CkStringBuilder::ckDispose(sbXml)
    CkXmlDSig::ckDispose(verifier)


    ProcedureReturn
EndProcedure