Buscar en este blog

martes, 26 de febrero de 2013

Como firmar la semilla del SII

Firma de semilla del SII

Una vez recupera la cadena que representa la semilla, debemos firmarla con nuestro certificado digital, de forma que el SII pueda cotejar quien firmo la semilla y si tiene permisos o no para entrar a los servicios disponibilizados por ellos. Sabemos que la consulta al SII utilizando el metodo maullin.getSeed() nos entregará una cadena string con la siguiente información:'1234567890123'.

Esta cadena debemos firmarla con el certificado digital del usuario registrado en el SII y que tenga los permisos de envío y consulta de documentos.Este certificado debería estar instalado en el servidor que realiza la consulta.


Expongo el codigo utilizado para preparar el valor de la semilla y luego firmarla.


/// 
/// Firma la semilla para poder validarla en el SII
/// 
private static string FirmarSemilla(string seed, string cn )
{

 ////
 //// Construya el cuerpo del documento en formato string.
 string resultado = string.Empty;
 string body = string.Format("{0}", double.Parse(seed).ToString());

 ////
 //// Recuperar el certificado para firmar el documento.
 //// utilizando el nombre del propietario del certificado o CN
 X509Certificate2 certificado = FuncionesComunes.obtenerCertificado(cn);

 ////
 //// Firme la semilla.
 try
 {
  resultado = Negocio.FirmarSemilla.firmarDocumentoSemilla(body, certificado);

 }
 catch (Exception)
 {
  resultado = string.Empty;
 }


 ////
 //// Regrese el valor de retorno
 return resultado;
 

}


/// 
/// Recupera un determinado certificado para poder firmar un documento
/// 
/// Nombre del certificado que se busca
/// X509Certificate2
public static X509Certificate2 obtenerCertificado(string CN)
{

   ////
   //// Respuesta
   X509Certificate2 certificado = null;

   ////
   //// Certificado que se esta buscando
   if (string.IsNullOrEmpty(CN) || CN.Length == 0)
      return certificado;

   ////
   //// Inicie la busqueda del certificado
   try
   {

      ////
      //// Abra el repositorio de certificados para buscar el indicado
      X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
      store.Open(OpenFlags.ReadOnly);
      X509Certificate2Collection Certificados1 = (X509Certificate2Collection)store.Certificates;
      X509Certificate2Collection Certificados2 = Certificados1.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
      X509Certificate2Collection Certificados3 = Certificados2.Find(X509FindType.FindBySubjectName, CN, false);

      ////
      //// Si hay certificado disponible envíe el primero
      if (Certificados3 != null && Certificados3.Count != 0)
         certificado = Certificados3[0];

      ////
      //// Cierre el almacen de sertificados
      store.Close();


   }
   catch (Exception)
   {
      certificado = null;
   }


   ////
   //// Regrese el valor de retorno 
   return certificado;

}








Expongo ademas la clase que realiza la firma de la semilla:


//// 
//// Firma el documento xml semilla
//// 
public static string firmarDocumentoSemilla(string documento, X509Certificate2 certificado)
{

 ////
 //// Cree un nuevo documento xml y defina sus caracteristicas
 XmlDocument doc = new XmlDocument();
 doc.PreserveWhitespace = false;
 doc.LoadXml(documento);

 ////
 //// Cree el objeto XMLSignature.
 SignedXml signedXml = new SignedXml(doc);
 
 ////
 //// Agregue la clave privada al objeto xmlSignature.
 signedXml.SigningKey = certificado.PrivateKey;
 
 ////
 //// Obtenga el objeto signature desde el objeto SignedXml.
 Signature XMLSignature = signedXml.Signature; 

 ////
 //// Cree una referencia al documento que va a firmarse
 //// si la referencia es "" se firmara todo el documento
 Reference reference = new Reference("");

 ////
 //// Representa la transformación de firma con doble cifrado para una firma XML  digital que define W3C.
 XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
 reference.AddTransform(env);
 
 ////
 //// Agregue el objeto referenciado al obeto firma.
 XMLSignature.SignedInfo.AddReference(reference);

 ////
 //// Agregue RSAKeyValue KeyInfo  ( requerido para el SII ).
 KeyInfo keyInfo = new KeyInfo();
 keyInfo.AddClause(new RSAKeyValue((RSA)certificado.PrivateKey));

 ////
 //// Agregar información del certificado x509
 keyInfo.AddClause(new KeyInfoX509Data(certificado));

 //// 
 //// Agregar KeyInfo al objeto Signature 
 XMLSignature.KeyInfo = keyInfo;

 ////
 //// Cree la firma
 signedXml.ComputeSignature();

 ////
 //// Recupere la representacion xml de la firma
 XmlElement xmlDigitalSignature = signedXml.GetXml();

 ////
 //// Agregue la representacion xml de la firma al documento xml
 doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, true));

 ////
 //// Limpie el documento xml de la declaracion xml ( Opcional, pera para nuestro proceso es valido  )
 if (doc.FirstChild is XmlDeclaration)
 {
  doc.RemoveChild(doc.FirstChild);
 }

 ////
 //// Regrese el valor de retorno
 return doc.InnerXml;




}



Lo que nos arrojara como resultado algo parecido a esto:



1234567890123










8slcL05kmrM8NGw4I9NSfRqYA9E=


jlbzatIIBLW8AjH++5uVTTrGIMVwGButuoAR88y/hvSc1+6/eW1K864fK3cKi76oArqk7lAM4pPokoXme0JT/hRXXGo6ecuKzO18z2WfPWwgnN0f3ac03TDu7PwfqiDG9mhQpYfIkNp6GNJIiqlg9PG2w1fOJ1QoypsrQmKq6YU=



2Pb4kEB19m7NmOUYew9f36325yrTLTPMU7qzYG2A0/BsubxDdgQw2Op0x6zXvOVX
sYI9KkPXtD5orKJMjwxYRv9wUWdyiE776Rv4ljfJO7EQhIK1fDQDnPt0HefBS06Xzg2QLBvLR+pe1vc6C02Dr99v+lnLA8mnZiJlRHndhNU=

AQAB



