Nel Posted November 16, 2022 at 01:13 PM Report #628196 Posted November 16, 2022 at 01:13 PM Em 16/11/2022 às 12:10, bugmen disse: Eu também estou a desenvolver em PHP. @Nel conseguiste adaptar o tcpdf? Podes dar-me umas luzes sff ? Andei à procura de novas versões do tcpdf mas sem sucesso. Estou a fazer a partir deste exemplo: https://tcpdf.org/examples/example_052/ Depois para poderes trabalhar a partir de um pdf existente tens de ligar com o FPDI: https://manuals.setasign.com/fpdi-manual/v1/the-fpdf-tpl-class/ A ideia seria subtituir a obter da signature onde eles usam o openssl_pkcs7_sign, pela hash assinada remotamente pelo SAFE. Mas ainda não funciona bem. Depois há ainda a questão do selo temporal.
Nel Posted November 16, 2022 at 01:20 PM Report #628197 Posted November 16, 2022 at 01:20 PM Em 16/11/2022 às 12:27, laboss disse: Podem testar os pdf's aqui https://validador.autenticacao.gov.pt/validation Os meus ficam assim Agora estou a fazer um ensaio com C# usando o iTextSharp Version 5.5.13.1 O resultado fica assim. É por faltar o LTV? Ou qual será o problema?
laboss Posted November 16, 2022 at 01:39 PM Report #628198 Posted November 16, 2022 at 01:39 PM (edited) Acho que está mal porque diz que o documento foi alterado ou está corrompido, mesmo sem ltv deve aparecer o nome que está na assinatura digital mesmo que esteja invalida O ltv nem é obrigatório, é recomendado Edited November 16, 2022 at 01:49 PM by laboss
samuquinha Posted November 16, 2022 at 05:58 PM Report #628217 Posted November 16, 2022 at 05:58 PM Bem, já estou a integrar com o oAuth e a obter os tokens necessários para assinar documentos, agora estou com um problema... de (des)conhecimento... Estou a obter uma string base64, com o conteudo do pdf (tipo isto: JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PC9MZW5ndGggNiAwIFIvRmlsdGVyIC9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nN1czZJdt3He36c4G6fmqjiH+P/RbiTSihxRpsQRUxUrC3o4HJF1hxRJKXb50bTNwpV1XiBVWajsrcubrNINoBt97sHcGVqzGlm0+sMBGt1Ao9EN4PLtpGZtJoX/I+LscnP/6zhdvN+oOXqbVZjWxLuLjYvaTS5kP4c4XTYYlUEI/034f7EBzeBsk5xjtNskGxkla5hDoRtzaIPIZ0VtECVb60F7H2t75Nzos03ttsHdporUYBW2sWigcj/bvPhok6Y/bPT0G/jz6tAgfP3ZnR2E7zZPNtZbaJtsxiKtU5pMdtO7882L+slr4/lTqh+ATW+z32DBKw0+iAbFJHmEvdZajDD07NqgIrBVg5ANAxgt...) Ao aplicar o hash SHA256 a essa string obtenho uma string (tipo isto: 30b3192f1bea185ae50ca071860af59d5c9489a5b710b35ed0eeb64e193c2701), só que aqui esta string parece ser haxadecimal, as estou a usar uma função HASH(string a encripatar, algoritmo) disponibilizada pelo SAP SQL Anywhere. Como não me parece que seja a string no ponto anterior, estou novamente a converter para base64, ficando tipo isto: MzBiMzE5MmYxYmVhMTg1YWU1MGNhMDcxODYwYWY1OWQ1Yzk0ODlhNWI3MTBiMzVlZDBlZWI2NGUxOTNjMjcwMQ== Tenho que adicionar a essa string o prefixo do SHA256, que também tenho alguma dúvida no valor: estou a considerar o valor 628 em base64 que é "NjI4M". Resumindo e baralhando, é-me retornada uma string base64 com a signature, mas pondo em pdf, dá erro a abrir o ficheiro. A ferramenta de desenvolvimento é Delphi 6, o velhinho... Alguma sugestão?
Nel Posted November 16, 2022 at 07:18 PM Report #628221 Posted November 16, 2022 at 07:18 PM Fica aqui em ensaio funcional em C# feito com o iTextSharp -Version 5.5.13.1 Os certificados foram guardados a partir do credentials/info Em PHP a dificuldade será fazer o que faz sn.getAuthenticatedAttributeBytes. Irei experimentar o SetaPdf-Signer, mas é pago. A vantagem é que o @bioshock já disponibilizou o código. using System; using System.Collections.Generic; using System.IO; using System.Security.Cryptography; using iTextSharp.text; using iTextSharp.text.pdf; using iTextSharp.text.pdf.security; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.X509; using X509Certificate = Org.BouncyCastle.X509.X509Certificate; namespace SAFE { public class SAFE_Sign { private static string src = @"D:\SAFE\Exemplo.pdf"; private static string dest = @"D:\SAFE\Exemplo-sign.pdf"; private static string certFile1 = @"D:\SAFE\cert1.der"; private static string certFile2 = @"D:\SAFE\cert2.der"; private static string certFile3 = @"D:\SAFE\cert3.der"; /* * https://www.linkedin.com/pulse/digital-signature-c-external-service-daniele-proietti/ */ //Install-Package iTextSharp -Version 5.5.13.1 public void safe_sign() { X509CertificateParser parser = new X509CertificateParser(); X509Certificate cert = parser.ReadCertificate(new FileStream(certFile1, FileMode.Open)); X509Certificate cert2 = parser.ReadCertificate(new FileStream(certFile2, FileMode.Open)); X509Certificate cert3 = parser.ReadCertificate(new FileStream(certFile3, FileMode.Open)); using (PdfReader reader = new PdfReader(src)) { using (MemoryStream ms = new MemoryStream()) { PdfStamper stamper = PdfStamper.CreateSignature(reader, ms, '\0'); // create the signature appearance PdfSignatureAppearance sap = stamper.SignatureAppearance; sap.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig"); sap.Reason = ""; sap.Location = ""; // It is then necessary to provide the PdfSignatureAppearance class with the certificate // with the public key to be used for the signature. sap.Certificate = cert; // The PDFSignature class contains information about the filter and sub-filters that are used // for validating the signature embedded in a signed or certified PDF document. PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); dic.Reason = sap.Reason; dic.Location = sap.Location; dic.Contact = sap.Contact; dic.Date = new PdfDate(sap.SignDate); sap.CryptoDictionary = dic; Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>(); exc.Add(PdfName.CONTENTS, (int)(8192 * 2 + 2)); sap.PreClose(exc); //Now we need to extract the hash of the document that will be sent to the signature service. Stream data = sap.GetRangeStream(); // The document digest is generated and put inside the attribute. // The signing is done over the DER encoded authenticatedAttributes. // This method provides that encoding and the parameters must be exactly the same as in GetEncodedPKCS7(byte[]). List<X509Certificate> chain = new List<X509Certificate>() { cert, cert2, cert3 }; PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", false); byte[] hash = DigestAlgorithms.Digest(data, DigestAlgorithms.GetMessageDigest("SHA256")); byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS); //create sha256 message digest using (SHA256 sha256 = SHA256.Create()) { sh = sha256.ComputeHash(sh); } //Add sha256SigPrefix byte[] sha256SigPrefix = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; int length = sha256SigPrefix.Length + sh.Length; byte[] sum = new byte[length]; sha256SigPrefix.CopyTo(sum, 0); sh.CopyTo(sum, sha256SigPrefix.Length); sh = sum; //Now the byte array representation of the authenticatedAttributes is ready to be signed. //converte to base64 String base64encodedDigest = Convert.ToBase64String(sh); //teste File.WriteAllText(hashFile, base64encodedDigest); Console.WriteLine("\nObtem SAFE signature"); string signatureBase64 = SAFE_Connect.getSignature(base64encodedDigest, "Exemplo.pdf"); Console.WriteLine("\nSAFE signature: " + signatureBase64); //decode to bytes byte[] signedHash = Convert.FromBase64String(signatureBase64); //When we have the signed hash available, the PDF composition process must be completed. sgn.SetExternalDigest(signedHash, null, "RSA"); byte[] encodedSig = sgn.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS); byte[] paddedSig = new byte[8192]; encodedSig.CopyTo(paddedSig, 0); PdfDictionary dic2 = new PdfDictionary(); dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true)); sap.Close(dic2); //Once finished the composition process of the PDF, we will have available in the “MemoryStream” the PDF signed; //what we need to do is to transform it in a byte array and save it to the disk. byte[] signed = ms.ToArray(); File.WriteAllBytes(dest, signed); } } } } } using System; using System.IO; using System.Net; using System.Text; using Newtonsoft.Json.Linq; namespace SAFE { public class SAFE_Connect { private static string baseURL = "https://pprsafe.autenticacao.gov.pt"; private static string credentialID = ""; private static string clientName = "clientTest"; private static string basicAuth = "clientTest:Test"; private static string SAFE_AccessToken = ""; private static string processId = "a015722c-456e-4abc-9efb-d774936ce749"; private static string SAFE_signAlgo = "1.2.840.113549.1.1.11"; public static string getSignature(string hash, string docname) { string token = SAFE_AccessToken; //get SAD string sad = authorize(token, hash, docname); //sign HASH string signature = null; if (sad != null) { signature = signHash(token, hash, sad, SAFE_signAlgo); } return signature; } public static string authorize(string token, string hash, string docname) { Uri loginURL = new Uri(baseURL + "/credentials/authorize"); JObject reqData = new JObject(); reqData.Add("clientData", new JObject( new JProperty("clientName", clientName), new JProperty("documentNames", new JArray(docname)), new JProperty("processId", processId) ) ); reqData.Add("credentialID", credentialID); reqData.Add("hashes", new JArray(hash) ); reqData.Add("numSignatures", 1); var httpWebRequest = (HttpWebRequest)WebRequest.Create(loginURL); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json; charset=UTF-8"; httpWebRequest.ContentLength = reqData.ToString().Length; httpWebRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(basicAuth)) ); httpWebRequest.Headers.Add("SAFEAuthorization", "Bearer " + token); //Send Request using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { streamWriter.Write(reqData.ToString()); } //Get Response var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); string result; using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } JObject respData = JObject.Parse(result); return respData.GetValue("sad").ToString(); } public static string signHash(string token, string hash, string sad, string signAlgo) { Uri loginURL = new Uri(baseURL + "/signatures/signHash"); JObject reqData = new JObject(); reqData.Add("clientData", new JObject( new JProperty("clientName", clientName), new JProperty("processId", processId) ) ); reqData.Add("credentialID", credentialID); reqData.Add("hashes", new JArray(hash)); reqData.Add("sad", sad); reqData.Add("signAlgo", signAlgo); var httpWebRequest = (HttpWebRequest)WebRequest.Create(loginURL); httpWebRequest.Method = "POST"; httpWebRequest.ContentType = "application/json; charset=UTF-8"; httpWebRequest.ContentLength = reqData.ToString().Length; httpWebRequest.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(basicAuth))); httpWebRequest.Headers.Add("SAFEAuthorization", "Bearer " + token); //Send Request using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) { streamWriter.Write(reqData.ToString()); } //Get Response var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse(); string result; using (var streamReader = new StreamReader(httpResponse.GetResponseStream())) { result = streamReader.ReadToEnd(); } JObject respData = JObject.Parse(result); return respData.GetValue("signatures")[0].ToString(); } } } 2 Report
bioshock Posted November 19, 2022 at 02:34 PM Report #628281 Posted November 19, 2022 at 02:34 PM Alguém faz ideia de quanto tempo demoram a aprovar / dar resposta quando se envia o email para eid@ama.pt para passar a produção?
laboss Posted November 19, 2022 at 02:46 PM Report #628282 Posted November 19, 2022 at 02:46 PM (edited) Depois de enviar as evidências todas e eles validarem os PDF foram 3 dias para receber as credenciais... mas já tinha assinado o protocolo Edited November 19, 2022 at 02:46 PM by laboss
samuquinha Posted November 21, 2022 at 05:19 PM Report #628302 Posted November 21, 2022 at 05:19 PM Boa tarde a todos, Alguém a usar Delphi para integração SAFE?
CPHJ1966 Posted November 22, 2022 at 09:32 AM Report #628305 Posted November 22, 2022 at 09:32 AM Bom dia. Alguém tem o desenvolvimento de integração com o SAFE em VB NET ? Obrigado
bugmen Posted November 22, 2022 at 11:46 AM Report #628310 Posted November 22, 2022 at 11:46 AM Em 16/11/2022 às 13:13, Nel disse: Estou a fazer a partir deste exemplo: https://tcpdf.org/examples/example_052/ Depois para poderes trabalhar a partir de um pdf existente tens de ligar com o FPDI: https://manuals.setasign.com/fpdi-manual/v1/the-fpdf-tpl-class/ A ideia seria subtituir a obter da signature onde eles usam o openssl_pkcs7_sign, pela hash assinada remotamente pelo SAFE. Mas ainda não funciona bem. Depois há ainda a questão do selo temporal. Obrigado. Tenho estado analisar o código do TCPDF e também não sei muito bem com adaptá-lo. Assim que conseguir um avanço partilho aqui. Uma questão no processo de autenticação OAuth da AMA. Que URL de redirecionamento devo utilizar no caso de ter "múltiplos" subdominios consoante o cliente? Exemplo: Na documentação referem que pode ser https://sub.dominio.pt ou https://dominio.pt/ .... Poderá ser no formato *.sub.dominio.pt? Exemplo : cliente1.sub.dominio.pt , cliente2.sub.dominio.pt ..... ? Não sei se fui claro, mas se alguém passou por esta questão que abordagem seguiu? Estou a desenvolver em PHP. Obrigado.
bioshock Posted November 23, 2022 at 03:31 PM Report #628331 Posted November 23, 2022 at 03:31 PM (edited) On 11/19/2022 at 2:46 PM, laboss said: Depois de enviar as evidências todas e eles validarem os PDF foram 3 dias para receber as credenciais... mas já tinha assinado o protocolo Já se passou 1 semana e nada 😔, ainda não me responderam ao email. Edited November 23, 2022 at 03:31 PM by bioshock
bioshock Posted November 30, 2022 at 03:42 PM Report #628442 Posted November 30, 2022 at 03:42 PM Já há decreto do adiamento da assinatura digital?
zeph Posted November 30, 2022 at 05:39 PM Report #628453 Posted November 30, 2022 at 05:39 PM (edited) On 11/22/2022 at 11:46 AM, bugmen said: Obrigado. Tenho estado analisar o código do TCPDF e também não sei muito bem com adaptá-lo. Assim que conseguir um avanço partilho aqui. Uma questão no processo de autenticação OAuth da AMA. Que URL de redirecionamento devo utilizar no caso de ter "múltiplos" subdominios consoante o cliente? Exemplo: Na documentação referem que pode ser https://sub.dominio.pt ou https://dominio.pt/ .... Poderá ser no formato *.sub.dominio.pt? Exemplo : cliente1.sub.dominio.pt , cliente2.sub.dominio.pt ..... ? Não sei se fui claro, mas se alguém passou por esta questão que abordagem seguiu? Estou a desenvolver em PHP. Obrigado. O que interessa é o dominio. Podes ter qualquer coisa desde que faça parte do dominio que registaste com eles. Eles verificam depois se o dominio que usaste no redirect do oauth esta registado com eles. Por isso, podes usar qualquer subdominio desde que pertença ao dominio que registaste. Edited November 30, 2022 at 05:42 PM by zeph 1 Report
zeph Posted November 30, 2022 at 05:43 PM Report #628454 Posted November 30, 2022 at 05:43 PM On 11/30/2022 at 3:42 PM, bioshock said: Já há decreto do adiamento da assinatura digital? Ainda não li nada sobre.
JorgeRocha Posted November 30, 2022 at 07:17 PM Report #628459 Posted November 30, 2022 at 07:17 PM Em 30/11/2022 às 15:42, bioshock disse: Já há decreto do adiamento da assinatura digital? Ainda estamos a espera de fato.. Jorge Rocha
Oscar_1234 Posted December 2, 2022 at 11:18 AM Report #628486 Posted December 2, 2022 at 11:18 AM On 10/29/2022 at 8:22 AM, laboss said: Depois de meteres o container da assinatura e basicamente isso, o código não consigo passar pois é da empresa, mas é basicamente isto https://stackoverflow.com/questions/54559547/external-signing-pdf-with-itext Não usei essa lib usei devexpress mas a muita gente a usar essa Hi, you have an example of a SAFE signature with devexpress? I did it with itext7 ... but it costs too much! thank you 🙂
jorang Posted December 13, 2022 at 05:58 PM Report #628833 Posted December 13, 2022 at 05:58 PM Já saiu o despacho a adiar a assinatura qualificada nos PDF: https://info.portaldasfinancas.gov.pt/pt/informacao_fiscal/legislacao/Despachos_SEAF/Documents/Despacho_SEAF_8_2022_XXIII.pdf
zeph Posted December 13, 2022 at 08:55 PM Report #628847 Posted December 13, 2022 at 08:55 PM Foi adiado até 31 de Dezembro de 2023, é isso?
marcolopes Posted December 13, 2022 at 09:11 PM Author Report #628848 Posted December 13, 2022 at 09:11 PM On 12/13/2022 at 8:55 PM, zeph said: Foi adiado até 31 de Dezembro de 2023, é isso? A factura electrónica PDF sim... a FE-AP (pelo meu entendimento) não: https://www.portugal-a-programar.pt/forums/topic/77364-at-questões-legais/page/320/#comment-628846 The simplest explanation is usually the correct one JAVA Utilities: https://github.com/marcolopes/dma
blacksnake Posted December 13, 2022 at 10:34 PM Report #628849 Posted December 13, 2022 at 10:34 PM (edited) Em 23/11/2022 às 15:31, bioshock disse: Já se passou 1 semana e nada 😔, ainda não me responderam ao email. Vamos la mais um aninho. Quem será que nao conseguiu terminar a tempo para levar a adiamento. Edited December 13, 2022 at 10:36 PM by blacksnake
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