The Digital Signing Framework of the Open Packaging Conventions

 

David Meltzer and Andrey Shur
Microsoft Corporation

September 2006

Applies to:
   OPC Digital Signing Framework
   W3C XML Digital Signature standard
   Microsoft .NET 3.0 Framework

Summary: Discusses the OPC Digital Signing Framework, providing an overview of the package components and supporting services, and examples of signing policy and its implementation. (12 printed pages)

Contents

Introduction
Components of the OPC Digital Signing Framework
   The XML Digital Signature Standard
   Representing Digital Signatures in Packages
   Signing Parts and Relationships
Programming Support for Package Signatures
   Signing Package Parts and Relationships
   Verifying Certificates and Signatures
Application Signing Policy
   XPS Documents
   Programming Support for XPS Signatures
References

Introduction

The packaging model specified by the Open Packaging Conventions (OPC) describes packages, parts, and relationships. Packages hold parts, which hold content and resources. Relationships are defined to connect the package to parts, and to connect various parts in the package.

This article discusses the OPC Digital Signing Framework, providing an overview of the package components and supporting services, and examples of signing policy and its implementation.

The Signing Framework includes an infrastructure for representing digital signatures, and the services for creating and validating signatures. The Signing Framework enables the W3C XML Digital Signature standard to be applied to package parts and relationships.

Using the Signing Framework, owners of package-based formats define and implement "signing policies" specific to their formats. The policies specify how to sign and validate the integral content of particular formats, and embody how signatures are used for different workflows. In fact, for a single format there may be several policies defined for use at different stages in the lifecycle of a document.

The signing policy for a package-based format is expressed in terms of signing parts and relationships, and possibly other document characteristics (such as validation of the intended display device, color-depth, or application version). A signing policy specifies which document components to sign and which to leave unsigned, if any. For example, a signing policy can be implemented to allow new parts and relationships to be added to a package, or a policy can cause a signature to be invalidated if new parts or signatures are added to a package.

This article assumes familiarity with the Open Packaging Conventions Specification and the W3C Recommendation XML-Signature Syntax and Processing.

Components of the OPC Digital Signing Framework

The XML Digital Signature Standard

The Signing Framework for packages uses the XML Digital Signature Standard, as defined in the W3C Recommendation XML-Signature Syntax and Processing. This Recommendation specifies the XML syntax and processing rules for producing and storing digital signatures.

The standard defines an XML signature element type, schema, and conformance requirements for signing and validating any kind of digital resource. The schema also defines elements for referencing resources and specifying signature-related algorithms.

Features of digital signatures

A digital signature can be used to determine whether the signed content has changed since it was signed. The signature contains a manifest of content that is hashed according to a well-known algorithm and stored in the signature when created. To determine if content has changed, a hash of the signed content is recreated and compared with the hash stored within the signature.

A digital signature can also be used to identify the signer of the content. The identity of the signer is represented by a certificate associated with the signature. The certificate may be embedded in the signature, or available elsewhere.

A digital signature does not "lock" a document or cause it to become encrypted (although it may already be encrypted). Document content remains unchanged after being signed. Digital signatures do not prevent signed content from being viewed by unintended consumers.

Representing Digital Signatures in Packages

Applications incorporate digital signatures in a package using a specified configuration of parts and relationships.

The Signing Framework uses elements and attributes from the packaging namespace where allowed by the XML Digital Signature standard. The signature elements defined in the packaging namespace support package-specific features that augment the standard without contradicting it. For a summary of the additions, see the section "Modifications to the XML Digital Signature Specification" of the OPC Specification.

The package parts defined for the Signing Framework are the Origin part, the XML Signature part, and the Certificate part. Each has a well-defined content type. Well-defined relationship types are used for connecting signature parts in a package, as specified in Appendix H, "Standard Namespaces and Content Types," of the OPC Specification.

Digital Signature Origin Part

The Digital Signature Origin part is the starting point for navigating through the signatures in a package. The Digital Signature Origin part is targeted from the package root using the Digital Signature Origin relationship. Multiple Signature parts may be targeted from the Origin part. If there are no signatures in the package, the Origin part will not be present.

Digital Signature XML Signature Part

Digital Signature XML Signature parts contain markup defined in the W3C Digital Signature standard as well as in the packaging namespace. The parts are targeted from the Digital Signature Origin part XML with the Digital Signature relationship.

Digital Signature Certificate Part

The X.509 certificate required for identifying the signer, if placed in the package, may be embedded within the XML Signature part, or stored in a separate Certificate part. The optional Certificate part is targeted from the XML Signature part with the Digital Signature Certificate relationship. The Certificate part can be shared between multiple Signature parts.