MIIF1DCCBLygAwIBAgIDAQNtMA0GCSqGSIb3DQEBBQUAMIHGMQswCQYDVQQG
EwJDTDEYMBYGA1UEChMPQWNlcHRhLmNvbSBTLkEuMTgwNgYDVQQLEy9BdXRv
cmlkYWQgY2VydGlmaWNhZG9yYSBDbGFzZSAzIHBlcnNvbmEgbmF0dXJhbDFD
MEEGA1UEAxM6QWNlcHRhLmNvbSBBdXRvcmlkYWQgY2VydGlmaWNhZG9yYSBD
bGFzZSAzIHBlcnNvbmEgbmF0dXJhbDEeMBwGCSqGSIb3DQEJARYPaW5mb0Bh
Y2VwdGEuY29tMB4XDTAxMDkyNTIxMDgxMloXDTAyMDkyNTIxMDgxMlowgZ8x
CzAJBgNVBAYTAkNMMRgwFgYDVQQKEw9BY2VwdGEuY29tIFMuQS4xLDAqBgNV
BAsTI0NlcnRpZmljYWRvIENsYXNlIDMgUGVyc29uYSBOYXR1cmFsMRwwGgYJ
KoZIhvcNAQkBFg1uY2hlbGVAc2lpLmNsMSowKAYDVQQDEyFOSUNPTEFTIFpB
UFJJQU4gQ0hFTEVCSUZTS0kgQkFFWkEwgZ8wDQYJKoZIhvcNAQEBBQADgY0A
MIGJAoGBANj2+JBAdfZuzZjlGHsPX9+t9ucq0y0zzFO6s2BtgNPwbLm8Q3YE
MNjqdMes17zlV7GCPSpD17Q+aKyiTI8MWEb/cFFncohO++kb+JY3yTuxEISC
tXw0A5z7dB3nwUtOl84NkCwby0fqXtb3OgtNg6/fb/pZywPJp2YiZUR53YTV
AgMBAAGjggJyMIICbjAdBggrBgEEAbVrDwQRFg9BY2VwdGEuY29tIFMuQS4w
JQYDVR0RBB4wHKAaBggrBgEEAcEBAaAOFgwxMC40MTEuODcxLTIwDwYIKwYB
Jh0z1DR3Pl3xOiaFIjSXsQO2PSzcA3wZXYF+KDrMul8e5lAF2NNiLmMVtXEx
ZykMaTGGWS0ZETDhJmBwEZGpP4+lt/JhgwF1Sb6wdrXp7MFCJUc1Tj+/5JqH
1kP0E63/hVElrcP0g8Zn8Z+vr/PMGW1kKgE0IyS4iJ8eIhNSK5phFyKJUn0l
BmIZX7u89d5u7X8=




Finalmente este es el documento xml firmado que se envía al SII.

