Morfas3 Posted March 15, 2021 at 03:30 PM Author Report Share #621685 Posted March 15, 2021 at 03:30 PM @reznor tens de criar uma chain com o certificado do user que obteste pelo serviço da Ama Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { certParse.ReadCertificate(cert.RawData) }; Link to comment Share on other sites More sharing options...
reznor Posted March 15, 2021 at 04:12 PM Report Share #621686 Posted March 15, 2021 at 04:12 PM @Morfas3 Este print é o resultado de quando valido o codigo SMS que me foi enviado. Perguntei à AMA se o campo "certificate" deveria vir a null e disseram-me que era normal e que o processo da CMD acaba aqui. Este certificado que falas é suposto vir aqui ou é um outro método que eles disponibilizam chamado GetCertificate que me retorna 3 certificados distintos? Obrigado Link to comment Share on other sites More sharing options...
Morfas3 Posted March 15, 2021 at 04:26 PM Author Report Share #621687 Posted March 15, 2021 at 04:26 PM sim o certificado vem noutro serviço, GetCertificate Link to comment Share on other sites More sharing options...
reznor Posted March 15, 2021 at 05:36 PM Report Share #621688 Posted March 15, 2021 at 05:36 PM @Morfas3 Recebo 3 certificado nesse getCertificate. Construo uma chain onde só 2 deles são parsed com sucesso, depois tento assinar mas a assinatura vem inválida. Estou a usar iTextSharp e não itext. Sabes se sao necessários os 3 certificados que mandam no método? Link to comment Share on other sites More sharing options...
Morfas3 Posted March 15, 2021 at 05:50 PM Author Report Share #621689 Posted March 15, 2021 at 05:50 PM eu usei o itext7 no fundo é quase a mesma coisa Tens de fazer fazer uma assinatura em branco quando vais buscar o hash do documento antes de enviar para a AMA. Eu tenho de ver melhor como foi feito para vos explicar, confesso que não posso espetar aqui o código de como foi feito, porque o código não me pertence. Link to comment Share on other sites More sharing options...
reznor Posted March 15, 2021 at 06:02 PM Report Share #621690 Posted March 15, 2021 at 06:02 PM @Morfas3 Certo nem é isso que se pretende, isto é um processo bastante complexo e ha pouca documentação. A questão de criar a assinatura em braco e enviar o hash esta ok, já esta á a assinar só que não está válida... Tenho de revalidar todo o codigo, pode ser alguma coisa que nao estou a fazer certo Link to comment Share on other sites More sharing options...
Morfas3 Posted March 15, 2021 at 07:02 PM Author Report Share #621691 Posted March 15, 2021 at 07:02 PM @reznor sobre o certificado o serviço traz um .pem e é so usares esse ficheiro a construir a chain sobre a assinatura em branco, tens de implementar outro container a implementar a IExternalSignatureContainer em que tens de fazer o hash do documento com o prefixo que eles falam na documentação isto na implementação do método byte[] Sign(Stream data), implementa também este metodo public void ModifySigningDictionary(PdfDictionary signDic) { signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite); signDic.Put(PdfName.SubFilter, tPdfName.Adbe_pkcs7_detached); } depois é fazer isto PdfSigner signer = new PdfSigner(pdfReader, filestream, new StampingProperties()); var chain = Getcertificado_do_user(filpath); signer.SetFieldName("fieldname"); this.SetCustomSignature(signer.GetDocument(), signer.GetSignatureAppearance(), chain[0], signatureLocation, signatureReason); IExternalSignatureContainer external = new ExternalContainer(PdfName.Adobe_PPKLite, PdfName.Adbe_pkcs7_detached); signer.SignExternalContainer(external, 8192); hashToSend = ((ExternalContainer)external).DocumentHash; Link to comment Share on other sites More sharing options...
Morfas3 Posted March 15, 2021 at 07:16 PM Author Report Share #621692 Posted March 15, 2021 at 07:16 PM @reznor esquci-me de um promenor this.SetCustomSignature é implementado por nós, mas basicamente é onde se faz a customização da assinatura, mas tem lá este pequeno truque importante este parametro que passas no metodo, signer.GetSignatureAppearance() serve para fazer isto abaixo signerappereance .SetCertificate(chain do certificado utilizador); Link to comment Share on other sites More sharing options...
reznor Posted March 16, 2021 at 11:06 AM Report Share #621694 Posted March 16, 2021 at 11:06 AM @Morfas3 Bom dia, não percebi a parte de fazer a hash do documento com o prefixo eles falam na documentação... De resto, penso que esta tudo implementado do meu lado 😉 Link to comment Share on other sites More sharing options...
Morfas3 Posted March 16, 2021 at 11:13 AM Author Report Share #621695 Posted March 16, 2021 at 11:13 AM @reznor eles têm lá um conjunto de byes do documento, agora não encontro a documentação mas penso que vai de encontro a estes bytes abaixo byte[] sha256SigPrefix = new byte[] { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 }; Link to comment Share on other sites More sharing options...
reznor Posted March 16, 2021 at 11:23 AM Report Share #621696 Posted March 16, 2021 at 11:23 AM @Morfas3 ok, já percebi, o que não estou a entender é que é dito lá no documento que "O hash enviado para os serviços deve ser o prefixo seguido do hash do documento.", isto vai seguir o EMSA-PKCS1-v1_5, estou com dificuldade em fazer isto, como computar estas duas hash para enviar para a CMD. É a primeira vez que estou a lidar com crypto, algumas coisas são completamente novas e peço desculpa se parecer demasiado parvo ou non-sense qualquer pergunta da minha parte Link to comment Share on other sites More sharing options...
Morfas3 Posted March 16, 2021 at 11:33 AM Author Report Share #621697 Posted March 16, 2021 at 11:33 AM (edited) @reznor basicamente tens de fazer byte[] docHash = Sha256.ComputeHash(array de bytes do doc), e juntar este bytearray ao array de bytes do prefixo Deixa lá quando andamos a implementar isto, quase que íamos chegar ao ponto de implementar o algorimto de hash que eles falam na documentação (visto que já não conseguiamos perceber o que estava mal), mas depois confirmei que o .net já tem isto. Foi muita tentativa e erro. Edited March 16, 2021 at 11:34 AM by Morfas3 1 Report Link to comment Share on other sites More sharing options...
reznor Posted March 16, 2021 at 03:07 PM Report Share #621708 Posted March 16, 2021 at 03:07 PM @Morfas3 Tentativa erra à fartazana, é como levar com brita na cara constantemente!! Já consegui assinar à partida, tenho alguns warnings no PDF Aconteceu-te algo do género? Já agora, eu não sei se estes testes em Pré Produção da AMA devem dar assinaturas válidas atenção, tentei perguntar mas é complicado do lado deles responder... Link to comment Share on other sites More sharing options...
Morfas3 Posted March 16, 2021 at 03:23 PM Author Report Share #621711 Posted March 16, 2021 at 03:23 PM @reznor tá quase, acho que também tive desses warnings, é suposto ser assinaturas váilidas sim. Deixa me olhar para os documentos que tenho para aqui. Link to comment Share on other sites More sharing options...
reznor Posted March 16, 2021 at 04:04 PM Report Share #621713 Posted March 16, 2021 at 04:04 PM @Morfas3 Está bem, muito obrigado pelo apoio! Link to comment Share on other sites More sharing options...
Labreu Posted March 17, 2021 at 12:02 AM Report Share #621716 Posted March 17, 2021 at 12:02 AM 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. Link to comment Share on other sites More sharing options...
reznor Posted March 17, 2021 at 09:35 AM Report Share #621717 Posted March 17, 2021 at 09:35 AM (edited) @Labreu Basicamente estás a fazer o mesmo que estamos a fazer, em relação ao hash que envias para a AMA, colocaste o prefixo? Aquela dica que o @Morfas3 deu antes da minha segunda imagem? Não estou a ter o encoding error, estou na fase em que tenho o doc assinado, se vir os detalhes de assinatura esta tudo ok (à primeira vista) e não sei qual sera o problema seguinte Edited March 17, 2021 at 09:35 AM by reznor Link to comment Share on other sites More sharing options...
Labreu Posted March 17, 2021 at 10:25 AM Report Share #621720 Posted March 17, 2021 at 10:25 AM (edited) 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... Edited March 17, 2021 at 10:43 AM by Labreu Mais informação Link to comment Share on other sites More sharing options...
reznor Posted March 17, 2021 at 10:50 AM Report Share #621722 Posted March 17, 2021 at 10:50 AM @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? Link to comment Share on other sites More sharing options...
Labreu Posted March 17, 2021 at 11:08 AM Report Share #621723 Posted March 17, 2021 at 11:08 AM 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... 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