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 }));
        }
Example #6
0
        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"));
        }
Example #8
0
        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
            }));
        }
Example #9
0
        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("MIIGGTCCBAGgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBfMQswCQYDVQQGEwJCUjETMBEGA1UECgwKSUNQLUJyYXNpbDEdMBsGA1UECwwUTGFjdW5hIFNvZnR3YXJlIC0gTFMxHDAaBgNVBAMME0xhY3VuYSBSb290IFRlc3QgdjEwHhcNMTUwMTE2MTk1MjQ1WhcNMjUwMTE2MTk1MTU1WjBfMQswCQYDVQQGEwJCUjETMBEGA1UECgwKSUNQLUJyYXNpbDEdMBsGA1UECwwUTGFjdW5hIFNvZnR3YXJlIC0gTFMxHDAaBgNVBAMME0xhY3VuYSBSb290IFRlc3QgdjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCDm5ey0c4ij8xnDnV2EBATjJbZjteEh8BBiGtVx4dWpXbWQ6hEw8E28UyLsF6lCM2YjQge329g7hMANnrnrNCvH1ny4VbhHMe4eStiik/GMTzC79PYS6BNfsMsS6+W18a45eyi/2qTIHhJYN8xS4/7pAjrVpjL9dubALdiwr26I3a4S/h9vD2iKJ1giWnHU74ckVp6BiRXrz2ox5Ps7p420VbVU6dTy7QR2mrhAus5va9VeY1LjvCH9S9uSf6kt+HP1Kj7hlOOlcnluXmuD/IN68/CQeC+dLOr0xKmDvYv7GWluXhxpUZmh6NaLzSGzGNACobOezKmby06s4CvsmMKQuZrTx113+vJkYSgI2mBN5v8LH60DzuvIhMvDLWPZCwfnyGCNHBwBbdgzBWjsfuSFJyaKdJLmpu5OdWNOLjvexqEC9VG83biYr+8XMiWl8gUW8SFqEpNoLJ59nwsRf/R5R96XTnG3mdVugcyjR9xe/og1IgJFf9Op/cBgCjNR/UAr+nizHO3Q9LECnu1pbTtGZguGDMABc+/CwKyxirwlRpiu9DkdBlNRgdd5IgDkcgFkTjmA41ytU0LOIbxpKHn9/gZCevq/8CyMa61kgjzg1067BTslex2xUZm44oVGrEdx5kg/Hz1Xydg4DHa4qlG61XsTDJhM84EvnJr3ZTYOwIDAQABo4HfMIHcMDwGA1UdIAQ1MDMwMQYFYEwBAQAwKDAmBggrBgEFBQcCARYaaHR0cDovL2xhY3VuYXNvZnR3YXJlLmNvbS8wOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDovL2NhdGVzdC5sYWN1bmFzb2Z0d2FyZS5jb20vY3Jscy9yb290MB8GA1UdIwQYMBaAFPtdXjCI7ZOfGUg8mrCoEw9z9zywMB0GA1UdDgQWBBT7XV4wiO2TnxlIPJqwqBMPc/c8sDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQ0FAAOCAgEAN/b8hNGhBrWiuE67A8kmom1iRUl4b8FAA8PUmEocbFv/BjLpp2EPoZ0C+I1xWT5ijr4qcujIMsjOCosmv0M6bzYvn+3TnbzoZ3tb0aYUiX4ZtjoaTYR1fXFhC7LJTkCN2phYdh4rvMlLXGcBI7zA5+Ispm5CwohcGT3QVWun2zbrXFCIigRrd3qxRbKLxIZYS0KW4X2tetRMpX6DPr3MiuT3VSO3WIRG+o5Rg09L9QNXYQ74l2+1augJJpjGYEWPKzHVKVJtf1fj87HN/3pZ5Hr2oqDvVUIUGFRj7BSel9BgcgVaWqmgTMSEvQWmjq0KJpeqWbYcXXw8lunuJoENEItv+Iykv3NsDfNXgS+8dXSzTiV1ZfCdfAjbalzcxGn522pcCceTyc/iiUT72I3+3BfRKaMGMURu8lbUMxd/38Xfut3Kv5sLFG0JclqD1rhI15W4hmvb5bvol+a/WAYT277jwdBO8BVSnJ2vvBUzH9KAw6pAJJBCGw/1dZkegLMFibXdEzjAW4z7wyx2c5+cmXzE/2SFV2cO3mJAtpaO99uwLvj3Y3quMBuIhDGD0ReDXNAniXXXVPfE96NUcDF2Dq2g8kj+EmxPy6PGZ15p1XZO1yiqsGEVreIXqgcU1tPUv8peNYb6jHTHuUyXGTzbsamGZFEDsLG7NRxg0eZWP1w="));
                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 }));
        }
Example #14
0
        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 }));
        }
Example #15
0
        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"));
        }
Example #18
0
        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"));
        }