Morfas3 5 Posted March 15 Author Report Share Posted March 15 @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 post Share on other sites
reznor 3 Posted March 15 Report Share Posted March 15 @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 post Share on other sites
Morfas3 5 Posted March 15 Author Report Share Posted March 15 sim o certificado vem noutro serviço, GetCertificate Link to post Share on other sites
reznor 3 Posted March 15 Report Share Posted March 15 @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 post Share on other sites
Morfas3 5 Posted March 15 Author Report Share Posted March 15 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 post Share on other sites
reznor 3 Posted March 15 Report Share Posted March 15 @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 post Share on other sites
Morfas3 5 Posted March 15 Author Report Share Posted March 15 @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 post Share on other sites
Morfas3 5 Posted March 15 Author Report Share Posted March 15 @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 post Share on other sites
reznor 3 Posted March 16 Report Share Posted March 16 @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 post Share on other sites
Morfas3 5 Posted March 16 Author Report Share Posted March 16 @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 post Share on other sites
reznor 3 Posted March 16 Report Share Posted March 16 @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 post Share on other sites
Morfas3 5 Posted March 16 Author Report Share Posted March 16 (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 by Morfas3 1 Report Link to post Share on other sites
reznor 3 Posted March 16 Report Share Posted March 16 @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 post Share on other sites
Morfas3 5 Posted March 16 Author Report Share Posted March 16 @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 post Share on other sites
reznor 3 Posted March 16 Report Share Posted March 16 @Morfas3 Está bem, muito obrigado pelo apoio! Link to post Share on other sites
Labreu 3 Posted March 17 Report Share Posted March 17 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 post Share on other sites
reznor 3 Posted March 17 Report Share Posted March 17 (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 by reznor Link to post Share on other sites
Labreu 3 Posted March 17 Report Share Posted March 17 (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 by Labreu Mais informação Link to post Share on other sites
reznor 3 Posted March 17 Report Share Posted March 17 @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 post Share on other sites
Labreu 3 Posted March 17 Report Share Posted March 17 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 post Share on other sites
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