diff --git a/experimental/facho-signer/facho-signer.c b/experimental/facho-signer/facho-signer.c index ef18be2..88c33e9 100644 --- a/experimental/facho-signer/facho-signer.c +++ b/experimental/facho-signer/facho-signer.c @@ -14,13 +14,21 @@ #define print_info(fmt, ...) fprintf(stdout, fmt, ##__VA_ARGS__) const xmlChar ublExtensionDSigNs[] = "urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2"; - +const xmlChar policyIdDescription[] = "Política de firma para facturas electrónicas de la República de Colombia."; +const xmlChar policyIdIdentifier[] = "https://facturaelectronica.dian.gov.co/politicadefirma/v2/politicadefirmav2.pdf"; + char *basename = NULL; // crea elemento /Invoice/ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent xmlNodePtr xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc); +// FeC requiere que el digest value del policy identifier sea +// apartir del contenido de la url. +xmlXadesPolicyIdentifierCtxPtr +xmlFachoPolicyIdentifierCtxFromFilename(const char *filename); + + int xmlFachoTmplXadesCreate(xmlDocPtr doc, xmlNodePtr signNode) { xmlNodePtr qualifyingPropertiesNode = NULL; @@ -28,6 +36,9 @@ xmlFachoTmplXadesCreate(xmlDocPtr doc, xmlNodePtr signNode) { xmlNodePtr signedSignaturePropertiesNode = NULL; xmlNodePtr signingCertificateNode = NULL; xmlNodePtr signaturePolicyIdentifierNode = NULL; + xmlNodePtr signaturePolicyIdNode = NULL; + xmlNodePtr sigPolicyIdNode = NULL; + xmlNodePtr sigPolicyHashNode = NULL; xmlNodePtr signerRoleNode = NULL; xmlNodePtr refNode = NULL; const xmlChar signedPropertiesId[] = "xmldsig-facho-signed-props"; @@ -78,12 +89,31 @@ xmlFachoTmplXadesCreate(xmlDocPtr doc, xmlNodePtr signNode) { goto fail; } + signaturePolicyIdNode = xmlXadesTmplAddSignaturePolicyId(signaturePolicyIdentifierNode); + if ( signaturePolicyIdNode == NULL ) { + print_error("error: failed to add SignaturePolicyId node.\n"); + goto fail; + } + + sigPolicyIdNode = xmlXadesTmplAddSigPolicyId(signaturePolicyIdNode, policyIdIdentifier, policyIdDescription); + if ( sigPolicyIdNode == NULL ) { + print_error("error: failed to add SigPolicyId node.\n"); + goto fail; + } + + sigPolicyHashNode = xmlXadesTmplAddSigPolicyHash(signaturePolicyIdNode, xmlSecTransformSha256Id); + if ( sigPolicyHashNode == NULL ) { + print_error("error: failed to add SigPolicyHash 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); @@ -217,7 +247,7 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw refNode = xmlSecTmplSignatureAddReference(signNode, xmlSecTransformSha256Id, - BAD_CAST "xmldsig-facho-ref1", + BAD_CAST "xmldsig-facho-ref2", BAD_CAST "#xmldsig-facho-KeyInfo", NULL); if ( refNode == NULL ) { @@ -263,7 +293,7 @@ xmlXadesSignFile(const char *filename, const char *pkcs12name, const char *passw goto done; } - xadesDsigCtx = xmlXadesDSigCtxCreate(dsigCtx); + xadesDsigCtx = xmlXadesDSigCtxCreate(dsigCtx, XADES_DIGEST_SHA256, NULL); if ( xadesDsigCtx == NULL ) { print_error("error: xades context creating failed.\n"); return(-1); @@ -358,3 +388,8 @@ xmlFachoTmplUBLExtensionAddExtensionContent(xmlDocPtr doc) { return(node); } + +xmlXadesPolicyIdentifierCtxPtr +xmlFachoPolicyIdentifierCtxFromFilename(const char *filename) { + return(NULL); +} diff --git a/experimental/facho-signer/xades/templates.c b/experimental/facho-signer/xades/templates.c index 3d7cf53..b9fd7d7 100644 --- a/experimental/facho-signer/xades/templates.c +++ b/experimental/facho-signer/xades/templates.c @@ -215,7 +215,7 @@ xmlXadesTmplAddCertDigest(xmlNodePtr certNode, const xmlChar *digestMethod, cons xmlNodePtr xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode) { xmlNodePtr cur; - + xmlXadesAssert2(signedSignaturePropertiesNode != NULL, NULL); cur = xmlSecAddChild(signedSignaturePropertiesNode, xmlXadesNodeSignaturePolicyIdentifier, xmlXadesDSigNs); @@ -230,20 +230,20 @@ xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNod xmlNodePtr xmlXadesTmplAddSignaturePolicyId(xmlNodePtr signaturePolicyIdentifierNode) { xmlNodePtr cur; - + xmlXadesAssert2(signaturePolicyIdentifierNode != NULL, NULL); cur = xmlSecAddChild(signaturePolicyIdentifierNode, xmlXadesNodeSignaturePolicyId, xmlXadesDSigNs); if (cur == NULL) { - xmlXadesInternalError("xmlsecAddChild(xmlXadesNodeSignaturePolicyId)", NULL); + xmlXadesInternalError("xmlsecAddChild(cur)", NULL); return(NULL); } - + return(cur); } xmlNodePtr -xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description, xmlSecTransformId policyDigestMethodId) { +xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description) { xmlNodePtr sigPolicyIdNode; xmlNodePtr node; int ret; @@ -276,7 +276,7 @@ xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifi return(NULL); } - ret = xmlSecNodeEncodeAndSetContent(node, identifier); + ret = xmlSecNodeEncodeAndSetContent(node, description); if (ret < 0) { xmlXadesInternalError("xmlSecNodeEncodeAndSetContent", NULL); xmlFreeNode(sigPolicyIdNode); @@ -288,7 +288,7 @@ xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifi } xmlNodePtr -xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode) { +xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode, xmlSecTransformId digestMethodId) { xmlNodePtr node; xmlXadesAssert2(parentNode != NULL, NULL); @@ -299,6 +299,11 @@ xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode) { return(NULL); } + if ( xmlXadesTmplAddDigest(node, digestMethodId->href, BAD_CAST "") == NULL) { + xmlXadesInternalError("xmlXadesTmplAddDigest(node, digestMethodId)", NULL); + return(NULL); + } + return node; } diff --git a/experimental/facho-signer/xades/xades.c b/experimental/facho-signer/xades/xades.c index 87a67f0..d8adfdf 100644 --- a/experimental/facho-signer/xades/xades.c +++ b/experimental/facho-signer/xades/xades.c @@ -12,48 +12,10 @@ #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); - } - } - } - - - 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); - } - - // obtener puntero a nodo - node = xpathResult->nodesetval->nodeTab[0]; - if ( node->type != XML_ELEMENT_NODE ) { - xmlXadesInternalError("expected element QualifyingProperties\n", NULL); - return(NULL); - } - - return(node); -} +xmlXadesXPathFirstElement(xmlDocPtr doc, const xmlChar *xpath); xmlXadesDSigCtxPtr -xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx) { +xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx, XADES_DIGEST_METHOD digestMethod, xmlXadesPolicyIdentifierCtxPtr policyCtx) { xmlXadesDSigCtxPtr ctx = NULL; ctx = malloc(sizeof(xmlXadesDSigCtx)); @@ -62,6 +24,8 @@ xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx) { } ctx->dsigCtx = dsigCtx; + ctx->digestMethod = digestMethod; + ctx->policyCtx = policyCtx; return ctx; } @@ -88,8 +52,18 @@ xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode) { 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(); + xmlChar *digestMethod = NULL; + EVP_MD *digest = NULL; + + switch(ctx->digestMethod) { + case XADES_DIGEST_SHA256: + digestMethod = (xmlChar *)xmlSecTransformSha256Id->href; + digest = (EVP_MD *) EVP_sha256(); + break; + default: + xmlXadesInternalError("xmlXadesDSigCtxSign not known how to handle digest method.\n", NULL); + return(-1); + } X509 *cert = xmlSecOpenSSLKeyDataX509GetCert(keyDataX509, i); if ( cert == NULL ) { @@ -144,6 +118,15 @@ xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode) { OPENSSL_free(issuerNumber); } + // digest de policy identifier + xmlNodePtr sigPolicyId = xmlXadesXPathFirstElement(signNode->doc, BAD_CAST "//xades:SigPolicyId/xades:Identifier[1]"); + if ( sigPolicyId == NULL ) { + xmlXadesInternalError("xmlXadesXPathFirstElement(xades:SigPolicyId/xades:Identifier\n", NULL); + return(-1); + } + xmlChar *identifier = xmlNodeListGetString(signNode->doc, sigPolicyId->xmlChildrenNode, 1); + printf("IDENTIFIER %s\n", identifier); + xmlFree(identifier); return xmlSecDSigCtxSign(ctx->dsigCtx, signNode); } @@ -157,3 +140,44 @@ xmlXadesDSigCtxDestroy(xmlXadesDSigCtxPtr ctx) { free(ctx); return(0); } + +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); + } + } + } + + + 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); + } + + // obtener puntero a nodo + node = xpathResult->nodesetval->nodeTab[0]; + if ( node->type != XML_ELEMENT_NODE ) { + xmlXadesInternalError("expected element QualifyingProperties\n", NULL); + return(NULL); + } + + return(node); +} diff --git a/experimental/facho-signer/xades/xades.h b/experimental/facho-signer/xades/xades.h index 6594e49..3671b38 100644 --- a/experimental/facho-signer/xades/xades.h +++ b/experimental/facho-signer/xades/xades.h @@ -1,8 +1,6 @@ #ifndef XADES_H #define XADES_H - - #include #include @@ -42,7 +40,7 @@ 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"; +static const xmlChar xmlXadesNodeSigPolicyId[] = "SigPolicyId"; static const xmlChar xmlXadesNodeIdentifier[] = "Identifier"; static const xmlChar xmlXadesNodeDescription[] = "Description"; static const xmlChar xmlXadesNodeSigPolicyHash[] = "SigPolicyHash"; @@ -56,14 +54,28 @@ static const xmlChar xmlXadesNodeX509IssuerNumber[] = "X509IssuerNumber"; static const xmlChar xmlXadesDSigNs[] = "http://uri.etsi.org/01903/v1.3.2#"; +typedef int xmlXadesSize; +typedef enum _XADES_DIGEST_METHOD{ + XADES_DIGEST_SHA256 +} XADES_DIGEST_METHOD; + +typedef int (*xmlXadesPolicyIdentifierContentCallback)(const xmlChar *policyId, xmlChar *content, xmlXadesSize *content_length); + +typedef struct _xmlXadesPolicyIdentifierCtx *xmlXadesPolicyIdentifierCtxPtr; +struct _xmlXadesPolicyIdentifierCtx { + XADES_DIGEST_METHOD digestMethod; + xmlXadesPolicyIdentifierContentCallback contentCallback; +}; + typedef struct _xmlXadesDSigCtx xmlXadesDSigCtx, *xmlXadesDSigCtxPtr; struct _xmlXadesDSigCtx { xmlSecDSigCtxPtr dsigCtx; + XADES_DIGEST_METHOD digestMethod; + xmlXadesPolicyIdentifierCtxPtr policyCtx; }; - xmlXadesDSigCtxPtr -xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx); +xmlXadesDSigCtxCreate(xmlSecDSigCtxPtr dsigCtx, XADES_DIGEST_METHOD digestMethod, xmlXadesPolicyIdentifierCtxPtr policyCtx); int xmlXadesDSigCtxSign(xmlXadesDSigCtxPtr ctx, xmlNodePtr signNode); @@ -74,35 +86,37 @@ 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, xmlSecTransformId digestMethodId); + xmlNodePtr xmlXadesTmplAddCert(xmlNodePtr signingCertificateNode); xmlNodePtr xmlXadesTmplAddCertDigest(xmlNodePtr signingCertificateNode, const xmlChar *digestMethod, const xmlChar *digestValue); +xmlNodePtr +xmlXadesTmplAddSignedSignatureProperties(xmlNodePtr parentNode, struct tm* signingTime); + xmlNodePtr xmlXadesTmplAddSignaturePolicyIdentifier(xmlNodePtr signedSignaturePropertiesNode); +xmlNodePtr +xmlXadesTmplAddSignaturePolicyId(xmlNodePtr signaturePolicyIdentifierNode); + +xmlNodePtr +xmlXadesTmplAddSigPolicyId(xmlNodePtr signaturePolicyId, const xmlChar* identifier, const xmlChar *description); + +xmlNodePtr +xmlXadesTmplAddSigPolicyHash(xmlNodePtr parentNode, xmlSecTransformId digestMethodId); + 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