Custom Signature Parts

Custom (application-specific) signature parts are permitted, but not handled, by the Signing Framework. A signature part that holds a form of signature other than an XML signature must be identified by a custom content type. In addition, a relationship with a custom relationship type must be used to target the part from the Digital Signature Origin part.

Signing Parts and Relationships

The XML Digital Signature standard allows the signing of addressable resources, which for a package are parts. The Signing Framework enables signing of parts. The relationships in a package, stored in a relationships part, can be signed all at once, or a subset of relationships can be specified for signing.

The content type of a part is signed, along with the part content, to ensure that a part in a validly signed package will be used or rendered as intended. Because the content type is not an addressable resource, a package-specific approach is taken to signing the content type value. When the package is signed, the content type of each signed part is stored in the query component of the URI referring to the signed part. When the package is consumed, the OPC Digital Signing Framework uses the content type value to ensure that the content type of the part has not changed since the part was signed.

When the relationships part is signed as a whole, all the relationships defined in that part are signed. To support signing policies that allow some contents of a package to change without invalidating the signature, the Signing Framework provides a mechanism for signing specified relationships. To sign specified relationships, the Signing Framework uses a special transform, the Relationships Transform (see Transform Algorithms).

The Relationships Transform creates a relationships part containing only the specified set of relationships. The obtained relationships part is used for signing and during signature validation.

Programming Support for Package Signatures

To sign and validate signatures, applications can use the .NET 3.0 classes PackageDigitalSignatureManager. The package-specific classes, defined in the System.IO.Packaging namespace, build on the digital signature classes of the Microsoft .NET 3.0 Framework defined in the System.Security.Cryptography.Xml namespace.

The PackageDigitalSignatureManager class is used for creating and validating signatures, and placing the signature infrastructure in a package. The signature is represented by an object based on the PackageDigitalSignature class.

Signing Package Parts and Relationships

An application defines a list of parts and relationships to sign according to its signing policy. The application then calls the PackageDigitalSignatureManager.Sign() method to create the signature and add the signature infrastructure to the package.

The sample code below demonstrates signing all the parts in the package except the relationships parts, signing all existing relationships originating from the package root, and embedding the certificate used for signing in the XML Signature part. The sample code assumes no signatures exist in the package at the beginning, and only one signature is applied prior to verification.

Beginning the Signing Process

To begin working with signatures in the package, first create a PackageDigitalSignatureManager, as shown below.

    // Open the package.
    Package package = Package.Open(filename);

    // Create the PackageDigitalSignatureManager
      PackageDigitalSignatureManager dsm =
        new PackageDigitalSignatureManager(package);

Certificate Embedding Options

A certificate may be represented either as a string embedded in the signature itself, as a separate part in the package, or as a resource outside of the package. If the certificate is to be placed within the package, an application specifies how the certificate will be persisted using the embedding options of the PackageDigitalSignature.CertificateOption property. After creating the PackageDigitalSignatureManager class, the embedding options for the certificate are set, as shown in the sample code below.

    //Specify that the certificate is embedded in the signature held
    //in the XML Signature part.

    //Certificate embedding options include:
    // InSignaturePart – Certificate is embedded in the signature.
    // InCertificatePart – Certificate is embedded in a 
    //                     separate certificate part

    dsm.CertificateOption =
        CertificateEmbeddingOption.InSignaturePart;

Signed Parts List

The list of parts to sign is specified using the URIs addressing the parts. In this sample, all parts in the package will be signed except the relationships parts, which are filtered out using the PackUriHelper.IsRelationshipPartUri() method.

    //Initialize a list to hold the part URIs to sign.

    System.Collections.Generic.List<Uri> partsToSign =
        new System.Collections.Generic.List<Uri>();

    //Add each part to the list, except relationships parts.
    foreach (PackagePart packagePart in package.GetParts())
    {
        if (!PackUriHelper.IsRelationshipPartUri(packagePart.Uri))
      partsToSign.Add(packagePart.Uri);
  }

Signed Relationships List

Individual relationships are signed using the Relationships Transform. Signing relationships this way allows new relationships to be added to the package without invalidating the signature.

Relationships are selected for signing by creating a list of PackageRelationshipSelector objects that will be used at the time of signing. PackageRelationshipSelector objects can be created as a group by relationship type (as defined in section "Standard Namespaces and Content Types" of the Open Packaging Conventions), or created individually by specifying relationship id, as in the sample below.

     //Create list of selectors for the list of relationships

     List<PackageRelationshipSelector> relationshipSelectors = 
          new List<PackageRelationshipSelector>();

     //Create one selector for each package-level relationship, based on id

  foreach (PackageRelationship relationship in package.GetRelationships())
            {
                relationshipSelectors.Add(new
                    PackageRelationshipSelector(relationship.sourceUri, 
                    PackageRelationshipSelectorType.Id, relationship.Id));
            }

