none
Assinatura RPS RRS feed

  • Pergunta

  • Pessoal, estou tentando fazer a assinatura digital da RPS,para enviar para prefeitura de São Paulo,Estou usando o seguinte codigo em C#.

     

    private static XmlDocument Gera_Assinatura_RPS(XmlDocument Xml, string uri, X509Certificate2 X509Cert)
            {
                try
                {
                    XmlDocument docXML = new XmlDocument();

                    docXML.PreserveWhitespace = true;
                    // Carrega o documento XML
                    docXML = Xml;
                    // Cria o objeto XML assinado
                    SignedXml signedXml = new SignedXml(docXML);
                    // Assina com a chave privada
                    signedXml.SigningKey = X509Cert.PrivateKey;
                    // Atribui o método de canonização
                    signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
                    // Atribui o método para assinatura
                    signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
                    // Cria a referencia
                    Reference reference = new Reference();
                 
                    // Pega a URI para ser assinada

                    XmlAttributeCollection _Uri = docXML.GetElementsByTagName(uri).Item(0).Attributes;
                    foreach (XmlAttribute _atributo in _Uri)
                    {
                        if (_atributo.Name == "xmlns")
                            reference.Uri = "#" + _atributo.InnerText;
                    }

                    // Adiciona o envelope à referência
                    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                    reference.AddTransform(env);
                    // Atribui o método do Hash
                    reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
                    // Adiciona a referencia ao XML assinado
                    signedXml.AddReference(reference);
                    // Cria o objeto keyInfo
                    KeyInfo keyInfo = new KeyInfo();
                    // Carrega a informação da KeyInfo
                    KeyInfoClause rsaKeyVal = new RSAKeyValue((System.Security.Cryptography.RSA)X509Cert.PrivateKey);
                    KeyInfoX509Data x509Data = new KeyInfoX509Data(X509Cert);
                    x509Data.AddSubjectName(X509Cert.SubjectName.Name.ToString());
                    keyInfo.AddClause(x509Data);
                    keyInfo.AddClause(rsaKeyVal);
                    // Adiciona a KeyInfo
                    signedXml.KeyInfo = keyInfo;
                    // Atribui uma ID à assinatura
                    ///signedXml.Signature.Id = "Assigned" + uri;
                    signedXml.Signature.Id = signedXml.Signature.Id + uri;
                    // Efetiva a assinatura
                    signedXml.ComputeSignature();
                    // Obtem o XML assinado
                    XmlElement xmlDigitalSignature = signedXml.GetXml();
                    // Adiciona o elemento assinado ao XML
                    docXML.DocumentElement.AppendChild(docXML.ImportNode(xmlDigitalSignature, true));
                    // Retorna o XML
                    return docXML;
                }
                catch (Exception erro) { throw erro; }
            }

     

    so que quando vou efetuar a assinatura no comando signedXml.ComputeSignature(); ele me traz o erro Elemento de referência mal formado., sera que alguem sabe o que esta acontecendo.

    Obrigado.

    segunda-feira, 17 de janeiro de 2011 18:20

