PureBasic
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
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