sexta-feira, 15 de maio de 2009

NF-e: Criando um validador para a NF-e em VB.NET


Vamos criar um pequeno aplicativo de validação da Nf-e, executável
em uma chamada por parâmetro. Para executar esse aplicativo, simplesmente
você deverá clicar no botão Iniciar no Windows e selecionar a opção Executar
no menu, informando o seguinte comando:

C:\ValidarNfe.exe C:\NF-E\13090404672291000115550040000000270000000730-nfe.xml

Veja o o exemplo na figura abaixo:





1) Inicie um novo projeto no Vb.NET.

2) Defina nas referências do projeto (Menu Projects - ValidarNfe Properties - aba References) os seguintes namespaces:

System
System.Data
System.Deployment
System.Drawing
System.Security
System.Web.Services
System.Windows.Forms
System.Xml

3) Inclua no formulário uma timer, uma label, um listbox e um botão.


A tela deve ficar como o mostrado abaixo:



4) Defina a propriedade interval do timer em 1000, e dê dois cliques sobre ele. Informe o seguinte código para o Timer:

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Show()
End Sub



5) Dentro do código do formulário (form1.vb), no início do mesmo, inclua as seguintes referências:

Imports System.Collections.Generic
Imports System.Text
Imports System.Xml
Imports System.Xml.Schema
Imports System.IO
Imports System.Windows.Forms
Imports System.Security.Cryptography.Xml
Imports System.Security.Cryptography.X509Certificates


6) No evento Load do formulário, acrescente este código:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim Valor As String

Me.Show()
If Command() <> "" Then
Valor = Command()
ValidaNfe(Valor)

Me.Focus()
Me.Show()
Me.WindowState = FormWindowState.Normal

End If

End Sub


7) O código do botão Fechar deve ser o que segue abaixo:

Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
End
End Sub

8) A função ValidaNfe é a que segue abaixo:

Private Sub ValidaNfe(ByVal NfeAler As String)

Try

'Abrir agora o arquivo XML criado e inserir o Protocolo encontrado!!
Dim arquivo2 As String = NfeAler
Dim xDoc As New XmlDocument : xDoc.Load(arquivo2)
Dim Tamanho As String
Dim Nfe As String


