Ver um Único Post

 
  #3 (permalink)  
Antigo 03/11/2009
Avatar de LuizVaz
LuizVaz LuizVaz está offline
Administrator
Super Admin
Points: 10,505, Level: 68 Points: 10,505, Level: 68 Points: 10,505, Level: 68
Activity: 0% Activity: 0% Activity: 0%
Last Achievements
 
Registrado em: Oct 2009
Localização: Belo Horizonte
Posts: 86
Thanks: 2
Thanked 6 Times in 6 Posts
Activity Longevity
0/20 20/20
Today Posts
sssssss86
Enviar mensagem via Windows Live Messenger para LuizVaz Enviar mensagem via Yahoo para LuizVaz
Lightbulb

Leonardo,

Acho que isso pode resolver o seu problema.
Tem que passar corretamente os dados do certificado para a função.
Senão dá pau mesmo.

O que fiz foi apresentar a caixa de seleção do certificado para o usuário.
Depois de selecionado, basta pegar os dados do objeto Certificate.

Código:
function TfrmMain.SignXML(fwWriteKeyInfo: _XMLDSIG_WRITEKEYINFO): Boolean;
const
  sCert: array [Boolean] of string = ('s',  '');
  sDisp: array [Boolean] of string = ('is', 'l');
var
  h, i: Cardinal;
  Sett, Cert, Certs, Store: OleVariant;
  s1, s2, sProvider, sContainer: String;
  eType: CAPICOM_PROV_TYPE;
  pKey, pKeyOut: IXMLDSigKey;
  sSigs, sX509: IXMLDOMNodeList;
  sSig: IXMLDOMNode;
begin
   Try
     Sett := CoSettings.Create;
     Sett.EnablePromptForCertificateUI := True;
     Store := CoStore.Create;
     Store.Open(CAPICOM_CURRENT_USER_STORE, 'My', CAPICOM_STORE_OPEN_EXISTING_ONLY);

     //Remove os Certificados que não são Signature da lista
     Certs  := Store.Certificates;
     for i := Store.Certificates.Count downto 1 do
       begin
         Cert := IInterface(Certs.Item[i]) as ICertificate2;
         if (not Cert.HasPrivateKey) then
           Certs.Remove(i);
       end;

     Try
       Cert := Null;
       s1 := sCert[Certs.Count = 0];
       s2 := sDisp[Certs.Count = 0];
       //---> Usuário Seleciona o Certificado 
       Certs := Certs.Select(Format('Certificado%s disponíve%s', [s1, s2]),
                             'Selecione o Certificado Digital para uso', FALSE);
       Cert := IInterface(Certs.Item[1]) as ICertificate2;
     Except
       on E: EOleException do
         begin
           i := e.ErrorCode;
           //---> Usuário abortou a seleção
           if i = $80880902 then
             Abort()
           else
             Raise;
         end;
     End;

     if not VarIsNull(Cert) then
     begin
       // Encopntra os <ds:Signature> nodes.
       FXMLDoc.setProperty('SelectionNamespaces', DSIGNS);
       sSigs := FXMLDoc.selectNodes('.//ds:Signature');

       if (sSigs.length = 0) then
          Exception.Create('A Tag Signature não foi encontrada no XML.');

       //É necessário ter a 1ª assinatura   
       FXMLDSig.signature := sSigs.item[0];   
       FXMLDSig.store := Store;
       //---> Dados necessários para gerar a assinatura
       eType := Cert.PrivateKey.ProviderType;
       sProvider := Cert.PrivateKey.ProviderName;
       sContainer := Cert.PrivateKey.ContainerName;

       // assina cada TAG Signature
       for i := 0 to (sSigs.length-1) do
       begin
         // próximo <ds:Signature> DOM node.
         FXMLDSig.signature := sSigs.item[i];
         // ---> Assinatura do campo Signature do XML
         pKey := FXMLDSig.createKeyFromCSP(eType, sProvider, sContainer, 0);

         if (pKey = nil) then
           Exception.Create('Invalid key.\n');
         pKeyOut := FXMLDSig.sign(pKey, fwWriteKeyInfo);

         // deixa no KeyInfo somente um X509Data 
         sX509 := FXMLDoc.selectNodes('//ds:X509Data[position() > 1]');
         if sX509.length > 0 then
           for h := (sX509.length-1) downto 0 do
           begin
             sSig := sX509.item[h].parentNode;
             sX509.item[h].text := '';
             sSig.removeChild(sX509.item[h]);
           end;             
       end;
     end;

     if (pKeyOut = nil) then
       Exception.Create('Falha durante assinatura.\n');
   finally

   end;

   Result := true;
end;
Resumindo, você está passando errado o conjunto de informações para a função createKeyFromCSP.

Qualquer coisa, pegue meu exemplo no:
http://opennfse.googlecode.com/files/NFSeSigner.zip

OBS.: Repare que usei OleVariant e não a interface em algumas variáveis.
Isso é importante, porque força o windows a usar a versão certa do Objeto na CAPICOM e XMLDOC.

Atenciosamente,
Luiz Vaz
Responder com Citação
 

Content Relevant URLs by vBSEO 3.3.0