Sample code for 30+ languages & platforms
SQL Server

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 SQL Server Downloads

SQL Server
-- Important: See this note about string length limitations for strings returned by sp_OAMethod calls.
--
CREATE PROCEDURE ChilkatSample
AS
BEGIN
    DECLARE @hr int
    -- Important: Do not use nvarchar(max).  See the warning about using nvarchar(max).
    DECLARE @sTmp0 nvarchar(4000)
    DECLARE @success int
    SELECT @success = 0

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

    SELECT @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

    DECLARE @xml int
    EXEC @hr = sp_OACreate 'Chilkat.Xml', @xml OUT
    IF @hr <> 0
    BEGIN
        PRINT 'Failed to create ActiveX component'
        RETURN
    END

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

    DECLARE @gen int
    EXEC @hr = sp_OACreate 'Chilkat.XmlDSigGen', @gen OUT

    EXEC sp_OASetProperty @gen, 'SigLocation', 'facturaElectronicaCompraVenta'
    EXEC sp_OASetProperty @gen, 'SigLocationMod', 0
    EXEC sp_OASetProperty @gen, 'SigNamespacePrefix', ''
    EXEC sp_OASetProperty @gen, 'SigNamespaceUri', 'http://www.w3.org/2000/09/xmldsig#'
    EXEC sp_OASetProperty @gen, 'SignedInfoCanonAlg', 'C14N'
    EXEC sp_OASetProperty @gen, 'SignedInfoDigestMethod', 'sha256'

    EXEC sp_OAMethod @gen, 'AddSameDocRef', @success OUT, '', 'sha256', 'C14N_WithComments', '', ''

    -- Provide your certificate + private key. (PFX password is test123)
    DECLARE @cert int
    EXEC @hr = sp_OACreate 'Chilkat.Cert', @cert OUT

    EXEC sp_OAMethod @cert, 'LoadPfxFile', @success OUT, 'qa_data/pfx/cert_test123.pfx', 'test123'
    IF @success <> 1
      BEGIN
        EXEC sp_OAGetProperty @cert, 'LastErrorText', @sTmp0 OUT
        PRINT @sTmp0
        EXEC @hr = sp_OADestroy @xml
        EXEC @hr = sp_OADestroy @gen
        EXEC @hr = sp_OADestroy @cert
        RETURN
      END
    EXEC sp_OAMethod @gen, 'SetX509Cert', @success OUT, @cert, 1

    EXEC sp_OASetProperty @gen, 'KeyInfoType', 'X509Data'
    EXEC sp_OASetProperty @gen, 'X509Type', 'Certificate'

    EXEC sp_OASetProperty @gen, 'Behaviors', 'EnvelopedTransformFirst'

    -- Load XML to be signed...
    DECLARE @sbXml int
    EXEC @hr = sp_OACreate 'Chilkat.StringBuilder', @sbXml OUT

    EXEC sp_OASetProperty @xml, 'EmitCompact', 1
    EXEC sp_OAMethod @xml, 'GetXmlSb', @success OUT, @sbXml

    -- Sign the XML...
    EXEC sp_OAMethod @gen, 'CreateXmlDSigSb', @success OUT, @sbXml
    IF @success <> 1
      BEGIN
        EXEC sp_OAGetProperty @gen, 'LastErrorText', @sTmp0 OUT
        PRINT @sTmp0
        EXEC @hr = sp_OADestroy @xml
        EXEC @hr = sp_OADestroy @gen
        EXEC @hr = sp_OADestroy @cert
        EXEC @hr = sp_OADestroy @sbXml
        RETURN
      END
    -- -----------------------------------------------

    -- Save the signed XML to a file.
    EXEC sp_OAMethod @sbXml, 'WriteFile', @success OUT, 'qa_output/signedXml.xml', 'utf-8', 1

    EXEC sp_OAMethod @sbXml, 'GetAsString', @sTmp0 OUT
    PRINT @sTmp0

    -- ----------------------------------------
    -- Verify the signatures we just produced...
    DECLARE @verifier int
    EXEC @hr = sp_OACreate 'Chilkat.XmlDSig', @verifier OUT

    EXEC sp_OAMethod @verifier, 'LoadSignatureSb', @success OUT, @sbXml
    IF @success <> 1
      BEGIN
        EXEC sp_OAGetProperty @verifier, 'LastErrorText', @sTmp0 OUT
        PRINT @sTmp0
        EXEC @hr = sp_OADestroy @xml
        EXEC @hr = sp_OADestroy @gen
        EXEC @hr = sp_OADestroy @cert
        EXEC @hr = sp_OADestroy @sbXml
        EXEC @hr = sp_OADestroy @verifier
        RETURN
      END

    DECLARE @numSigs int
    EXEC sp_OAGetProperty @verifier, 'NumSignatures', @numSigs OUT
    DECLARE @verifyIdx int
    SELECT @verifyIdx = 0
    WHILE @verifyIdx < @numSigs
      BEGIN
        EXEC sp_OASetProperty @verifier, 'Selector', @verifyIdx
        DECLARE @verified int
        EXEC sp_OAMethod @verifier, 'VerifySignature', @verified OUT, 1
        IF @verified <> 1
          BEGIN
            EXEC sp_OAGetProperty @verifier, 'LastErrorText', @sTmp0 OUT
            PRINT @sTmp0
            EXEC @hr = sp_OADestroy @xml
            EXEC @hr = sp_OADestroy @gen
            EXEC @hr = sp_OADestroy @cert
            EXEC @hr = sp_OADestroy @sbXml
            EXEC @hr = sp_OADestroy @verifier
            RETURN
          END
        SELECT @verifyIdx = @verifyIdx + 1
      END

    PRINT 'All signatures were successfully verified.'

    EXEC @hr = sp_OADestroy @xml
    EXEC @hr = sp_OADestroy @gen
    EXEC @hr = sp_OADestroy @cert
    EXEC @hr = sp_OADestroy @sbXml
    EXEC @hr = sp_OADestroy @verifier


END
GO