Nfe = arquivo2
Tamanho = Replace(Nfe, "C:\", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\BACKUP\200905\", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\BACKUP", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\AENVIAR", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\AENVIAR", "")
Tamanho = Replace(Tamanho, "\", "")
Tamanho = Replace(Tamanho, "\NF-E", "")
Tamanho = Replace(Tamanho, "NF-E", "")
Tamanho = Replace(Tamanho, "SisWin", "")
Tamanho = Replace(Tamanho, "SisWin", "")

'Fazer uma cópia d arquivo XML para gerar a assinatura
Dim CaminhoArquivo As String = "C:\NF-E\XML\" + Tamanho

'Salva o Arquivo
xDoc.Save(CaminhoArquivo)

'Selecionar certificado
SelecionarCertificado()

'Assinar o XML
Dim OAd As New AssinaturaDigitalClass()
Dim pDadosNfe As String
Dim vStringNfe As String
'Dim msgResultado As String


OAd.Assinar(CaminhoArquivo, "infNFe", oCertificado)

If OAd.vResultado = 0 Then 'Assinado corretamente

pDadosNfe = OAd.vXMLStringAssinado
vStringNfe = pDadosNfe.Substring(pDadosNfe.IndexOf("<NFe"), pDadosNfe.Length - pDadosNfe.IndexOf("<NFe"))


Else 'Ocorreu algum erro na assinatura
MessageBox.Show(OAd.vResultadoString, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If

'Validar o XML
Dim TxtXSD As String

TxtXSD = "C:\tmp\Schemas NF-e\nfe_v1.10.xsd"

If Not CaminhoArquivo = String.Empty And Not TxtXSD = String.Empty Then

Resultado = True
Dim settings As New XmlReaderSettings()
AddHandler settings.ValidationEventHandler, AddressOf Me.ValidationEventHandler

'Valida o arquivo XML com o seu Schema XSD
lstValida.Items.Add("Validando o arquivo XML " & CaminhoArquivo & " com o arquivo de Schema : " & TxtXSD)

Try

settings.ValidationType = ValidationType.Schema
settings.Schemas.Add("http://www.portalfiscal.inf.br/nfe",xmlReader.Create(TxtXSD))
Using XmlValidatingReader As XmlReader = XmlReader.Create(CaminhoArquivo, settings)
While XmlValidatingReader.Read()

End While

End Using

Catch ex As Exception

lstValida.Items.Add(ex.Message)
Exit Sub
End Try

lstValida.Items.Add("Status Validação -> " & IIf(Resultado = True, "Arquivo validado com SUCESSO", "Validação FALHOU"))

Else
MsgBox("Informe o arquivo XML e o arquivo XSD.")
End If


Catch ex As Exception

'se ocorrer uma exceção exibe a mensagem
lstValida.Items.Add(ex.Message)

End Try

End Sub

A função ValidaNfe chama outras duas funções em seu início: uma que seleciona o certificado automaticamente e outra que assina o documento. O código da função SelecionarCertificado() é que segue abaixo:

Function SelecionarCertificado() As Boolean

Dim vRetorna As Boolean
Dim oX509Cert As New X509Certificate2
Dim store As New X509Store
Dim collection As New X509Certificate2Collection
Dim collection1 As New X509Certificate2Collection
Dim collection2 As New X509Certificate2Collection
Dim scollection As New X509Certificate2Collection
Dim msgResultado As String
Dim xnome As String

xnome = "CN=CERTIFICADOTESTE:09999991000115, OU=Autenticado por AR Fenacon, OU=RFB e-CNPJ A1, OU=Secretaria da Receita Federal do Brasil - RFB, L=Manaus, S=AM, O=ICP-Brasil, C=BR"

oX509Cert = New X509Certificate2()
store = New X509Store("MY", StoreLocation.CurrentUser)
store.Open(OpenFlags.ReadOnly Or OpenFlags.OpenExistingOnly)
collection = store.Certificates
collection1 = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, False)
collection2 = collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, False)

'Encontra o certificado digital pelo nome do mesmo, se precisar pergunta por isso
'Resolvido em 13/05/2009 às 15:05h
scollection = collection.Find(X509FindType.FindBySubjectDistinguishedName, xnome, False)


'Para selecionar o certificado de uma lista
'scollection = X509Certificate2UI.SelectFromCollection(collection2, "Certificado(s) Digital(is) disponível(is)", "Selecione o certificado digital para uso no aplicativo", X509SelectionFlag.SingleSelection)

If (scollection.Count = 0) Then

msgResultado = "Nenhum certificado digital foi selecionado ou o certificado selecionado está com problemas."
MessageBox.Show(msgResultado, "Advertência", MessageBoxButtons.OK, MessageBoxIcon.Warning)
vRetorna = False

Else

oX509Cert = scollection.Item(0) 'Para selecionar o item em Vb.NET
oCertificado = oX509Cert
vRetorna = True
'msgResultado = "Certificado Selecionado."
'MessageBox.Show(msgResultado, "Advertência", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Return vRetorna

End If

End Function

-----------------

Voce deve informar em xnome o nome por extenso do Certificado que irá usar para validar a XML a ser assinado. Para obter o nome por extenso do seu certificado você pode usar a próprioa função acima habilitando a que pede a seleção de certicados de uma lista e colocando o seguinte comando no Else da função acima:

xnome = oCertificado.Subject.ToString

Esse comando colocará o nome do certificado na variável xnome. Se você debugar, pode pegar o nome extenso do certificado que deve usar para validar o XML e colocar dentro da váriavel, como fiz no início do código:

xnome = "CN=CERTIFICADOTESTE:09999991000115, OU=Autenticado por AR Fenacon, OU=RFB e-CNPJ A1, OU=Secretaria da Receita Federal do Brasil - RFB, L=Manaus, S=AM, O=ICP-Brasil, C=BR"


Para a assinatura digital uma classe é acrescentada totalmente no final da classe do formulário. Essa classe é responsável pela assinatura do XML. Eis o código abaixo:

