Página 1 de 1

Checagem de assinatura

Enviado: 20 Jun 2016 22:03
por JoséQuintas
Achei isto no site da Microsoft, mas ainda em fase de conversão.
Não vai ser muito diferente no Harbour, porque usa classes do XML 5.0
É pra validar a assinatura do XML.

Código: Selecionar todos

Dim xmldoc As New DOMDocument50
Dim xmldsig As New MXDigitalSignature50
Dim dsigKey As IXMLDSigKey
Dim dataObj As IXMLDOMNode

Const DSIGNS = "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
Const INFILE = "signature.verify.dsa.xml"

Private Function WriteLine(ByVal str As String)
    Text1.Text = Text1.Text + str + vbNewLine
End Function
Private Function writeClear()
    Text1.Text = ""
End Function

Private Function LoadXML(ByVal file As String)
    ' Read input xml file and display the content in the text1.
    Path = App.Path + "\" + file
    xmldoc.async = False
    xmldoc.preserveWhiteSpace = True
    xmldoc.validateOnParse = False
    xmldoc.resolveExternals = False
    If xmldoc.Load(Path) = False Then
        WriteLine "Can't load " + Path
        WriteLine "Reason: " + xmldoc.parseError.reason
        LoadXML = False
        Exit Function
    End If
    xmldoc.setProperty "SelectionNamespaces", DSIGNS
    Set xmldsig.signature = xmldoc.selectSingleNode(".//ds:Signature")
    LoadXML = True
End Function


Private Function VerifyXML()
    If xmldsig.signature Is Nothing Then
        WriteLine "Invalid signature."
        VerifyXML = False
        Exit Function
    End If

    Set oKeyInfo = xmldoc.selectSingleNode(".//ds:KeyInfo/ds:KeyValue")
    If oKeyInfo Is Nothing Then
        WriteLine "Invalid <KeyInfo> element."
        VerifyXML = False
        Exit Function
    End If

    Set oPubKey = xmldsig.createKeyFromNode(oKeyInfo)
    If oPubKey Is Nothing Then
        WriteLine "Can't generate public key for verification."
        VerifyXML = False
        Exit Function
    End If

    Set oVerifiedKey = xmldsig.verify(oPubKey)
    If oVerifiedKey Is Nothing Then
        WriteLine "Signature not verified."
    End If

    WriteLine "Signature verified."
    VerifyXML = True
End Function

Private Sub Form_Load()

    writeClear
    WriteLine "Verifyin signature."
    If LoadXML(INFILE) = True Then
        VerifyXML
    End If
End Sub
Durante conversão pra Harbour, fui confirmar aqueles componentes iniciais, aonde eram usados no fonte e.... não encontrei.
Fui no VB, e acrescentei no fonte: "Option Explicit", algo como a checagem -w3 -es2 que existe no Harbour.
E não é que deu erro nas linhas, porque não usa pra bost. nenhuma.
Belo exemplo de colocar lixo em fonte.... rs

Checagem de assinatura

Enviado: 20 Jun 2016 22:10
por JoséQuintas
Ainda não testado e nem melhorado.
Pra quem tiver tudo na mão e quiser "brincar".

Código: Selecionar todos

#define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"
#define INFILE "signature.verify.dsa.xml"

MEMVAR XmlDoc, XmlDSig

PROCEDURE Main

   PRIVATE XmlDoc, XmlDSig

   XmlDoc  := win_OleCreateObject( "MSXML2.DOMDocument.5.0" )
   XmlDSig := win_OleCreateObject( "MSXML2.MXDigitalDignature.5.0" )

   IF LoadXml( INFILE )
      VerifyXml()
   ENDIF
   RETURN

FUNCTION LoadXml( cFile )

   XmlDoc:Async := .F.
   XmlDoc:PreserveWhiteSpace := .T.
   XmlDoc:ValidateOnParse := .F.
   XmlDoc:ResolveExternals := .F.

   IF XmlDoc:Load( cFile ) == .F.
      MsgExclamation( "Cannot load file. reason " + XmlDoc:ParseError:Reason )
      RETURN .F.
   ENDIF
   XmlDoc:SetProperty( "SelectionNameSpaces", DSIGNS )
   XmlDsig:Signature := XmlDoc:SelectSingleNode( ".//ds:Signature" )
   RETURN .T.

