diff --git a/experimental/facho-signer/Makefile b/experimental/facho-signer/Makefile index dfd089f..d363230 100644 --- a/experimental/facho-signer/Makefile +++ b/experimental/facho-signer/Makefile @@ -6,10 +6,12 @@ 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) +CFLAGS += -Ixades LDFLAGS = $(shell pkg-config libxml-2.0 --libs) LDFLAGS += $(shell pkg-config xmlsec1 --libs) LDFLAGS += $(shell pkg-config xmlsec1-openssl --libs) +LDFLAGS += xades/templates.c xades/xades.c 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 index fcce6f9..ef18be2 100644 --- a/experimental/facho-signer/facho-signer.c +++ b/experimental/facho-signer/facho-signer.c @@ -1,6 +1,4 @@ -#include -#include - +#include "xades/xades.h" #include #include @@ -8,6 +6,9 @@ #include #include +#include +#include + #define print_error(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__) #define print_info(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) @@ -20,6 +21,76 @@ char *basename = NULL; xmlNodePtr xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc); +int +xmlFachoTmplXadesCreate(xmlDocPtr doc, xmlNodePtr signNode) { + xmlNodePtr qualifyingPropertiesNode = NULL; + xmlNodePtr signedPropertiesNode = NULL; + xmlNodePtr signedSignaturePropertiesNode = NULL; + xmlNodePtr signingCertificateNode = NULL; + xmlNodePtr signaturePolicyIdentifierNode = NULL; + xmlNodePtr signerRoleNode = NULL; + xmlNodePtr refNode = NULL; + const xmlChar signedPropertiesId[] = "xmldsig-facho-signed-props"; + const xmlChar signedPropertiesRef[] = "#xmldsig-facho-signed-props"; + + qualifyingPropertiesNode = xmlXadesTmplQualifyingPropertiesCreate(doc, signNode, BAD_CAST "xades-ref1"); + if ( qualifyingPropertiesNode == NULL ) { + print_error("error: failed to add QualifyingProperties node.\n"); + goto fail; + } + + signedPropertiesNode = xmlXadesTmplAddSignedProperties(qualifyingPropertiesNode, signedPropertiesId); + if ( signedPropertiesNode == NULL ) { + print_error("error: xades failed to add signed properties node.\n"); + goto fail; + } + + refNode = xmlSecTmplSignatureAddReference(signNode, + xmlSecTransformSha256Id, + BAD_CAST "xmldsig-facho-ref1", + signedPropertiesRef, + BAD_CAST "http://uri.etsi.org/01903#SignedProperties"); + if ( refNode == NULL ) { + print_error("error: failed to add reference to signature template xades.\n"); + goto fail; + } + if ( xmlSecTmplReferenceAddTransform(refNode, xmlSecTransformInclC14NId) == NULL ) { + print_error("error: failed to add enveloped transform to reference for xades\n"); + goto fail; + } + + const time_t now = time(NULL); + signedSignaturePropertiesNode = xmlXadesTmplAddSignedSignatureProperties(signedPropertiesNode, localtime(&now)); + if ( signedSignaturePropertiesNode == NULL ) { + print_error("error: xades failed to add signed signature properties node.\n"); + goto fail; + } + + signingCertificateNode = xmlXadesTmplAddSigningCertificate(signedSignaturePropertiesNode, xmlSecTransformSha256Id); + if ( signingCertificateNode == NULL ) { + print_error("error: failed to add SigningCertificate node \n"); + goto fail; + } + + signaturePolicyIdentifierNode = xmlXadesTmplAddSignaturePolicyIdentifier(signedSignaturePropertiesNode); + if ( signaturePolicyIdentifierNode == NULL ) { + print_error("error: failed to add PolicyIdentifier node\n"); + goto fail; + } + + signerRoleNode = xmlXadesTmplAddSignerRole(signedSignaturePropertiesNode, BAD_CAST "supplier"); + if ( signerRoleNode == NULL ) { + print_error("error: failed to add SignerRole node.\n"); + goto fail; + } + + return(0); + fail: + xmlUnlinkNode(qualifyingPropertiesNode); + xmlFreeNode(qualifyingPropertiesNode); + return(-1); +} + static int xmlXadesAppInit() { xmlInitParser(); @@ -107,6 +178,7 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw xmlNodePtr x509DataNode = NULL; xmlNodePtr node = NULL; xmlSecDSigCtxPtr dsigCtx = NULL; + xmlXadesDSigCtxPtr xadesDsigCtx = NULL; int res = -1; @@ -170,6 +242,12 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw goto done; } + + if ( xmlFachoTmplXadesCreate(doc, signNode) < 0 ){ + print_error("error: xmlFachoTmplXadesCreate failed.\n"); + goto done; + } + dsigCtx = xmlSecDSigCtxCreate(NULL); if ( dsigCtx == NULL ) { print_error("error: dsig context creating failed\n"); @@ -185,7 +263,13 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw goto done; } - if ( xmlSecDSigCtxSign(dsigCtx, signNode) < 0 ) { + xadesDsigCtx = xmlXadesDSigCtxCreate(dsigCtx); + if ( xadesDsigCtx == NULL ) { + print_error("error: xades context creating failed.\n"); + return(-1); + } + + if ( xmlXadesDSigCtxSign(xadesDsigCtx, signNode) < 0 ) { print_error("error: signature failed\n"); goto done; } @@ -203,6 +287,10 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw res = 0; done: + if ( xadesDsigCtx != NULL ) { + xmlXadesDSigCtxDestroy(xadesDsigCtx); + } + if ( dsigCtx != NULL ) { xmlSecDSigCtxDestroy(dsigCtx); } diff --git a/experimental/facho-signer/xades/templates.c b/experimental/facho-signer/xades/templates.c new file mode 100644 index 0000000..3d7cf53 --- /dev/null +++ b/experimental/facho-signer/xades/templates.c @@ -0,0 +1,422 @@ +#include "xades.h" + +#include + +#include +#include + + +static xmlNodePtr +xmlXadesTmplAddDigest(xmlNodePtr parentNode, const xmlChar *digestMethod, const xmlChar *digestValue); + +xmlNodePtr +xmlXadesAddChildRecursiveNs(xmlNodePtr startNode, const xmlChar* path, const xmlChar* nsPrefix) { + char *curToken; + char* cpath = strdup((char *)path); + char* savePtr; + xmlNodePtr curNode = NULL; + xmlNodePtr parentNode = startNode; + + + curToken = strtok_r(cpath, "/", &savePtr); + while(curToken != NULL) { + curNode = xmlSecFindChild(parentNode, BAD_CAST curToken, nsPrefix); + if (curNode == NULL) { + curNode = xmlSecAddChild(parentNode, BAD_CAST curToken, nsPrefix); + if (curNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(%s)", curToken); + return(NULL); + } + } + + parentNode = curNode; + + curToken = strtok_r(NULL, "/", &savePtr); + } + + free(cpath); + return(curNode); +} + +xmlNodePtr +xmlXadesTmplQualifyingPropertiesCreate(xmlDocPtr doc, xmlNodePtr signatureNode, const xmlChar *id) { + xmlNodePtr objectNode; + xmlNodePtr qualifyingPropertiesNode; + + xmlNewGlobalNs(doc, xmlXadesDSigNs, BAD_CAST "xades"); + + objectNode = xmlSecTmplSignatureAddObject(signatureNode, NULL, NULL, NULL); + if (objectNode == NULL) { + xmlXadesInternalError("xmlSecTmplSignatureAddObject(signatureNode)", NULL); + return(NULL); + } + + qualifyingPropertiesNode = xmlSecAddChild(objectNode, xmlXadesNodeQualifyingProperties, xmlXadesDSigNs); + if (qualifyingPropertiesNode == NULL) { + xmlXadesXmlError2("xmlNewDocNode", NULL, "node=%s", xmlXadesErrorsSafeString(xmlXadesNodeQualifyingProperties)); + return(NULL); + } + + if (id != NULL) { + xmlSetProp(qualifyingPropertiesNode, BAD_CAST "Id", id); + } + + return(qualifyingPropertiesNode); +} + +xmlNodePtr +xmlXadesTmplQualifyingPropertiesCreateNsPref(xmlDocPtr doc, const xmlChar* id, const xmlChar* nsPrefix) { + xmlNodePtr qualifyingPropertiesNode; + xmlNsPtr ns; + + // crear nodo + qualifyingPropertiesNode = xmlNewDocNode(doc, NULL, xmlXadesNodeQualifyingProperties, NULL); + if (qualifyingPropertiesNode == NULL) { + xmlXadesXmlError2("xmlNewDocNode", NULL, "node=%s", xmlXadesErrorsSafeString(xmlXadesNodeQualifyingProperties)); + return(NULL); + } + + // crear namespace y asignar + ns = xmlNewNs(qualifyingPropertiesNode, xmlXadesDSigNs, nsPrefix); + if (ns == NULL) { + xmlXadesXmlError2("xmlNewNs", NULL, + "ns=%s", xmlXadesErrorsSafeString(xmlXadesDSigNs)); + xmlFreeNode(qualifyingPropertiesNode); + return(NULL); + } + xmlSetNs(qualifyingPropertiesNode, ns); + + if (id != NULL) { + xmlSetProp(qualifyingPropertiesNode, BAD_CAST "Id", id); + } + + + return (qualifyingPropertiesNode); +} + +xmlNodePtr +xmlXadesTmplAddSignedProperties(xmlNodePtr qualifyingPropertiesNode, const xmlChar* id) { + xmlNodePtr cur; + + xmlXadesAssert2(qualifyingPropertiesNode != NULL, NULL); + + cur = xmlSecAddChild(qualifyingPropertiesNode, xmlXadesNodeSignedProperties, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedProperties)", NULL); + return(NULL); + } + + if (id != NULL) { + xmlSetProp(cur, BAD_CAST "Id", id); + } + + return(cur); +} + +xmlNodePtr +xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr signedPropertiesNode, struct tm* signingTime) { + xmlNodePtr cur; + xmlNodePtr node; + + xmlXadesAssert2(signedPropertiesNode != NULL, NULL); + + // add SignedSignatureProperties + node = xmlSecAddChild(signedPropertiesNode, xmlXadesNodeSignedSignatureProperties, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignedSignatureProperties)", NULL); + return(NULL); + } + + // add SignigTime + cur = xmlSecAddChild(node, xmlXadesNodeSigningTime, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigningTime)", NULL); + xmlFreeNode(node); + return(NULL); + } + + { + int ret; + char strtime[200]; + + if (strftime(strtime, sizeof(strtime), "%Y-%m-%dT%T", signingTime) == 0) { + xmlXadesInternalError("strftime", NULL); + xmlFreeNode(cur); + xmlFreeNode(node); + return(NULL); + } + + ret = xmlSecNodeEncodeAndSetContent(cur, BAD_CAST strtime); + if (ret < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlFreeNode(cur); + xmlFreeNode(node); + return(NULL); + } + } + + return(node); +} + +xmlNodePtr +xmlXadesTmplAddSigningCertificate(xmlNodePtr signedSignaturePropertiesNode, xmlSecTransformId digestMethodId) { + xmlNodePtr node; + + xmlXadesAssert2(signedSignaturePropertiesNode != NULL, NULL); + if (xmlSecFindChild(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, xmlXadesDSigNs) != NULL) { + xmlXadesNodeAlreadyPresentError(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, NULL); + return(NULL); + } + + node = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSigningCertificate, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSigningCertificate)", NULL); + return(NULL); + } + + return(node); +} + +xmlNodePtr +xmlXadesTmplAddCert(xmlNodePtr signingCertificateNode) { + xmlNodePtr certNode; + + xmlXadesAssert2(signingCertificateNode != NULL, NULL); + + certNode = xmlSecAddChild(signingCertificateNode, xmlXadesNodeCert, xmlXadesDSigNs); + if (certNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeCert)", NULL); + return(NULL); + } + + return(certNode); +} + +xmlNodePtr +xmlXadesTmplAddCertDigest(xmlNodePtr certNode, const xmlChar *digestMethod, const xmlChar *digestValue) { + xmlNodePtr node; + + xmlXadesAssert2(certNode != NULL, NULL); + + node = xmlSecAddChild(certNode, xmlXadesNodeCertDigest, xmlXadesDSigNs); + if ( node == NULL ) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeCertDigest)", NULL); + return(NULL); + } + + if ( xmlXadesTmplAddDigest(node, digestMethod, digestValue) == NULL) { + xmlXadesInternalError("xmlXadesTmplAddDigest(node, digestMethodId)", NULL); + return(NULL); + } + + return(certNode); +} + +xmlNodePtr +xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode) { + xmlNodePtr cur; + + xmlXadesAssert2(signedSignaturePropertiesNode != NULL, NULL); + + cur = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSignaturePolicyIdentifier, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSignaturePolicyIdentifier)", NULL); + return(NULL); + } + + return(cur); +} + +xmlNodePtr +xmlXadesTmplAddSignaturePolicyId(xmlNodePtr signaturePolicyIdentifierNode) { + xmlNodePtr cur; + + xmlXadesAssert2(signaturePolicyIdentifierNode != NULL, NULL); + + cur = xmlSecAddChild(signaturePolicyIdentifierNode, xmlXadesNodeSignaturePolicyId, xmlXadesDSigNs); + if (cur == NULL) { + xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSignaturePolicyId)", NULL); + return(NULL); + } + + return(cur); +} + +xmlNodePtr +xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description, xmlSecTransformId policyDigestMethodId) { + xmlNodePtr sigPolicyIdNode; + xmlNodePtr node; + int ret; + + sigPolicyIdNode = xmlSecAddChild(signaturePolicyId, xmlXadesNodeSigPolicyId, xmlXadesDSigNs); + if (sigPolicyIdNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigPolicyId)", NULL); + return(NULL); + } + + node = xmlSecAddChild(sigPolicyIdNode, xmlXadesNodeIdentifier, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeIdentifier)", NULL); + xmlFreeNode(sigPolicyIdNode); + return(NULL); + } + + ret = xmlSecNodeEncodeAndSetContent(node, identifier); + if (ret < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlFreeNode(sigPolicyIdNode); + xmlFreeNode(node); + return(NULL); + } + + node = xmlSecAddChild(sigPolicyIdNode, xmlXadesNodeDescription, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeDescription)", NULL); + xmlFreeNode(sigPolicyIdNode); + return(NULL); + } + + ret = xmlSecNodeEncodeAndSetContent(node, identifier); + if (ret < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlFreeNode(sigPolicyIdNode); + xmlFreeNode(node); + return(NULL); + } + + return(sigPolicyIdNode); +} + +xmlNodePtr +xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode) { + xmlNodePtr node; + xmlXadesAssert2(parentNode != NULL, NULL); + + //add policyHash + node = xmlSecAddChild(parentNode, xmlXadesNodeSigPolicyHash, xmlXadesDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSigPolicyHash)", NULL); + return(NULL); + } + + return node; +} + +// MACHETE(bit4bit) como usar SecTransform para almacenar el digest +static xmlNodePtr +xmlXadesTmplAddDigest(xmlNodePtr parentNode, const xmlChar *digestMethod, const xmlChar *digestValue) { + xmlNodePtr node; + + xmlXadesAssert2(parentNode != NULL, NULL); + + node = xmlSecAddChild(parentNode, xmlSecNodeDigestMethod, xmlSecDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlSecNodeDigestMethod)", NULL); + return(NULL); + } + if (xmlSetProp(node, xmlSecAttrAlgorithm, digestMethod) == NULL) { + xmlXadesXmlError2("xmlSetProp", NULL, + "name=%s", xmlXadesErrorsSafeString(xmlSecAttrAlgorithm)); + xmlUnlinkNode(node); + xmlFreeNode(node); + return(NULL); + } + + node = xmlSecAddChild(parentNode, xmlSecNodeDigestValue, xmlSecDSigNs); + if (node == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlSecNodeDigestValue)", NULL); + return(NULL); + } + + if (xmlSecNodeEncodeAndSetContent(node, digestValue) < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + return(NULL); + } + + return parentNode; +} + +xmlNodePtr +xmlXadesTmplAddSignerRole(xmlNodePtr signedSignaturePropertiesNode, const xmlChar* role) { + xmlNodePtr signerRoleNode; + xmlNodePtr claimedRolesNode; + xmlNodePtr claimedRoleNode; + int ret; + + signerRoleNode = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSignerRole, xmlXadesDSigNs); + if (signerRoleNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeSignerRole)", NULL); + return(NULL); + } + + claimedRolesNode = xmlSecAddChild(signerRoleNode, xmlXadesNodeClaimedRoles, xmlXadesDSigNs); + if (claimedRolesNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeClaimedRoles)", NULL); + xmlUnlinkNode(signerRoleNode); + xmlFreeNode(signerRoleNode); + return(NULL); + } + + claimedRoleNode = xmlSecAddChild(claimedRolesNode, xmlXadesNodeClaimedRole, xmlXadesDSigNs); + if (claimedRoleNode == NULL) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeClaimedRole)", NULL); + xmlUnlinkNode(signerRoleNode); + xmlFreeNode(signerRoleNode); + return(NULL); + } + + ret = xmlSecNodeEncodeAndSetContent(claimedRoleNode, role); + if (ret < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlUnlinkNode(signerRoleNode); + xmlFreeNode(signerRoleNode); + return(NULL); + } + + return(signerRoleNode); +} + + +xmlNodePtr +xmlXadesTmplAddIssuerSerial(xmlNodePtr certNode, const xmlChar *issuerName, const xmlChar *issuerNumber) { + xmlNodePtr issuerSerialNode; + xmlNodePtr node; + + xmlXadesAssert2(certNode != NULL, NULL); + + issuerSerialNode = xmlSecAddChild(certNode, xmlXadesNodeIssuerSerial, xmlXadesDSigNs); + if ( issuerSerialNode == NULL ) { + xmlXadesInternalError("xmlSecAddChild(certNode, xmlXadesIssuerSerial)", NULL); + return(NULL); + } + + node = xmlSecAddChild(issuerSerialNode, xmlXadesNodeX509IssuerName, xmlSecDSigNs); + if ( node == NULL ) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeX509IssuerName)", NULL); + xmlFreeNode(issuerSerialNode); + return(NULL); + } + + if (xmlSecNodeEncodeAndSetContent(node, issuerName) < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlUnlinkNode(issuerSerialNode); + xmlFreeNode(issuerSerialNode); + return(NULL); + } + + node = xmlSecAddChild(issuerSerialNode, xmlXadesNodeX509IssuerNumber, xmlSecDSigNs); + if ( node == NULL ) { + xmlXadesInternalError("xmlSecAddChild(xmlXadesNodeX509IssuerNumber)", NULL); + xmlFreeNode(issuerSerialNode); + return(NULL); + } + + if (xmlSecNodeEncodeAndSetContent(node, issuerNumber) < 0) { + xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); + xmlUnlinkNode(issuerSerialNode); + xmlFreeNode(issuerSerialNode); + return(NULL); + } + + return(issuerSerialNode); +} diff --git a/experimental/facho-signer/xades/xades.c b/experimental/facho-signer/xades/xades.c index 75d5c85..87a67f0 100644 --- a/experimental/facho-signer/xades/xades.c +++ b/experimental/facho-signer/xades/xades.c @@ -1,58 +1,159 @@ #include "xades.h" -int -xmlFachoAppSign(xmlDocPtr doc, - xmlSecTransformId hashMethodId) { - xmlXadesAssert2(doc != NULL, NULL); - xmlNodePtr cur; - xmlNodePtr signedSignaturePropertiesNode; - xmlNodePtr signaturePolicyIdentifierNode; - xmlNodePtr signaturePolicyIdNode; - xmlChar* signedPropertiesId = BAD_CAST "ref1-signedprops"; - time_t now = time(NULL); - - cur = xmlXadesTmplQualifyingPropertiesCreateNsPref(doc, "qualify-ref1", BAD_CAST "ds"); - if (cur == NULL) { - return(-1); +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static xmlNodePtr +xmlXadesXPathFirstElement(xmlDocPtr doc, const xmlChar *xpath) { + xmlXPathContextPtr xpathCtx; + xmlXPathObjectPtr xpathResult; + xmlNodePtr node; + + // obtener QualifyingProteries + + xpathCtx = xmlXPathNewContext(doc); + /* register namespaces */ + // TOMADO DE: xmlsec1/src/xpath.c + for(xmlNsPtr ns = xmlDocGetRootElement(doc)->nsDef; ns != NULL; ns = ns->next) { + /* check that we have no other namespace with same prefix already */ + if((ns->prefix != NULL) && (xmlXPathNsLookup(xpathCtx, ns->prefix) == NULL)){ + int ret = xmlXPathRegisterNs(xpathCtx, ns->prefix, ns->href); + if(ret != 0) { + xmlXadesXmlError2("xmlXPathRegisterNs", NULL, + "prefix=%s", xmlSecErrorsSafeString(ns->prefix)); + return(NULL); + } + } } - cur = xmlXadesTmplAddSignedProperties(cur, signedPropertiesId); - if (cur == NULL) { - return(-1); + + xpathResult = xmlXPathEvalExpression(BAD_CAST "//ds:Object/xades:QualifyingProperties[1]", xpathCtx); + if ( xmlXPathNodeSetIsEmpty( xpathResult->nodesetval ) ) { + xmlXadesInternalError("can't find ds:Signature/ds:Object/xades:QualifyingProperties \n", NULL); + xmlXPathFreeObject(xpathResult); + return(NULL); } - signedSignaturePropertiesNode = xmlXadesTmplAddSignedSignatureProperties(cur, now); - if (signedSignaturePropertiesNode == NULL) { - return(-1); + // obtener puntero a nodo + node = xpathResult->nodesetval->nodeTab[0]; + if ( node->type != XML_ELEMENT_NODE ) { + xmlXadesInternalError("expected element QualifyingProperties\n", NULL); + return(NULL); } - // addSigningCertificate - - // addSignaturePolicyIdentifier - - signaturePolicyIdNode = xmlXadesAddChildRecursiveNs(signedSignaturePropertiesNode, BAD_CAST "SignaturePolicyIdentifier/SignaturePolicyId", xmlXadesDSigNs) - if (signaturePolicyIdNode == NULL) { - return(-1); - } - cur = xmlXadesTmplAddSigPolicyId(signaturePolicyIdNode, identifier, description, hashMethodId); - if (cur == NULL) { - return(-1); - } - // SignaturePolicyIdentifier/SignaturePolicyId/SigPolicyHash - cur = xmlXadesTmplAddSigPolicyHash(signaturePolicyIdNode); - if (cur == NULL) { - return(-1); - } - cur = xmlXadesTmplAddDigest(cur, hashMethodId); - if (cur == NULL) { - return(-1); - } - - // addSignerRole - xmlXadesTmplAddSignerRole(signedSignaturePropertiesNode, BAD_CAST "supplier"); - - cur = xmlSecTmplSignatureAddReference(xmlDocGetRootElement(doc), - hashMethodId, - signedPropertiesId, - NULL, NULL); + return(node); +} + +xmlXadesDSigCtxPtr +xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx) { + xmlXadesDSigCtxPtr ctx = NULL; + + ctx = malloc(sizeof(xmlXadesDSigCtx)); + if ( ctx == NULL ) { + return(NULL); + } + + ctx->dsigCtx = dsigCtx; + return ctx; +} + +int +xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode) { + xmlNodePtr signingCertificateNode = NULL; + xmlSecKeyDataPtr keyDataX509; + xmlSecSize certsSize; + + signingCertificateNode = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//ds:Object/xades:QualifyingProperties//xades:SigningCertificate[1]"); + if ( signingCertificateNode == NULL ) { + return(-1); + } + + keyDataX509 = xmlSecKeyEnsureData(ctx->dsigCtx->signKey, xmlSecKeyDataX509Id); + if ( keyDataX509 == NULL ) { + xmlXadesInternalError("failed to get X509.\n", NULL); + return(-1); + } + + certsSize = xmlSecOpenSSLKeyDataX509GetCertsSize(keyDataX509); + for (xmlSecSize i = 0; i < certsSize; i++) { + // calculamos el digest del certificado + unsigned char md[EVP_MAX_MD_SIZE]; + unsigned int md_n; + // TODO(bit4bit) podemos obtener el digest de openssl por medio de la transformacion? o se puede usar la transformacion para generar el digest? + xmlChar *digestMethod = (xmlChar *)xmlSecTransformSha256Id->href; + const EVP_MD *digest = EVP_sha256(); + + X509 *cert = xmlSecOpenSSLKeyDataX509GetCert(keyDataX509, i); + if ( cert == NULL ) { + xmlXadesInternalError("openssl: failed to get X509 cert.\n", NULL); + return(-1); + } + + X509_digest(cert, digest, md, &md_n); + xmlChar *digestValue = xmlSecBase64Encode(md, md_n, 0); + + xmlNodePtr certNode = xmlXadesTmplAddCert(signingCertificateNode); + if ( certNode == NULL ) { + xmlXadesInternalError("xmlXadesTmplAddCert(signingCertificateNode)\n", NULL); + return(-1); + } + + // adicionamos digest + xmlXadesTmplAddCertDigest(certNode, + digestMethod, + digestValue); + + char *issuerName = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); + + /* TODO(bit4bit) formatear? + char *issuerNamePtr = issuerName; + + for(issuerNamePtr = strchr(issuerNamePtr, '/'); issuerNamePtr != NULL; issuerNamePtr = strchr(issuerNamePtr, '/')) { + if (issuerNamePtr == issuerName) { + issuerName += 1; + } else { + *issuerNamePtr = ','; + } + }*/ + + ASN1_INTEGER *serial = X509_get_serialNumber(cert); + BIGNUM *bn = ASN1_INTEGER_to_BN(serial, NULL); + if ( bn == NULL ) { + xmlXadesInternalError("unable to convert ASN1_INTEGER_to_BN to BN\n", NULL); + return(-1); + } + char *issuerNumber = BN_bn2dec(bn); + if ( issuerNumber == NULL ) { + xmlXadesInternalError("unable to convert BN to decimal string\n", NULL); + return(-1); + } + + if (xmlXadesTmplAddIssuerSerial(certNode, BAD_CAST issuerName, BAD_CAST issuerNumber) == NULL) { + xmlXadesInternalError("xmlXadesTmplAddIssuerSerial", NULL); + return(-1); + } + BN_free(bn); + OPENSSL_free(issuerNumber); + } + + return xmlSecDSigCtxSign(ctx->dsigCtx, signNode); +} + + +int +xmlXadesDSigCtxDestroy(xmlXadesDSigCtxPtr ctx) { + if ( ctx == NULL ) { + return(-1); + } + + free(ctx); + return(0); } diff --git a/experimental/facho-signer/xades/xades.h b/experimental/facho-signer/xades/xades.h index 07e482c..6594e49 100644 --- a/experimental/facho-signer/xades/xades.h +++ b/experimental/facho-signer/xades/xades.h @@ -1,20 +1,45 @@ #ifndef XADES_H #define XADES_H + + #include #include #include +#include +#include +#include +#include #include "xmlsec1/errors_helpers.h" +#define xmlXadesAssert2(p, ret) \ + xmlSecAssert2(p, ret) + +#define xmlXadesNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) \ + xmlSecNodeNotFoundError(errorFunction, startNode, targetNodeName, errorObject) + +#define xmlXadesXmlError2(errorFunction, errorObject, msg, param) \ + xmlSecXmlError2(errorFunction, errorObject, msg, param) + +#define xmlXadesErrorsSafeString(msg) \ + xmlSecErrorsSafeString(msg) + +#define xmlXadesInternalError(errorFunction, errorObject) \ + xmlSecInternalError(errorFunction, errorObject) + +#define xmlXadesNodeAlreadyPresentError(parent, nodeName, errObject) \ + xmlSecNodeAlreadyPresentError(parent, nodeName, errObject) + static const xmlChar xmlXadesNodeQualifyingProperties[] = "QualifyingProperties"; static const xmlChar xmlXadesNodeSignedProperties[] = "SignedProperties"; static const xmlChar xmlXadesNodeSignedSignatureProperties[] = "SignedSignatureProperties"; static const xmlChar xmlXadesNodeSigningTime[] = "SigningTime"; static const xmlChar xmlXadesNodeSigningCertificate[] = "SigningCertificate"; -static const xmlChar xmlXadesNodeCertificate[] = "Cert"; +static const xmlChar xmlXadesNodeCert[] = "Cert"; +static const xmlChar xmlXadesNodeCertDigest[] = "CertDigest"; static const xmlChar xmlXadesNodeSignaturePolicyIdentifier[] = "SignaturePolicyIdentifier"; static const xmlChar xmlXadesNodeSignaturePolicyId[] = "SignaturePolicyId"; static const xmlChar xmlXadesNodeSigPolicyId[] = "SignaturePolicyId"; @@ -25,21 +50,59 @@ static const xmlChar xmlXadesNodeSigPolicyHash[] = "SigPolicyHash"; static const xmlChar xmlXadesNodeSignerRole[] = "SignerRole"; static const xmlChar xmlXadesNodeClaimedRoles[] = "ClaimedRoles"; static const xmlChar xmlXadesNodeClaimedRole[] = "ClaimedRole"; - +static const xmlChar xmlXadesNodeIssuerSerial[] = "IssuerSerial"; +static const xmlChar xmlXadesNodeX509IssuerName[] = "X509IssuerName"; +static const xmlChar xmlXadesNodeX509IssuerNumber[] = "X509IssuerNumber"; + static const xmlChar xmlXadesDSigNs[] = "http://uri.etsi.org/01903/v1.3.2#"; +typedef struct _xmlXadesDSigCtx xmlXadesDSigCtx, *xmlXadesDSigCtxPtr; +struct _xmlXadesDSigCtx { + xmlSecDSigCtxPtr dsigCtx; +}; + + +xmlXadesDSigCtxPtr +xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx); + +int +xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode); + +int +xmlXadesDSigCtxDestroy(xmlXadesDSigCtxPtr ctx); + +xmlNodePtr +xmlXadesTmplQualifyingPropertiesCreate(xmlDocPtr doc, xmlNodePtr signatureNode, const xmlChar *id); + xmlNodePtr xmlXadesTmplQualifyingPropertiesCreateNsPref(xmlDocPtr doc, const xmlChar* id, const xmlChar* nsPrefix); +xmlNodePtr +xmlXadesTmplAddSignedProperties(xmlNodePtr qualifyingPropertiesNode, const xmlChar* id); xmlNodePtr -xmlXadesTmplAddSigningCertificate(xmlNodePtr parentNode); +xmlXadesTmplAddSigningCertificate(xmlNodePtr parentNode, xmlSecTransformId digestMethodId); xmlNodePtr xmlXadesTmplAddCert(xmlNodePtr signingCertificateNode); + +xmlNodePtr +xmlXadesTmplAddCertDigest(xmlNodePtr signingCertificateNode, const xmlChar *digestMethod, const xmlChar *digestValue); + +xmlNodePtr +xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode); + +xmlNodePtr +xmlXadesTmplAddSignerRole(xmlNodePtr signedSignaturePropertiesNode, const xmlChar* role); + xmlNodePtr xmlXadesTmplAddSignaturePolicyIdentifierSignaturePolicyId(xmlNodePtr signedSignaturePropertiesNode); + xmlNodePtr xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr parentNode, struct tm* signingTime); + +xmlNodePtr +xmlXadesTmplAddIssuerSerial(xmlNodePtr certNode, const xmlChar *issuerName, const xmlChar *issuerNumber); + xmlNodePtr xmlXadesAddChildRecursiveNs(xmlNodePtr parentNode, const xmlChar* path, const xmlChar* nsPrefix); #endif //XADES_H