Public Class AssinaturaDigitalClass

Public vResultado As Integer
Public vResultadoString As String
Public vXMLStringAssinado As String
Public XmlDoc As XmlDocument

Sub Assinar(ByVal pArqXMLAssinar As String, ByVal pUri As String, ByVal pCertificado As X509Certificate2)

'Abrir o arquivo XML a ser assinado e ler o seu conteúdo
Dim SR As StreamReader
Dim vXMLString As String

SR = File.OpenText(pArqXMLAssinar)
vXMLString = SR.ReadToEnd()
SR.Close()

' //Atualizar atributos de retorno com conteúdo padrão
vResultado = 0
vResultadoString = "Assinatura realizada com sucesso"

Try

'Verifica o certificado a ser utilizado na assinatura
Dim _xnome As String
Dim _X509Cert As X509Certificate2
Dim store As X509Store
Dim collection As X509Certificate2Collection
Dim collection1 As X509Certificate2Collection

_xnome = ""

_xnome = pCertificado.Subject.ToString()

_X509Cert = New X509Certificate2()
store = New X509Store("MY", StoreLocation.CurrentUser)
store.Open(OpenFlags.ReadOnly Or OpenFlags.OpenExistingOnly)

collection = store.Certificates
collection1 = collection.Find(X509FindType.FindBySubjectDistinguishedName, _xnome, False)


If (collection1.Count = 0) Then
vResultado = 2
vResultadoString = "Problemas no certificado digital"
Else

' certificado ok
'oX509Cert = scollection.Item(0)

_X509Cert = collection1.Item(0)
Dim x As String
x = _X509Cert.GetKeyAlgorithm().ToString()

' Create a new XML document.
Dim doc As New XmlDocument
doc = New XmlDocument()

'Format the document to ignore white spaces.
doc.PreserveWhitespace = False

' Load the passed XML file using it’s name.
Try
doc.LoadXml(vXMLString)

' Verifica se a tag a ser assinada existe é única
Dim qtdeRefUri As Integer
qtdeRefUri = doc.GetElementsByTagName(pUri).Count

If (qtdeRefUri = 0) Then
' a URI indicada não existe
vResultado = 4
vResultadoString = "A tag de assinatura " + pUri.Trim() + " não existe"

Else
' Existe mais de uma tag a ser assinada
If (qtdeRefUri > 1) Then
' existe mais de uma URI indicada
vResultado = 5
vResultadoString = "A tag de assinatura " + pUri.Trim() + " não é unica"
Else

Try
' Create a SignedXml object.
Dim signedXml As SignedXml
signedXml = New SignedXml(doc)

' Add the key to the SignedXml document
signedXml.SigningKey = _X509Cert.PrivateKey

' Create a reference to be signed
Dim reference As New Reference
reference = New Reference()

'--------- RETIRAR COMENTÁRIOS DAS LINHAS ABAIXO
' pega o uri que deve ser assinada
Dim _Uri As XmlAttributeCollection
Dim _atributo As XmlAttribute

_Uri = doc.GetElementsByTagName(pUri).Item(0).Attributes
For Each _atributo In _Uri
If (_atributo.Name = "Id") Then
reference.Uri = "#" + _atributo.InnerText

End If
Next

' Add an enveloped transformation to the reference.
Dim env As New XmlDsigEnvelopedSignatureTransform
env = New XmlDsigEnvelopedSignatureTransform()
reference.AddTransform(env)

Dim c14 As New XmlDsigC14NTransform
c14 = New XmlDsigC14NTransform()
reference.AddTransform(c14)

' Add the reference to the SignedXml object.
signedXml.AddReference(reference)

' Create a new KeyInfo object
Dim keyinfo As New KeyInfo
keyinfo = New KeyInfo()

' Load the certificate into a KeyInfoX509Data object
' and add it to the KeyInfo object.
keyinfo.AddClause(New KeyInfoX509Data(_X509Cert))

' Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyinfo
signedXml.ComputeSignature()

' Get the XML representation of the signature and save
' it to an XmlElement object.
Dim xmlDigitalSignature As XmlElement
xmlDigitalSignature = signedXml.GetXml()