Todas as Respostas

  • Veja esta dica da microsoft: http://msdn.microsoft.com/en-us/library/x8xwex4b.aspx

     


    Just Be Humble Malange!
    terça-feira, 18 de janeiro de 2011 14:47
    Moderador
  • Malange nesse exemplo pelo que entendi ele esta assinando o arquivo inteiro, no meu caso preciso assinar uma RPS separadamente e depois adicionar essa RPS a um lote e assinar o lote tambem?
    terça-feira, 18 de janeiro de 2011 15:13
  • Malange nesse exemplo pelo que entendi ele esta assinando o arquivo inteiro, no meu caso preciso assinar uma RPS separadamente e depois adicionar essa RPS a um lote e assinar o lote tambem?


    E ai alguem poderia me ajudar com a assinatura da rps de são paulo, ja consigo assinar o lote mas não estou conseguindo assinar individualmente cada rps.

    Obrigado

     

    sábado, 5 de fevereiro de 2011 21:46
  • Estou com o mesmo problema do rafael achei esse código em c# (http://nf-eletronica.com/blog/?p=47) que assina todo o xml

    mais preciso que ele assine tbm após cada tag infrps.

    segunda-feira, 7 de fevereiro de 2011 13:06
  • Estou com o mesmo problema do rafael achei esse código em c# (http://nf-eletronica.com/blog/?p=47) que assina todo o xml

    mais preciso que ele assine tbm após cada tag infrps.

    Ricardo da uma olhada nesse link, e ve se te ajuda.

    https://nfse.recife.pe.gov.br/arquivos/WsNFSeNacional.pdf

    segunda-feira, 7 de fevereiro de 2011 17:44
  • Rafael, no meu caso eh BH, mais mesmo assim não tinha nada mostrando como assiner a RPS.

    vc conseguiu assinar as RPS? Anota meus contatos ai ricardodavidss@gtalk.com, fox_3_d@hotmail.com

     

    segunda-feira, 7 de fevereiro de 2011 18:55
  • Rafael, no meu caso eh BH, mais mesmo assim não tinha nada mostrando como assiner a RPS.

    vc conseguiu assinar as RPS? Anota meus contatos ai ricardodavidss@gtalk.com, fox_3_d@hotmail.com

     

    Ricardo no meu caso e São Paulo, mas não consegui tambem.
    segunda-feira, 7 de fevereiro de 2011 19:55
  • Rafael, no meu caso eh BH, mais mesmo assim não tinha nada mostrando como assiner a RPS.

    vc conseguiu assinar as RPS? Anota meus contatos ai ricardodavidss@gtalk.com, fox_3_d@hotmail.com

     

    Ricardo no meu caso e São Paulo, mas não consegui tambem.

    Alguém conseguiu resolver isso?
    sexta-feira, 25 de março de 2011 02:01
  • Rafael, no meu caso eh BH, mais mesmo assim não tinha nada mostrando como assiner a RPS.

    vc conseguiu assinar as RPS? Anota meus contatos ai ricardodavidss@gtalk.com, fox_3_d@hotmail.com

     

    Ricardo no meu caso e São Paulo, mas não consegui tambem.

    Alguém conseguiu resolver isso?

    Boa tarde, vocês conseguiram resolver este problema?

    Estou com a mesma dúvida, principalmente em relação a São Paulo, pois não sei se funciona da forma que o Rafael falou,

    de assinar cada rps e em seguida assinar o lote?

    Ajuda aí pessoal!

    terça-feira, 12 de julho de 2011 21:10
  • Rodrigo bom dia, estou com o mesmo problema em São Paulo... você conseguiu resolver ?
    quarta-feira, 13 de julho de 2011 14:44
  • Rodrigo bom dia, estou com o mesmo problema em São Paulo... você conseguiu resolver ?

    Infelizmente não meu amigo, mas na verdade estou conseguindo assinar, porém da forma incorreta, pelo menos é o retorno que estou tendo do webservice:

    <Codigo>1206</Codigo>
    <Descricao>Assinatura Digital do RPS incorreta.</Descricao>

    Mandei um e-mail para prefeitura de SP, com o arquivo em anexo para ver se eles me auxiliam, qualquer novidade posto por aqui, peço a todos que façam o mesmo para nos ajudarmos.

    Abraço!

    • Sugerido como Resposta Rodrigo Valença segunda-feira, 1 de agosto de 2011 20:35
    segunda-feira, 25 de julho de 2011 21:02
  • Ola Rodrigo, o que você tem que fazer e assinar cada RPS separadamente depois adicionar essas RPS no lote e assinar o lote.
    terça-feira, 26 de julho de 2011 14:21
  • Rodrigo bom dia, estou com o mesmo problema em São Paulo... você conseguiu resolver ?

    Consegui resolver...

    No meu caso o problema era na assinatura adicional que corresponde aquela assinatura da cadeia de caracteres que devemos montar. Eu estava montando essa string com o valor de serviços e deduções sem utilizar os zeros dos centavos, por exemplo:

    250,00 (Valor dos serviços)

    000000000000250 (Valor que eu estava montando, errado!)

    000000000025000 (Valor correto a ser montado)

    Portanto AdemirLuiz, verifica se você está montando direitinho essa string que devemos assinar para cada RPS.

    Obrigado a Rafa Alves e aos demais colegas!


    segunda-feira, 1 de agosto de 2011 20:35
  • Ola Rafa e demais colegas...

     

    Meu problema agora é outro, estou tentando utilizar o método de consulta de lote RPS, e não estou entendendo muito quanto a mensagem xml. Lembrando que isso é referente a São Paulo, estou com dúvidas na parte "Signature", elemento exigido na estrutura da msg a ser enviada pela consulta. Gostaria de saber se neste elemento "Signature", vou apenas copiar o conteúdo existente no mesmo elemento("Signature") encontrado no lote já enviado, ou se devo montar essa estrutura, ex: Cabecalho, NumerodoLote ,etc, em um arquivo xml e gerar uma nova assinatura específica deste xml.

    Obrigado, aguardo uma resposta.

    segunda-feira, 1 de agosto de 2011 20:43
  • Rodrigo eu estou com o mesmo problema.  Já conferi item por item da cadeia de caracteres e está tudo rigorosamente dentro do padrão do manual.  Mas ainda assim eu continuo recebendo o mesmo erro.  Estou assinando da seguinte forma:

     

    AssinarRPS(X509Certificate2 cert, String sAssinatura) 
    { 
    ASCIIEncoding enc = new ASCIIEncoding(); 
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
    SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
    rsa = cert.PrivateKey as RSACryptoServiceProvider;
    byte[] sAssinaturaByte = enc.GetBytes(sAssinatura); 
    byte[] hash = sha1.ComputeHash(sAssinaturaByte); 
    sAssinaturaByte = rsa.SignHash(hash, "SHA1"); 
    string convertido = Convert.ToBase64String(sAssinaturaByte);
    return convertido; 
    }

    Alguma dica?

    segunda-feira, 1 de agosto de 2011 21:24
  • Rodrigo eu estou com o mesmo problema.  Já conferi item por item da cadeia de caracteres e está tudo rigorosamente dentro do padrão do manual.  Mas ainda assim eu continuo recebendo o mesmo erro.  Estou assinando da seguinte forma:

     

     

    AssinarRPS(X509Certificate2 cert, String sAssinatura) 
    { 
    ASCIIEncoding enc = new ASCIIEncoding(); 
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
    SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
    rsa = cert.PrivateKey as RSACryptoServiceProvider;
    byte[] sAssinaturaByte = enc.GetBytes(sAssinatura); 
    byte[] hash = sha1.ComputeHash(sAssinaturaByte); 
    sAssinaturaByte = rsa.SignHash(hash, "SHA1"); 
    string convertido = Convert.ToBase64String(sAssinaturaByte);
    return convertido; 
    }

    Alguma dica?

     

    Abaixo segue meu código em C#, aparentemente o teu tá correto, mas mesmo assim analisa direitinho. Outra dica: vai debugando o projeto e no final quando a string estiver montada, você confere mesmo se está correta, após isso você deixa o método assiná-la para ver se dar certo. Analisa bem, pois no começo eu estava achando que eu estava fazendo correto, mas por uma bobagem já não é validado. Boa sorte!
    public static string AssinaturaAdicional(string texto)
            {           
                X509Certificate2 cert = new X509Certificate2();
                Certificado certificado = new Certificado();
                cert = certificado.BuscaNroSerie(util.ParametroConfig("NoSerieCertificado", "xxx"), false, false);
                try
                {
                    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
                    RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                    RSA = (RSACryptoServiceProvider)cert.PrivateKey;
                    
                    byte[] sAssinaturaByte = enc.GetBytes(texto);
                    RSAPKCS1SignatureFormatter rsaf = new RSAPKCS1SignatureFormatter(RSA);
                    SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
                    byte[] hash = null;
                    hash = SHA1.ComputeHash(sAssinaturaByte);
                    rsaf.SetHashAlgorithm("SHA1");
                    sAssinaturaByte = rsaf.CreateSignature(hash);
                    string convertido = null;
                    convertido = Convert.ToBase64String(sAssinaturaByte);
                    
                    return convertido;
                }
    terça-feira, 2 de agosto de 2011 11:17
  • Prezados Amigos,

     

    Depois de muito procurar por todos os fóruns e nunca encontrar a solução para resolver o problema da assinatura adicional do RPS que sempre retornava o erro 1206 <Descricao>Assinatura Digital do RPS incorreta.</Descricao>, com a ajuda do Rodrigo e do meu amigo George consegui a validação do PedidoEnvioLoteRPS.

    Tudo não passa de uma grande falta de atenção:

    O problema na maioria das vezes não está no Hash que geramos com sha1 e nem na assinatura com RSA-SHA1. A maioria dos códigos que encontramos por aí pelos fóruns explicando como fazer esta assinatura estão corretos. O grande problema na maioria dos casos, acredito eu, está na concatenação dos campos para formar a string de 86 posições.

    Se está recebendo o erro 1206 e está utilizando o método abaixo para a assinatura adicional e seu RPS é da cidade de são paulo, então meu amigo é muito provável que seu erro esteja na concatenação da string, mais precisamente nos campos ValorServicos e ValorDeducoes.

    O que ocorre é que na maioria das vezes quando as pessoas descobrem o erro, se calam, mas todos procuram ajuda. NÃO VOU ME CALAR!!! RS

    Seguindo a boa vontade do Rodrigo Valença que descobriu e postou a solução reforçarei o comentário dele concordando com o que disse que mesmo após eu ler achei que não houvesse erros na minha string.

    Veja abaixo:

    R$ 20.500,00 (Valor dos serviços)

    R$ 5.000,00 (Valor das Deduções)

     

    De acordo com o exemplo do manual, o valor de R$ 20.500,00 fica assim no xml <ValorServicos>20500</ValorServicos>

    Repare que no xml foi ocultado as casas decimais.

     

    Naturalmente acabamos montando desta forma o nosso xml e na hora de montar a string apenas pegamos este valor e acrescentamos os zeros à esquerda ficando assim: 000000000020500 (ESTÁ ERRADOOO!!!)

    Precisamos exibir as duas casas decimais, mesmo sendo Zero.

    Forma correta do ValorServicos na string é 000000002050000

    Tendo esta atenção para estes dois campos possivelmente você conseguirá ver o tão esperado true nas tags <Sucesso>true</Sucesso> do retorno.

    O método para assinar segue abaixo:

     

    AssinarRPS(X509Certificate2 cert, String sAssinatura) 
    { 
    ASCIIEncoding enc = new ASCIIEncoding(); 
    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
    SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider(); 
    rsa = cert.PrivateKey as RSACryptoServiceProvider;
    byte[] sAssinaturaByte = enc.GetBytes(sAssinatura); 
    byte[] hash = sha1.ComputeHash(sAssinaturaByte); 
    sAssinaturaByte = rsa.SignHash(hash, "SHA1"); 
    string convertido = Convert.ToBase64String(sAssinaturaByte);
    return convertido; 
    }

     

    Um grande abraço para todos e muitíssimo obrigado pela ajuda Rodrigo!!!

     

    • Sugerido como Resposta HugoFernandes_ quinta-feira, 13 de setembro de 2012 15:49
    terça-feira, 2 de agosto de 2011 18:02
  • Valeu, parabens Leandro. Boa sorte na continuidade do projeto!

     

    Abraço!

    quarta-feira, 3 de agosto de 2011 11:47
  • Ola Rafa e demais colegas...

     

     Meu problema agora é outro, estou tentando utilizar o método de consulta de lote RPS, e não estou entendendo muito quanto a mensagem xml. Lembrando que isso é referente a São Paulo, estou com dúvidas na parte "Signature", elemento exigido na estrutura da msg a ser enviada pela consulta. Gostaria de saber se neste elemento "Signature", vou apenas copiar o conteúdo existente no mesmo elemento("Signature") encontrado no lote já enviado, ou se devo montar essa estrutura, ex: Cabecalho, NumerodoLote ,etc, em um arquivo xml e gerar uma nova assinatura específica deste xml.

    Obrigado, aguardo uma resposta.

    Pessoal, quanto a esta minha dúvida, falando com o suporte de SP, me explicaram que cada uma das mensagens a serem enviadas, precisam de assinaturas. Portanto, cada mensagem obrigatoriamente precisa de sua própria assinatura. 

    Desculpem pela dúvida boba, mas na dúvida melhor perguntar. :P

    Abraço!

    quarta-feira, 3 de agosto de 2011 11:50
  • Estava a horas quebrando a cabeça, era exatamente isso. Muitissimo obrigado Leandro e Rodrigo.
    quinta-feira, 7 de novembro de 2013 19:33
  •     public class Assinador
        {
            public string Ass(string xmlMensagem, string uri)
            {
                //
                //   le o arquivo xml
                //
                string _uri;
                string _stringXml;
    
                _stringXml = xmlMensagem;
                _uri = uri;
                //
                //  realiza assinatura
                //
                AssinaturaDigital AD = new AssinaturaDigital();
                //
                //  cria cert
                //
                X509Certificate2 cert = new X509Certificate2();
                //
                //  seleciona certificado do repositório MY do windows
                //
                Certificado certificado = new Certificado();
                cert = certificado.BuscaNomeCert2("CN=NFe - Associacao NF-e:99999090910270, C=BR, L=PORTO ALEGRE, O=Teste Projeto NFe RS, OU=Teste Projeto NFe RS, S=RS");
    
                //int resultado = AD.Assinar(_stringXml, _uri, cert);
    
                string result = string.Empty;
    
                try
                {
                    XmlDocument xmlDoc = AD.AplicaAssinatura(_stringXml, _uri, cert);
                    result = xmlDoc.OuterXml;
                }
    
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
    
                return result;
            }
    
        }
    
        public class AssinaturaDigital
        {
            public XmlDocument AplicaAssinatura(string xml, string uri, X509Certificate2 cert)
            {
                try
                {
                    // Obtem o certificado
                    X509Certificate2 X509Cert = cert;
                    // Cria um documento XML para carregar o XML
                    XmlDocument docXML = new XmlDocument();
                    docXML.PreserveWhitespace = true;
                    // Carrega o documento XML
                    docXML.LoadXml(xml);
                    // Cria o objeto XML assinado
                    SignedXml signedXml = new SignedXml(docXML);
                    // Assina com a chave privada
                    signedXml.SigningKey = X509Cert.PrivateKey;
                    // Atribui o método de canonização
                    signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
                    // Atribui o método para assinatura
                    signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
                    // Cria a referencia
                    Reference reference = new Reference("");
                    // Pega a URI para ser assinada
                    XmlAttributeCollection _Uri = docXML.GetElementsByTagName(uri).Item(0).Attributes;
                    foreach (XmlAttribute _atributo in _Uri)
                    {
                        if (_atributo.Name == "Id")
                            reference.Uri = "#" + _atributo.InnerText;
                    }
                    // Adiciona o envelope à referência
                    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
                    reference.AddTransform(env);
                    // Atribui o método do Hash
                    reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
                    // Adiciona a referencia ao XML assinado
                    signedXml.AddReference(reference);
                    // Cria o objeto keyInfo
                    KeyInfo keyInfo = new KeyInfo();
                    // Carrega a informação da KeyInfo
                    KeyInfoClause rsaKeyVal = new RSAKeyValue((RSA)X509Cert.PrivateKey);
                    KeyInfoX509Data x509Data = new KeyInfoX509Data(X509Cert);
                    x509Data.AddSubjectName(X509Cert.SubjectName.Name.ToString());
                    keyInfo.AddClause(x509Data);
                    keyInfo.AddClause(rsaKeyVal);
                    // Adiciona a KeyInfo
                    signedXml.KeyInfo = keyInfo;
                    // Atribui uma ID à assinatura
                    signedXml.Signature.Id = "#" + uri;
                    // Efetiva a assinatura
                    signedXml.ComputeSignature();
                    bool signed = signedXml.CheckSignature(cert, true);
                    // Obtem o XML assinado
                    XmlElement xmlDigitalSignature = signedXml.GetXml();
                    // Adiciona o elemento assinado ao XML
                    docXML.DocumentElement.AppendChild(docXML.ImportNode(xmlDigitalSignature, true));
    
                    // Retorna o XML
                    return docXML;
                }
                catch (Exception erro) { throw erro; }
            }
        }
    
        public class Certificado
        {
            public X509Certificate2 BuscaNomeCert2(string nome)
            {
                X509Store store = new X509Store(StoreLocation.CurrentUser);
                store.Open(OpenFlags.ReadWrite);
                X509Certificate2Collection certCollection = store.Certificates;
                X509Certificate2 cert = null;
    
                // Loop through each certificate and find the certificate 
                // with the appropriate name.
                foreach (X509Certificate2 c in certCollection)
                {
                    if (c.Subject == nome)
                    {
                        cert = c;
                        break;
                    }
                }
                store.Close();
                return cert;
            }

    Deu certo pra mim assim... Normalmente no trecho onde tem Reference reference = new Reference(""), as pessoas esquecem de colocar as aspas pra dizer que não é uma transformação envelopada... Se funcionar, por favor, marcar como resposta... ;)

    Igo Soares Ventura (17)

    igo1-2@hotmail.com

    igo.scitus@hotmail.com

    SCITUS Informática - Excelência na Qualidade


    quarta-feira, 10 de setembro de 2014 19:55