assinar com o cartão do cidadão docs em pdf

Jul 18, 2011 at 12:05 PM

Ola muito boa tarde!

estou a criar uma aplicação em c# para assinar documentos em pdf, o meu problema esta em conseguir obter os certificados para os "injectar" com o itextsharp dentro do pdf, será possível dar-me uma ajuda e visto que a documentação não esta muito clara ? 

obrigado!

Nov 23, 2011 at 11:01 PM

Oi (Não sei se já desistis-te desta thread)

            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false);            
            X509Certificate2Collection coll2 = store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, true);

            int count = (coll2.Count + coll.Count);
            X509Certificate2 cert = (coll.Count > 0 ? coll[0] : (coll2.Count > 0 ? coll2[0] : null));
            store.Close();
            if ((count < 1) || cert == null)
            {
                throw new ArgumentException("No Certificate");
            }

Basicamente depende da maneira como procuras. Esta é uma de várias maneiras. Espero que te ajude.


Feb 2, 2012 at 5:10 PM
Edited Feb 2, 2012 at 5:10 PM

Oi.

Eu também estive há algum tempo à volta da mesma coisa. Usei um código muito semelhante ao que o Ricardo Guerreiro colocou aqui na thread, e usei o seguinte código para assinar um byte[]:

protected override byte[] SignMsg(Byte[] msg, X509Certificate2 signerCert, string pin, bool detached)
{
      //  Place message in a ContentInfo object.
      //  This is required to build a SignedCms object.
      ContentInfo contentInfo = new ContentInfo(msg);

       //  Instantiate SignedCms object with the ContentInfo above.
       //  Has default SubjectIdentifierType IssuerAndSerialNumber.
      SignedCms signedCms = new SignedCms(contentInfo, detached);


       //  Formulate a CmsSigner object for the signer.
       CmsSigner cmsSigner = new CmsSigner(signerCert);
       // Include the following line if the top certificate in the
       // smartcard is not in the trusted list.
       cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly;

       //?????????????????????????

       //  Sign the CMS/PKCS #7 message. The second argument is
       //  needed to ask for the pin.
       signedCms.ComputeSignature(cmsSigner, false);

       //  Encode the CMS/PKCS #7 message.
       return signedCms.Encode();
}

Este código funciona bem, no entanto é-me pedido através da popup do cartão do cidadão o pin do certificado de assinatura. Tenho tentado, sem sucesso, nos últimos 2 dias usar um dialogo meu para obter o PIN, e validar de alguma forma o PIN para que a janela não me apareça. Já tentei onde tenho os ??????????? usar o seguinte código:

 

SCWatcher sw = SCWatcher.GetInstance();
EIDPT.Init(sw.ListReaders()[0]);
EIDPT.VerifyPINNoAlert(signaturePin.Id, pinvalue);

Em que o pin value é o valor do PIN, e o signaturePin é o Pin correcto obtido a partir de EIDPT.GetPINs();

No entanto, sempre sem sucesso. Ele pede-me sempre o pin usando a janela do middleware do cartão do cidadão. O problemático é que a aplicação que eu tinha feito para assinar 1 pdf, recebeu uma refactorização e agora assinar N documentos, ou seja, durante o processo de assintura aparecem N janelas a pedir o mesmo PIN. 

Alguém sabe se existe alguma forma de impedir que a janela apareça, e chamar o código que a janela chama para validação do PIN de assinatura.

 

Muito Obrigado

 

João Miguel

Feb 3, 2012 at 8:55 AM
Edited Feb 3, 2012 at 9:29 AM

Boas João,

Eu até algum tempo estive a investigar (e até ao ponto que investiguei) as conclusões é que era impossível fazer isso usando um Cartão do Cidadão.

O cartão de cidadão "parece-me" mete o certificado com a chave pública na Personal Store enquanto mantém  a chave Privada no próprio Cartão.