' Gravar o elemento no documento XML
doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, True))
XmlDoc = New XmlDocument()
XmlDoc.PreserveWhitespace = False
XmlDoc = doc

' Atualizar a string do XML já assinada
vXMLStringAssinado = XmlDoc.OuterXml

' Gravar o XML no HD
' abre um stream para escrita e cria um StreamWriter para implementar o stream
Dim fs As New FileStream(pArqXMLAssinar, FileMode.OpenOrCreate, FileAccess.Write)
Dim SW_2 As New StreamWriter(fs)
SW_2.Flush()
SW_2.BaseStream.Seek(0, SeekOrigin.Begin)
SW_2.Write(vXMLStringAssinado)
SW_2.Flush()
SW_2.Close()

Catch ex As Exception
vResultado = 6
vResultadoString = "Erro ao assinar o documento - " + ex.Message

End Try

End If

End If

Catch ex As Exception

vResultado = 3
vResultadoString = "XML mal formado - " + ex.Message

End Try

End If

Catch ex As Exception

vResultado = 1
vResultadoString = "Problema ao acessar o certificado digital" + ex.Message

End Try

End Sub

End Class


9) Dentro do botão que faz a validação é repassado o código do arquivo XSD que faz a validação:

TxtXSD = "C:\tmp\Schemas NF-e\nfe_v1.10.xsd"

Um EventHandler se faz necessário para a leitura da validação do XSD.

Abaixo, vemos o código da função de validação do EventHandler:


Public Sub ValidationEventHandler(ByVal sender As Object, ByVal args As ValidationEventArgs)


Resultado = False

'lstValida.Items.Add(vbTab + "Erro de Validação : " + args.Message)

If args.Severity = XmlSeverityType.Warning Then

MsgBox("Nenhum arquivo de Schema foi encontrado para efetuar a validação...")

ElseIf args.Severity = XmlSeverityType.Error Then

lstValida.Items.Add(args.Message)
'MsgBox("Ocorreu um erro durante a validação....")

End If

If Not (args.Exception Is Nothing) Then ' Erro na validação do schema XSD

'lstValida.Items.Add(args.Exception.SourceUri + "," & args.Exception.LinePosition & "," & args.Exception.LineNumber)
'MsgBox(args.Exception.SourceUri + "," & args.Exception.LinePosition & "," & args.Exception.LineNumber)

End If

End Sub

Essa função será chamada para retornar o erro que possa estar acontecendo com algum ponto do arquivo XML.

Pronto!!

Cada passo de uma validação para a Nf-e foi descrita acima.

Posto o código completo do arquivo form1.VB abaixo para dirrimir quaisquer dúvidas:

'Validador para arquivos Nf-e
'Data de criação: 12/05/2009
'Para ser utilizado com o Visual Basic 6
'A aplicação funciona com chamada de parâmetro na linha digitável
'Para executar esse aplicativo, use a linha de comando do Windwos
'clicando no botão iniciar de depois em Executar:
'Exemplo de chamada: C:\ValidarNfe.exe C:\NF-E\13090404672291000115550040000000270000000730-nfe.xml
'Desenvolvedor: Manoel Leonardo Metelis Florindo

Imports System.Collections.Generic
Imports System.Text
Imports System.Xml
Imports System.Xml.Schema
Imports System.IO
Imports System.Windows.Forms
Imports System.Security.Cryptography.Xml
Imports System.Security.Cryptography.X509Certificates

Public Class Form1

Private Resultado As Boolean = True
Public oCertificado As New X509Certificate2
Public vStrXmlRetorno As String
Public vArqERRRetorno As String
Public vPastaXMLErro As String
Public vPastaXMLEnvio As String
Public vArqXMLRetorno As String
Public vPastaXMLRetorno As String
Public vXmlNfeDadosMsg As String
Public vAmbiente As Integer
Public vUF As Integer

Private Sub ValidaNfe(ByVal NfeAler As String)

Try

'Abrir agora o arquivo XML criado e inserir o Protocolo encontrado!!
Dim arquivo2 As String = NfeAler
Dim xDoc As New XmlDocument : xDoc.Load(arquivo2)
Dim Tamanho As String
Dim Nfe As String


