Invoice Signing¶
How to sign UBL invoices with a CSID certificate and private key.
Example¶
pub fn main() {
use fatoora_core::invoice::sign::invoice_hash_base64_from_xml_str;
use fatoora_core::invoice::xml::parse::parse_signed_invoice_xml;
let signed_xml_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/invoices/sample-simplified-invoice.xml");
let signed_xml = std::fs::read_to_string(&signed_xml_path).expect("read signed invoice xml");
let signed = parse_signed_invoice_xml(&signed_xml).expect("parse signed invoice");
let hash = invoice_hash_base64_from_xml_str(&signed_xml).expect("compute invoice hash");
let qr = signed.qr_code();
let signing_time = signed.signed_properties().signing_time();
assert!(!hash.is_empty());
assert!(!qr.is_empty());
let _ = signing_time;
}
from fatoora.invoice import parse_signed_invoice_xml
# signed_xml_path = "path/to/signed_invoice.xml"
signed_xml = signed_xml_path.read_text(encoding="utf-8")
signed = parse_signed_invoice_xml(signed_xml)
hash_b64 = signed.hash_base64()
qr = signed.qr_code()
signing_time = signed.signing_time()
assert hash_b64
assert qr
import { Signer } from 'fatoority';
export function signInvoice(xml, certificatePem, keyPem) {
return Signer.fromPem(certificatePem, keyPem).signXml(xml);
}
public static string SignInvoice(string xml, string certificatePem, string keyPem)
{
using var signer = Signer.FromPem(certificatePem, keyPem);
using var invoice = FinalizedInvoice.FromXml(xml);
using var signed = signer.Sign(invoice); // Consumes invoice's inner state.
return signed.IntoXml();
}
#include "fatoora.h"
#include <stdio.h>
#include <stdlib.h>
/* File I/O belongs to the application; the signing API takes byte buffers. */
static unsigned char *read_der(const char *path, size_t *length) {
FILE *file = fopen(path, "rb");
if (!file) return NULL;
unsigned char *data = NULL;
if (fseek(file, 0, SEEK_END)) goto done;
long size = ftell(file);
if (size <= 0 || size > 1024 * 1024) goto done;
rewind(file);
data = malloc((size_t)size);
if (!data) goto done;
if (fread(data, 1, (size_t)size, file) != (size_t)size) {
free(data);
data = NULL;
} else {
*length = (size_t)size;
}
done:
fclose(file);
return data;
}
int main(int argc, char **argv) {
if (argc != 4) {
fprintf(stderr, "Usage: %s invoice.xml certificate.der private-key.der\n", argv[0]);
return 1;
}
size_t cert_len = 0, key_len = 0;
unsigned char *cert = read_der(argv[2], &cert_len);
unsigned char *key = read_der(argv[3], &key_len);
if (!cert || !key) {
fputs("Unable to read certificate or private key DER.\n", stderr);
free(cert);
free(key);
return 1;
}
FatooraSigner *signer = NULL;
FatooraFinalizedInvoice *invoice = NULL;
FatooraSignedInvoice *signed_invoice = NULL;
FatooraError *error = NULL;
char *xml = NULL;
FatooraStatus status = FATOORA_OK;
int exit_code = 1;
#define TRY(call) do { status = (call); if (status != FATOORA_OK) goto cleanup; } while (0)
TRY(fatoora_signer_from_der(cert, cert_len, key, key_len, &signer, &error));
TRY(fatoora_finalized_invoice_from_file(argv[1], &invoice, &error));
/* Signing consumes invoice's inner state; its outer handle still needs free. */
TRY(fatoora_signer_sign(signer, invoice, &signed_invoice, &error));
TRY(fatoora_signed_invoice_into_xml(signed_invoice, &xml, &error));
puts(xml);
exit_code = 0;
cleanup:
if (exit_code) fprintf(stderr, "Error %d: %s\n", (int)status, fatoora_error_message(error));
fatoora_string_free(xml);
fatoora_signed_invoice_free(signed_invoice);
fatoora_finalized_invoice_free(invoice);
fatoora_signer_free(signer);
fatoora_error_free(error);
free(cert);
free(key);
return exit_code;
}
Notes¶
- Signed invoice metadata (signature/public key/signed props hashes) are exposed as getters.
- The C example reads certificate/key DER in the application and uses the invoice file helper. Signing consumes the finalized invoice; all handles are released during cleanup.
See also: Invoice Signing Reference
C examples include fatoora.h; compile the adapter once with your application.
See the C build instructions.
See the JavaScript / TypeScript reference for installation and runtime contracts.
See the C# / .NET reference for installation, imports, and ownership rules.