FUNCTION VerifyXml()

   LOCAL oKeyInfo, oPubKey, oVerifiedKey

   IF XmlDSig:Signature == NIL
      MsgExclamation( "Invalid Signature" )
      RETURN .F.
   ENDIF
   oKeyInfo := XmlDoc:selectSingleNode( ".//ds:KeyInfo/ds:KeyValue" )
   IF oKeyInfo == NIL
      MsgExclamation( "Invalid <KeyInfo> Element" )
      RETURN .F.
   ENDIF
   oPubKey := XmlDSig:CreateKeyFromNode( oKeyInfo )
   IF oPubKey == NIL
      MsgExclamation( "Cannot generate public key for verification" )
      RETURN .F.
   ENDIF
   oVerifiedKey := XmlDSig:Verify( oPubKey )
   IF oVerifiedKey == NIL
      MsgExclamation( "Signature not verified" )
      RETURN .F.
   ENDIF
   MsgExclamation( "Signature Ok" )
   RETURN .T.

Checagem de assinatura

Enviado: 21 Jun 2016 15:38
por JoséQuintas
Depois do primeiro teste ok.

Código: Selecionar todos


#define DSIGNS "xmlns:ds='http://www.w3.org/2000/09/xmldsig#'"

PROCEDURE Main( cFileName )

   ? ChkSignature( cFileName )
   Inkey(0)
   RETURN


FUNCTION ChkSignature( cXml )

   LOCAL XmlDoc, XmlDSig, cXmlRetorno := "Undefined Error"
   LOCAL oKeyInfo, oPubKey, oVerifiedKey, oSignature

   BEGIN SEQUENCE WITH __BreakBlock()
      XmlDoc  := win_OleCreateObject( "MSXML2.DOMDocument.5.0" )
      XmlDSig := win_OleCreateObject( "MSXML2.MXDigitalSignature.5.0" )

      XmlDoc:Async              := .F.
      XmlDoc:PreserveWhiteSpace := .T.
      XmlDoc:ValidateOnParse    := .F.
      XmlDoc:ResolveExternals   := .F.

      IF .NOT. XmlDoc:Load( cXml )
         cXmlRetorno := "Cannot load file. reason " + XmlDoc:ParseError:Reason
         BREAK
      ENDIF
      XmlDoc:SetProperty( "SelectionNamespaces", DSIGNS )
      oSignature := XmlDoc:SelectSingleNode( ".//ds:Signature" )
      IF oSignature == NIL
         cXmlRetorno := "Not Found Signature"
         BREAK
      ENDIF
      XmlDSig:Signature := oSignature
      oKeyInfo := XmlDoc:selectSingleNode( ".//ds:KeyInfo/ds:X509Data" )
      IF oKeyInfo == NIL
         cXmlRetorno := "Invalid <KeyInfo> Element"
         BREAK
      ENDIF
      oPubKey := XmlDSig:CreateKeyFromNode( oKeyInfo )
      IF oPubKey == NIL
         cXmlRetorno := "Cannot generate public key for verification"
         BREAK
      ENDIF
      oVerifiedKey := XmlDSig:Verify( oPubKey )
      IF oVerifiedKey == NIL
         cXmlRetorno := "Signature not verified"
         BREAK
      ENDIF
      cXmlRetorno := "OK"
   END SEQUENCE
   RETURN cXmlRetorno

Checagem de assinatura

Enviado: 21 Jun 2016 15:42
por JoséQuintas
Faltou dizer: precisa do XML5 instalado.

Checagem de assinatura

Enviado: 21 Jun 2016 18:46
por JoséQuintas
Precisa melhorar a rotina, e pegar mais situações.
Quando a assinatura é inválida, gera erro de run-time e isso causa retornar "erro desconhecido".
Acaba deixando na dúvida se a rotina falhou ou se é erro de assinatura mesmo.

