/// <summary> /// Create Xades <QualifyingProperties> from the <SignatureProperties> and <DataObjectProperties> elements /// </summary> /// <param name="signedXml"></param> /// <param name="document"></param> /// <param name="certificate"></param> private void CreateXadesQualifyingProperties(XadesSignedXml signedXml, XmlDocument document, X509Certificate2 certificate) { string signatureRootId = CreateId(XadesSignatureRootId); string signedPropertiesId = CreateId(XadesSignedPropertiesId); // build xades XML XmlElement qualifyingProperties = document.CreateElement("QualifyingProperties", XadesNamespaceUrl); qualifyingProperties.SetAttribute("Target", $"#{signatureRootId}"); XmlElement signedProperties = qualifyingProperties.CreateChild("SignedProperties", XadesNamespaceUrl); signedProperties.SetAttribute("Id", signedPropertiesId); XmlElement signatureProperties = SignatureProperties.CreateXadesSignatureProperties(document, certificate, SignatureType); signedProperties.AppendChild(signatureProperties); XmlElement dataObjectProperties = CreateXadesDataObjectProperties(document); if (dataObjectProperties.ChildNodes.Count > 0) { signedProperties.AppendChild(dataObjectProperties); } // add reference to xades XML signedXml.AddXadesObject(new DataObject(null, null, null, qualifyingProperties)); Reference signedPropertiesReference = new Reference($"#{signedPropertiesId}") { TransformChain = XadesTransformChain, DigestMethod = XadesDigestMethod, Type = XadesReferenceType }; signedXml.AddReference(signedPropertiesReference); signedXml.Signature.Id = signatureRootId; }
public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); Page page = doc.NewPage(); TextFormat tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 }; page.Graphics.DrawString( "Hello, World!\r\nSigned below by GcPdfWeb SignDoc sample.", tf, new PointF(72, 72)); // Init a test certificate: var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties(); sp.Certificate = cert; sp.Location = "GcPdfWeb Sample Browser"; sp.SignerName = "GcPdfWeb"; // Init a signature field to hold the signature: SignatureField sf = new SignatureField(); sf.Widget.Rect = new RectangleF(72, 72 * 2, 72 * 4, 36); sf.Widget.Page = page; sf.Widget.BackColor = Color.LightSeaGreen; sf.Widget.TextFormat.Font = StandardFonts.Helvetica; sf.Widget.ButtonAppearance.Caption = $"Signer: {sp.SignerName}\r\nLocation: {sp.Location}"; // Add the signature field to the document: doc.AcroForm.Fields.Add(sf); // Connect the signature field and signature props: sp.SignatureField = sf; // Sign and save the document: // NOTES: // - Signing and saving is an atomic operation, the two cannot be separated. // - The stream passed to the Sign() method must be readable. doc.Sign(sp, stream); // Rewind the stream to read the document just created // into another GcPdfDocument and verify the signature: stream.Seek(0, SeekOrigin.Begin); GcPdfDocument doc2 = new GcPdfDocument(); doc2.Load(stream); SignatureField sf2 = (SignatureField)doc2.AcroForm.Fields[0]; if (!sf2.Value.VerifySignature()) { throw new Exception("Failed to verify the signature"); } // Done (the generated and signed document has already been saved to 'stream'). return(doc.Pages.Count); }
// This method is almost exactly the same as the SignDoc sample, // but adds a second signature field (does not sign it though): private Stream CreateAndSignPdf() { GcPdfDocument doc = new GcPdfDocument(); Page page = doc.NewPage(); TextFormat tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 }; page.Graphics.DrawString( "Hello, World!\r\nSigned below TWICE by GcPdfWeb SignIncremental sample.", tf, new PointF(72, 72)); // Init a test certificate: var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties(); sp.Certificate = cert; sp.Location = "GcPdfWeb Sample Browser"; sp.SignerName = "GcPdfWeb"; // Init a signature field to hold the signature: SignatureField sf = new SignatureField(); sf.Widget.Rect = new RectangleF(72, 72 * 2, 72 * 4, 36); sf.Widget.Page = page; sf.Widget.BackColor = Color.LightSeaGreen; // Add the signature field to the document: doc.AcroForm.Fields.Add(sf); // Connect the signature field and signature props: sp.SignatureField = sf; // Add a second signature field: SignatureField sf2 = new SignatureField() { Name = "SecondSignature" }; sf2.Widget.Rect = new RectangleF(72, 72 * 3, 72 * 4, 36); sf2.Widget.Page = page; sf2.Widget.BackColor = Color.LightYellow; // Add the signature field to the document: doc.AcroForm.Fields.Add(sf2); var ms = new MemoryStream(); doc.Sign(sp, ms); return(ms); }
public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); // Load a signed document (we use code similar to the SignDoc sample): doc.Load(CreateAndSignPdf()); // Init a second certificate: var pfxPath = Path.Combine("Resources", "Misc", "JohnDoe.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "secret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp2 = new SignatureProperties() { Certificate = cert, Location = "GcPdfWeb Sample Browser", SignerName = "Jaime Smith", }; // Find the 2nd (not yet filled) signature field: var sfld2 = doc.AcroForm.Fields["SecondSignature"] as SignatureField; // Connect the signature field and signature props: sp2.SignatureField = sfld2 ?? throw new Exception("Unexpected: could not find 'SecondSignature' field"); // Sign and save the document: doc.Sign(sp2, stream); // Rewind the stream to read the document just created // into another GcPdfDocument and verify all signatures: stream.Seek(0, SeekOrigin.Begin); GcPdfDocument doc2 = new GcPdfDocument(); doc2.Load(stream); foreach (var fld in doc2.AcroForm.Fields) { if (fld is SignatureField sfld) { if (!sfld.Value.VerifySignature()) { throw new Exception($"Failed to verify signature for field {sfld.Name}"); } } } // Done (the generated and signed document has already been saved to 'stream'). return(doc.Pages.Count); }
// Main entry point of this sample: public int CreatePDF(Stream stream) { // Set up a font collection with the fonts we need: _fc.RegisterDirectory(Path.Combine("Resources", "Fonts")); // Set that font collection on input fields' text layout // (we will also set it on all text layouts that we'll use): _inputTl.FontCollection = _fc; // Set up layout and formatting for input fields: _inputTl.ParagraphAlignment = ParagraphAlignment.Center; _inputTf.FontName = "Segoe UI"; _inputTf.FontSize = 12; _inputTf.FontBold = true; // Create the time sheet input form // (in a real-life scenario, we probably would only create it once, // and then re-use the form PDF): var doc = MakeTimeSheetForm(); // At this point, 'doc' is an empty AcroForm. // In a real-life app it would be distributed to employees // for them to fill and send back. FillEmployeeData(doc); // // At this point the form is filled with employee's data. // // Supervisor data (in a real app, these would probably be fetched from a db): var supName = "Jane Donahue"; var supSignDate = DateTime.Now.ToShortDateString(); SetFieldValue(doc, _Names.EmpSuper, supName); SetFieldValue(doc, _Names.SupSignDate, supSignDate); // The next step is to 'flatten' the form: we loop over document AcroForm's fields, // drawing their current values in place, and then remove the fields. // This produces a PDF with text fields' values as part of the regular (non-editable) content: FlattenDoc(doc); // Now we digitally sign the flattened document on behalf of the 'manager': var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties(); sp.Certificate = cert; sp.Location = "GcPdfWeb - TimeSheet sample"; sp.SignerName = supName; // Connect the signature field and signature props: SignatureField supSign = doc.AcroForm.Fields.First(f_ => f_.Name == _Names.SupSign) as SignatureField; sp.SignatureField = supSign; supSign.Widget.ButtonAppearance.Caption = supName; // Some browser PDF viewers do not show form fields, so we render a placeholder: supSign.Widget.Page.Graphics.DrawString("digitally signed", new TextFormat() { FontName = "Segoe UI", FontSize = 9 }, supSign.Widget.Rect); // Done, now save the document with supervisor signature: doc.Sign(sp, stream); // Dispose images only after the document is saved: _disposables.ForEach(d_ => d_.Dispose()); return(doc.Pages.Count); }
// Main entry point of this sample: public int CreatePDF(Stream stream) { // Set up a font collection with the fonts we need: _fc.RegisterDirectory(Path.Combine("Resources", "Fonts")); // Set that font collection on input fields' text layout // (we will also set it on all text layouts that we'll use): _inputTl.FontCollection = _fc; // Set up layout and formatting for input fields: _inputTl.ParagraphAlignment = ParagraphAlignment.Center; _inputTf.FontName = "Segoe UI"; _inputTf.FontSize = 12; _inputTf.FontBold = true; // Create the time sheet input form // (in a real-life scenario, we probably would only create it once, // and then re-use the form PDF): var doc = MakeTimeSheetForm(); // At this point, 'doc' is an empty AcroForm. // In a real-life app it would be distributed to employees // for them to fill and send back. using (var empSignedStream = FillEmployeeData(doc)) { // // At this point 'empSignedStream' contains the form filled with employee's data and signed by them. // // Load the employee-signed document: doc.Load(empSignedStream); // Fill in supervisor data: var supName = "Jane Donahue"; var supSignDate = DateTime.Now.ToShortDateString(); SetFieldValue(doc, _Names.EmpSuper, supName); SetFieldValue(doc, _Names.SupSignDate, supSignDate); // Digitally sign the document on behalf of the supervisor: var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties() { Certificate = cert, Location = "GcPdfWeb - TimeSheet Incremental", SignerName = supName, SignatureDigestAlgorithm = SignatureDigestAlgorithm.SHA512, // Connect the signature field and signature props: SignatureField = doc.AcroForm.Fields.First(f_ => f_.Name == _Names.SupSign) as SignatureField, }; // Any changes to the document would invalidate the employee's signature, so we cannot do this: // supSign.Widget.ButtonAppearance.Caption = supName; // // Done, now save the document with supervisor signature: // NOTE: in order to not invalidate the employee's signature, // we MUST use incremental update here (which is true by default in Sign() method): doc.Sign(sp, stream); _logo.Dispose(); return(doc.Pages.Count); } }
// Fill in employee info and working hours with sample data: private Stream FillEmployeeData(GcPdfDocument doc) { // For the purposes of this sample, we fill the form with random data: var empName = "Jaime Smith"; SetFieldValue(doc, _Names.EmpName, empName); SetFieldValue(doc, _Names.EmpNum, "12345"); SetFieldValue(doc, _Names.EmpDep, "Research & Development"); SetFieldValue(doc, _Names.EmpTitle, "Senior Developer"); SetFieldValue(doc, _Names.EmpStatus, "Full Time"); var rand = new Random((int)DateTime.Now.Ticks); DateTime workday = DateTime.Now.AddDays(-15); while (workday.DayOfWeek != DayOfWeek.Sunday) { workday = workday.AddDays(1); } TimeSpan wkTot = TimeSpan.Zero, wkReg = TimeSpan.Zero, wkOvr = TimeSpan.Zero; for (int i = 0; i < 7; ++i) { // Start time: var start = new DateTime(workday.Year, workday.Month, workday.Day, rand.Next(6, 12), rand.Next(0, 59), 0); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][0], start.ToShortDateString()); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][1], start.ToShortTimeString()); // End time: var end = start.AddHours(rand.Next(8, 14)).AddMinutes(rand.Next(0, 59)); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][2], end.ToShortTimeString()); var tot = end - start; var reg = TimeSpan.FromHours((start.DayOfWeek != DayOfWeek.Saturday && start.DayOfWeek != DayOfWeek.Sunday) ? 8 : 0); var ovr = tot.Subtract(reg); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][3], reg.ToString(@"hh\:mm")); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][4], ovr.ToString(@"hh\:mm")); SetFieldValue(doc, _Names.DtNames[_Names.Dows[i]][5], tot.ToString(@"hh\:mm")); wkTot += tot; wkOvr += ovr; wkReg += reg; // workday = workday.AddDays(1); } SetFieldValue(doc, _Names.TotalReg, wkReg.TotalHours.ToString("F")); SetFieldValue(doc, _Names.TotalOvr, wkOvr.TotalHours.ToString("F")); SetFieldValue(doc, _Names.TotalHours, wkTot.TotalHours.ToString("F")); SetFieldValue(doc, _Names.EmpSignDate, workday.ToShortDateString()); // Digitally sign the document on behalf of the 'employee': var pfxPath = Path.Combine("Resources", "Misc", "JohnDoe.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "secret", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties() { Certificate = cert, DocumentAccessPermissions = AccessPermissions.FormFillingAndAnnotations, Reason = "I confirm time sheet is correct.", Location = "TimeSheetIncremental sample", SignerName = empName, }; // Connect the signature field and signature props: SignatureField empSign = doc.AcroForm.Fields.First(f_ => f_.Name == _Names.EmpSign) as SignatureField; sp.SignatureField = empSign; empSign.Widget.ButtonAppearance.Caption = empName; // Some browser PDF viewers do not show form fields, so we render a placeholder: empSign.Widget.Page.Graphics.DrawString("digitally signed", new TextFormat() { FontName = "Segoe UI", FontSize = 9 }, empSign.Widget.Rect); // We now 'flatten' the form: loop over document AcroForm's fields, // drawing their current values in place, and then remove the fields. // This produces a PDF with text fields' values as part of the regular // (non-editable) content (we leave fields filled by the supervisor): FlattenDoc(doc, _Names.EmpSuper, _Names.SupSignDate); // Done, now save the document with employee's signature: var ms = new MemoryStream(); // Note that we do NOT use incremental update here (3rd parameter is false) // as this is not needed yet (but will be needed/used when signing by supervisor later): doc.Sign(sp, ms, false); return(ms); }
public int CreatePDF(Stream stream) { GcPdfDocument doc = new GcPdfDocument(); Page page = doc.NewPage(); TextFormat tf = new TextFormat() { Font = StandardFonts.Times, FontSize = 14 }; page.Graphics.DrawString( "Hello, World!\r\nSigned below by GcPdfWeb SignatureAppearance sample.", tf, new PointF(72, 72)); // Init a test certificate: var pfxPath = Path.Combine("Resources", "Misc", "GcPdfTest.pfx"); X509Certificate2 cert = new X509Certificate2(File.ReadAllBytes(pfxPath), "qq", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); SignatureProperties sp = new SignatureProperties(); sp.Certificate = cert; sp.Location = "GcPdfWeb Sample Browser"; sp.SignerName = "GcPdfWeb"; // Create a signature field to hold the signature: SignatureField sf = new SignatureField(); // Add the signature field to the document: doc.AcroForm.Fields.Add(sf); // Connect the signature field and signature props: sp.SignatureField = sf; // Set up the signature field: sf.Widget.Rect = new RectangleF(page.Size.Width - 72 * 4, 72 * 2, 72 * 3, 72); sf.Widget.Page = page; // Widget visual props will be overridden by sf.Widget.AppearanceStreams.Normal.Default set below: sf.Widget.BackColor = Color.PeachPuff; sf.Widget.Border = new GrapeCity.Documents.Pdf.Annotations.Border() { Color = Color.SaddleBrown, Width = 3, }; sf.Widget.ButtonAppearance.Caption = $"Signer: {sp.SignerName}\r\nLocation: {sp.Location}"; // Create custom signature appearance stream: var rc = new RectangleF(PointF.Empty, sf.Widget.Rect.Size); var fxo = new FormXObject(doc, rc); rc.Inflate(-4, -4); fxo.Graphics.FillEllipse(rc, Color.CornflowerBlue); fxo.Graphics.DrawEllipse(rc, new Pen(Color.RoyalBlue, 3)); rc.Inflate(-5, -5); fxo.Graphics.DrawEllipse(rc, new Pen(Color.LightSteelBlue, 1)); fxo.Graphics.DrawString($"Signed by {sp.SignerName}\non {DateTime.Now.ToShortDateString()}.", new TextFormat() { FontName = "Times New Roman", FontSize = 14, FontItalic = true, ForeColor = Color.Navy }, fxo.Bounds, TextAlignment.Center, ParagraphAlignment.Center, false); sf.Widget.AppearanceStreams.Normal.Default = fxo; // Reset signature appearance so that the widget appearance stream is used: sp.SignatureAppearance = null; // Sign and save the document: // NOTES: // - Signing and saving is an atomic operation, the two cannot be separated. // - The stream passed to the Sign() method must be readable. doc.Sign(sp, stream); // Done (the generated and signed docment has already been saved to 'stream'). return(doc.Pages.Count); }