locked
Digital signature show wrong sign date Ask RRS feed

  • Question

  • I am learning digital signature and how to sign it in c#.Here is my code:

    Signature.cs

    public class Signature
        {
        static readonly string RT_OfficeDocument = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
        static readonly string OfficeObjectID = "idOfficeObject";
        static readonly string SignatureID = "idPackageSignature";
        static readonly string ManifestHashAlgorithm = "http://www.w3.org/2000/09/xmldsig#sha1";
    
        // Entry Point
        public static void DigiSign(string tempfile)
        {
        // Open the Package    
            using (Package package = Package.Open(tempfile))
            {
                // Get the certificate
                X509Certificate2 certificate = GetCertificate();
                SignAllParts(package, certificate);
            }
        }
    
        private static void SignAllParts(Package package, X509Certificate certificate)
        {
            if (package == null) throw new ArgumentNullException("SignAllParts(package)");
            List<Uri> PartstobeSigned = new List<Uri>();
            List<PackageRelationshipSelector> SignableReleationships = new List<PackageRelationshipSelector>();
    
            foreach (PackageRelationship relationship in package.GetRelationshipsByType(RT_OfficeDocument))
            {
                // Pass the releationship of the root. This is decided based on the RT_OfficeDocument (http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument)
                CreateListOfSignableItems(relationship, PartstobeSigned, SignableReleationships);
            }
            // Create the DigitalSignature Manager
            PackageDigitalSignatureManager dsm = new PackageDigitalSignatureManager(package);
            dsm.CertificateOption = CertificateEmbeddingOption.InSignaturePart;
    
            string signatureID = SignatureID;
            string manifestHashAlgorithm = ManifestHashAlgorithm;
            System.Security.Cryptography.Xml.DataObject officeObject = CreateOfficeObject(signatureID, manifestHashAlgorithm);
            Reference officeObjectReference = new Reference("#" + OfficeObjectID);
    
            try
            {
                dsm.Sign(PartstobeSigned, certificate, SignableReleationships, signatureID, new System.Security.Cryptography.Xml.DataObject[] { officeObject }, new Reference[] { officeObjectReference });
            }
            catch (CryptographicException ex)
            {
                Console.WriteLine(ex.InnerException.ToString());
            }
    
        }// end:SignAllParts()
    
        /**************************SignDocument******************************/
        //  This function is a helper function. The main role of this function is to 
        //  create two lists, one with Package Parts that you want to sign, the other 
        //  containing PacakgeRelationshipSelector objects which indicate relationships to sign.
        /*******************************************************************/
        static void CreateListOfSignableItems(PackageRelationship relationship, List<Uri> PartstobeSigned, List<PackageRelationshipSelector> SignableReleationships)
        {
            // This function adds the releation to SignableReleationships. And then it gets the part based on the releationship. Parts URI gets added to the PartstobeSigned list.
            PackageRelationshipSelector selector = new PackageRelationshipSelector(relationship.SourceUri, PackageRelationshipSelectorType.Id, relationship.Id);
            SignableReleationships.Add(selector);
            if (relationship.TargetMode == TargetMode.Internal)
            {
                PackagePart part = relationship.Package.GetPart(PackUriHelper.ResolvePartUri(relationship.SourceUri, relationship.TargetUri));
                if (PartstobeSigned.Contains(part.Uri) == false)
                {
                    PartstobeSigned.Add(part.Uri);
                    // GetRelationships Function: Returns a Collection Of all the releationships that are owned by the part.
                    foreach (PackageRelationship childRelationship in part.GetRelationships())
                    {
                        CreateListOfSignableItems(childRelationship, PartstobeSigned, SignableReleationships);
                    }
                }
            }
        }
        /**************************SignDocument******************************/
        //  Once you create the list and try to sign it, Office will not validate the Signature.
        //  To allow Office to validate the signature, it requires a custom object which should be added to the 
        //  signature parts. This function loads the OfficeObject.xml resource.
        //  Please note that GUID being passed in document.Loadxml. 
        //  Background Information: Once you add a SignatureLine in Word, Word gives a unique GUID to it. Now while loading the
        //  OfficeObject.xml, we need to make sure that The this GUID should match to the ID of the signature line. 
        //  So if you are generating a SignatureLine programmtically, then mmake sure that you generate the GUID for the 
        //  SignatureLine and for this element. 
        /*******************************************************************/
    
        static System.Security.Cryptography.Xml.DataObject CreateOfficeObject(
           string signatureID, string manifestHashAlgorithm)
        {
            XmlDocument document = new XmlDocument();
            document.LoadXml(String.Format(Properties.Resources.OfficeObject, signatureID, manifestHashAlgorithm, "{3CF6B91E-C5F6-46A4-B036-72597274FCC0}"));
            System.Security.Cryptography.Xml.DataObject officeObject = new System.Security.Cryptography.Xml.DataObject();
            // do not change the order of the following two lines
            officeObject.LoadXml(document.DocumentElement); // resets ID
            officeObject.Id = OfficeObjectID; // required ID, do not change
            return officeObject;
        }
        /********************************************************/
    
        static X509Certificate2 GetCertificate()
        {
            X509Store certStore = new X509Store(StoreLocation.CurrentUser);
            certStore.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certs = X509Certificate2UI.SelectFromCollection(certStore.Certificates, "Select a certificate", "Please select a certificate",
                    X509SelectionFlag.SingleSelection);
            return certs.Count > 0 ? certs[0] : null;
        }
    }

    Program.cs

    class Program
    {
        static void Main(string[] args)
        {
                Signature.DigiSign(@"D:\abc.docx");
        }
    }


    After signed ,in the Additional Information of the signature , the system date/time(sign time) is diferrent from my local time and the date/time format too.I try to change my local time zone and reset date/time but it still not work. What am i missing?

    I can't upload image so i provide a link to it : https://i.stack.imgur.com/hPHJk.png

    Tuesday, July 10, 2018 4:25 PM

All replies

  • After signed ,in the Additional Information of the signature , the system date/time(sign time) is diferrent from my local time and the date/time format too.I try to change my local time zone and reset date/time but it still not work. What am i missing?

    I can't upload image so i provide a link to it : https://i.stack.imgur.com/hPHJk.png

    I'm guessing you're on the west coast of the United States.  The content and format of these signature fields are dictated by standards.  The time is stored in UTC, because the person reading the signature is very likely not going to be in the same time zone.  The format of the date/time is also dictated by the standards, not by your preferences.

    In other words, it is all working fine.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Wednesday, July 11, 2018 7:28 AM
  • Hi Khoa Dinh,

    Thank you for posting here.

    For your question, how to do you sign the time? In your code, I do not find the code which you used to set the time. Is the time a Timestamp? If yes, you could refer to the link below to set a Timestamp.

    https://github.com/disig/TimeStampClient

    https://docs.microsoft.com/en-us/windows/desktop/seccrypto/signedcode-timestamp

    Best Regards,

    Wendy


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, July 11, 2018 9:34 AM
  • I just copy your code and run, but it do not work, noty erro on 

    document.LoadXml(String.Format(Properties.Resources.OfficeObject, signatureID, manifestHashAlgorithm, "{3CF6B91E-C5F6-46A4-B036-72597274FCC0}"));

    please help me

    thank

    Friday, July 5, 2019 4:34 AM