

Labreu
New Member-
Posts
10 -
Joined
-
Last visited
Labreu's Achievements
boolean user (2/5)
3
Reputation
-
Boas. Se alguém tiver interesser, criei uma demo online: https://github.com/luisabreu/AmaCmdSigning
-
Boas pessoal! FInalmente, está a funcionar como deve: https://stackoverflow.com/questions/66671008/itext7-deferred-signing-not-producing-a-valid-signed-pdf?noredirect=1#comment117931277_66671008 btw, parece q a assinatura inicial (so com o CMS PdfPCKS7) so e adequado em algumas situacoes. Nos comentarios, o mkl explica a diferenca entre as duas formas de assinar...Agora, ver como faco o timestamp disto! que aventura...
-
Boas pessoal. O código que tenho aqui está produzir mm resultado. O aviso no pdf faz sentido (acho) pq os certificados enviados não pertencem a uma chain fidedigna. No meu caso, ainda estou a tentar perceber o que é que o comentário que tive num post do stackoverflow quer dizer: Basicamente, e de acordo com este user, a forma de criar o container para injetar a assinatura da AMA está errada. Eu já mudei o código para tentar seguir as ideias dele, mas a verdade é que nao esta a funcionar. Já agora, e por curiosidade, o código que estou a usar no método Sign do IExternalSignatureContainer que preparar o hash passou a ser: public override byte[] Sign(Stream data) { // create PCKS7 for getting byte attributes var sgn = new PdfPKCS7(null, _certificates.ToArray(), DigestAlgorithms.SHA256, false); DocumentDigest = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256); var docBytesHash = sgn.GetAuthenticatedAttributeBytes(DocumentDigest, PdfSigner.CryptoStandard.CMS, null, null); var totalHash = new byte[_sha256SigPrefix.Length + docBytesHash.Length]; _sha256SigPrefix.CopyTo(totalHash, 0); docBytesHash.CopyTo(totalHash, _sha256SigPrefix.Length); DataToSend = totalHash; return new byte[0]; } Como ele diz que depois o GetEncodedPKCS7 tem de ser chamado com os mesmos parametros que o GetAuthenticatedAttributeBytes, enstao esou a guarda o hash e o digest originais. Depois, alterei ainda o Sign do outro IExternalSignatureContainer que é usado para injetar a assinatura recebida da AMA para: public byte[] Sign(Stream data) { var sgn = new PdfPKCS7(null, _certificates.ToArray(), DigestAlgorithms.SHA256, false); sgn.SetExternalDigest(_signature, null, "RSA"); var encodedSig = sgn.GetEncodedPKCS7(_documentHash, PdfSigner.CryptoStandard.CMS, null, null, null); return encodedSig; } Infelizmente, os resultados sao negativos 😞
-
@Morfas3Sim, essa parte está ok. A questão aqui é outra: a forma como geramoso CMS para colocar a assinatura não está correta (na verdade, os mues conhecimentos limitados na área não me permitem aferir bem qual a solução correta, mas parece q apesar de o adobe mostrar corretamente o certificado, a assinatura como está implementada não é totalmente correta...)
-
Infelizmente, só consegui responder hoje (limitação número de posts?)... Nesta altura, produzo o mm resultado "visual" que o @reznor. A questão é que parece que a assinatura efetuada não está 100% correta pq ainda deveria incluir os "atributos" do documento (ver resposta e comentários desta entrada)...
-
Ok, progresso...afinal n posso gerar o hash a partir do ficheiro com assinatura vazia, mas sim so dos bytes do ficheiro...aha.....agora ver a parte do certificado.
-
O teu está ok! da erro pq a chain de certificados nao e confiavel (presumo q se passares producao a coisa funciona sem erros). No meu caso, estou a gerar mal o hash do documento, mas ainda ainda nao percebi o erro....
-
Damn...sim, já está melhor, mas ainda devo ter um erro aqui no cálculo do hash. Agora já mostra info assinatura mas dá o erro tipico do ficheiro modificado depois da assinatura...
-
Sim, penso que estou a fazer corretamente isso. Basicamente, estou a fazer o seguinte (C#): public byte[] GetDocHashFromPreparedDocToSign(string pathToOriginalPdf, string pathToPreparedToBeSignedPdf, List<X509Certificate> certificates) { var pdfSigner = new PdfSigner(new PdfReader(pathToOriginalPdf), new FileStream(pathToPreparedToBeSignedPdf, FileMode.Create), new StampingProperties()); pdfSigner.SetFieldName(_signatureFieldname); var appearance = pdfSigner.GetSignatureAppearance(); appearance.SetPageRect(new Rectangle(144, 144, 200, 100)) .SetPageNumber(1) .SetCertificate(certificates[0]); var container = new ExternalBlankSignatureContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached); pdfSigner.SignExternalContainer(container, 8192); byte[] sha256SigPrefix = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; // get hash from pdf with reserved space and preprending with specified using var stream = File.OpenRead(pathToPreparedToBeSignedPdf); var data = DigestAlgorithms.Digest(stream, DigestAlgorithms.SHA256); var totalHash = new byte[sha256SigPrefix.Length + data.Length]; sha256SigPrefix.CopyTo(totalHash, 0); data.CopyTo(totalHash, sha256SigPrefix.Length); return totalHash; } O resultado deste metodo e passado para o servico da CMD: var pdfManager = new PdfManager(); var pathToSigned = "c:\\temp\\doc1.pdf"; var docHash = pdfManager.GetDocHashFromPreparedDocToSign(pathDocPdf, pathToSigned, certificates); var signReq = new SignRequest { ApplicationId = applicationId, DocName = "Doc1.pdf", Hash = docHash, Pin = pinCmdBase64, UserId = userIdBase64 }; SignStatus resScmdSign = await client.SCMDSignAsync(signReq); O resultado devolvido esta ok (200), pelo que me limito a chamar o ValidateOptAsync: var resValidacaoPin = await client.ValidateOtpAsync(codeBase64, resScmdSign.ProcessId, applicationId); if(resValidacaoPin.Status.Code == "200") { var pathToSignedWithSiognature = "c:\\temp\\doc1_signed.pdf"; // valid signature, replace temporary with new one pdfManager.SignPreparedToBeSignedDoc(pathToSigned, pathToSignedWithSiognature, resValidacaoPin.Signature); } E já agora, o método SignPreparedToBeSignedDoc: public void SignPreparedToBeSignedDoc(string pathToPreparedToBeSignedPdf, string pathToSignedFile, byte[] signature) { var document = new PdfDocument(new PdfReader(pathToPreparedToBeSignedPdf)); using var writer = new FileStream(pathToSignedFile, FileMode.Create); var container = new ExternalInjectingSignatureContainer(signature); PdfSigner.SignDeferred(document, _signatureFieldname, writer, container); } internal class ExternalInjectingSignatureContainer : IExternalSignatureContainer { private readonly byte[] _signature; public ExternalInjectingSignatureContainer(byte[] signature) { _signature = signature; } public byte[] Sign(Stream data) => _signature; public void ModifySigningDictionary(PdfDictionary signDic) { } } Edição: Relativamente aos certificados, estou a recuperar a chain devolvida pela AMA e a utilizar o primeiro certificado. O código de recuperação dos certificados é o seguinte: public static List<X509Certificate> ConvertStringToCertificate(string certificate) { byte[] bytes = Encoding.ASCII.GetBytes(certificate); var certs = new X509CertificateParser().ReadCertificates(bytes) .Cast<X509Certificate>() .ToList(); return certs; } Basicamente, faco o SignDeferred e passo o array de bytes devolvido pelo valdateopt da CMD... À primeira vista, parece-me que isto está certo, mas às tantas estou a falhar algo óbvio...
-
Boas pessoal. Tb estou a tentar implementar a assinatura digital mas estou a ter o mesmo erro na assinatura que o @reznor estava a ter. Na prática, esotu obter certificado sem pin, recuperar a chain de certificados (lista) através do bouncy castle e a utilizar a mm estratégia que estão usar aqui... Acho eu... Mas está mm a me faltar algo simples... @reznor alguma dica para passar da imagem 1 a 2? Já agora, estavas a ter o ber encoding error? Obrigado.