public static void Sign(Signature signature, PDFMetadata metadata, string input, string output)
        {
            if (signature == null)
            {
                throw new NullReferenceException();
            }

            if (signature.Store == null)
            {
                throw new NullReferenceException();
            }

            /* Get Store Private Key and Certificate Chain */

            var name = GetPrivateKeyName(signature.Store);

            if (string.IsNullOrEmpty(name))
            {
                throw new InvalidOperationException("No private key available");
            }

            var privateKey = signature.Store.GetKey(name).Key;

            X509Certificate[] certificateChain = GetCertificateChain(signature.Store, name);

            if (certificateChain == null)
            {
                throw new InvalidOperationException("No private key available");
            }

            /* Prepare file input/output */

            var reader     = new PdfReader(input, null);
            var outputFile = new FileStream(output, FileMode.Create, FileAccess.Write);
            var stamper    = PdfStamper.CreateSignature(reader, outputFile, '\0', null, true);

            stamper.MoreInfo    = metadata.InfoHashtable;
            stamper.XmpMetadata = metadata.XmpMetadata;

            /* Create Siganture Appearance */

            PdfSignatureAppearance signatureAppearance = CreateSignatureAppearance(stamper, signature);

            signatureAppearance.SetCrypto(privateKey, certificateChain, null, PdfSignatureAppearance.WINCER_SIGNED);
            signatureAppearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS;

            PdfSignature pdfSignature = new PdfSignature(PdfName.ADOBE_PPKLITE, new PdfName("adbe.pkcs7.detached"));

            pdfSignature.Reason   = signatureAppearance.Reason;
            pdfSignature.Location = signatureAppearance.Location;
            pdfSignature.Contact  = signatureAppearance.Contact;
            pdfSignature.Date     = new PdfDate(signatureAppearance.SignDate);
            signatureAppearance.CryptoDictionary = pdfSignature;

            // Preallocate excluded byte-range for the signature content (hex encoded)

            var excludedByteRange = new Dictionary <PdfName, int> ();

            excludedByteRange[PdfName.CONTENTS] = ContentEstimated * 2 + 2;
            signatureAppearance.PreClose(new Hashtable(excludedByteRange));

            // Sign the document

            PKCS7SignDocument(privateKey, certificateChain, signatureAppearance, "SHA-256");
        }
        public async Task <IActionResult> Sign(string uuid, string password, string description)
        {
            if (string.IsNullOrEmpty(uuid) || string.IsNullOrEmpty(password))
            {
                return(View("OperationNotAllowed"));
            }

            var document = await DBContext.Document
                           .SingleOrDefaultAsync(m => m.Uuid == uuid);

            if (document == null)
            {
                return(NotFound());
            }

            if (document.MimeType != "application/pdf")
            {
                return(View("InvalidDocument"));
            }

            var x509certificate = HttpContext.Connection.ClientCertificate;

            if (x509certificate == null)
            {
                return(View("OperationNotAllowed"));
            }

            var certificate = await DBContext.Certificate
                              .SingleOrDefaultAsync(r => r.SerialNumber == x509certificate.SerialNumber);

            if (certificate == null || certificate.ReviewerUuid != document.ReviewerUuid)
            {
                return(View("OperationNotAllowed"));
            }

            if (certificate.ExpireDate < DateTime.Now.Date)
            {
                certificate.Revoked    = true;
                certificate.RevokeDate = DateTime.UtcNow.Date;
                DBContext.Certificate.Update(certificate);
                await DBContext.SaveChangesAsync();
            }

            if (certificate.Revoked == true)
            {
                return(RedirectToAction("CertificateExpired", "Certificates"));
            }

            var pkcs12store = TrustManager.LoadPkcs12Store(certificate.Uuid, password, CertificateType.ReviewerCertificate);

            if (pkcs12store == null)
            {
                return(View("OperationNotAllowed"));
            }

            var reviewer = await DBContext.Reviewer
                           .SingleOrDefaultAsync(r => r.Uuid == certificate.ReviewerUuid);

            var metadata = new PDFMetadata()
            {
                Title    = "PDF Signed Document" + document.Name,
                Author   = certificate.Reviewer.Name,
                Creator  = certificate.Reviewer.Name,
                Producer = certificate.Reviewer.Name,
                Keywords = "UUID:" + document.Uuid,
                Subject  = "Signed Document"
            };

            var signature = new Signature()
            {
                Store      = pkcs12store,
                Reason     = "Document Aproved, Date:" + DateTime.UtcNow.Date,
                Page       = 1,
                Contact    = certificate.Reviewer.Email,
                CustomText = "Signed by " + reviewer.Name + " on " + DateTime.UtcNow.Date.ToString("dd-MM-yyyy") + " - " + description,
                Top        = 10,
                Left       = 10,
                Width      = 200,
                Height     = 50,

                Multi   = false,
                Visible = true
            };

            SignatureManager.Sign(
                signature,
                metadata,
                FileManager.DocumentRoot + "/" + document.Uuid,
                FileManager.DocumentRoot + "/" + document.Uuid + "-signed");

            document.SignatureDate = DateTime.UtcNow.Date;
            DBContext.Document.Update(document);
            await DBContext.SaveChangesAsync();

            var message = await RenderService
                          .RenderToStringAsync("Email/DocumentSigned", document);

            var attachments = new List <Attachment> ();

            attachments.Add(
                await EmailManager.LoadAttachment(
                    FileManager.DocumentRoot + "/" + document.Uuid + "-signed",
                    "Signed by " + reviewer.Name + "-" + document.Name,
                    document.MimeType));

            attachments.Add(
                await EmailManager.LoadAttachment(
                    TrustManager.CertificatePath(
                        certificate.Uuid,
                        CertificateType.ReviewerCertificate,
                        StoreFormat.CRT),
                    "public.crt",
                    "application/x-x509-ca-cert"));

            attachments.Add(
                await EmailManager.LoadAttachment(
                    TrustManager.CertificatePath(
                        "root",
                        CertificateType.AuthorityCertificate,
                        StoreFormat.CRT),
                    "authority.crt",
                    "application/x-x509-ca-cert"));

            var response = await EmailManager.SendEmailHTML(
                message,
                EmailManager.Sender,
                certificate.Reviewer.Email,
                "Your signed document is ready",
                attachments
                );

            if (!response.Successful)
            {
                return(View("ErrorSendingDocument", document));
            }

            return(View("DocumentSigned", document));
        }