When creating a PackageRelationshipSelector with PackageRelationshipSelectorType.Id, the one relationship having the unique id specified will be selected for signing. When creating a selector with PackageRelationshipSelectorType.Type, all the relationships with the specified type are selected for signing. If relationships of the same type are later added to a package, the signature will be invalidated.

Creating the Certificate Object

Prior to signing, a valid X.509 certificate is obtained by instantiating an object of type System.Security.Cryptography.X509Certificates.X509Certificate2. This object is passed to the PackageDigitalSignatureManager.Sign() method at the time of signing. For more information about creating certificate objects, see the System.Security.Cryptography.X509Certificates namespace.

Applying the Signature

After creating the list of parts and relationships to sign, and obtaining the certificate object, an application calls the PackageDigitalSignatureManager.Sign() method.

     //Sign package using components created above

     PackageDigitalSignature signature = dsm.Sign(partsToSign, 
          x509Certificate, relationshipSelectors);

     //After signing, close the package.
     //The signature will be persisted in the package.
     package.Close();

When the Sign() method is called, the hash is generated and stored in the signature manifest, and the signature part is created. If the signature infrastructure already exists in the package, the new signature part will be added (if allowed). If the infrastructure does not yet exist in the package, the Sign() method creates the infrastructure and places it in the package.

Verifying Certificates and Signatures

Applications may verify a certificate or a signature. Prior to verifying the signature, the certificate should be verified. The object that represents the signature in the package, PackageDigitalSignature, has a property "Signer" which returns the certificate used for creating that signature, if it is in the package. If the certificate is not embedded in the package, the application obtains the certificate from a location known to the application.

The PackageDigitalSignatureManager.VerifyCertificate() method is used to validate the obtained certificate, checking the certificate structure, expiration date, and chain status. For more information about chain status, see X509ChainStatusFlag Enumeration in the .NET Framework Class Library.

Application developers can use the certificate status to support their signing policies. For example, an application can specify that only certificates issued after certain dates are acceptable.

The PackageDigitalSignatureManager.VerifySignatures() method is used to validate all the signatures in the package. This method only validates the signatures, not the certificates associated with the signatures.

The sample code below can be used to validate the certificate and signature placed in the package in the signing samples. The sample code assumes that no additional signatures have been added to the package.

    // Open the package.

    Package package = Package.Open(filename);

    // Create the PackageDigitalSignatureManager

    PackageDigitalSignatureManager dsm =
        new PackageDigitalSignatureManager(package);

    // Verify the collection of certificates in the package (one, in this case)

        foreach(PackageDigitalSignature signature in pdsm.Signatures)
        {
        if(PackageDigitalSignatureManager.VerifyCertificate(signature.Signer)
            != X509ChainStatusFlags.NoError)
              {
                // Application-specific code for error handling 
                // or certificate validation 
              }
        }
 
   // For this example, if all certificates are valid,
   // verify all signatures in the package.
 
    VerifyResult vResult = dsm.VerifySignatures(false);
    Console.WriteLine("Result " + vResult.ToString());

    // Close the package.

    package.Close();

Application Signing Policy

Applications using package-based formats define their own policies as part of the Signing Framework. The policy is determined by the element types and workflow requirements of the format. In this section, the signing policy is described for one Microsoft package-based format: the XPS Document format.

XPS Documents

The XPS Document format is based on the Open Packaging Conventions, as specified in the XML Paper Specification. The XML Paper Specification defines the policy for signing XPS Documents. Within that policy, there are signing options available to support application features or workflow.

Signing Policy for XPS Document Packages

The signing policy for XPS Documents describes the set of parts and relationships that must be signed so the content can be validated. As a part of this policy, an application may create a signature that optionally includes a combination of particular parts that are adjunct to the content, such as the CoreProperties part. Signing these parts will prevent them from being changed without invalidating the signature. In addition, applications may optionally sign the relationships part attached to the Digital Signature Origin part in the signature, prohibiting new signatures from being added to the document without invalidating the signature.

In order for a signature to be valid, the XPS Document signing policy requires that certain parts and relationships are included in the signature. No unrecognized parts or relationships can be signed. When verifying a signature, an application must confirm that all required parts and relationships are signed.

XPS Document Parts to Sign