Neste momento imagino deixar o :Verify em bloco de erro separado do restante.
Ainda não sei se vai precisar mais partes separadas em bloco de erro próprio.

Checagem de assinatura

Enviado: 21 Jun 2016 18:53
por JoséQuintas
Idéia:

Código: Selecionar todos

   ...
   cXmlRetorno := "Bad Signature or Digest Value"
   oVerifiedKey := XmlDSig:Verify( oPubKey ) 
   IF oVerifiedKey == NIL 
      cXmlRetorno := "Signature not verified" 
      BREAK 
   ENDIF 
   cRetorno := "OK"
END SEQUENCE
RETURN cRetorno
Se der erro, vai retornar "Bad Signature or Digest Value", porque sai do BEGIN/END, e mantém o último conteúdo em cXmlRetorno.
Se seguir em frente, e der NIL, mostra "SIgnature not verified"
E se for até o fim, vai retornar "OK".

Dá até pra usar esse esquema no restante, aonde for preciso.

Agora é testar com muitos XMLs pra pegar mais situações.

Nota: neste último teste, que gerou erro de run-time, apenas troquei duas letras do XML por "XX", pra tornar a assinatura inválida.


Nota2:

Código: Selecionar todos

oKeyInfo := XmlDoc:selectSingleNode( ".//ds:KeyInfo/ds:X509Data" )
Não pensem que sou expert nessas coisas, que não sou, isso foi no chute mesmo.
Me pareceu que o segundo ds: era um sub-elemento. Coloquei igual está no XML e deu certo..... rs

Checagem de assinatura

Enviado: 21 Jun 2016 20:43
por janio
JoseQuintas escreveu:
Faltou dizer: precisa do XML5 instalado.
Sem ter nada a ver com o assunto (ou talvez tenha), em uma rotina para consultar o CNPJ na receita federal, tem dado erro na rotina abaixo:

Código: Selecionar todos

	Try
		oServer:= CreateObject( "MSXML2.ServerXMLHTTP.5.0")
	Catch
		MsgStop('Erro na Criação do Serviço','Consulta')
		Return aRetorno
	End

Em todos os computadores que já testei sempre deu certo, mas em um especificamente tem dado erro: "ERRO NA CRIÇÃO DO SERVIÇO"!

Não consegui identificar o que essa maquina tem (ou não tem) que faz essa rotina não funcionar nela!

Tem ideia do que pode ser?

Janio

Checagem de assinatura

Enviado: 21 Jun 2016 21:48
por JoséQuintas
Sim, para o tem a ver, e para o ter idéia... rs

O final 5.0 indica XML 5.0.
Isso não vém instalado no Windows. Só saiu como parte do Office.

Como usa CreateObject() é provável que use o xHarbour, então troque o 5.0 por 6.0.
O 5.0 é especial que vém no Office, é o único que trata assinatura digital.
Se isso não envolve assinatura/certificado, melhor o 6.0 que faz parte do Windows.

Notas:
Se for Harbour, e win_OleCreateObject(), nem precisa versão, já seleciona automático o que for preciso.
Pelo menos pra Fazenda/NFE, tem webservice que exige 5.0 ou 6.0, então é possível que algo no servidor possa obrigar determinada versão.
O ACBR também usa isso, talvez tenha instalado ACBR nas outras máquinas, o que já instalou o XML 5.0.
E se mexer com certificado/assinatura, também a CAPICOM.

Checagem de assinatura

Enviado: 22 Jun 2016 10:03
por JoséQuintas
Ainda testando a rotina de checagem.
Por enquanto um teste encima de notas recentes, mas direto no XML autorizado, o que não seria correto.
O resultado foi este:

Código: Selecionar todos

TipoXml  OK      ERRO
110100   1713    178    
110111     30      2    
110110     70      3    
Acusou assinatura inválida em 10% dos XMLs. Depois vou tentar descobrir o motivo.