102 comentarios:

  1. Hola Marcelo,
    Muy bueno el tutorial, pero no encuentro la referencia a la clase de obtenerCertificado en FuncionesComunes. Donde estan estas definiciones?

    De antemano muchas gracias

    ResponderEliminar
  2. Estimado,
    Tienes razon, pero gracias a tu consulta he incluído el codigo de los certificados, espero te ayude.

    ResponderEliminar
  3. Marcelo,
    El proceso indicado funciona a la perfeccion, pero lo modifique hacia el cruce del numero de serie del certificado y el CA (Ya que en mi equipo poseo mas de un certificado con el mismo Subject.

    Me realiza todo OK hasta la generacion del XML Firmado para solicitar el token, pero el SII me continua respondiendo de que el elemento "Semilla" no existe, siendo que se que esta dentro del XML que me retorna el "FirmarSemilla". Sabes que pueda estar ocurriendo?

    El XML Firmado que envio al SII a traves de getToken(pszXml) es:


    000990386498ZjTfG52iYYARqoh/3yHPAMFgO6Q=xh6T9bbtu+jBZoJuHm61RPzOAPun/t/WRaAP6c9VU/sriHnV8yATXb/w7cLzCYpBC4Z7e/zPHjGruojkZqFE8nsyN37/XJbQnE08coVMrjyBnaZKsZ7FBzE67CaqKDv87J411ZpYO4LuPlXuWnsnuKjZ2zBk576B0+niKrWwxhs=7G4Ok3d3ysFiagsfDi6HbQE65c6svg+IfYoUZnF59wqStbFqXlCaVFqam8HD3rc/HLhoV9eHeWj9SQ5OJ4AAMFah8TqKJY7YlHKS7pPIZWamJ3z13CJ+TQ3IkZ71OegnZvo5/txPb2WQ/R+/sUFHDVkgA0beV/miLduVlLjX8H0=AQABMIIF+DCCBOCgAwIBAgIKH9pr1QAAAAAw+jANBgkqhkiG9w0BAQUFADCB0jELMAkGA1UEBhMCQ0wxHTAbBgNVBAgTFFJlZ2lvbiBNZXRyb3BvbGl0YW5hMREwDwYDVQQHEwhTYW50aWFnbzEUMBIGA1UEChMLRS1DRVJUQ0hJTEUxIDAeBgNVBAsTF0F1dG9yaWRhZCBDZXJ0aWZpY2Fkb3JhMTAwLgYDVQQDEydFLUNFUlRDSElMRSBDQSBGSVJNQSBFTEVDVFJPTklDQSBTSU1QTEUxJzAlBgkqhkiG9w0BCQEWGHNjbGllbnRlc0BlLWNlcnRjaGlsZS5jbDAeFw0xMjA3MTgyMTMzNTlaFw0xMzA3MTgyMTMzNTlaMIG3MQswCQYDVQQGEwJDTDEdMBsGA1UECBMUUkVHSU9OIE1FVFJPUE9MSVRBTkExETAPBgNVBAcTCFNhbnRpYWdvMTAwLgYDVQQKEydTb2NpZWRhZCBkZSBJbmZvcm1hdGljYSB5IFJlc2VydmEgTHRkYSAxHzAdBgNVBAMTFkZlbGlwZSAgQnJpdG8gIFBlYXJzb24xIzAhBgkqhkiG9w0BCQEWFGZicml0b0ByZXNlcnZhbWUubmV0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsbg6Td3fKwWJqCx8OLodtATrlzqy+D4h9ihRmcXn3CpK1sWpeUJpUWpqbwcPetz8cuGhX14d5aP1JDk4ngAAwVqHxOooljtiUcpLuk8hlZqYnfPXcIn5NDciRnvU56Cdm+jn+3E9vZZD9H7+xQUcNWSADRt5X+aIt25WUuNfwfQIDAQABo4ICazCCAmcwPQYJKwYBBAGCNxUHBDAwLgYmKwYBBAGCNxUIgtyDL4WTjGaF1Z0XguLcJ4Hv7Dxhg+a1E4OjvSECAWQCAQMwHQYDVR0OBBYEFCwj+WeJbazpqwpN02/yOIPi7eEFMAsGA1UdDwQEAwIE8DAfBgNVHSMEGDAWgBR44T6f0hKzejyNzTAOU7NDKQezVTA+BgNVHR8ENzA1MDOgMaAvhi1odHRwOi8vY3JsLmUtY2VydGNoaWxlLmNsL2VjZXJ0Y2hpbGVjYUZFUy5jcmwwIwYDVR0RBBwwGqAYBggrBgEEAcEBAaAMFgowODcwMjU4MC0yMCMGA1UdEgQcMBqgGAYIKwYBBAHBAQKgDBYKOTY5MjgxODAtNTCCAU0GA1UdIASCAUQwggFAMIIBPAYIKwYBBAHDUgUwggEuMC0GCCsGAQUFBwIBFiFodHRwOi8vd3d3LmUtY2VydGNoaWxlLmNsL0NQUy5odG0wgfwGCCsGAQUFBwICMIHvHoHsAEMAZQByAHQAaQBmAGkAYwBhAGQAbwAgAEYAaQByAG0AYQAgAFMAaQBtAHAAbABlAC4AIABIAGEAIABzAGkAZABvACAAdgBhAGwAaQBkAGEAZABvACAAZQBuACAAZgBvAHIAbQBhACAAcAByAGUAcwBlAG4AYwBpAGEAbAAsACAAcQB1AGUAZABhAG4AZABvACAAaABhAGIAaQBsAGkAdABhAGQAbwAgAGUAbAAgAEMAZQByAHQAaQBmAGkAYwBhAGQAbwAgAHAAYQByAGEAIAB1AHMAbwAgAHQAcgBpAGIAdQB0AGEAcgBpAG8wDQYJKoZIhvcNAQEFBQADggEBAIX4iEJp9TS932m7gVFGHmsjUU2e36L4pTYxsUahTGPcpdxcahZO1EPJFjsP8bZqjwiqWA5UXa9x7Q6P+SatfkomABluYaZhwpWJtQEABFfuMPuLgM3GrTsKcMSPNheRFsSUKMBupRnR7ZkrEpzfawLV3hX29behrJLG66cTCXXWktDIqCPVOH3406nCBLyQUvCIca/tZ+MXy1m3ZNLvztcQnz2+s/Yrhe20pHQfuxVx/dHn9Gmb1DEOKMFLUXE6A02vjX1xEqndR2Ljo+zKgP21EdfGJ/aPPMPj7AnEQehwSekJERTQBqWjSso6UTHaPtTGZOrGIQdP27Js2CcUQ2c=

    y el SII me responde:



    06
    XML Invalido, elemento Semilla no existe, funcion getSeed



    Slds
    Felipe Brito

    ResponderEliminar
    Respuestas
    1. Hola Felipe, quizás le sirva a otro (ya que es uno poco antiguo el post). A mi me apsaba lo mismo y el error era que teníamos el elemento , en vez de

      Eliminar
  4. Estimado Felipe:

    El proceso de firmado de la semilla consta de la siguiente:

    Recuperar Semilla: Utilizando el metodo getSeed()

    Firmar semilla: Utilizando tu clase para firmar.

    Y posteriormente debes recuperar el token del SII: Utilizando el metodo getToken()

    Quizas el probela este en que la semilla firmada solo dura dos minutos activa o que consultas al ambiente de producción en vez de el ambiente de certificacion.

    Quizas no entendí correctamente el problema, así que te pido que me envés los xmls que generas y recepcionas en un archivo rar para verlos.

    Yo tengo la rutina completa de este procedimiento asi que quieres puedo enviartelo a un correo que me especifiques.

    Atte.
    Marcelo Rojas Rojas
    Desarrollador .Net

    ResponderEliminar
  5. Seria buenisima obtener el proceso completo, mi correo es brito.felipe@gmail.com. Por que de lo que me comentas, efectivamente estoy realizando todo en un mismo proceso y al ambiente de certificacion:

    Dim getSeed As New Hefesto.Proxys.Certificacion.CrSeedService
    Dim seed As String = (getSeed.getSeed())
    seed = cleanSeed(seed) 'limpiar el XML para obtener el seed string
    getSeed.Dispose()

    Dim seedDoc As String = FirmarSemilla(seed, "1f da 6b d5 00 00 00 00 30 fa", "E-CERTCHILE")
    Console.WriteLine(seedDoc)
    Dim getToken As New Hefesto.Proxys.Certificacion.GetTokenFromSeedService()
    Dim token As String
    token = getToken.getToken(seedDoc)
    Console.WriteLine(token)

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Hola Felipe Brito, consulta.. por que en FirmarSemilla tienes 3 parametros de entrada, si en el ejemplo solo existen 2 parametros.

      -> public static string FirmarSemilla(string seed, string cn)

      ???
      Saludos

      Eliminar
  6. Muy bueno tu articulo, la verdad es que ando un tiempo tratando de hacer lo de la factura electronica con .net . saque varias ideas de tus codigos. Ya genero todo hasta en envio (EnvioDTE), y lo subo manualmente a Maullin, me dice que lo recibio, pero al recibizar mi correo tengo el mail con error "RFR - Rechazado por Error en Firma", saque la idea de la firma de tu firmado de semilla.???

    ResponderEliminar
    Respuestas
    1. Estimados el error en la firma se debe que al canonizar el setdte se debe modificar el tag por y ahí pueden calcular el hash, lo pueden ver en esta pagina http://www.cryptosys.net/pki/xmldsig-ChileSII.html#xmldsiginsii.

      Por favor publiquenlo en otros foros ya que hay mucha gente con este problema y hay personas que están cobrando por darte un poco de información que sii no te da.

      Eliminar
  7. Logancl

    Un detalle, la firma de la semilla es similar a la de un DTE, una de las diferencias que existen es que en la firma de la semilla no existe una referencia y por ende se firma todo el documento. En los DTEs, IECV o SetDTE existe un nodo que representa desde donde se va a firmar. Te recomiendo por el momento que revises tus DTES y verifiques que estas pasasndo la referencia correcta y no "". Si sigues teniendo problemas escribame nuevamente.

    Espero haber ayudado

    ResponderEliminar
  8. gracias por tu respuesta.
    como referece le paso #t33f00000100 por ejemplo.

    Reference reference = new Reference(miref);

    y es resto todo igual como en la firma de semilla. la verdad es que ya me esta sacando de canes narajas!!

    ResponderEliminar
    Respuestas
    1. He publicado un pequeño algoritmo para firmar el DTE en http://lenguajedemaquinas.blogspot.com/2013/05/como-firmar-el-dte.html espero te sirva. Si no es asi ponte en contacto conmigo.

      Eliminar
    2. ya lo vi, gracias... lo diferente es el Transform( que tu no aplicas) y el tema de no identar el xml.
      aun no lo pongo en practica... asi que te estoy contando,.

      Eliminar
  9. Marcelo al tratar de ocupar la función firmarDocumentoSemilla(documento As String, certificado As X509Certificate2) As String

    me aparecen varios error de que algunos objetos no estan definidos
    por ejemplo SignedXml(doc), XmlDsigEnvelopedSignatureTransform() entre otros.
    Lo que importo al principio es
    Imports System
    Imports System.Security.Cryptography
    Imports System.Security.Cryptography.Xml
    Imports System.Text
    Imports System.Xml
    Imports AutentificarSII.cl.sii.maullin
    Imports System.Security.Cryptography.X509Certificates

    Me falta alguna clase para estos espacios de nombres.
    Atento a sus comentarios

    Saludos



    ResponderEliminar
    Respuestas
    1. Particularmente en este caso, debes cargar la libreria manualmente.

      System.Security.Cryptography

      Agregar referencia a mano. una vez efectuado esto, el IDE carga correctamente


      Eliminar
  10. Ok marcelo muchas gracias, hasta el momento obtengo la semilla firmada del SII, sin problemas, el procedimiento lo traspase todo a vb.net, me voy a tratar de conseguir un certificado valido para realizar el firmado de la semilla y obtener el Token, ya que aun no tengo el cliente para realizar la aplicación si hay varios interesados, pero tengo que estar seguro de poder realizar sin problemas todo el proceso.

    Otras cosas que he probado hasta ahora es crear los pdf, codigo de barra PDF417, trabajar con xml.

    Que otra cosa crees que pueda necesitar aprender para poder comenzar con el proceso, la idea es tener todos los conocimientos necesarios.

    Atento a tus comentarios

    Saludos


    ResponderEliminar
  11. Bueno,

    Necesitas aprender a validar los dte y set dte con los schemas del SII.

    Como generar los libros electrónicos de compra y venta

    Esto es importante en el flujo de la facturación electrónica

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. Ok Marcelo, voy a empezar a construir los XML, tengo una duda con respecto a eso, puedo tomar el ejemplo que esta en la pagina del SII y cambiarle los datos desde mi archivo de texto y luego validar la estructura del archivo con el programa altova XMLSpy.

      El archivo de ejemplo es Documento ID="F60T33">

      Eliminar
  12. Estimado Marcelo,

    muchas gracias nuevamente por toda la información que nos brindas.

    Tengo una pregunta: Para firmar la semilla y solicitar el token necesitas un signature. De donde sale esa firma? del Certificado adquirido (ej. Acepta?)

    Ese tema no me esta muy claro, he leido demasiada documentación y ya me he mareado un poco.

    Muchas gracias y un saludo,
    Sebastian

    ResponderEliminar
  13. Estimado,

    Para firmar la semilla necesitas tener el certificado de la persona autorizda a firmar documentos ante el SII. De este certificado se extrae informacion de la persona y algunos datso mas de ella, con la cual se crea la firma. Esta firma se adjunta a la semilla, lo que da como resultado la semilla firmada. Cuando envias la semilla firmada al SII ellos extraen gracias a la clave publica los datos de la persona que firmo la semilla. Cuando esta persona es reconocida por el SII te regresan un token. Este resultado indica que ya estas logeado en el SII.

    Cuando firmas la semilla envias algunos datos del firmador, como el nombre, rut, direccion comercial, etc. Tambien envias la clave publica del certificado con la cual el SII puede obtener la informacion del certificado.

    Espero haber ayudado con tu duda.

    ResponderEliminar
    Respuestas
    1. Hola Marcelo,

      Muchas gracias por la rápida respuesta. Me ha ayudado mucho!

      La verdad es que estoy trabajando contra reloj es este tema :-(

      Un abrazo y nuevamente muchas gracias,
      Sebastian

      Eliminar
    2. Hola Marcelo,

      Espero que estes bien. Tengo otra pregunta. Se puede utilizar el mismo certificado digital en dos computadoras diferentes. Por ejemplo, en un servidor de pruebas y luego en el de producción?

      Muchas gracias y muchos saludos,
      Sebastian

      Eliminar
    3. Eso es correcto, aunque debes asegurar que nadie tenga acceso directoa ellos. Sin perjuicio de esto si ambos servidores son maquina distintas no xiste ningun problema en utilizarlos de esa forma.

      Eliminar
    4. Hola Marcelo,

      Realmente estoy muy agracedido por toda tu ayuda, no tienes idea de lo que me estas ayudando! :-)

      Tengo otra pregunta:

      Estoy diseñando un proyecto para incorporar el proceso de facturas electronicas en un programa de facturación. La cuestión es que ayer me han dicho que por la Ley 19.799 no puedo realizar e implementar la solución que estoy pensando, ya que solo puede ser implementada por los proveedores autorizados. Es verdad esto?

      De ante mano muchas gracias!

      Saludos Cordiales,
      Sebastian

      Eliminar
    5. Estimado,

      Creo que estas confundido, lo que ocurre es que als empresas pueden utilizar tres metodos para facturar:

      - Utilizar la web del SII
      - Comprar un software de facturación
      - O crea uno propio

      En otras palabras las empresas pueden crear su propio software y no estar amarrado a terceros.


      Asi que puedes seguir con tus desarrollos tranquilo.

      Lo unico que debes tener presente es que tu cliente sea emisor y receptor electrónico

      Atte.
      Marcelo Rojas Rojas
      Analista Desarrollador

      Eliminar
  14. Hola Marcelo,

    muchas gracias por tu respuesta!

    Saludos,
    Sebastian

    ResponderEliminar
  15. Marcelo,

    Ya estoy enviando la semilla firmada, pero el SII me responde lo siguiente:



    05
    XML Invalido, firma invalida, funcion valSignedXml



    Te queria mandar el XML con la semilla firmada a un correo para que me des tu opinion. Aunque te adelanto que esta igual al ejemplo mostrado en el documento del SII. No le falta nada.
    Tengo la duda respecto a que tipo de certificado usaste en tus ejemplos para firmar. En mi caso estoy leyendo el archivo PFX en formato PKCS12 que me entrego la entidad certificadora (Acepta.com). Esta instalado en el almacen de Explorer que uso regularmente para autenticarme en el portal MIPYME y facturar, pero como te mencione, no lo leo desde ese repositorio. Abro directamente el PFX y luego embebo la clave publica en el XML que mando al SII.

    Gracias de antemano!
    Oliver

    ResponderEliminar
    Respuestas
    1. Estimado Oliver,

      Puedes enviarme la informacion a hefesto.fe.valida.dte@gmail.com : Y te respondo, ahora estoy full con un tema pero podrè contestarte a la noche.

      Eliminar
    2. Hola Marcelo y Oliver,

      Tengo una duda con respecto al certificado digital y leyendo el comentario de Oliver veo que es parecida a lo que expone. Mi duda es desde donde se debe leer el certificado digital y en que formato debe estar. Por ejemplo compre uno que viene en .pfx este lo debo leer tal cual en ese formato o existe otra manera de leer el certificado digital. Se que en explorer queda almacenado y se puede exportar, pero en el caso de otros sistemas operativos o de usar chrome, como se realizaria ese proceso.

      Saludos

      Eliminar
    3. Estimado Mario,
      El certificado pfx te funcionará correctamente. Puedes en ambiente windows instalarlo en el pc y luego leerlo con alguna rutina que lea el storage de certificados. En .Net puedes encontrar varias rutinas para leerlos cuando estan instalados en la maquina local. Tambien puedes leerlo pasando al constructor X509Certificate2 la fullpath del certificado y su password. Esto te regresará el objeto certificado X509Certificate para que lo puedas utilizar para firmar documentos. En otros lenguajes debería existir un constructor que te permita recuperar el certificado utilizando la fullpath del documento y su password.

      Eliminar
  16. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  17. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  18. Marcelo,
    por fin autentique:

    <?xml version="1.0" encoding="UTF-8"?>
    <SII:RESPUESTA xmlns:SII="http://www.sii.cl/XMLSchema">
    <SII:RESP_BODY>
    <TOKEN>YWFt4v77dXiF2</TOKEN>
    </SII:RESP_BODY>
    <SII:RESP_HDR>
    <ESTADO>00</ESTADO>
    <GLOSA>Token Creado</GLOSA>
    </SII:RESP_HDR>
    </SII:RESPUESTA>

    El proceso de firma estaba bien, pero faltaba aclarar un detalle: La firma de la semilla en realidad aplica la firma sobre el xml completo por lo que el 'case' del texto debe ser identico al publicado por el SII:

    <getToken><item><Semilla>1162937468</Semilla></item></getToken>

    osea getToken no es lo mismo que gettoken, ya que cambia completamente la digesta de la firma y el SII la rechaza. Un pequeño gran detalle...

    Como aporte, me gustaria mandarte el codigo completo en java para que lo publiques en tu blog ya que en la web aparte de esto no he visto nada relacionado.

    Gracias!
    Oliver

    ResponderEliminar
    Respuestas
    1. Oliver, que debe ir dentro del tag "pszXml" (parámetros de entrada): sólo la firma, todo el xml getToken? esté debe ir codificado ?, por esta razón te pido un ejemplo, por favor.
      Saludos y gracias

      Eliminar
    2. pregunta solo se envia 1162937468 ?? nada mas no va la semilla antes ? o la firma ? tengo muchas dudas respecto a esto la información es muy engorrosa y falta mas detalles o ejemplos no se creo que los foros y los pdf de SII dan por sabido muchas cosas o lo dan por entendido

      Eliminar
    3. Hola Oliver,
      Como estas?
      Me gustaría saber si has publicado el código en java en algún blog.
      Saludos

      Eliminar
  19. Muchas gracias estimado,

    La verdad que siempre es bueno poder tener el consejo y experiencia de aquellos que desarrollan en JAVA y otros lenguajes. Se agreadece mucho la informacion pues todos aprenderemos.

    Muy Agreadecido

    ResponderEliminar
  20. Marcelo después de un tiempo he retomado el aprendizaje de la factura electrónica, me conseguí un certificado valido y estoy en el proceso de firmar la semilla.

    Mi consulta es el parametro CN que utilizas para buscar el certificado, es el nombre de la serie del certificado, ya que paso la siguiente instrucción y no encuentra el certificado en el repositorio.

    FirmarSemilla(txtSoloSemilla.Text, "61 C7 32 52 00 00 00 00 B2 41")

    y donde dice

    '//
    '// Si hay certificado disponible envíe el primero
    If Certificados3 IsNot Nothing AndAlso Certificados3.Count <> 0 Then
    certificado = Certificados3(0)
    End If

    No encuentra el certificado.

    Que podría ser.

    Atento a tus comentarios

    Saludos

    ResponderEliminar
    Respuestas
    1. Hola yo tengo el mismo problema no se que valor debo entregas al parámetro CN si alguien me pudiera ayudar por favor.
      gracias

      Eliminar
    2. Hola Puedes entregar el Rut , nombre completo..etc, algún atributo que lo haga distinguible.

      Eliminar
  21. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  22. Estimado Marcelo:

    Gracias por toda tu ayuda, me gustaría saber a que se refiere esta linea de código

    resultado = Negocio.FirmarSemilla.firmarDocumentoSemilla(body, certificado);



    Saludos,

    Víctor

    ResponderEliminar
    Respuestas
    1. Estimado,

      Mucho de mi codigo esta estructurado, por esta razon hago referencia a clases, sin embargo a esto la linea que mencionas hace referencia a la funcion

      "firmarDocumentoSemilla" que esta un poco mas abajo, la cual firma la semilla. Solo debes modificar la linea por el nombre de la funcion para que funcione.

      Eliminar
  23. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  24. Hola marcelo, es factible que subas un ejemplo de como queda finalmente el xml a enviar, porque tengo dudas de como tiene que ir el xml dentro de los "parametros de entrada" (codificado) saludos y gracias

    ResponderEliminar
    Respuestas
    1. Francisca,

      Por supuesto, dame unos minutos y lo publico.

      Atte.
      Marcelo Rojas Rojas

      Eliminar
    2. Marcelo, por favor recuerda subir el xml :)
      Saludos gracias

      Eliminar
    3. Marcelo, que debe ir dentro del tag "pszXml" (parámetros de entrada): sólo la firma, todo el xml getToken? esté debe ir codificado ?, por esta razón te pido un ejemplo, por favor.
      Saludos y gracias

      Eliminar
  25. Hola Marcelo, tengo una consulta, en la funcion "FirmarSemilla" el parametro "seed" deberia recibir la semilla completa como XML recibida desde el SII o solo el numero de esta, hasta donde yo entiendo debería recibir el XML completo de la semilla pero me da un error al parsear con double.Parse(seed).ToString()... saludos y gracias

    ResponderEliminar
    Respuestas
    1. Estimado,

      Lo que debe ir es el contenido del documento xml, es decir el numero completo que te envian.

      string body = string.Format("{0}", double.Parse(seed).ToString());

      donde seed es igual al por ejemplo : "00123456789"

      Eliminar
  26. Estimado:
    En este momento me encuentro trabajando en python con sockets, ya tengo funcionando toda la parte soap, de hecho saco la semilla sin problemas, el tema es que me sale firma invalida, mi consulta es se hace el digesto completo <getToken>......</getToken> o se firma el <item>......</item>. Quedo atento.
    Muchas gracias.
    Saludos.

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar

    2. Ejemplo

      string body = string.Format("<getToken><item><Semilla>{0}</Semilla></item></getToken>", double.Parse(seed).ToString());

      Eliminar
    3. Osea lo que deduzco de eso es que tengo que eliminar los \n y los ceros de delante de la semilla, todo en una sola linea.
      Muchísimas gracias por la pronta respuesta!!.

      Eliminar
  27. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  28. Hola Marcelo

    Yo estoy firmando todo el nodo GetToken pero siempre me regresa un error de tipo 21 que dice que la firma es inválida.

    ¿Crees que te pueda mandar el XML Request a ver si descubres qué está mal?.

    ResponderEliminar
    Respuestas
    1. A mi me pasa lo mismo y segun esta URL(http://quabr.com/27950770/signing-xml-with-php-xmlseclibs-php) es porque faltan algunos TAG en el XML, Marcelo podrias ayudarme como incluir estos tag necesarios en el XML, ya que tengo el mismo problema que no puedo obtener el token

      Eliminar
  29. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  30. Buenas , saludos ! consulta como saber cual valor es cual donde buscarlo en el certificado digital , tengo uno simple x e-cerfchile y otro por acepta, como se cual es el exponent ,modulus , etc asi como sale en el pdf de sii tengo muchas dudas respecto a eso tengo valores que no se parecen en nada por ej. clave publica =RSA(1024 Bits), huella digital ,identificador clave del titular, num de serie, entre otros pocos pero ninguno con esos nombres, agradezco despejen mis dudas ya que estoy super atrasado con un desarrollo


    1234567890123


    gfnpbQ8vKMQzAJF/nuQxC/Gg=
    pvzPlABsnc9V4M2Wc+QcI8=
    AQAB
    MlBR08xDjAMBgNVBAcTBUNIRUxFMQww
    CgYDVQQtvAfDCCQxMeLAtNJKWJDCN199bO5CUiA3iTlr5BEtu
    DjmnF5dg6L0z03pXOfoaF9bD3zsgPjMRxYAZP33uj/prVHUv0E9g
    U8d/xvdWE21d6AGKGtklmQGSuW8wKogWokKkP
    UfKDlmcWkaSAv056hkvzPlABsnc9V4M2Wc+QcI8CAwEAATANB
    gkqhkiG9w0BAakRk8i3bCCAakRk8i==

    ResponderEliminar
    Respuestas
    1. Este comentario ha sido eliminado por el autor.

      Eliminar
    2. http://www.sii.cl/factura_electronica/autenticacion.pdf

      Eliminar
  31. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  32. estimado después de obtener el token que sigue ..
    jose luis

    ResponderEliminar
    Respuestas
    1. Estimado,

      Una vez que el SII te regresa el token, quiere decir que ya estas autenticado en el SII. Con esta información ya puedes subir tus documentos DTE al SII o realizar consultas a los web services del SII.

      Eliminar
  33. gracias por tu respuesta.
    otra consulta el dte es el xml de la informacion de la factura este se envia firmado al sii y este te envia una respuesta.
    ?
    que mas pasos devo seguir para seguir adelante
    gracias por tu tiempo

    ResponderEliminar
    Respuestas
    1. Efectivamente el SII responde con un xml indicando un trackid de la operación, luego debes consultar este trackid para saber si el documento que enviaste esta aceptado o no en el SII. Debes realizar la recepción del xml de respuesta y luego consultar el valor del trackid. Eso son los pasos a seguir estimado.

      Eliminar
    2. ¿Se puede consultar este trackid de forma automática?

      Eliminar
    3. Estimado

      Efectivamente puede consultar el trackid de forma automatica, debe conocer el proceso de :

      - Autenticación automatica constra el SII
      - Utilizar el web services Consulta de estado de Dte

      Con esta información puedes construír la rutina para realizarlo de forma autimatica.

      Atte.
      Marcelo Rojas Rojas

      Eliminar
  34. Que tal Marcelo estoy trabajando con esto. Ya pude obtener la semilla ahora lo que necesito es firmarla. Lo que me quedan dudas es sobre el certificado digital. Quería saber como lo puedo conseguir. Lo puedo generar yo o es obligatorio solicitárselo al cliente. Que estension tiene el certificado como archivo. Muchas Gracias

    ResponderEliminar
    Respuestas
    1. Estimado Maximiliano
      El certificado debe ser emitido por una entidad certificadora, como acepta.com, camara de comercio, etc. Este certificado debe ser del representante legal de la empresa para poder iniciar el proceso de certificación en el SII. La extension puede ser pfx.

      Atte.
      Marcelo Rojas Rojas

      Eliminar
    2. Muchas Gracias Marcelo por la respuesta. Ya le solicite al cliente que genere el certificado.

      Eliminar
  35. Que tal Marcelo, te queria preguntar el certificado hay que instalarlo para probarlo. O lo podes usar sin instalar. Muchas Gracias

    ResponderEliminar
    Respuestas
    1. Estimado

      Puedes instalar el certificado en la pc y luego trabajar con el. Opcionalmente puedes usar el constructor de x509Certificate2 para cargar el certificado usando la ruta fisica del certificado y su password.

      Eliminar
  36. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  37. Buenos días. Estoy desarollando un proyecto en MVC4 en el cual hago uso de:

    CrSeedClient seedClient = new CrSeedClient();
    string RespuestaSemilla = seedClient.getSeed();

    En un principio me generaba una excepción y lo solucioné actualizando la versión de .NET Framework a la 4.6

    Ahora getSeed(); me devuelve un NULL.
    Pruebo el servicio com programas como SOAPUI y me funciona perfectamente.
    ¿A que puede deberse?
    Gracias de antemano.

    ResponderEliminar
    Respuestas
    1. Hola estimado yo tengo el mismo proble al momento de pedir la semilla, pudo solucionar este problema favor comentar.

      Eliminar
    2. Buena pregunta, lo vamos a investigar
      paciencia

      Eliminar
    3. Buenas tardes.

      Actualmente tengo el mismo problema con la funcion getSeed() que devuelve NULL

      Alguna idea como se puede corregir esto? o es problema de .NET contra SII? Uso la version 4.5.2

      Gracias de antemano.

      Eliminar
  38. Estimado Marcelo, un excelente artículo, pero me gustaría saber si tienes información de cómo leer la información del Certificado instalado en el PC del Cliente a través de la WEB, sin tener el certificado instalado en el Servidor. Estoy pensando en que mi aplicación web está alojada en un Hosting .NET, y el certificado está en los PC de los clientes.
    Saludos y muchas gracias.

    ResponderEliminar
    Respuestas
    1. Estimado,

      De forma ortodoxa no es posible hacer lo que indicas. Necesitas tener un servidor con seguridad y aun así necesitas certificados de autenticación de los emisores de certificados nacionales para poder validar los tuyos. Podrías crear un plugin para el browser y firmar los documentos en tu cliente. Podrías tambien serializar el certificado y su clave privada y cifralos para luego enviarlo al servidor ( OJO )

      Atte.
      Marcelo Rojas Rojas

      Eliminar
  39. Estimado, sabe de alguier que realizara la misma funcion pero en php? mediante php logre obtener la semilla pero no logro entender como firmarla.

    ResponderEliminar
  40. Estimado Marcelo,

    Quería saber si me podría ayudar con lo siguiente:

    En el método para firmar la semilla se cae en la linea:

    //// Cree la firma
    signedXml.ComputeSignature();

    Me sale el siguiente mensaje en esa linea "System.Security. Signing key is not loaded.".

    En mi caso estoy trabajando con visual basic.

    Muchas gracias por su ayuda.

    ResponderEliminar
    Respuestas
    1. Cuando veo que trae la variable Certidicado tengo lo siguiente:

      HasPrivateKey = False
      PrivateKey = Nothing

      Ademas mencionarte que ese certificado lo recién instale hoy en mi maquina para realizar las pruebas. Me aparece como certificados de Otras Personas Issued By E-Sign Class 2 Firma Tributaria CA. ¿Es ese cierto?

      Eliminar
    2. Hola a todos, resolví este problema, y era porque no tenia bien instalado el certificado. Agrego un link en donde pueden ver el manual de instalación de los certificados digitales: http://www.sii.cl/factura_electronica/guia_inst_cert_digital.htm

      Eliminar
  41. Estimados al consumir el WS, me devuelve el siguiente error:

    No such operation 'getToken'

    ResponderEliminar
  42. Buenas Tardes,
    estoy haciendo una prueba de llamar el webservice de obtenet token directamente y el response me trae:




    [string]




    estos es cuando se invoca el el webservice, segun SII, debo colocar "pszXml" el xml q arme , pero debe estar dentro el:.
    Otra duda ya en el request esta el tag "getToken", dentro del tag:pszXml, debe volve a comenzar el getToken otra vez?

    Gracias de antemano por la ayuda.

    ResponderEliminar
    Respuestas
    1. Estimado,

      favor enviar imagen de la respuesta pues no se ve bien lo que mando.

      Gracias

      Eliminar
    2. En el google doc: esta la imagen del response y request. Como te comente quisiera saber que debo enviar en el tag PSZXML
      https://drive.google.com/file/d/1U-yqvCCl1hkwwpb8XszIWXpQOIEOoliR/view?usp=sharing

      Eliminar
  43. Envio request:

    <:ody>

    008953271472PWWnPtCa7f/bsxn0A+xbZ0Vm8T4=Re9esDu+ykmx04nwaTD29KfgCudEwWU3tmXHSbeOdCPZoe7yAGQ5whq9qsqqQlHufDKwbGNbnpEYzdKWMQ0Q8E4k/raCU9XLTv1wCdLeHZ5tkzvoMzNTMaPrmMCur3u0Jo79TGzCkzqRtf/cMZfXj6TVaLu7Wzpw7vsPnzkzw1k=MIIChjCCAe8CCAogGAMEF0QBMA0GCSqGSIb3DQEBCwUAMIGHMQswCQYDVQQGEwJERTEcMBoGA1UEChMTU0FQIFRydXN0IENvbW11bml0eTETMBEGA1UECxMKU0FQIFdlYiBBUzEUMBIGA1UECxMLSTAwMjAyMTEzNTMxLzAtBgNVBAMTJlIzUCBTU0YgU0FNTDIgU2VydmljZSBQcm92aWRlciAtIEZpcm1hMB4XDTE4MDMwNDE3NDQwMVoXDTM4MDEwMTAwMDAwMVowgYcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNTQVAgVHJ1c3QgQ29tbXVuaXR5MRMwEQYDVQQLEwpTQVAgV2ViIEFTMRQwEgYDVQQLEwtJMDAyMDIxMTM1MzEvMC0GA1UEAxMmUjNQIFNTRiBTQU1MMiBTZXJ2aWNlIFByb3ZpZGVyIC0gRmlybWEwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALGVOOTW69eAYXaobe/7VH1apJX0wXJa5XGHbItiUjBaN4BBSbQkw3EudUus8GA4kv3XD+V+2ZQzAgh3vaWPPr7shoGdFNkgdPl5p9YQyXBzTfDJAsfBuzH2MWZV7d/3hQO7kpBp2RDEHVlNZAbUz09pkkiiv+shchkYaa/G8hdFAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAeTB/TVU1PkyjR5AAuWVju+vcEktz92PaQoy0cQ8l8gsNKObTGbeYVb/b0aW2749JFKKzbh0gEjJAFoZ9f+fCfGSxD15Y3t/96YQlUtfPNqtgy2KUQY7t9uLiNxp2SlopOsVIcs4s/X9cGRCHzytw/HmPpBdX8KHoNJEjmK+/EpM=sZU45Nbr14Bhdqht7/tUfVqklfTBclrlcYdsi2JSMFo3gEFJtCTDcS51S6zwYDiS/dcP5X7ZlDMCCHe9pY8+vuyGgZ0U2SB0+Xmn1hDJcHNN8MkCx8G7MfYxZlXt3/eFA7uSkGnZEMQdWU1kBtTPT2mSSKK/6yFyGRhpr8byF0U=AQAB




    el response:




    soapenv:Server.userException
    org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.




    ResponderEliminar
  44. En el google doc: esta la imagen del response y request. Comot e indique quisiera saber que debo enviar en el tag
    https://drive.google.com/file/d/1U-yqvCCl1hkwwpb8XszIWXpQOIEOoliR/view?usp=sharing

    ResponderEliminar
    Respuestas
    1. Estimado,
      tu problema es otro, lo que ocurre es que tienes problemas con la conección al SII. Esto se produce por una actualización de seguridad de windows que se instala de forma automatica en tu equipo. Para solucionar este problema debes ejecutar un script que te ayudará.


      - Crea un archivo con cualquier nombre y colocale extensión reg

      - Luego completa el archivo con las siguientes lineas
      Windows Registry Editor Version 5.00

      [HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319]
      "SchSendAuxRecord"=dword:00000000

      Windows Registry Editor Version 5.00

      [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v4.0.30319]
      "SchSendAuxRecord"=dword:00000000

      - Ejecuta el archivo como administrador de la maquina.

      Esto debería solucionar el problema.

      Atte.
      Marcelo Rojas Rojas

      Eliminar
    2. Buenos dias, De antemano Gracias.

      Aplique el archivo, pero igual me genera el mismo error. Te comento, si solicito el WS sin datos en tag PsZxml, el Ws me responde con un error de los identificado com respuesta, si envio la información en el tab PsZxml me genera ese error de Servidor. No se si el problema radique en que el envio por eso la pregunta orignal si este Tag no va el getToken porque ya esta como parte de WS?.

      Saludos y gracias

      Orangel Tochon

      Eliminar
    3. Buenos dias, al enviar los datos del XMl dentro PSZml , se debe enviar encode, ( sustituir < por < etc) y me entrega el numero de Token.
      Ahora tengo otro problema y no se en que condiciones tiene que estar el ambiente de certificación?
      Cuando envio WS, para solicitar el token con el certificado pero en el ambiente PRD me entrega el token, pero cuando lo hago en el Ambiente de certificación me entre el error "10" con la descripción del error "11".
      Entiendo que el certificado es por rut no por dirección WEb, revisamos y el usuario tiene todos los permisos en Ambiente de Certificación, No se si este ambiente para poder entrar debo estar en estatus de "postulación"?

      Gracias de antemano por la ayuda
      Orangel Tochón

      Eliminar
  45. Estimado, podrian brindarme las urls de los WSDL de CERTIFICACION y PRODUCCION? No encuentro ninguna información. Quisiera las url para acceder a los servicios de:

    - Obtener Semilla
    - Obtener Token
    - Consultar Folios
    - Envio DTE

    ResponderEliminar
  46. No entiendo por qué tienes este código:

    string body = string.Format("{0}", double.Parse(seed).ToString());

    Pudiendo tener esto:

    string body = double.Parse(seed).ToString();

    ResponderEliminar
    Respuestas
    1. Estimado,

      lo que pasa es que la variable seed tiene el siguiente formato
      '00123456789' entonces al convertirla a long solo me queda 123456789 y es ese valor que dejo en body. Técnicamente solo lo deja mas bonito. Gracias por el aporte.

      Atte.
      Marcelo Rojas Rojas

      Eliminar
  47. Sorry, ya entendi, lo que pasa es que tu blog elimina los tags!

    ResponderEliminar
  48. Ojo que en tu codigo tienes esto:

    string body = string.Format("(gettoken)(item)(semilla){0}(/semilla)(/item)(/gettoken)", ...etc)

    Pero semilla debe estar escrito con S mayuscula:

    string body = string.Format("(gettoken)(item)(Semilla){0}(/Semilla)(/item)(/gettoken)", ...etc)

    Nota: usé espacios para que tu blog no se coma los tags

    ResponderEliminar