From ebc67d1327e41b5cd71f8663af9d57b5f315877a Mon Sep 17 00:00:00 2001 From: bit4bit Date: Sat, 11 Dec 2021 22:16:43 +0000 Subject: [PATCH] facho-signer: primer firmador sin xades FossilOrigin-Name: c10547642e8d5e6f5b6e6e3a71b8294ebe566a68a2bd14a9233e21ae016aef20 --- experimental/facho-signer/Makefile | 15 ++ experimental/facho-signer/facho-signer.c | 272 +++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 experimental/facho-signer/Makefile create mode 100644 experimental/facho-signer/facho-signer.c diff --git a/experimental/facho-signer/Makefile b/experimental/facho-signer/Makefile new file mode 100644 index 0000000..dfd089f --- /dev/null +++ b/experimental/facho-signer/Makefile @@ -0,0 +1,15 @@ +.PHONY: facho-signer + +CC = gcc + +CFLAGS = -Wall -Werror -std=gnu11 +CFLAGS += $(shell pkg-config libxml-2.0 --cflags) +CFLAGS += $(shell pkg-config xmlsec1 --cflags) +CFLAGS += $(shell pkg-config xmlsec1-openssl --cflags) + +LDFLAGS = $(shell pkg-config libxml-2.0 --libs) +LDFLAGS += $(shell pkg-config xmlsec1 --libs) +LDFLAGS += $(shell pkg-config xmlsec1-openssl --libs) + +facho-signer: crypto.c facho-signer.c + $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/experimental/facho-signer/facho-signer.c b/experimental/facho-signer/facho-signer.c new file mode 100644 index 0000000..fcce6f9 --- /dev/null +++ b/experimental/facho-signer/facho-signer.c @@ -0,0 +1,272 @@ +#include +#include + + +#include +#include +#include +#include +#include + + +#define print_error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) +#define print_info(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) + +const xmlChar ublExtensionDSigNs[] = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"; + +char *basename = NULL; + +// crea elemento /Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent +xmlNodePtr +xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc); + +static int +xmlXadesAppInit() { + xmlInitParser(); + LIBXML_TEST_VERSION; + + if ( xmlSecInit() < 0 ) { + print_error("xmlsec initialization failed.\n"); + return(-1); + } + + if ( xmlSecCheckVersion() != 1 ) { + print_error("loaded xmlsec library version is not compatible.\n"); + return(-1); + } + +#ifdef XMLSEC_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLLoadLibrary( NULL ) < 0) { + fprintf(stderr, "Error: unable to load default xmlsec-crypto library. Make sure\n" + "that you have it installed and check shared libraries path\n" + "(LD_LIBRARY_PATH and/or LTDL_LIBRARY_PATH) environment variables.\n"); + return(-1); + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + if ( xmlSecCryptoAppInit(NULL) < 0 ) { + print_error("crypto initialization failed.\n"); + return(-1); + } + + if ( xmlSecCryptoInit() < 0 ) { + print_error("xmlsec-crypto initialization failed.\n"); + return(-1); + } + + return(0); +} + +static int +xmlXadesAppShutdown() { + + if ( xmlSecCryptoShutdown() < 0 ) { + print_error("xmlSecCryptoShutdown failed.\n"); + } + + if ( xmlSecCryptoAppShutdown() < 0 ) { + print_error("xmlSecCryptoAppShutdown failed.\n"); + } + + if ( xmlSecShutdown() < 0 ) { + print_error("xmlsec shutdown failed.\n"); + } + + xmlCleanupParser(); + return(0); +} + +/* + X509 *cert = xmlSecOpenSSLKeyDataX509GetCert(keyData, 0); + if (cert == NULL) { + print_error("xmlSecOpenSSLKeyDataX509GetKeyCert fail\n"); + } + + char *issuer = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + + printf("x509 issuer: %s\n", issuer); + + //https://stackoverflow.com/questions/9749560/how-to-calculate-x-509-certificates-sha-1-fingerprint-in-c-c-objective-c + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int n; + const EVP_MD *digest = EVP_get_digestbyname("sha256"); + X509_digest(cert, digest, md, &n); + printf("%s", "Fingerprint:"); + for(int pos = 0; pos < 19 ; pos++) { + printf("%02x:", md[pos]); + } + printf("%02x\n", md[19]); +*/ + +static int +xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *password) { + xmlDocPtr doc = NULL; + xmlNodePtr signNode = NULL; + xmlNodePtr refNode = NULL; + xmlNodePtr keyInfoNode = NULL; + xmlNodePtr x509DataNode = NULL; + xmlNodePtr node = NULL; + xmlSecDSigCtxPtr dsigCtx = NULL; + + int res = -1; + + if (filename == NULL) { + return(-1); + } + + doc = xmlParseFile(filename); + if ( (doc == NULL) || (xmlDocGetRootElement(doc) == NULL) ) { + print_error("error: unable to parse file %s\n", filename); + goto done; + } + + signNode = xmlSecTmplSignatureCreate(doc, xmlSecTransformInclC14NId, + xmlSecTransformRsaSha256Id, NULL); + if ( signNode == NULL ) { + print_error("error: failed to create signature template.\n"); + goto done; + } + + xmlAddChild(xmlDocGetRootElement(doc), signNode); + + refNode = xmlSecTmplSignatureAddReference(signNode, + xmlSecTransformSha256Id, + BAD_CAST "xmldsig-facho-ref0", // id + BAD_CAST "", //uri + NULL); //type + if ( refNode == NULL ) { + print_error("error: failed to add reference to signature template.\n"); + goto done; + } + if ( xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformEnvelopedId) == NULL ) { + print_error("error: failed to add enveloped transform to reference\n"); + goto done; + } + + refNode = xmlSecTmplSignatureAddReference(signNode, + xmlSecTransformSha256Id, + BAD_CAST "xmldsig-facho-ref1", + BAD_CAST "#xmldsig-facho-KeyInfo", + NULL); + if ( refNode == NULL ) { + print_error("error: failed to add reference to signature template key-info.\n"); + goto done; + } + + keyInfoNode = xmlSecTmplSignatureEnsureKeyInfo(signNode, BAD_CAST "xmldsig-facho-KeyInfo"); + if ( keyInfoNode == NULL ) { + print_error("error: failed to add key info.\n"); + goto done; + } + + x509DataNode = xmlSecTmplKeyInfoAddX509Data(keyInfoNode); + if ( x509DataNode == NULL ) { + print_error("error: failde to add x509 DATA \n"); + goto done; + } + + if ( xmlSecTmplX509DataAddCertificate(x509DataNode) == NULL ) { + print_error("error: failde to add x509Certificate node\n"); + goto done; + } + + dsigCtx = xmlSecDSigCtxCreate(NULL); + if ( dsigCtx == NULL ) { + print_error("error: dsig context creating failed\n"); + return(-1); + } + + dsigCtx->signKey = xmlSecCryptoAppKeyLoad(pkcs12name, + xmlSecKeyDataFormatPkcs12, + password, + NULL, NULL); + if ( dsigCtx->signKey == NULL ) { + print_error("error: failed to load pkcs12\n"); + goto done; + } + + if ( xmlSecDSigCtxSign(dsigCtx, signNode) < 0 ) { + print_error("error: signature failed\n"); + goto done; + } + + node = xmlFachoTmplUBLExtensionAddExtensionContent(doc); + if ( node == NULL ) { + print_error("error: failed to add UBLExtensions/UBLExtension/ExtensionContent\n"); + goto done; + } + xmlUnlinkNode(signNode); + xmlSecAddChildNode(node, signNode); + + xmlDocDump(stdout, doc); + + res = 0; + + done: + if ( dsigCtx != NULL ) { + xmlSecDSigCtxDestroy(dsigCtx); + } + + if ( doc != NULL ) { + xmlFreeDoc(doc); + } + return(res); +} + +int main(int argc, char *argv[]) { + basename = argv[0]; + int exitStatus = EXIT_SUCCESS; + + if (argc != 4) { + print_error("%s: \n", basename); + return(EXIT_FAILURE); + } + + if ( xmlXadesAppInit() < 0 ) { + print_error("initialization failed.\n"); + return(EXIT_FAILURE); + } + + if ( xmlXadesSignFile( argv[1], argv[2], argv[3] ) != 0 ) { + print_error("%s", "fail to sign file\n"); + exitStatus = EXIT_FAILURE; + } + + xmlXadesAppShutdown(); + return(exitStatus); +} + + + +xmlNodePtr +xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc) { + xmlNodePtr node = NULL; + xmlNodePtr parent = NULL; + const xmlChar ublExtensionsName[] = "UBLExtensions"; + const xmlChar ublExtensionName[] = "UBLExtension"; + const xmlChar extensionContentName[] = "ExtensionContent"; + + parent = xmlSecFindNode(xmlDocGetRootElement(doc), ublExtensionsName, ublExtensionDSigNs); + if ( parent == NULL ) { + parent = xmlSecAddChild(xmlDocGetRootElement(doc), ublExtensionsName, ublExtensionDSigNs); + if ( parent == NULL ) { + print_error("error: failed to cleate UBLExtensions.\n"); + return(NULL); + } + } + + node = xmlSecAddChild(parent, ublExtensionName, ublExtensionDSigNs); + if ( node == NULL ) { + print_error("error: failed to add UBLExtension\n"); + xmlFreeNode(parent); + return(NULL); + } + + node = xmlSecAddChild(node, extensionContentName, ublExtensionDSigNs); + if ( node == NULL ) { + print_error("error: failed to add ExtensionContent"); + return(NULL); + } + + return(node); +}