Nfe = arquivo2
Tamanho = Replace(Nfe, "C:\", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\BACKUP\200905\", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\BACKUP", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\AENVIAR", "")
Tamanho = Replace(Tamanho, "F:\SisWin\NFE\AENVIAR", "")
Tamanho = Replace(Tamanho, "\", "")
Tamanho = Replace(Tamanho, "\NF-E", "")
Tamanho = Replace(Tamanho, "NF-E", "")
Tamanho = Replace(Tamanho, "SisWin", "")
Tamanho = Replace(Tamanho, "SisWin", "")

'Fazer uma cópia d arquivo XML para gerar a assinatura
Dim CaminhoArquivo As String = "C:\NF-E\XML\" + Tamanho

'Salva o Arquivo
xDoc.Save(CaminhoArquivo)

'Selecionar certificado
SelecionarCertificado()

'Assinar o XML
Dim OAd As New AssinaturaDigitalClass()
Dim pDadosNfe As String
Dim vStringNfe As String
'Dim msgResultado As String


OAd.Assinar(CaminhoArquivo, "infNFe", oCertificado)

If OAd.vResultado = 0 Then 'Assinado corretamente

pDadosNfe = OAd.vXMLStringAssinado
vStringNfe = pDadosNfe.Substring(pDadosNfe.IndexOf("<NFe"), pDadosNfe.Length - pDadosNfe.IndexOf("<NFe"))

Else 'Ocorreu algum erro na assinatura
MessageBox.Show(OAd.vResultadoString, "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error)
End If

'Validar o XML
Dim TxtXSD As String

TxtXSD = "C:\tmp\Schemas NF-e\nfe_v1.10.xsd"

If Not CaminhoArquivo = String.Empty And Not TxtXSD = String.Empty Then

Resultado = True
Dim settings As New XmlReaderSettings()
AddHandler settings.ValidationEventHandler, AddressOf Me.ValidationEventHandler

'Valida o arquivo XML com o seu Schema XSD
lstValida.Items.Add("Validando o arquivo XML " & CaminhoArquivo & " com o arquivo de Schema : " & TxtXSD)

Try

settings.ValidationType = ValidationType.Schema
settings.Schemas.Add("http://www.portalfiscal.inf.br/nfe", XmlReader.Create(TxtXSD))
Using XmlValidatingReader As XmlReader = XmlReader.Create(CaminhoArquivo, settings)
While XmlValidatingReader.Read()

End While

End Using

Catch ex As Exception

lstValida.Items.Add(ex.Message)
Exit Sub
End Try

lstValida.Items.Add("Status Validação -> " & IIf(Resultado = True, "Arquivo validado com SUCESSO", "Validação FALHOU"))

Else
MsgBox("Informe o arquivo XML e o arquivo XSD.")
End If


Catch ex As Exception

'se ocorrer uma exceção exibe a mensagem
lstValida.Items.Add(ex.Message)

End Try

End Sub


Function SelecionarCertificado() As Boolean

Dim vRetorna As Boolean
Dim oX509Cert As New X509Certificate2
Dim store As New X509Store
Dim collection As New X509Certificate2Collection
Dim collection1 As New X509Certificate2Collection
Dim collection2 As New X509Certificate2Collection
Dim scollection As New X509Certificate2Collection
Dim msgResultado As String
Dim xnome As String

xnome = "CN=COPLAST INDUSTRIA E COMERCIO DE RESIDUOS PLASTICO:04672291000115, OU=Autenticado por AR Fenacon, OU=RFB e-CNPJ A1, OU=Secretaria da Receita Federal do Brasil - RFB, L=Manaus, S=AM, O=ICP-Brasil, C=BR"

oX509Cert = New X509Certificate2()
store = New X509Store("MY", StoreLocation.CurrentUser)
store.Open(OpenFlags.ReadOnly Or OpenFlags.OpenExistingOnly)
collection = store.Certificates
collection1 = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, False)
collection2 = collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, False)

'Encontra o certificado digital pelo nome do mesmo, se precisar pergunta por isso
'Resolvido em 13/05/2009 às 15:05h
scollection = collection.Find(X509FindType.FindBySubjectDistinguishedName, xnome, False)


'Para selecionar o certificado de uma lista
'scollection = X509Certificate2UI.SelectFromCollection(collection2, "Certificado(s) Digital(is) disponível(is)", "Selecione o certificado digital para uso no aplicativo", X509SelectionFlag.SingleSelection)

If (scollection.Count = 0) Then

msgResultado = "Nenhum certificado digital foi selecionado ou o certificado selecionado está com problemas."
MessageBox.Show(msgResultado, "Advertência", MessageBoxButtons.OK, MessageBoxIcon.Warning)
vRetorna = False

Else

oX509Cert = scollection.Item(0) 'Para selecionar o item em Vb.NET
oCertificado = oX509Cert
xnome = oCertificado.Subject.ToString
vRetorna = True
'msgResultado = "Certificado Selecionado."
'MessageBox.Show(msgResultado, "Advertência", MessageBoxButtons.OK, MessageBoxIcon.Warning)
Return vRetorna

End If

End Function

Public Sub ValidationEventHandler(ByVal sender As Object, ByVal args As ValidationEventArgs)


Resultado = False

'lstValida.Items.Add(vbTab + "Erro de Validação : " + args.Message)

If args.Severity = XmlSeverityType.Warning Then

MsgBox("Nenhum arquivo de Schema foi encontrado para efetuar a validação...")

ElseIf args.Severity = XmlSeverityType.Error Then

lstValida.Items.Add(args.Message)
'MsgBox("Ocorreu um erro durante a validação....")

End If

If Not (args.Exception Is Nothing) Then ' Erro na validação do schema XSD

'lstValida.Items.Add(args.Exception.SourceUri + "," & args.Exception.LinePosition & "," & args.Exception.LineNumber)
'MsgBox(args.Exception.SourceUri + "," & args.Exception.LinePosition & "," & args.Exception.LineNumber)

End If

End Sub


Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
End
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim Valor As String

Me.Show()
'Valor = "F:\SisWin\NFE\BACKUP\200905\13090504672291000115550040000001520000002017-nfe.XML"
'ValidaNfe(Valor)
If Command() <> "" Then
Valor = Command()
ValidaNfe(Valor)

Me.Focus()
Me.Show()
Me.WindowState = FormWindowState.Normal

End If

End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Me.Show()
End Sub
End Class
Public Class AssinaturaDigitalClass

Public vResultado As Integer
Public vResultadoString As String
Public vXMLStringAssinado As String
Public XmlDoc As XmlDocument

Sub Assinar(ByVal pArqXMLAssinar As String, ByVal pUri As String, ByVal pCertificado As X509Certificate2)

'Abrir o arquivo XML a ser assinado e ler o seu conteúdo
Dim SR As StreamReader
Dim vXMLString As String

SR = File.OpenText(pArqXMLAssinar)
vXMLString = SR.ReadToEnd()
SR.Close()

' //Atualizar atributos de retorno com conteúdo padrão
vResultado = 0
vResultadoString = "Assinatura realizada com sucesso"

Try

'Verifica o certificado a ser utilizado na assinatura
Dim _xnome As String
Dim _X509Cert As X509Certificate2
Dim store As X509Store
Dim collection As X509Certificate2Collection
Dim collection1 As X509Certificate2Collection

_xnome = ""

_xnome = pCertificado.Subject.ToString()

_X509Cert = New X509Certificate2()
store = New X509Store("MY", StoreLocation.CurrentUser)
store.Open(OpenFlags.ReadOnly Or OpenFlags.OpenExistingOnly)

collection = store.Certificates
collection1 = collection.Find(X509FindType.FindBySubjectDistinguishedName, _xnome, False)


If (collection1.Count = 0) Then
vResultado = 2
vResultadoString = "Problemas no certificado digital"
Else

' certificado ok
'oX509Cert = scollection.Item(0)

_X509Cert = collection1.Item(0)
Dim x As String
x = _X509Cert.GetKeyAlgorithm().ToString()

' Create a new XML document.
Dim doc As New XmlDocument
doc = New XmlDocument()

'Format the document to ignore white spaces.
doc.PreserveWhitespace = False

' Load the passed XML file using it’s name.
Try
doc.LoadXml(vXMLString)

' Verifica se a tag a ser assinada existe é única
Dim qtdeRefUri As Integer
qtdeRefUri = doc.GetElementsByTagName(pUri).Count

If (qtdeRefUri = 0) Then
' a URI indicada não existe
vResultado = 4
vResultadoString = "A tag de assinatura " + pUri.Trim() + " não existe"

Else
' Existe mais de uma tag a ser assinada
If (qtdeRefUri > 1) Then
' existe mais de uma URI indicada
vResultado = 5
vResultadoString = "A tag de assinatura " + pUri.Trim() + " não é unica"
Else

Try
' Create a SignedXml object.
Dim signedXml As SignedXml
signedXml = New SignedXml(doc)

' Add the key to the SignedXml document
signedXml.SigningKey = _X509Cert.PrivateKey

' Create a reference to be signed
Dim reference As New Reference
reference = New Reference()

'--------- RETIRAR COMENTÁRIOS DAS LINHAS ABAIXO
' pega o uri que deve ser assinada
Dim _Uri As XmlAttributeCollection
Dim _atributo As XmlAttribute

_Uri = doc.GetElementsByTagName(pUri).Item(0).Attributes
For Each _atributo In _Uri
If (_atributo.Name = "Id") Then
reference.Uri = "#" + _atributo.InnerText

End If
Next

' Add an enveloped transformation to the reference.
Dim env As New XmlDsigEnvelopedSignatureTransform
env = New XmlDsigEnvelopedSignatureTransform()
reference.AddTransform(env)

Dim c14 As New XmlDsigC14NTransform
c14 = New XmlDsigC14NTransform()
reference.AddTransform(c14)

' Add the reference to the SignedXml object.
signedXml.AddReference(reference)

' Create a new KeyInfo object
Dim keyinfo As New KeyInfo
keyinfo = New KeyInfo()

' Load the certificate into a KeyInfoX509Data object
' and add it to the KeyInfo object.
keyinfo.AddClause(New KeyInfoX509Data(_X509Cert))

' Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyinfo
signedXml.ComputeSignature()

' Get the XML representation of the signature and save
' it to an XmlElement object.
Dim xmlDigitalSignature As XmlElement
xmlDigitalSignature = signedXml.GetXml()

' Gravar o elemento no documento XML
doc.DocumentElement.AppendChild(doc.ImportNode(xmlDigitalSignature, True))
XmlDoc = New XmlDocument()
XmlDoc.PreserveWhitespace = False
XmlDoc = doc

' Atualizar a string do XML já assinada
vXMLStringAssinado = XmlDoc.OuterXml

' Gravar o XML no HD
' abre um stream para escrita e cria um StreamWriter para implementar o stream
Dim fs As New FileStream(pArqXMLAssinar, FileMode.OpenOrCreate, FileAccess.Write)
Dim SW_2 As New StreamWriter(fs)
SW_2.Flush()
SW_2.BaseStream.Seek(0, SeekOrigin.Begin)
SW_2.Write(vXMLStringAssinado)
SW_2.Flush()
SW_2.Close()

Catch ex As Exception
vResultado = 6
vResultadoString = "Erro ao assinar o documento - " + ex.Message

End Try

End If

End If

Catch ex As Exception

vResultado = 3
vResultadoString = "XML mal formado - " + ex.Message

End Try

End If

Catch ex As Exception

vResultado = 1
vResultadoString = "Problema ao acessar o certificado digital" + ex.Message

End Try

End Sub

End Class

2 comentários:

Anônimo disse...

Fico muito agradecido pelas dicas disponibilizadas.


Obrigado

Unknown disse...

Muito legal, estou testando...

UM APLICATIVO PARA LEITURA DEVOCIONAL ANUAL DA BIBLIA EM ANDROID

Olá, pessoal!  Este novo projeto foi criado em Visual Studio 2019 em C#.Net com o Xamarin. Já está disponível no Google Play para vocês baix...