public ActionResult SignCodComplete(SignatureCompleteModel model) { byte[] signatureContent; try { var signer = new XmlElementSigner(); // Set the document to be signed and the policy, exactly like in the SignCod method signer.SetXml(Storage.GetSampleCodEnvelope()); signer.SetPolicy(getSignaturePolicy()); // Set the signature computed on the client-side, along with the "transfer data" signer.SetPrecomputedSignature(model.Signature, model.TransferData); // It is not necessary to set the signing certificate nor the element ID to be signed, both are contained in the "transfer data" // Call ComputeSignature(), which validates the signature of the "to-sign-hash" and finishes the signature process signer.ComputeSignature(); // Get the signed XML as an array of bytes signatureContent = signer.GetSignedXml(); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate is revoked. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // Store the signature file on the folder "App_Data/" and redirect to the SignCodResult action with the filename. var filename = Storage.StoreFile(signatureContent, ".xml"); return(RedirectToAction("SignCodResult", new SignatureInfoModel() { Filename = filename })); }
public ActionResult Complete(SignatureCompleteModel model) { byte[] signatureContent; try { // Recover the "transfer data" content stored in a temporary file. if (!StorageMock.TryGetFile(model.TransferDataFileId, out byte[] transferDataContent))
public ActionResult Index(SignatureStartModel model) { byte[] toSignBytes, transferData; SignatureAlgorithm signatureAlg; try { // Verify if the userfile exists and get its absolute path. string userfilePath; if (!StorageMock.TryGetFile(model.UserFile, out userfilePath)) { return(HttpNotFound()); } // Decode the user's certificate. var cert = PKCertificate.Decode(model.CertContent); // Get an instance of the PadesSigner class. var padesSigner = new PadesSigner(); // Set the file to be signed. padesSigner.SetPdfToSign(userfilePath); // Set the signer certificate. padesSigner.SetSigningCertificate(cert); // Set the signature policy. padesSigner.SetPolicy(GetSignaturePolicy()); // Set a visual representation for the signature. padesSigner.SetVisualRepresentation(PadesVisualElements.GetVisualRepresentationForPkiSdk(cert)); // Generate the "to-sign-bytes". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy, as well as the "transfer data", // a byte-array that will be needed on the next step. toSignBytes = padesSigner.GetToSignBytes(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The thumbprint of the selected certificate. // - The "transfer data" used to validate the signature in complete action. Its content is stored in // a temporary file (with extension .bin) to be shared with the Complete action. // - The "to-sign-hash" (digest of the "to-sign-bytes") to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertThumb = model.CertThumb, TransferDataFileId = StorageMock.Store(transferData, ".bin"), ToSignHash = signatureAlg.DigestAlgorithm.ComputeHash(toSignBytes), DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete", new { userfile = model.UserFile })); }
public ActionResult Complete(SignatureCompleteModel model) { byte[] signedPdf; try { // Recover session data from Index action var sessionModel = Session["ITextSessionModel"] as ITextSessionModel; if (sessionModel == null) { // This should not happen return(RedirectToAction("Index")); } // Decode Certificate var certificate = new X509CertificateParser().ReadCertificate(model.CertContent); // Compute the external digest var pkcs7 = new PdfPKCS7(null, new X509Certificate[] { certificate }, DigestAlgorithm, false); pkcs7.SetExternalDigest(model.Signature, null, "RSA"); // Get a padded PKCS#7 byte[] pkcs7Encoded = pkcs7.GetEncodedPKCS7(sessionModel.RangeDigest); if (pkcs7Encoded.Length > 8192) // It shouldn't happen { throw new InvalidOperationException("PKCS37 encoded shouldn't be bigger than the space reserved for it"); } byte[] pkcs7Padded = new byte[8192]; pkcs7Encoded.CopyTo(pkcs7Padded, 0); // Instanciate a PDF dictionary var sigDictionary = new PdfDictionary(); // Write the PKCS#7 padded on the signature dictionary sigDictionary.Put(PdfName.CONTENTS, new PdfString(pkcs7Padded).SetHexWriting(true)); // Finally, close the PDF appearance to finish the signature process sessionModel.SignatureApperance.Close(sigDictionary); // Receive the signed PDF bytes from the its stream, which was storage by the session variable signedPdf = sessionModel.SignedPdfStream.ToArray(); // Close the signed PDF stream sessionModel.SignedPdfStream.Close(); } catch (Exception ex) { ModelState.AddModelError("", ex.ToString()); return(View()); } finally { // Clear the object stored on the Session Session.Remove("SignatureCompleteModel"); } TempData["SignatureInfoModel"] = new SignatureInfoModel() { File = Storage.StoreFile(signedPdf, ".pdf") }; return(RedirectToAction("SignatureInfo")); }
public ActionResult SignCodeh(string id, SignatureStartModel model) { // Recover XML envelope with signed COD element from "storage" based on its ID byte[] content; string extension; if (!Storage.TryGetFile(id, out content, out extension)) { return(HttpNotFound()); } byte[] toSignHash, transferData; SignatureAlgorithm signatureAlg; try { // Instantiate a CadesSigner class var signer = new XmlElementSigner(); // Set the XML to sign signer.SetXml(content); // Set the ID of the CODEH element signer.SetToSignElementId("CODEH"); // Decode the user's certificate and set as the signer certificate signer.SetSigningCertificate(PKCertificate.Decode(model.CertContent)); // Set the signature policy signer.SetPolicy(getSignaturePolicy()); // Generate the "to-sign-hash". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy. toSignHash = signer.GenerateToSignHash(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (SignCodehComplete action), we'll need once again some information: // - The thumpprint of the selected certificate // - The "to-sign-hash" // - The OID of the digest algorithm to be used during the signature operation // - The "transfer data" TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertThumb = model.CertThumb, ToSignHash = toSignHash, DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid, TransferData = transferData }; return(RedirectToAction("SignCodehComplete", new { id })); }
public ActionResult SignCodehComplete(string id, SignatureCompleteModel model) { // Recover XML envelope with signed COD element from "storage" based on its ID byte[] content; if (!StorageMock.TryGetFile(id, out content)) { return(HttpNotFound()); } byte[] signatureContent; try { // Recover the "transfer data" content stored in a temporary file. byte[] transferDataContent; if (!StorageMock.TryGetFile(model.TransferDataFileId, out transferDataContent)) { return(HttpNotFound()); } // Get an instance of the XmlElementSigner class. var signer = new XmlElementSigner(); // Set the document to be signed and the policy, exactly like in the SignCodeh method signer.SetXml(content); signer.SetPolicy(getSignaturePolicy()); // Set the signature computed on the client-side, along with the "transfer data" signer.SetPrecomputedSignature(model.Signature, transferDataContent); // Call ComputeSignature(), which validates the signature of the "to-sign-hash" and finishes the signature process signer.ComputeSignature(); // Get the signed XML as an array of bytes signatureContent = signer.GetSignedXml(); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate is revoked. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (SignatureInfo action), we'll render the following information: // - The filename to be available to download in next action. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureInfoModel"] = new SignatureInfoModel() { // Store the signature file on the folder "App_Data/" and redirect to the SignCodehResult action with the filename. File = StorageMock.Store(signatureContent, ".xml") }; return(RedirectToAction("SignCodehSignatureInfo")); }
public ActionResult Index(SignatureStartModel model) { byte[] toSignHash, transferData; SignatureAlgorithm signatureAlg; try { // Instantiate a XmlElementSigner class var signer = new XmlElementSigner(); // Set the data to sign, which in the case of this example is a fixed sample document signer.SetXml(Storage.GetSampleNFeContent()); // static Id from node <infNFe> from SampleNFe.xml document signer.SetToSignElementId("NFe35141214314050000662550010001084271182362300"); // Decode the user's certificate and set as the signer certificate signer.SetSigningCertificate(PKCertificate.Decode(model.CertContent)); // Set the signature policy signer.SetPolicy(getSignaturePolicy()); // Generate the "to-sign-hash". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy. toSignHash = signer.GenerateToSignHash(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The content of the selected certificate only used to render the user's certificate information // after the signature is completed. It is no longer needed for the signature process. // - The thumpprint of the selected certificate. // - The "transfer data" used to validate the signature in complete action. // - The "to-sign-hash" to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store this value on TempData, that will store in dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertContent = model.CertContent, CertThumb = model.CertThumb, TransferData = transferData, ToSignHash = toSignHash, DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete")); }
public async Task <ActionResult> Complete(SignatureCompleteModel model) { string fileId; PKCertificate signerCert; try { // Get an instance of the PadesSignatureFinisher2 class, responsible for completing the // signature process. var signatureFinisher = new PadesSignatureFinisher2(Util.GetRestPkiClient()) { // Set the token for this signature (rendered in a hidden input field, see the view). Token = model.Token, // Set the signature computed (rendered in a hidden input field, see the view). Signature = model.Signature }; // Call the FinishAsync() method, which finalizes the signature process and returns a // SignatureResult object. var result = await signatureFinisher.FinishAsync(); // The "Certificate" property of the SignatureResult object contains information about the // certificate used by the user to sign the file. signerCert = result.Certificate; // At this point, you'd typically store the signed PDF on your database. For demonstration // purposes, we'll store the PDF on our mock Storage class. // The SignatureResult object has various methods for writing the signature file to a stream // (WriteTo()), local file (WriteToFile()), open a stream to read the content (OpenRead()) // and get its contents (GetContent()). For large files, avoid the method GetContent() to // avoid memory allocation issues. using (var resultStream = result.OpenRead()) { fileId = StorageMock.Store(resultStream, ".pdf"); } // If you prefer a simpler approach without stream, simply do: //fileId = StorageMock.Store(result.GetContent(), ".pdf"); } catch (ValidationException ex) { // Return to Index view rendering the error message. ModelState.AddModelError("", ex.Message); return(View()); } // Render the signature infomation return(View("SignatureInfo", new SignatureInfoModel() { File = fileId, SignerCertificate = signerCert })); }
public ActionResult Index(SignatureStartModel model) { byte[] toSignHash, transferData; SignatureAlgorithm signatureAlg; try { // Instantiate a CadesSigner class var signer = new XmlElementSigner(); // Set the data to sign, which in the case of this example is a fixed sample "COD envelope" signer.SetXml(StorageMock.GetSampleCodEnvelopeContent()); // Set the ID of the COD element signer.SetToSignElementId("COD"); // Decode the user's certificate and set as the signer certificate signer.SetSigningCertificate(PKCertificate.Decode(model.CertContent)); // Set the signature policy signer.SetPolicy(getSignaturePolicy()); // Generate the "to-sign-hash". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy. toSignHash = signer.GenerateToSignHash(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (SignCodComplete action), we'll need once again some information: // - The thumpprint of the selected certificate // - The "to-sign-hash" // - The OID of the digest algorithm to be used during the signature operation // - The "transfer data" used to validate the signature in complete action.Its content is stored in // a temporary file (with extension .bin) to be shared with the Complete action. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertThumb = model.CertThumb, ToSignHash = toSignHash, DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid, TransferDataFileId = StorageMock.Store(transferData, ".bin"), }; return(RedirectToAction("Complete")); }
public ActionResult Complete(SignatureCompleteModel model) { byte[] signatureContent; try { // Recover the "transfer data" content stored in a temporary file. byte[] transferDataContent; if (!StorageMock.TryGetFile(model.TransferDataFileId, out transferDataContent)) { return(HttpNotFound()); } // Get an instance of the PadesSigner class. var padesSigner = new PadesSigner(); // Set the signature policy. padesSigner.SetPolicy(GetSignaturePolicy()); // Set the signature computed on the client-side, along with the "transfer data" (rendered in a hidden field, see the view) padesSigner.SetPreComputedSignature(model.Signature, transferDataContent); // Call ComputeSignature(), which does all the work, including validation of the signer's certificate and of the resulting signature padesSigner.ComputeSignature(); // Get the signed PDF as an array of bytes signatureContent = padesSigner.GetPadesSignature(); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate is revoked. ModelState.AddModelError("", ex.ValidationResults.ToString()); // Return userfile to continue the signature with the same file. return(View(model)); } // On the next step (SignatureInfo action), we'll render the following information: // - The filename to be available to download in next action. // - The signer's certificate information to be rendered. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureInfoModel"] = new SignatureInfoModel() { // Store the signature file on the folder "App_Data/" and redirects to the SignatureInfo action with the filename. // With this filename, it can show a link to download the signature file. File = StorageMock.Store(signatureContent, ".pdf") }; return(RedirectToAction("SignatureInfo")); }
public ActionResult Index(SignatureStartModel model) { byte[] toSignBytes; SignatureAlgorithm signatureAlg; try { // Instantiate a CadesSigner class var cadesSigner = new CadesSigner(); // Set the data to sign, which in the case of this example is a fixed sample document cadesSigner.SetDataToSign(Storage.GetSampleDocContent()); // Decode the user's certificate and set as the signer certificate cadesSigner.SetSigningCertificate(PKCertificate.Decode(model.CertContent)); // Set the signature policy cadesSigner.SetPolicy(getSignaturePolicy()); // Generate the "to-sign-bytes". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy. toSignBytes = cadesSigner.GenerateToSignBytes(out signatureAlg); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The content of the selected certificate used to validate the signature in complete action. // - The thumbprint of the selected certificate. // - The "to-sign-bytes" used to validate the signature in complete action. // - The "to-sign-hash" (digest of the "to-sign-bytes") to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertContent = model.CertContent, CertThumb = model.CertThumb, ToSignBytes = toSignBytes, ToSignHash = signatureAlg.DigestAlgorithm.ComputeHash(toSignBytes), DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete")); }
public ActionResult Complete(SignatureCompleteModel model) { byte[] signatureContent; try { // Instantiate a CadesSigner class var cadesSigner = new CadesSigner(); // Set the document to be signed and the policy, exactly like in the Start method cadesSigner.SetDataToSign(Storage.GetSampleDocContent()); cadesSigner.SetPolicy(getSignaturePolicy()); // Set signer's certificate cadesSigner.SetSigningCertificate(PKCertificate.Decode(model.CertContent)); // Set the signature computed on the client-side, along with the "to-sign-bytes" (rendered in a hidden input field, see the view) cadesSigner.SetPrecomputedSignature(model.Signature, model.ToSignBytes); // Call ComputeSignature(), which does all the work, including validation of the signer's certificate and of the resulting signature cadesSigner.ComputeSignature(); // Get the signature as an array of bytes signatureContent = cadesSigner.GetSignature(); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate is revoked. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (SignatureInfo action), we'll render the following information:] // - The filename to be available to download in next action. // - The signer's certificate information to be rendered. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureInfoModel"] = new SignatureInfoModel() { // Store the signature file on the folder "App_Data/" and redirects to the SignatureInfo action with the filename. // With this filename, it can show a link to download the signature file. Filename = Storage.StoreFile(signatureContent, ".p7s"), UserCert = PKCertificate.Decode(model.CertContent) }; return(RedirectToAction("SignatureInfo")); }
public ActionResult Start(SignatureStartModel model) { byte[] toSignBytes, transferData; SignatureAlgorithm signatureAlg; try { // Verify if the userfile exists and get its absolute path. string userfilePath; if (!StorageMock.TryGetFile(model.UserFile, out userfilePath)) { return(HttpNotFound()); } // Decode the user's certificate. var cert = PKCertificate.Decode(model.CertContent); // Get an instance of the PadesSigner class. var padesSigner = new PadesSigner(); // Set the file to be signed. padesSigner.SetPdfToSign(userfilePath); // REQUIRED! // Provide the signer's certificate. You must sign with a valid digital // certificate of a doctor, who was registered on CRM. In this sample, // we used a sample certificate stored on server to do the execute this // sample. padesSigner.SetSigningCertificate(cert); // REQUIRED! // Define the trust arbitrator, which will configure the signer to // some kind of certificate. In the case of this sample, only // ICP-Brasil certificates will be accepted in the defined standard. var trustArbitrator = new LinkedTrustArbitrator(TrustArbitrators.PkiBrazil); #if DEBUG // For development purposes, we also trust in Lacuna Software's test certificates. var lacunaRoot = Lacuna.Pki.PKCertificate.Decode(Convert.FromBase64String("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")); trustArbitrator.Add(new TrustedRoots(lacunaRoot)); #endif // REQUIRED! // Use a policy accepted by ICP-Brasil. We use the trust arbitrator // defined above to configure the policy. padesSigner.SetPolicy(PadesPoliciesForGeneration.GetPadesBasic(trustArbitrator)); // REQUIRED! // Use a custom signature field name. This field MUST have the // "Emitente" keyword as the last keyword. padesSigner.SetCustomSignatureFieldName("Signature1 Emitente"); // REQUIRED! // Set Certification Level to not allow changes after signed. padesSigner.SetCertificationLevel(PadesCertificationLevel.CertifiedNoChangesAllowed); // Set a visual representation for the signature. padesSigner.SetVisualRepresentation(PadesVisualElements.GetVisualRepresentationForPkiSdk(cert)); // Generate the "to-sign-bytes". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy, as well as the "transfer data", // a byte-array that will be needed on the next step. toSignBytes = padesSigner.GetToSignBytes(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The thumbprint of the selected certificate. // - The "transfer data" used to validate the signature in complete action. Its content is stored in // a temporary file (with extension .bin) to be shared with the Complete action. // - The "to-sign-hash" (digest of the "to-sign-bytes") to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertThumb = model.CertThumb, TransferDataFileId = StorageMock.Store(transferData, ".bin"), ToSignHash = signatureAlg.DigestAlgorithm.ComputeHash(toSignBytes), DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete", new { userfile = model.UserFile })); }
public ActionResult Index(SignatureStartModel model) { byte[] toSignBytes; SignatureAlgorithm signatureAlg; try { // Instantiate a CadesSigner class var cadesSigner = new CadesSigner(); if (!string.IsNullOrEmpty(model.CmsFile)) { // Verify if the cmsfile exists and get the content of the cmsfile. byte[] cmsfileContent; if (!StorageMock.TryGetFile(model.CmsFile, out cmsfileContent)) { return(HttpNotFound()); } // If the URL argument "cmsfile" is filled, the user has asked to co-sign a previously signed // CMS. We'll set the path to the CMS to be co-signed, which was perviously saved in the // App_Data folder by the POST action on this controller. cadesSigner.SetSignatureToCoSign(cmsfileContent); } else { // Verify if the userfile exists and get the content of the userfile. byte[] userfileContent; if (!StorageMock.TryGetFile(model.UserFile, out userfileContent)) { return(HttpNotFound()); } // If the URL argument "userfile" is filled, it means the user was redirected here by // UploadController (signature with file uploaded by user). We'll set the path of the file to // be signed, which was saved in the App_Data folder by UploadController. cadesSigner.SetDataToSign(userfileContent); } // Decode the user's certificate and set as the signer certificate. var cert = PKCertificate.Decode(model.CertContent); cadesSigner.SetSigningCertificate(cert); // Set the signature policy cadesSigner.SetPolicy(getSignaturePolicy()); // Generate the "to-sign-bytes". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy. toSignBytes = cadesSigner.GenerateToSignBytes(out signatureAlg); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The content of the selected certificate used to validate the signature in complete action. // - The thumbprint of the selected certificate. // - The "to-sign-bytes" used to validate the signature in complete action. // - The "to-sign-hash" (digest of the "to-sign-bytes") to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { UserFile = model.UserFile, CmsFile = model.CmsFile, CertContent = model.CertContent, CertThumb = model.CertThumb, ToSignBytes = toSignBytes, ToSignHash = signatureAlg.DigestAlgorithm.ComputeHash(toSignBytes), DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete", new { userfile = model.UserFile, cmsfile = model.CmsFile })); }
public ActionResult Complete(SignatureCompleteModel model) { byte[] signatureContent; try { // Instantiate a CadesSigner class var cadesSigner = new CadesSigner(); // Set the document to be signed, exactly like in the Start method if (!string.IsNullOrEmpty(model.CmsFile)) { // Verify if the cmsfile exists and get the content of the cmsfile. byte[] cmsfileContent; if (!StorageMock.TryGetFile(model.CmsFile, out cmsfileContent)) { return(HttpNotFound()); } // If the URL argument "cmsfile" is filled, the user has asked to co-sign a previously signed // CMS. We'll set the path to the CMS to be co-signed, which was perviously saved in the // App_Data folder by the POST action on this controller. cadesSigner.SetSignatureToCoSign(cmsfileContent); } else { // Verify if the userfile exists and get the content of the userfile. byte[] userfileContent; if (!StorageMock.TryGetFile(model.UserFile, out userfileContent)) { return(HttpNotFound()); } // If the URL argument "userfile" is filled, it means the user was redirected here by // UploadController (signature with file uploaded by user). We'll set the path of the file to // be signed, which was saved in the App_Data folder by UploadController. cadesSigner.SetDataToSign(userfileContent); } // Set the signature policy, exactly like in the Start method. cadesSigner.SetPolicy(getSignaturePolicy()); // Decode the user's certificate and set as the signer certificate. var cert = PKCertificate.Decode(model.CertContent); cadesSigner.SetSigningCertificate(cert); // Set the signature computed on the client-side, along with the "to-sign-bytes" (rendered in a hidden input field, see the view) cadesSigner.SetPrecomputedSignature(model.Signature, model.ToSignBytes); // Call ComputeSignature(), which does all the work, including validation of the signer's certificate and of the resulting signature cadesSigner.ComputeSignature(); // Get the signature as an array of bytes signatureContent = cadesSigner.GetSignature(); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate is revoked. ModelState.AddModelError("", ex.ValidationResults.ToString()); // Return userfile to continue the signature with the same file. return(View("Complete", model)); } // On the next step (SignatureInfo action), we'll render the following information:] // - The filename to be available to download in next action. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureInfoModel"] = new SignatureInfoModel() { // Store the signature file on the folder "App_Data/" and redirects to the SignatureInfo action with the filename. // With this filename, it can show a link to download the signature file. File = StorageMock.Store(signatureContent, ".p7s") }; return(RedirectToAction("SignatureInfo")); }
public ActionResult Start(SignatureStartModel model) { byte[] toSignHash, rangeDigest; PdfSignatureAppearance sigAppearance; MemoryStream signedPdfStream; try { // Decode Certificate var certificate = new X509CertificateParser().ReadCertificate(model.CertContent); // Create a PdfReader with the PDF that will be signed var reader = new PdfReader(Storage.GetSampleDocContent() /* here we're using a sample document */); // Open the Signed PDF stream and create a pdf stamper. signedPdfStream = new MemoryStream(); var stamper = PdfStamper.CreateSignature(reader, signedPdfStream, '\0'); // Create the signature appearance sigAppearance = stamper.SignatureAppearance; // Add a crypto dictionary to the signature appearance sigAppearance.CryptoDictionary = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED); // Inform the pkcs7 padded max size, which is 8kb var exc = new Dictionary <PdfName, int>(); exc.Add(PdfName.CONTENTS, 8192 * 2 + 2); // Preclose the signature apperance, only closing it after the signature is computed // (see the Complete method below) sigAppearance.PreClose(exc); // Compute the digests to be signed var pkcs7 = new PdfPKCS7(null, new X509Certificate[] { certificate }, DigestAlgorithm, false); using (var data = sigAppearance.GetRangeStream()) { // Compute the Range Digest rangeDigest = DigestAlgorithms.Digest(data, DigestAlgorithm); // Compute the toSignHash var authAttributes = pkcs7.getAuthenticatedAttributeBytes(rangeDigest, null, null, CryptoStandard.CMS); using (var ms = new MemoryStream(authAttributes)) { toSignHash = DigestAlgorithms.Digest(ms, DigestAlgorithm); } } } catch (Exception ex) { ModelState.AddModelError("", ex.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The thumbprint of the selected certificate // - The content of the selected certificate used to validate the signature in complete action. // - The "to-sign-hash" // - The digest algorithm // We'll store these values on TempData, which is a temporary dictionary shared between actions during a redirect. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertThumb = model.CertThumb, CertContent = model.CertContent, ToSignHash = toSignHash, DigestAlgorithm = DigestAlgorithm }; // During the "post-signing" step (see method Complete(SignatureCompleteModel) below), iTextSharp requires references // to the same objects rangeDigest, sigAppearance and signedPdfStream used during this step. This means we have to // use the Session object to store these objects. // // Please notice that this has very serious implications if you intend to develop a web application that can be executed // simulteneously on multiple servers. Tipically, in such cases, uses of the Session object to store data between requests // are replaced by storing the data on a database or filesystem shared between the servers. However, since the objects // sigAppearance and signedPdfStream are complex, non-serializable objects, such strategy would not apply! Session.Add("ITextSessionModel", new ITextSessionModel() { RangeDigest = rangeDigest, SignatureApperance = sigAppearance, SignedPdfStream = signedPdfStream }); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // !!! WARNING: USING SESSION TO STORE COMPLEX, NON-SERIALIZABLE OBJECTS !!! // // (please see comments on the beggining on this file for alternatives) return(RedirectToAction("Complete")); }
public ActionResult Index(SignatureStartModel model) { byte[] toSignBytes, transferData; SignatureAlgorithm signatureAlg; try { // Decode the user's certificate var cert = PKCertificate.Decode(model.CertContent); // Instantiate a PadesSigner class var padesSigner = new PadesSigner(); // Set the PDF to sign, which in the case of this example is a fixed sample document padesSigner.SetPdfToSign(Storage.GetSampleDocContent()); // Set the signer certificate padesSigner.SetSigningCertificate(cert); // Set the signature policy padesSigner.SetPolicy(getSignaturePolicy()); // Set the signature's visual representation options (this is optional). For more information, see // http://pki.lacunasoftware.com/Help/html/98095ec7-2742-4d1f-9709-681c684eb13b.htm var visual = new PadesVisualRepresentation2() { // Text of the visual representation Text = new PadesVisualText() { // Compose the message CustomText = String.Format("Assinado digitalmente por {0}", cert.SubjectDisplayName), // Specify that the signing time should also be rendered IncludeSigningTime = true, // Optionally set the horizontal alignment of the text ('Left' or 'Right'), if not set the default is Left HorizontalAlign = PadesTextHorizontalAlign.Left }, // Background image of the visual representation Image = new PadesVisualImage() { // We'll use as background the image in Content/PdfStamp.png Content = Storage.GetPdfStampContent(), // Opacity is an integer from 0 to 100 (0 is completely transparent, 100 is completely opaque). Opacity = 50, // Align the image to the right HorizontalAlign = PadesHorizontalAlign.Right }, // Set the position of the visual representation Position = PadesVisualAutoPositioning.GetFootnote() }; padesSigner.SetVisualRepresentation(visual); // Generate the "to-sign-bytes". This method also yields the signature algorithm that must // be used on the client-side, based on the signature policy, as well as the "transfer data", // a byte-array that will be needed on the next step. toSignBytes = padesSigner.GetToSignBytes(out signatureAlg, out transferData); } catch (ValidationException ex) { // Some of the operations above may throw a ValidationException, for instance if the certificate // encoding cannot be read or if the certificate is expired. ModelState.AddModelError("", ex.ValidationResults.ToString()); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The content of the selected certificate only used to render the user's certificate information // after the signature is completed. It is no longer needed for the signature process. // - The thumbprint of the selected certificate. // - The "transfer data" used to validate the signature in complete action. // - The "to-sign-hash" (digest of the "to-sign-bytes") to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { CertContent = model.CertContent, CertThumb = model.CertThumb, TransferData = transferData, ToSignHash = signatureAlg.DigestAlgorithm.ComputeHash(toSignBytes), DigestAlgorithmOid = signatureAlg.DigestAlgorithm.Oid }; return(RedirectToAction("Complete")); }
public async Task <ActionResult> Index(SignatureStartModel model) { ClientSideSignatureInstructions signatureParams; try { // Get an instance of the PadesSignatureStarter class, responsible for receiving the // signature elements and start the signature process. var signatureStarter = new PadesSignatureStarter(Util.GetRestPkiClient()) { // Set the unit of measurement used to edit the pdf marks and visual representations. MeasurementUnits = PadesMeasurementUnits.Centimeters, // Set the signature policy. SignaturePolicyId = StandardPadesSignaturePolicies.Basic, // Set a SecurityContext to be used to determine trust in the certificate chain. SecurityContextId = Util.GetSecurityContextId(), // Set a visual representation for the signature. VisualRepresentation = new PadesVisualRepresentation() { // The tags {{name}} and {{national_id}} will be substituted according to the user's // certificate: // // name : Full name of the signer; // national_id : If the certificate is ICP-Brasil, contains the signer's CPF. // // For a full list of the supported tags, see: // https://github.com/LacunaSoftware/RestPkiSamples/blob/master/PadesTags.md Text = new PadesVisualText("Signed by {{name}} ({{national_id}})") { // Specify that the signing time should also be rendered. IncludeSigningTime = true, // Optionally set the horizontal alignment of the text ('Left' or 'Right'), if // not set the default is Left. HorizontalAlign = PadesTextHorizontalAlign.Left }, // We'll use as background the image in Content/PdfStamp.png. Image = new PadesVisualImage(Util.GetPdfStampContent(), "image/png") { // Opacity is an integer from 0 to 100. (0 is completely transparent, 100 is // completely opaque) Opacity = 50, // Align the image to the right. HorizontalAlign = PadesHorizontalAlign.Right }, // Position of the visual representation. We have encapsulated this code in a method // to include several possibilities depending on the argument passed. Experiment // changing the argument to see different examples of signature positioning. Once you // decide which is best for your case, you can place the code directly here. Position = PadesVisualElements.GetVisualPositioning(1) } }; // Set certificate's content. (received from a hidden field on the form submission, its value // is filled on javascript, see signature-start-form.js) signatureStarter.SetSignerCertificate(model.CertContent); // Set PDF to be signed. signatureStarter.SetPdfToSign(Util.GetSampleDocPath()); /* * Optionally, add marks to the PDF before signing. These differ from the signature visual * representation in that they are actually changes done to the document prior to signing, * not binded to any signature. Therefore, any number of marks can be added, for instance * one per page, whereas there can only be one visual representation per signature. However, * since the marks are in reality changes to the PDF, they can only be added to documents * which have no previous signatures, otherwise such signatures would be made invalid by the * changes to the document (see property PadesSignatureStarter.BypassMarksIfSigned). This * problem does not occurr with signature visual representations. * * We have encapsulated this code in a method to include several possibilities depending on * the argument passed. Experiment changing the argument to see different examples of PDF * marks. Once you decide which is best for your case, you can place the code directly here. */ //signatureStarter.PdfMarks.Add(PadesVisualElements.GetPdfMark(1)); // Call the StartAsync() method, which initiates the signature. This yields the parameters // for the signature using the certificates. signatureParams = await signatureStarter.StartAsync(); } catch (ValidationException ex) { // Return to Index view rendering the error message. ModelState.AddModelError("", ex.Message); return(View()); } // On the next step (Complete action), we'll need once again some information: // - The token that identifies the signature process on REST PKI service. // - The thumbprint of the selected certificate. // - The "to-sign-hash" to be signed. (see signature-complete-form.js) // - The OID of the digest algorithm to be used during the signature operation. // We'll store these values on TempData, which is a dictionary shared between actions. TempData["SignatureCompleteModel"] = new SignatureCompleteModel() { Token = signatureParams.Token, CertThumb = model.CertThumb, ToSignHash = signatureParams.ToSignHash, DigestAlgorithmOid = signatureParams.DigestAlgorithmOid }; return(RedirectToAction("Complete")); }