Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Internet (https://www.clubdelphi.com/foros/forumdisplay.php?f=3)
-   -   TICKET BAI (TicketBAI); Nuevo sistema de la Agencia Tributaria del Pais Vasco (https://www.clubdelphi.com/foros/showthread.php?t=94264)

Galaxian 12-04-2021 12:48:32

Ejemplo (parte1)
 
Código Delphi [-]
var
success: Boolean;
xmlToSign: HCkXml;
gen: HCkXmlDSigGen;
object1: HCkXml;
cert: HCkCert;
sbXml: HCkStringBuilder;
verifier: HCkXmlDSig;
numSigs: Integer;
verifyIdx: Integer;
verified: Boolean;

begin
success := True;
//  Load the XML to be signed from a file...
xmlToSign := CkXml_Create();
CkXml_LoadXmlFile(xmlToSign,'xmlToSign.xml');

gen := CkXmlDSigGen_Create();

CkXmlDSigGen_putSigLocation(gen,'T:TicketBai');
CkXmlDSigGen_putSigLocationMod(gen,0);
CkXmlDSigGen_putSigId(gen,'Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-Signature');
CkXmlDSigGen_putSigNamespacePrefix(gen,'ds');
CkXmlDSigGen_putSigNamespaceUri(gen,'h_t_t_p:w_w_w_.w3.org/2000/09/xmldsig#');
CkXmlDSigGen_putSigValueId(gen,'Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-SignatureValue');
CkXmlDSigGen_putSignedInfoCanonAlg(gen,'C14N');
CkXmlDSigGen_putSignedInfoDigestMethod(gen,'sha256');

Galaxian 12-04-2021 12:52:43

Ejemplo (parte2)
 
Código Delphi [-]
//  Set the KeyInfoId before adding references..
CkXmlDSigGen_putKeyInfoId(gen,'Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-KeyInfo');

//  Create an Object to be added to the Signature.
object1 := CkXml_Create();
CkXml_putTag(object1,'xades:QualifyingProperties');
CkXml_AddAttribute(object1,'xmlns:xades','h_t_t_p://uri.etsi.org/01903/v1.3.2#');
CkXml_AddAttribute(object1,'Id','Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-QualifyingProperties');
CkXml_AddAttribute(object1,'Target','#Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-Signature');
CkXml_AddAttribute(object1,'xmlns:ds','h_t_t_p://w_w_w.w3.org/2000/09/xmldsig#');
CkXml_UpdateAttrAt(object1,'xades:SignedProperties',True,'Id','Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-SignedProperties');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signi  ngTime','TO BE GENERATED BY CHILKAT');
CkXml_UpdateAttrAt(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:SigningCert  ificate|xades:Cert|xades:CertDigest|ds:DigestMethod',True,'Algorithm','h_t_t_p://w_w_w.w3.org/2001/04/xmlenc#sha512');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signi  ngCertificate|xades:Cert|xades:CertDigest|ds:DigestValue','TO BE GENERATED BY CHILKAT');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signi  ngCertificate|xades:Cert|xades:IssuerSerial|ds:X509IssuerName','TO BE GENERATED BY CHILKAT');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signi  ngCertificate|xades:Cert|xades:IssuerSerial|ds:X509SerialNumber','TO BE GENERATED BY CHILKAT');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signa  turePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyId|xades:Identifier','h_t_t_p_s://w_w_w.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signa  turePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyId|xades:Description','');
CkXml_UpdateAttrAt(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePo  licyIdentifier|xades:SignaturePolicyId|xades:SigPolicyHash|ds:DigestMethod',True,'Algorithm','h_t_t_  p://w_w_w.w3.org/2001/04/xmlenc#sha256');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:Signa  turePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyHash|ds:DigestValue','Quzn98x3PMbSHwbUza  j5f5KOpiH0u8bvmwbbbNkO9Es=');

Galaxian 12-04-2021 12:54:52

Ejemplo (parte3)
 
Código PHP:

CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedSignatureProperties|xades:SignaturePolicyIdentifier|xades:SignaturePolicyId|xades:SigPolicyQualifiers|xades:SigPolicyQualifier|xades:SPURI','h_t_t_p_s://w_w_w.batuz.eus/fitxategiak/batuz/ticketbai/sinadura_elektronikoaren_zehaztapenak_especificaciones_de_la_firma_electronica_v1_0.pdf');
CkXml_UpdateAttrAt(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat',True,'ObjectReference','#Reference-7e6f3481-4acc-47de-90fd-67878ad15e8e');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Description','');
CkXml_UpdateAttrAt(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier',True,'Qualifier','OIDAsURN');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Identifier','urn:oid:1.2.840.10003.5.109.10');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:ObjectIdentifier|xades:Description','');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:MimeType','text/xml');
CkXml_UpdateChildContent(object1,'xades:SignedProperties|xades:SignedDataObjectProperties|xades:DataObjectFormat|xades:Encoding','');

CkXmlDSigGen_AddObject(gen,'',CkXml__getXml(object1),'',''); 


benjy.sr 12-04-2021 12:55:33

No puedo conectar
 
Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 540581)
Parece que tiene que ver con el certificado (o relacionado con TSL).

Pues parece que si era por eso, muchas gracias Neftali.
Ahora me pide el certificado, pero la respuesta es vacía, revisando la respuesta el código es el 500, y el texto es "Internal server error",..... no sé qué puede ser

Galaxian 12-04-2021 12:57:34

Ejemplo (parte4)
 
Código PHP:

//  -------- Reference 1 --------
CkXmlDSigGen_AddSameDocRef(gen,'','sha512','C14N','','h_t_t_p://w_w_w.w3.org/2000/09/xmldsig#Object');
CkXmlDSigGen_SetRefIdAttr(gen,'','Reference-7e6f3481-4acc-47de-90fd-67878ad15e8e');

//  -------- Reference 2 --------
CkXmlDSigGen_AddObjectRef(gen,'Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-SignedProperties','sha512','','','h_t_t_p://uri.etsi.org/01903#SignedProperties');

//  -------- Reference 3 --------
CkXmlDSigGen_AddSameDocRef(gen,'Signature-63c35f38-2b5f-4600-b3da-3ddee86d62b3-KeyInfo','sha512','','','');

//  Load a certificate that has been pre-installed on the Windows system
//  This includes certificates on smartcards and USB tokens
cert := CkCert_Create();
success := CkCert_LoadByCommonName(cert,'The cert Subject CN');
if (
success <> Truethen
  begin
    Memo1
.Lines.Add(CkCert__lastErrorText(cert));
    Exit;
  
end;
CkXmlDSigGen_SetX509Cert(gen,cert,True);

CkXmlDSigGen_putKeyInfoType(gen,'X509Data+KeyValue');
CkXmlDSigGen_putX509Type(gen,'Certificate');

//  Load XML to be signed...
sbXml := CkStringBuilder_Create();
CkXml_GetXmlSb(xmlToSign,sbXml);

CkXmlDSigGen_putBehaviors(gen,'IndentedSignature,TransformSignatureXPath');

//  Sign the XML...
success := CkXmlDSigGen_CreateXmlDSigSb(gen,sbXml);
if (
success <> Truethen
  begin
    Memo1
.Lines.Add(CkXmlDSigGen__lastErrorText(gen));
    Exit;
  
end;
//  -----------------------------------------------

//  Save the signed XML to a file.
success := CkStringBuilder_WriteFile(sbXml,'qa_output\signedXml.xml','utf-8',False);

Memo1.Lines.Add(CkStringBuilder__getAsString(sbXml)); 


Galaxian 12-04-2021 13:00:21

El ejemplo anterior crea una firma digital prácticamente idéntica a la original.
Para rizar el rizo se pueden generar dos UUID (los de 'signature' y 'reference') y modificar el código para que cada vez tenga unos UUID distintos

Galaxian 12-04-2021 13:15:13

Para enviar (es código C++, que es el lenguaje que uso, aunque su traducción a Pascal/Delphi no el muy complicada porque la estructura es la misma, aunque su sintaxis difiera un poco:

Código PHP:

CkRest rest;
CkSocket socket;

success socket.SetSslClientCertPfx("d:\\xxx.pfx","xxxxxxxxxx");
if (
success != true) {std::cout << socket.lastErrorText() << "\r\n"; return;}

bool bTls true;
int port 443;
int maxWaitMs 5000;

success socket.Connect("pruesarrerak.bizkaia.eus",port,bTls,maxWaitMs);

if (
success != true
{
    
std::cout << "Connect Failure Error Code: " << socket.get_ConnectFailReason() << "\r\n";
    
std::cout << socket.lastErrorText() << "\r\n";
    return;
}

bool bAutoReconnect true;

// Use the connection:
success rest.UseConnection(socket,bAutoReconnect);
if (
success != true) {std::cout << rest.lastErrorText() << "\r\n"; return;}

CString jsn="{\"con\":\"LROE\",\"apa\":\"1.1\",\"inte\":{\"nif\":\"XXXXXXXXXX\",\"nrs\":\"XXXXXXXXXX\"},\"drs\":{\"mode\":\"140\",\"ejer\":\"2020\"}}";
cTexto dat=cFicheroBase::Leer("D:\\Ejemplo_LROE_140.xml").Texto();

rest.put_Utf8(SI);

rest.AddHeader("Accept-Encoding","gzip");
rest.AddHeader("Content-Encoding","gzip");
rest.AddHeader("Content-Type","application/octet-stream");
rest.AddHeader("eus-bizkaia-n3-version","1.0");
rest.AddHeader("eus-bizkaia-n3-content-type","application/xml");
rest.AddHeader("eus-bizkaia-n3-data",jsn);

int rst=rest.SendReqStringBody("POST","/N3B4000M/aurkezpena",dat);
rst=rest.ReadResponseHeader();
cchar *cr=rest.responseHeader();

CkByteData rb;
rst=rest.ReadRespBodyBinary(rb);
const 
uchar *dta=rb.getData();
int lng=rb.getSize();

cBinario rb2(dta,lng);
rb2=cCompresion::Descomprimir::Gzip(rb2);

return; 

Hay que tener en cuenta que la librería chilkat reconoce la cabecera 'Content-Encoding: gzip" y COMPRIME el envío y DESCOMPRIME la respuesta, que, a su vez, está comprimida, por lo que habrá que descomprimirla.

Los certificados no solo pueden cargarse de pfx, sino también del almacén de Windows o usar uno cargado anteriormente

Pau Haro 12-04-2021 13:26:33

Buenas,

Tengo problemas con el envio a Bizkaia, llega la solicitud al servidor pero la respuesta es incorrecta, por que el Id="xmldsig-bb95c614-22fb-4afe-9e6f-b46f4c46f971" no esta bien generado, esta cadena la genero usando el siguiente codigo en Java -> "xmldsig-" + UUID.randomUUID().toString();

Esto no esta funcionando y a diferencia de Guipuzkoa, Bizakaia no me retorna respuesta correcta por tener el ID mal. Estoy usando SecureBlackBox para realizar la firma de mi documento, si alguien me pudiera decir como generar el ID con SecureBackBox o con metodos nativos de Java, se lo agradeceria.

Saludos!

Neftali [Germán.Estévez] 12-04-2021 13:56:52

Cita:

Empezado por Galaxian (Mensaje 540589)
Hay que tener en cuenta que la librería chilkat reconoce la cabecera 'Content-Encoding: gzip" y COMPRIME el envío y DESCOMPRIME la respuesta, que, a su vez, está comprimida, por lo que habrá que descomprimirla.
Los certificados no solo pueden cargarse de pfx, sino también del almacén de Windows o usar uno cargado anteriormente


Gracias nuevamente.
^\||/^\||/^\||/^\||/

espinete 13-04-2021 15:17:33

Hola a tod@s.

Después de tanto tiempo y de tener encaminado el desarrollo del TicketBAI (al menos el envío y consulta de facturas), me surge una pregunta un poco tonta pero necesito estar seguro...

Para el envío de información del LROE existen varios métodos: ingresos con software garante, facturas con software garante, anulación...

Pero hay otros que indican "sin software garante", o "ingresos sin factura" y otros más.

Teniendo en cuenta que en mi caso estaría haciendo la integración en un software de facturación, es obvio pensar que solo tendría que implementar aquellos esquemas/envíos "con software garante", no? ¿O estoy obviando algo que no he entendido del todo?

No sé si existe información sobre para qué se usa cada caso exactamente, pero imagino que en mi caso concreto solo tendría que preocuparme por implementar el envío de facturas hechas con mi software, nada más.

¿Es correcto?

Neftali [Germán.Estévez] 13-04-2021 17:01:56

Aquí en preguntas frecuentes hay esto (a ver si te aclara algo):






aar1 16-04-2021 07:36:42

error en validación de firma
 
Buenos días.

Estoy utilizando ChilKat para firmar el XML del TicketBai y como certificado digital uno de los certificados de PRODUCCIÓN de IZENPE. Al enviar el fichero XML al entorno de pruebas de Gipuzkoa el fichero es aceptado pero me devuelve el código 008 El mensaje ha sido modificado en tránsito o la firma no está bien realizada -- SignedInfo failed to verify. [src/xml2signatureobj.cpp(315)] - (10606)

No sé si a alguno de vosotros os ha pasado lo mismo y si esto se debe al certificado digital que estoy utilizando.

Un saludo.

bilbur 16-04-2021 10:47:04

Recibo mismo error 008


Firma y envío con PHP (en procesos separados)



Certificado FNMT


Investigaré y si encuentro "algo" lo comentaré aquí


Un saludo

Neftali [Germán.Estévez] 16-04-2021 11:47:15

Cita:

Empezado por aar1 (Mensaje 540601)
pero me devuelve el código 008 El mensaje ha sido modificado en tránsito o la firma no está bien realizada -- SignedInfo failed to verify. [src/xml2signatureobj.cpp(315)] - (10606)

No sé si a alguno de vosotros os ha pasado lo mismo y si esto se debe al certificado digital que estoy utilizando.

Nosotros hemos tenido este error.
Es debido (al menos en nuetro caso) a problemas en la codificación.
Normalmente en el paso entre la firma del XML y el envío.

Revisad si el contenido de lo que habéis firmado (justo después de firmar) es lo mismo que estáis enviando. Sobre todo revisad si en la razón social o en alguno de las cadenas que enviáis hay caracteres extraños (con acentos, tildes,...).

A veces el resultado del envío lo grabamos en fichero o trabajamos con Streams y sin darnos cuenta la codificación cambia. Revisad entre UTF8, UTF8 BOM y ANSI.

Revisad por ejemplo si estáis utilizando Streams, que la clase TStream en la creación posee opciones de codificación.

Al final nosotros acabamos comparando el contenido en cada paso (Editor Hexadecimal) y nos dimos cuenta de que el character Ó (de la razón social) al realizar la firma con los SBB se estaba cambiando (cofidicación implícita).

NOTA: Ahora estoy probando con esta empresa... :cool::cool::D:D.

Galaxian 16-04-2021 11:48:22

Cita:

Empezado por bilbur (Mensaje 540602)
Recibo mismo error 008


Firma y envío con PHP (en procesos separados)


Certificado FNMT


Investigaré y si encuentro "algo" lo comentaré aquí


Un saludo

Supongo que te ha pasado lo mismo que a mi y a aar1: que en vez de cargar el archivo XML se ha usado la función getAsString para obtener el XML firmado y enviarlo a batuz, pero hay una cosa que se debe tener en cuenta, y es que la cadena obtenida es ASCII, por lo que justo antes de la llamada a getAsString hay que usar put_Utf(true) para que la genere en UTF-8 o bien convertir el XML ASCII a UTF-8 antes de enviarlo.

aar1 16-04-2021 12:01:17

Buenos días.

Problema solucionado, era por la codificación al enviar el XML firmado, hay que convertirlo a formato utf-8 antes de enviarlo al entorno de pruebas.

Chilkat dispone del objeto StringBuilder que contiene el método LoadFile y permite indicar el charset.

Muchas gracias por la ayuda.

aar1 16-04-2021 13:05:13

LROE Bizkaia
 
Hola a todos.

Ahora estoy haciendo pruebas para enviar el documento LROE y me devuelve el error B4_1000002, Todos los registros incluidos en la petición son incorrectos.

He revisado la codificación de la información que se envía y está en utf-8.

Un saludo.

Galaxian 16-04-2021 19:43:07

Cita:

Empezado por aar1 (Mensaje 540606)
Hola a todos.

Ahora estoy haciendo pruebas para enviar el documento LROE y me devuelve el error B4_1000002, Todos los registros incluidos en la petición son incorrectos.

He revisado la codificación de la información que se envía y está en utf-8.

Un saludo.

En el XML devuelto tienes la información de qué es lo que ha pasado. Ten en cuenta que está comprimido.

Para obtenerlo no puedes hacer un 'FullRequest...', ya que esas funciones no están pensadas para respuestas binarias sino JSON o XML, por lo que hay que hacer una petición por partes (por claridad he quitado el control de errores):

Cita:

rest.SendReqStringBody("POST","/N3B4000M/aurkezpena",dat);
rest.ReadResponseHeader();

const char *cr=rest.responseHeader(); // Cabeceras

CkByteData rb;
rest.ReadRespBodyBinary(rb); // Cuerpo (aquí es donde está el XML comprimido)
const uchar *db64=rb.getEncoded("base64");
Ahora ya tienes el XML comprimido en base64, por lo que solo queda decodificar y descomprimir.

aar1 17-04-2021 11:37:47

Muchas gracias Galaxian.

He conseguido leer el archivo XML que se envía de respuesta en el body y así poder corregir los errores que tenía en la generación del Ticket Bai.

Ahora ya obtengo la respuesta "correcto" por parte del entorno de pruebas de Bizkaia.

Un saludo.

bilbur 17-04-2021 19:23:55

Cita:

Empezado por Galaxian (Mensaje 540604)
Supongo que te ha pasado lo mismo que a mi y a aar1: que en vez de cargar el archivo XML se ha usado la función getAsString para obtener el XML firmado y enviarlo a batuz, pero hay una cosa que se debe tener en cuenta, y es que la cadena obtenida es ASCII, por lo que justo antes de la llamada a getAsString hay que usar put_Utf(true) para que la genere en UTF-8 o bien convertir el XML ASCII a UTF-8 antes de enviarlo.


Por fin he conseguido enviar a Guipuzcoa en pruebas facturas firmadas y recibir respuesta correcta.


En mi caso se trataba de firma mal realizada por no respetar el esquema XAdES/XMLDSI, por lo que he modificado mi esquema (el orden de los "<ds:Reference") y ya funciona bien.


Utilizo dos validadores de firma online:


http://tools.chilkat.io/xmlDsigVerify.cshtml


https://web.uanataca.com/pe/servicio...ma-electronica


El primero y previo a los cambios en mi esquema, el de chlikat me daba este resultado
Signature Verified
Number of Reference Digests = 3
Reference 1 digest is valid.
Reference 2 digest is valid.
Reference 3 digest is valid.
Pero era rechazado por Guipuzcoa


El segundo, uanataca, me daba el error de no respetar el esquema.


Ahora ya da correcto en los dos validadores y en el envío a Guipuzcoa


Pongo esto porque me fiaba (y me fio aunque un poco menos) de chlikat y pensando que el xml firmado era correcto buscaba corregir errores donde no correspondía.


Cuando vaya avanzando un poco más, si a alguien le interesa, subiré lo que estoy desarrolando en PHP (sin dependencia de terceros ni para generar el xml, firmar ni enviar)


Un saludo a todos


La franja horaria es GMT +2. Ahora son las 00:19:12.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi