20 de abril de 2009

Trabalhando com o Certificate Store do Windows

Vem se tornando popular ultimamente o uso de Certificados Digitais para autenticar documentos eletronicamente; a introdução da Nota Fiscal Eletrônica e da Escrituração Digital devem dar um impulso definitivo, já que praticamente todas as empresas terão que adotá-lo para poder assinar as informações enviadas para a Receita Federal.

Mas, o que é na prática um Certificado Digital ? Como é que o Windows trabalha com isso ? O Certificado em si, a grosso modo, é apenas um arquivo onde são armazenadas informações sobre quem outorgou o certificado (uma CA, ou Certificate Authority) e a quem é que foi outorgado o certificado (uma pessoa física ou jurídica ou ainda um computador) bem como um código público (a chave). O Certificado, portanto, associa uma chave pública a uma entidade (empresa, pessoa ou computador). Há um artigo no Wikipedia mais detalhado sobre esse assunto.

Se você (ou sua empresa ou seu computador) é quem recebeu o certificado, você também possui a chave privada, isto é, o código que só você conhece e que será usado para assinar um documento digital, garantindo-lhe a integridade, a autenticidade e conferindo validade jurídica ao documento.

No Windows, o acesso aos Certificados disponíveis se dá de forma centralizada, através do Armazém de Certificados Digitais (ou Certificate Store) . Isto é, uma vez que o certificado foi registrado no computador, não importa onde ele está armazenado : o acesso deve ser feito a partir do store. Para acessá-lo a partir do Windows, vá em Iniciar -> Executar e digite
mmc \windows\system32\certmgr.msc


Esse programa mostra de forma estruturada quais são os certificados presentes em seu computador: aqueles de uso exclusivo de seu usuário (Personal), as Autoridadades Certificadoras (tanto as de nível mais alto na hierarquia certificadora - as root ou raíz - quanto as intermediárias, que dependem da root), etc.

Via programação, o framework do .NET também fornece uma forma estruturada de acessar o Store, através do namespace System.Security.Cryptography.X509Certificates. São basicamente 3 classes para acessar os certificados :
  • X509Store : Representa o acesso ao Store. O construtor dela exige que se estipule qual parte da estrutura deve ser acessada. Use as definições na classe StoreName para identificar, por exemplo, os certificados particulares ("My") ou as Autoridades Certificadoras ("CA"). Pode optar também por informar apenas a localização, através da classe StoreLocation (somente os meus certicados ou todos os certificados presentes no computador).
  • X509Certificate2Collection : Uma lista dos certificados armazenados no Store aberto com a classe anterior.
  • X509Certificate2: Representa um certificado na coleção.
O exemplo abaixo em C# percorre a lista de certificados na Store "My", procurando os válidos e que possuam chave privada.

X509Certificate2Collection lcerts;
X509Store lStore = new X509Store (StoreName.My, StoreLocation.CurrentUser);

// Abre o Store
lStore.Open(OpenFlags.ReadOnly);

// Lista os certificados
lcerts = lStore.Certificates;

foreach (X509Certificate2 cert in lcerts)
{
if (cert.HasPrivateKey && cert.NotAfter > DateTime.Now && cert.NotBefore < DateTime.Now)
{
// Faz o uso do certificado....
// Por exemplo, assinar um docto.
}
}
lStore.Close();

14 comentários :

Anônimo disse...

Show!!!

Anônimo disse...

Off-line esse codigo acima funciona, porém on-line não. Como solucionar esse problema ?

Timoteo (timoteo.vix@gmail.com)

Luís Gustavo Fabbro disse...

Olá, Timóteo

O que você quer dizer com usar o Certificate Store online ? Está querendo acessar um Store existente em outro computador ? Há alguma mensagem de erro ?

O exemplo que está no post acessa apenas os certificados particulares, isto é, aqueles registrados na área MY do Store no computador local. Outras formas de acessar os certicados podem ser encontradas na documentação da classe do Store do.NET, no endereço http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509store.aspx.