Como a própria assinatura envolve usar a chave privada para cifrar o documento, precisas sempre de aceder ao cartão e isso envolve que despolete o popup que te permita o acesso :(.

O problema está que o pelo decreto lei 290-D/99 dita que cada uma destas cifras deverá ser única de modo a garantir a autenticidade da mesma. Se o programa que estás falando prevê um refactoring nesse modo tem cuidado com estas nuances.

Quanto ao resto a única alternativa que descobri seria usando apenas um certificado normal (.pfx) com propriedades de assinatura e com a chave privada embutida.

Mesmo assim ando a ver se descobro alternativas visto que tou com um problema semelhante num projecto.

Ricardo Guerreiro

 

Feb 3, 2012 at 9:51 AM

Bom dia Ricardo.

Quero-te agradecer antes de tudo pela rápida resposta. Vou partilhar contigo uma solução que encontrei neste blog:

http://www.infinitec.de/post/2010/11/22/Setting-the-PIN-of-a-smartcard-programmatically.aspx

E alterando o código na método SignPDF:

SCWatcher sw = SCWatcher.GetInstance();
EIDPT.Init(sw.ListReaders()[0]);
EIDPT.VerifyPINNoAlert(signaturePin.Id, pinvalue);

para:

signerCert.SetPinForPrivateKey("123456");

O pin do certificado parece estar a ser colocado quando as dlls de segurança o pedem para a assinatura de PDF.

No entanto esta solução apenas funciona em Windows 7 ou Vista, e não em Windows XP. Desde já admito que o meu background é Java, e não .Net, e que não consigo perceber muito bem o código do blog. Simplesmente copiei para o meu projecto, usei, e funcionou. Suponho que alguns dos métodos nativos que ele esta a invocar das dlls seja diferente para windows XP. A verdade é que não consigo por isto a funcionar para windows XP.

Foram os meus 2 cêntimos sobre esta questão... se por acaso conseguir dar a volta para windows XP, serás o primeiro a saber.

Obrigado pela ajuda mais uma vez.

João Simas

Feb 5, 2012 at 8:36 PM
Edited Feb 5, 2012 at 8:37 PM

Boas João,

Antes de mais obrigado pelo código. Quanto ao do Windows XP parece-me estranho visto que desde que se tenha o Middleware do CC instalado com a eidpt.dll no system32 isso deveria funcionar :S.

Verificas-te se a .Net Framework é a mesma que usas-te no 7 e Vista (provavelmente Stupid Question)?

Ricardo Guerreiro

Feb 6, 2012 at 9:24 AM

Bom dia.

Estou a usar a versão 3.5 .net (sim, igual em ambos os sistemas).

Entretanto já fiz um comentário ao post onde encontrei o código que usei, a perguntar se por acaso ele teria alguma dica para mim sobre a razão porque aquele código não funcionava em windows xp, mas infelizmente a resposta dele não me ajudou assim muito:

"Hi,
sorry, but I have no clue what this error message means.
But the code works on Windows 2003...
Kind regards"

:(

Por agora creio que em windows xp os utilizadores vão mesmo ter que colocar o PIN por cada pdf a assinar... como eu costumo dizer "o que tem que ser, tem muita força..".

Se voltar a ter novidades sobre este assunto serás o primeiro a saber.

Muito obrigado pela ajuda

João Simas

Feb 7, 2012 at 2:18 PM

Olha se calhar tenho novidades.

Dependendo do Visual Studio onde compilaste a DLL do eidpt.dll tenta instalar o "Microsoft Visual C++ Redistributable Package" dessa versão senão existir já.

Tipo VS2010 -> MVC++ 2010 RP.

Eu tive "empanado" num problema destes a algum tempo em que me dava erro em que não achava o eidpt.dll (e ela estava ao pé do executável numa máquina). A razão disso é que faltava a DLL do MVC (go figures....).

Espero que te ajude a resolver o erro dessa máquina.

E quando fiz aquele comentário da "eidpt.dll na system32" (podes esquecer :P afinal não é necessária).

Ricardo Guerreiro

Oct 30, 2012 at 4:44 PM

Viva,

estou a tentar desenvolver um projecto em VS2012 sobre windows 8 x64 com o código signedCms.ComputeSignature(...) não me está a aparecer o popup middleware a solicitar o pin de assinatura! No entanto se chamar a leitura da morada o popup do pin da morada aparece-me. Alguém tem algum projecto de assinatura nestas novas plataformas a funcionar?

Obrigado

João Almeida

Feb 17, 2014 at 9:59 AM
Sinceramente já experimentei de tudo e também não estou a conseguir também obter a chave privada do certificado digital de Assinatura.
Também estou a desenvolver em VS2012, Windows 8 x64 e não percebo como se faz uma assinatura com base no certificado..
Alguém pode ajudar?

Obrigado,

Guilherme.