The following table contains the list of parts that must be signed in all XPS documents, and the parts that are optionally signed. For relationships, the XPS signing policy specifies that required relationships (relationships targeting required parts) are always signed using the OPC-defined Relationships Transform. If a part is signed, the relationships that target it must also be signed.

Part Type Policy
FixedDocumentSequence part Must be signed
FixedDocument part Must be signed
DocumentStructure parts Must be signed
SignatureDefinitions part Must be signed
FixedPage parts Must be signed
Required resource parts (such as fonts, images) Must be signed
StoryFragments parts Must be signed
Thumbnail parts Must be signed
CoreProperties part Optionally signed
Digital Signature Origin part Optionally signed
Digital Signature Certificate part Optionally signed
PrintTicket parts Optionally signed
DiscardControl parts Optionally signed

For more information about the XPS signing policy, see the section "XPS Document Package Features: Digital Signatures: Signing Rules" in the XML Paper Specification.

Markup Compatibility Signing Policy

The XML Paper Specification describes a means for including alternate content in an XPS Document: markup compatibility. Alternate content is placed within elements from the Markup Compatibility namespace. By policy, XPS Documents that have Markup Compatibility elements and attributes cannot be validly signed, unless the signing application recognizes all of the content alternatives as equivalent. Only XPS Documents containing elements and attributes that are recognized can be signed or validated.

Countersignatures

More than one signature can be applied to the content of an XPS Document. For example, content representing a legal contract may require several people to apply their signatures, indicating the content signed and the signer's identity.

Adding a new signature always creates a new relationship within the relationships part attached to the Digital Signature Origin part. In order to add new signatures to an XPS Document without invalidating existing signatures, this relationships part must remain unsigned (although a subset of relationships may be signed). If the relationships part is included in a signature, that signature will be invalidated by all subsequently applied signatures.

Validating XPS Signatures

In addition to defining signature creation, the XPS signing policy also specifies how to verify a signature as valid. The policy defines states of validity for a signature that include incompliant, broken, questionable, and valid, as shown in the following table.

Signature Status All required parts and relationships are signed? Signature includes only recognized content? Hash of signed content is verified? Signed Markup Compatibility content is recognized? Certificate is valid?
Incompliant NO

YES

n/a

NO

n/a

n/a

n/a

n/a

n/a

n/a

Broken YES YES NO n/a n/a
Questionable YES

YES

YES

YES

YES

YES

NO

YES

n/a

NO

Valid YES YES YES YES YES

The XPS Viewer displays questionable and broken XPS signatures, as well as valid XPS signatures. Incompliant signatures are not enumerated.

Programming Support for XPS Signatures

When working with an XPS Document, applications can use the methods in the XpsDigitalSignature class. This class is based on the PackageDigitalSignature class and includes methods that follow the algorithms and requirements specified in the XPS Digital Signature Specification. The signing and validation methods verify that all the required parts and relationships of an XPS Document are signed.

Signing an XPS Document

The XpsDocument.SignDigitally() method is used to sign an XPS Document. Prior to calling the method, an application must have an X.509 certificate, which can be obtained using the object System.Security.Cryptography.X509Certificates.X509Certificate2.

     // Open the XPS Document

     XpsDocument document = new XpsDocument(dstContainer,
          FileAccess.ReadWrite);

     // Obtain the certificate object from a file

     X509Certificate certificate =
          509Certificate.CreateFromCertFile(certFilename);

     // Create the signature and add it to the document using
     // the OPC Signing Framework

     document.SignDigitally(certificate, true, 
          XpsDigSigPartAlteringRestrictions.None);

XpsDigSigPartAlteringRestrictions can be used to specify additional restrictions for a signature, based on signing policy. This parameter specifies whether to exclude the CoreMetadata and/or SignatureOrigin parts from the signature. The excluded parts can then be altered later without invalidating the signature. For example, excluding the CoreMetadata part from the signature enables an application to change some document properties without invalidating the signature.

The PrintTicket and DiscardControl parts are excluded from the signatures created by the SignDigitally() method, although these parts may be optionally signed in an application-specific way.

Verifying an XPS Document Signature

One or many signatures may be stored with an XPS Document. The signatures can be obtained from XpsDocument.Signatures property. Each signature is represented by an instance of the XpsDigitalSignature object.

In the sample below, only the first signature in the collection is verified.

     // Open the XPS Document.

     // Obtain the first enumerated signature.

     foreach (XpsDigitalSignature digitalSignature in
              document.Signatures)
     { 
          // Verify the signature object, if present.

          if (digitalSignature.Verify() ==
     System.IO.Packaging.PackageDigitalSignature.VerifyResult.Success)
          {
         //Signature is valid
          }
     }

References