Anônimo disse...

Como acessar o certificado no servidor ?
como o comentário do Timóteo ?

t+
Edson Domenech
domenechbr@gmail.com

Luís Gustavo Fabbro disse...

O namespace System.Security.Cryptography.X509Certificates do .NET, usado nos exemplos do blog, não disponibiliza meios de acessar o Certificate Store remotamente, isso é, com esse namespace você só pode acessar o Store de seu próprio computador.

Aqui na ABC71 nós resolvemos esse problema criando um serviço Windows que fica instalado no servidor, junto com os certificados e com toda a comunicação com a Receita Federal. Portanto, foi suficiente ler o Store local.

Se esse tipo de solução não é aplicável ao seu sistema, você pode contornar o problema usando diretamente a função da API do Windows CertOpenStore. Ela permite acessar Stores remotos, mas para usá-la com o .NET você precisará mapear algumas funções da DLL CRYPT32. Há um artigo bastante completo em http://hamidshahid.blogspot.com/2009/02/reading-x509-certificates-from-remote.html, incluindo o código necessário em C#.

Anônimo disse...

Ola Luís Gustavo,
Estou quebrando a cabeça com o seguinte problema: tenho uma aplicação web que gera e assina um xml de nota fiscal. Essa aplicação usa um token do tipo a3. Quando eu executo a aplicação pelo visual studio funciona tudo bem mas quando a aplicação é publicada no iis ela não enxerga nenhum certificado. Axo que o problema tem relação com as permissões do usuário do iis, estou tentando descobrir uma pasta de certificados que seja visível para todos os usuários. Vc teria alguma idéia sobre isso? Obrigado
arturcostta@gmail.com

Luís Gustavo Fabbro disse...

Artur

Pode ser que você tenha importado seu certificado num lugar do Store que o IIS não tem acesso. Dê uma olha em no link http://balaiotecnologico.blogspot.com/2011/09/funcionamento-do-certificate-store-do.html.

Se não me engano, certificados A3 exigem senha para poderem ser usados - ao menos na primeira vez. Caso esteja apresentando uma tela para o usuário digitar a senha, terá problemas quando sua aplicação for publicada no IIS, já que o serviço em si não tem interface visual.

Bolívar Arthur Butzke disse...

Olá Luís!

Estou fazendo uma pesquisa para desenvolver uma aplicação que assine NF-e via Web, com certificado digital A3.

Já pesquisei bastante e obtive alguns avanços, mas ainda não consegui chegar a uma solução para o problema.

Utilizando a CAPICOM com javascript eu consigo abrir o Certificate Store do Windows na máquina do cliente e ler o certificado A3, mas não sei como continuar com o processo da assinatura do XML da NF-e.

Utilizando a X509Certificate e SignedXml do .NET é possível ler o certificado e realizar a assinatura, mas só funciona em sistemas desktop rodando na máquina do cliente, não consigo fazer funcionar na web.

Ficaria muito grato se você pudesse me ajudar nessa pesquisa, dar alguma dica ou ideia para que eu possa tentar resolver este problema.

Muito obrigado!

Bolívar Arthur Butzke disse...

Olá Luís!

Estou trabalhando em uma pesquisa para desenvolver uma aplicação web que faça a assinatura de NF-e com certificado A3.

Nos últimos dias tenho testado diversas soluções e ainda não consegui fazer uma 100% funcional. Já utilizei a CAPICOM com javascript para acessar o Certificate Store na máquina do cliente, mas não encontrei solução para realizar a assinatura do XML com javascript ou de alguma outra forma no lado cliente.

Usando SignedXml, X509Certificate2 e outras classes do .NET consegui fazer um exemplo funcional tanto para desktop quanto para web, mas só funciona se eu estiver rodando local, com o certificado A3 conectado no servidor e rodando pelo Visual Studio.

