reznor Posted March 17, 2021 at 11:16 AM Report Share #621725 Posted March 17, 2021 at 11:16 AM @Labreu Deves estar parado no mesmo sitio que eu. Estou a pesquisar algumas coisas a ver se chego a alguma conclusão e na esperança que, mais uma vez, @Morfas3 me dê alguma luz daquilo que possa estar errado ou menos bem... Se tu validares manualmente a assinatura passa a ser válida, só que não é isso que se pretende... estou um bocado sem soluções para ser sincero Link to comment Share on other sites More sharing options...
Labreu Posted March 17, 2021 at 11:39 AM Report Share #621726 Posted March 17, 2021 at 11:39 AM 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.... Link to comment Share on other sites More sharing options...
Morfas3 Posted March 17, 2021 at 11:40 AM Author Report Share #621727 Posted March 17, 2021 at 11:40 AM estou sem tempo para responder, desculpem malta, ver se logo olho para o que postaram Link to comment Share on other sites More sharing options...
reznor Posted March 17, 2021 at 12:15 PM Report Share #621728 Posted March 17, 2021 at 12:15 PM (edited) @Labreu public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, List<X509Certificate> clientCertificate. byte[] prefix) { using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; //invisivel appearance.SetVisibleSignature(new Rectangle(0, 0, 0, 0), 1, signatureFieldName); IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); PdfSignature pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); appearance.SignDate = DateTime.Now; appearance.CryptoDictionary = pdfSignature; appearance.Certificate = clientCertificate[0]; var level = reader.GetCertificationLevel(); if (level != PdfSignatureAppearance.NOT_CERTIFIED) { throw new Exception("Could not apply -certlevel option. At most one certification per pdf is allowed, but source pdf contained already a certification."); } appearance.CertificationLevel = level; MakeSignature.SignExternalContainer(appearance, external, 8192); byte[] array = SHA256.Create().ComputeHash(appearance.GetRangeStream()); return prefix.Concat(array).ToArray(); } } } O meu método de assinatura é este, estou com o campo de assinatura invisível, de resto acho que é o que temos falado.Valida, eu estou a usar itextsharp Em relação ao meu resultado, nao sei se esta OK sinceramente, deveria ser suposto validar mesmo que em ambiente de testes... Edited March 17, 2021 at 12:16 PM by reznor Link to comment Share on other sites More sharing options...
reznor Posted March 17, 2021 at 12:16 PM Report Share #621729 Posted March 17, 2021 at 12:16 PM @Morfas3 Tranquilo, sem qualquer stresse 🙂 Link to comment Share on other sites More sharing options...
Labreu Posted March 17, 2021 at 02:33 PM Report Share #621731 Posted March 17, 2021 at 02:33 PM 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. Link to comment Share on other sites More sharing options...
reznor Posted March 17, 2021 at 02:40 PM Report Share #621732 Posted March 17, 2021 at 02:40 PM Exacto @Labreu tens de gerar um bloco "vazio" no pdf onde queres assinar e enviar essa hash, tal como o @Morfas3 indicou. Entretanto consegui esclarecer com a AMA e eles dizem que em PP é normal que a assinatura não esteja validada, em PROD sim. Entretanto alguma dúvida diz-me. Link to comment Share on other sites More sharing options...
Morfas3 Posted March 17, 2021 at 08:06 PM Author Report Share #621735 Posted March 17, 2021 at 08:06 PM 8 horas atrás, reznor disse: @Labreu public static byte[] GetBytesToSign(string unsignedPdf, string tempPdf, string signatureFieldName, List<X509Certificate> clientCertificate. byte[] prefix) { using (PdfReader reader = new PdfReader(unsignedPdf)) { using (FileStream os = File.OpenWrite(tempPdf)) { PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0'); PdfSignatureAppearance appearance = stamper.SignatureAppearance; //invisivel appearance.SetVisibleSignature(new Rectangle(0, 0, 0, 0), 1, signatureFieldName); IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); PdfSignature pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); appearance.SignDate = DateTime.Now; appearance.CryptoDictionary = pdfSignature; appearance.Certificate = clientCertificate[0]; var level = reader.GetCertificationLevel(); if (level != PdfSignatureAppearance.NOT_CERTIFIED) { throw new Exception("Could not apply -certlevel option. At most one certification per pdf is allowed, but source pdf contained already a certification."); } appearance.CertificationLevel = level; MakeSignature.SignExternalContainer(appearance, external, 8192); byte[] array = SHA256.Create().ComputeHash(appearance.GetRangeStream()); return prefix.Concat(array).ToArray(); } } } O meu método de assinatura é este, estou com o campo de assinatura invisível, de resto acho que é o que temos falado.Valida, eu estou a usar itextsharp Em relação ao meu resultado, nao sei se esta OK sinceramente, deveria ser suposto validar mesmo que em ambiente de testes... Olá @reznor, em pre prod tem de dar assinaturas validas, deve ser algum nabo a responder do lado da ama para te calar e não o chateares mais, eu lembro que assinar e dar sucesso Acho que tas a fazer ai umas coisas mal, tas a fazer o hash do do appearance e não do doc todo. Eu essa parte tenho dentro do metodo que implementa o sign do externalblanckcontainer, que recebe uma stream e ai sim faço a concatenação com o prefixo. depois de fazer o signexternalcontainer é so fazeres (blanckExternalContainer)external).DocumentHash; e tens o hash Link to comment Share on other sites More sharing options...
Morfas3 Posted March 17, 2021 at 08:10 PM Author Report Share #621736 Posted March 17, 2021 at 08:10 PM 10 horas atrás, reznor disse: @Labreu Penso que te falta algo no método Sign do IExternalSignatureContainer implementado: public byte[] Sign(Stream data) { PdfPKCS7 sgn = new PdfPKCS7(null, certificado.ToArray(), "SHA256", false); sgn.SetExternalDigest(this.signedBytes, null, "RSA"); return sgn.GetEncodedPKCS7(); } Onde "certificado" é a lista de certificados do método GetCertificate depois de tratado, podes validar? É isso mesmo, esta parte ta correcta @reznor @Labreu só de referir que têm de ter dois "externalcontainers" um para extrair o hash com a assinatura em branco e o outro para cravar a assinatura Link to comment Share on other sites More sharing options...
Labreu Posted March 18, 2021 at 10:04 AM Report Share #621752 Posted March 18, 2021 at 10:04 AM 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)... Link to comment Share on other sites More sharing options...
Morfas3 Posted March 18, 2021 at 10:34 AM Author Report Share #621755 Posted March 18, 2021 at 10:34 AM (edited) 43 minutes ago, Labreu said: 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)... public class ExternalEmptySignatureContainer : IExternalSignatureContainer { public void ModifySigningDictionary(PdfDictionary signDic) { signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite); signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached); } public byte[] Sign(Stream data) { // Store the data to sign and return an empty array Data = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256); return new byte[0]; } public byte[] Data; } No metodo sign tens de adicionar aqui o prefixo de bytes que ama indica na documentação. Edited March 18, 2021 at 10:47 AM by Morfas3 1 Report Link to comment Share on other sites More sharing options...
Labreu Posted March 18, 2021 at 11:10 AM Report Share #621756 Posted March 18, 2021 at 11:10 AM @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...) Link to comment Share on other sites More sharing options...
reznor Posted March 18, 2021 at 06:31 PM Report Share #621759 Posted March 18, 2021 at 06:31 PM @Morfas3 Olá! Obrigado pela resposta, eu estou a faze exatamente isso e o resultado que tenho é o mesmo: public byte[] Sign(Stream data) { byte[] sha256SigPrefix = new byte[] {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,0x05, 0x00, 0x04, 0x20}; Data = sha256SigPrefix.Concat(DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256)).ToArray(); return new byte[0]; } Este meu método Sign para a Assinatura em branco condiz agora com o que transmitiste! é chamado aqui (ao fazer a assinatura em braco) (...) MakeSignature.SignExternalContainer(appearance, external, 8192); var ssa = ((ExternalBlankSignatureContainer)external).Data; (...) E tenho de retorno um byte[51] limpinho para a minha variável "ssa". Ao fazer embed da minha assinatura de retorno da AMA: public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signature, List<X509Certificate> certificates) { using (PdfReader reader = new PdfReader(signedPdf)) { using (FileStream os = new FileStream(tempPdf, FileMode.Create, FileAccess.ReadWrite)) { IExternalSignatureContainer external = new MyExternalSignatureContainer(signature, certificates); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } } e cá está o bicho... Entretanto(e sem querer) cliquei no botão "Show Issuer Policy"... e não há página sequerhttps://www.scee.gov.pt/pcert?lang=ENU Sinceramente já não sei qual o resultado ou o que podemos esperar daqui, muitas questões e pouca documentação e informações vagas... a AMA devia disponibilizar mais info acerca do assunto. @Labreu pois, lá está a situação... eu também não sou o CR7 das assinaturas digitais e não consigo dizer que solução é a mais correta... um belo serviço aqui de verdade 🥴🥴🥴 Link to comment Share on other sites More sharing options...
Morfas3 Posted March 18, 2021 at 07:03 PM Author Report Share #621760 Posted March 18, 2021 at 07:03 PM (edited) 34 minutes ago, reznor said: @Morfas3 Olá! Obrigado pela resposta, eu estou a faze exatamente isso e o resultado que tenho é o mesmo: Este meu método Sign para a Assinatura em branco condiz agora com o que transmitiste! é chamado aqui (ao fazer a assinatura em braco) (...) MakeSignature.SignExternalContainer(appearance, external, 8192); var ssa = ((ExternalBlankSignatureContainer)external).Data; (...) E tenho de retorno um byte[51] limpinho para a minha variável "ssa". Ao fazer embed da minha assinatura de retorno da AMA: public static void EmbedSignature(string tempPdf, string signedPdf, string signatureFieldName, byte[] signature, List<X509Certificate> certificates) { using (PdfReader reader = new PdfReader(signedPdf)) { using (FileStream os = new FileStream(tempPdf, FileMode.Create, FileAccess.ReadWrite)) { IExternalSignatureContainer external = new MyExternalSignatureContainer(signature, certificates); MakeSignature.SignDeferred(reader, signatureFieldName, os, external); } } } e cá está o bicho... Entretanto(e sem querer) cliquei no botão "Show Issuer Policy"... e não há página sequerhttps://www.scee.gov.pt/pcert?lang=ENU Sinceramente já não sei qual o resultado ou o que podemos esperar daqui, muitas questões e pouca documentação e informações vagas... a AMA devia disponibilizar mais info acerca do assunto. @Labreu pois, lá está a situação... eu também não sou o CR7 das assinaturas digitais e não consigo dizer que solução é a mais correta... um belo serviço aqui de verdade 🥴🥴🥴 public byte[] Sign(Stream data) { byte[] sha256SigPrefix = new byte[] {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,0x05, 0x00, 0x04, 0x20}; Data = sha256SigPrefix.Concat(DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256)).ToArray(); return new byte[0]; } @reznorpode nao ter nada haver mas retorna o resultado da concatenação no sign, tas a retornar um array de bytes vazio, não sei se implica alguma coisa Acho que tens o racicionio correcto, a unica diferença é usares o itextsharp em vez do itext 7 Edited March 18, 2021 at 07:05 PM by Morfas3 Link to comment Share on other sites More sharing options...
Morfas3 Posted March 18, 2021 at 08:27 PM Author Report Share #621761 Posted March 18, 2021 at 08:27 PM (edited) @reznor provavelmente deve ser a mesma coisa, no sign faz isto SHA256 Sha256 = SHA256.Create(); byte[] docHash = Sha256.ComputeHash(data); Aqui EmbedSignature(string tempPdf, string signedPdf, o signedPdf é o teu pdf com a assinatura em branco certo? Edited March 18, 2021 at 08:28 PM by Morfas3 Link to comment Share on other sites More sharing options...
reznor Posted March 18, 2021 at 10:34 PM Report Share #621762 Posted March 18, 2021 at 10:34 PM @Morfas3 Em relação ao teu primeiro comentário, acho que não faz nada de qualquer forma troquei o retorno e tudo fica igual! Já começo a duvidar do itextsharp... No segundo comentário, sim é o PDF com a assinatura em branco e fazer o ComputeHash retorna-me exatamente o mesmo byte[] que o que já estou a fazer... Que bico de obra... Link to comment Share on other sites More sharing options...
Labreu Posted March 19, 2021 at 11:29 AM Report Share #621763 Posted March 19, 2021 at 11:29 AM 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: Quote No. To use a PdfPKCS7 pkcs7 properly, you have to call pkcs7.GetAuthenticatedAttributeBytes with the document hash (without the sha256SigPrefix) to get the signed attributes to be, hash and sign them, set the resulting signature bytes using pkcs7.SetExternalDigest, and eventually call pkcs7.GetEncodedPKCS7 with the same parameters as the original GetAuthenticatedAttributeBytes call. – mkl yesterday 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 😞 Link to comment Share on other sites More sharing options...
Labreu Posted March 19, 2021 at 07:28 PM Report Share #621765 Posted March 19, 2021 at 07:28 PM 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... Link to comment Share on other sites More sharing options...
reznor Posted March 23, 2021 at 07:59 AM Report Share #621781 Posted March 23, 2021 at 07:59 AM @Labreu Bom dia! Consegues ter o ficheiro assinado em PP com assinatura válida já? Link to comment Share on other sites More sharing options...
Popular Post Labreu Posted March 23, 2021 at 02:03 PM Popular Post Report Share #621789 Posted March 23, 2021 at 02:03 PM Boas. Se alguém tiver interesser, criei uma demo online: https://github.com/luisabreu/AmaCmdSigning 3 Report Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now