A dificuldade está enorme, já tentei pesquisar sobre a possível solução que você comentou mais acima, com o CertOpenStore mas não consegui criar um exemplo que funcione.

Ficaria muito grato se você ou alguém pudesse me dar uma ajuda, uma ideia ou exemplo para que eu possa concluir esta pesquisa.

Grande Abraço e Parabéns pelo blog, tem muito conteúdo bom!

Luís Gustavo Fabbro disse...

Bolivar

Como você já consegue usar o CAPICOM no javascript para acessar o Certificate Store, creio que assinar um documento com essas tecnologias passa a ser questão de instanciar as interfaces corretas.

Você precisará acessar as interfaces ISigner2 (cuja classe do activeX é CAPICOM.Signer) e ISignedData (classe CAPICOM.SignedData). O post Assinando documentos com CAPICOM traz um exemplo de como usá-las em Delphi.


[]s

memarques disse...

Prezado Luis

Obrigado por compartilhar esse código.

Tenho uma questão e espero que você “ainda” veja esse seu blog … kkkk

Tenho aqui na empresa 2 tipos de cetificados: Um Token, e um com leitora de Cartões.

Uso os dois normalmente para assinar a emissão de NFes através de um software específico.

Em ambos, a senha PIN é pedida quando o acesso é feito no Token ou no Card, através do programa emissor que uso. Pois bem, fui tentar usar o certificado usando o Token e o Card (claro ambos A3) e estou tento problemas na utilização do Card.

Percebi que quando “plugo” o Token o certificado é colocado na pasta “Pessoal” através do “certmgr.msc “, mas o certificado do Card fica na pasta “Outras Pessoas”.

Usando:

“Dim storePessoal As New X509Store”

Consigo “achar” e usar o certificado do Token normalmente, que pede o pin qdo usado, mas nessa “STORE” o certificado do card não é colocado e portanto não é encontrado.

Para o CARD eu usei: (tentativa)

“Dim storeCard As New X509Store(“AddressBook”)”

Nessa store eu consigo achar o certificado do CARD, mas qdo eu o seleciono e uso, não é apresentada a tela pedindo o PIN dele e portanto o uso desse certificado dá erro.

Você poderia ajudar-me a usar o Certificado A3 (em Card) que é colocado na pasta “Outras Pessoas” ?

Obrigado novamente, ate
Mauro

Luís Gustavo Fabbro disse...

Mauro

A ativação da tela que solicita a senha para uso do certificado não está no certificado. Mas você pode criar sua própria versão da tela para solicitar essa informação.

Uma vez que você localizou o certificado correto, pode criar uma nova instância de X509Certificate2 passando-lhe a senha obtida junto ao usuário e os dados do certificado encontrado. Algo assim:

// Encontra o certificado correto
X509Certificate2 cert = EncontraCertificado();

// Abre sua tela e solicita senha p/
// usar o certificado
string senha = SolicitaSenhaCert ();

X509KeyStorageFlags flags =
X509KeyStorageFlags.PersistKeySet |
X509KeyStorageFlags.MachineKeySet;

X509Certificate2 novoCert;
novoCert = new X509Certificate2 (cert.RawData, senha, flags);

Use o novoCert para assinar os documentos e invocar os Web Services da SEFAZ.

[]s

Gabriel do Vale disse...

Olá, desta forma o certificado copiado fica sem o private key...Assim não dando pra assinar a NFe.

Sabe como podemos resolver isso?

Luís Gustavo Fabbro disse...

Gabriel

Provavelmente o certificado já foi importado para o certificate store sem a chave privada. Obtenha a versão original dele e reimporte no store.

[]s

Postar um comentário

OBS: Os comentários enviados a este Blog são submetidos a moderação. Por isso, eles serão publicados somente após aprovação.

Observação: somente um membro deste blog pode postar um comentário.