Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Base / System / IO / Packaging / PackageDigitalSignatureManager.cs / 1 / PackageDigitalSignatureManager.cs
//------------------------------------------------------------------------------ // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This class provides api's to add/remove/verify signatures on an MMCF container. // // History: // 03/22/2004: BruceMac: Initial Implementation // //----------------------------------------------------------------------------- // Allow use of presharp warning numbers [6506] unknown to the compiler #pragma warning disable 1634, 1691 using System; using System.Collections.Generic; using System.Windows; // For Exception strings - SRID using System.Text; // for StringBuilder using System.Diagnostics; // for Assert using System.Security; // for SecurityCritical tag using System.Security.Permissions; // for LinkDemand using System.Security.Cryptography.Xml; // for SignedXml using System.Security.Cryptography.X509Certificates; // for X509Certificate using MS.Internal.IO.Packaging; // for internal helpers using System.Collections.ObjectModel; // for ReadOnlyCollection<> using MS.Internal; // for ContentType namespace System.IO.Packaging { ////// Options for storing the signing Certificate /// public enum CertificateEmbeddingOption : int { ////// Embed certificate in its own PackagePart (or share if same cert already exists) /// InCertificatePart = 0, // embed the certificate in its own, possibly-shared part ////// Embed certificate within the signature PackagePart /// InSignaturePart = 1, // embed the certificate within the signature ////// Do not embed /// NotEmbedded = 2, // do not embed the certificate at all } ////// Type of the handler that is invoked if signature validation is non-success. /// /// signature /// event arguments - containing the result ///true to continue verifying other signatures, false to abandon effort public delegate void InvalidSignatureEventHandler(object sender, SignatureVerificationEventArgs e); ////// Signature Verification Event Args - information about a verification event /// public class SignatureVerificationEventArgs : EventArgs { //----------------------------------------------------- // // Public Members // //----------------------------------------------------- ////// Signature being processed /// public PackageDigitalSignature Signature { get { return _signature; } } ////// Result of Verification /// public VerifyResult VerifyResult { get { return _result; } } //------------------------------------------------------ // // Internal Members // //----------------------------------------------------- internal SignatureVerificationEventArgs(PackageDigitalSignature signature, VerifyResult result) { // verify arguments if (signature == null) throw new ArgumentNullException("signature"); if (result < VerifyResult.Success || result > VerifyResult.NotSigned) throw new System.ArgumentOutOfRangeException("result"); _signature = signature; _result = result; } //------------------------------------------------------ // // Private Members // //------------------------------------------------------ private PackageDigitalSignature _signature; private VerifyResult _result; } ////// PackageDigitalSignatureManager /// public sealed class PackageDigitalSignatureManager { #region Public Members //----------------------------------------------------- // // Public Events // //------------------------------------------------------ ////// Event to subscribe to for signature validation activities /// public event InvalidSignatureEventHandler InvalidSignatureEvent; //----------------------------------------------------- // // Public Properties // //----------------------------------------------------- ////// Does this container hold digital signatures? /// ///true if signatures exist ///this does not evaluate the signatures - they may be invalid even if this returns true public bool IsSigned { get { EnsureSignatures(); return (_signatures.Count > 0); } } ////// Signatures in container /// ///read only list of immutable signatures found in the container public ReadOnlyCollectionSignatures { get { // ensure signatures are loaded from origin EnsureSignatures(); // Return a read-only collection referring to them. // This list will be automatically updated when the underlying collection is changed. if (_signatureList == null) _signatureList = new ReadOnlyCollection (_signatures); return _signatureList; } } /// /// ContentType - Transform mapping dictionary /// ///Dictionary of transform Uri's indexed by ContentType. /// Contains a single transform to be applied /// before hashing any Part encountered with that ContentType public DictionaryTransformMapping { get { return _transformDictionary; } } /// /// Handle of parent window to use when displaying certificate selection dialog /// ////// not necessary if certificates are provided in calls to sign public IntPtr ParentWindow { get { return _parentWindow; } set { _parentWindow = value; } } ////// Hashalgorithm to use when creating/verifying signatures /// ////// defaults to SHA1 public String HashAlgorithm { get { return _hashAlgorithmString; } set { if (value == null) throw new ArgumentNullException("value"); if (value == String.Empty) throw new ArgumentException(SR.Get(SRID.UnsupportedHashAlgorithm), "value"); _hashAlgorithmString = value; } } ////// How to embed certificates when Signing /// ///public CertificateEmbeddingOption CertificateOption { get { return _certificateEmbeddingOption; } set { if ((value < CertificateEmbeddingOption.InCertificatePart) || (value > CertificateEmbeddingOption.NotEmbedded)) throw new ArgumentOutOfRangeException("value"); _certificateEmbeddingOption = value; } } /// /// How to format the SignatureTime in new signatures /// ///Legal formats specified in Opc book and reproduced here: /// YYYY-MM-DDThh:mm:ss.sTZD /// YYYY-MM-DDThh:mm:ssTZD /// YYYY-MM-DDThh:mmTZD /// YYYY-MM-DD /// YYYY-MM /// YYYY /// /// where: /// Y = year, M = month integer (leading zero), D = day integer (leading zero), /// hh = 24hr clock hour /// mm = minutes (leading zero) /// ss = seconds (leading zero) /// .s = tenths of a second /// public String TimeFormat { get { return _signatureTimeFormat; } set { if (value == null) throw new ArgumentNullException("value"); if (XmlSignatureProperties.LegalFormat(value)) _signatureTimeFormat = value; else throw new FormatException(SR.Get(SRID.BadSignatureTimeFormatString)); } } //----------------------------------------------------- // // Public Fields // //------------------------------------------------------ ////// Name of signature origin part /// ////// This value may vary by Package because the name is not formally defined. While this /// implementation will generally use the same default value, the value returned by this property will reflect /// whatever origin is already present in the current Package (if any) which may vary between implementations. /// public Uri SignatureOrigin { get { OriginPartExists(); // force search for OriginPart in case it is different from default return _originPartName; } } ////// Type of default signature origin relationship /// ///static public String SignatureOriginRelationshipType { get { return _originRelationshipType; } } /// /// Default hash algorithm /// ///static public String DefaultHashAlgorithm { get { return _defaultHashAlgorithm; } } //----------------------------------------------------- // // Public Methods // //------------------------------------------------------ /// /// Create a new PackageDigitalSignature manager /// /// container to work with ///based on the default origin ///package is null public PackageDigitalSignatureManager(Package package) { if (package == null) throw new ArgumentNullException("package"); _parentWindow = IntPtr.Zero; _container = package; // initialize the transform dictionary with defaults _transformDictionary = new Dictionary(4); _transformDictionary[PackagingUtilities.RelationshipPartContentType.ToString()] = SignedXml.XmlDsigC14NTransformUrl; // relationship parts _transformDictionary[XmlDigitalSignatureProcessor.ContentType.ToString()] = SignedXml.XmlDsigC14NTransformUrl; // xml signature } #region Sign /// /// Sign - prompts for certificate and embeds it /// /// list of parts to sign ///Set ParentWindow before this call if you want to make the certificate /// selection dialog modal to a particular window. Does not prompt for certificates if none could be located in the default certificate store. ///null if no certificate could be located, or if the user cancels from the certificate selection dialog. public PackageDigitalSignature Sign(IEnumerableparts) { X509Certificate certificate = PromptForSigningCertificate(ParentWindow); if (certificate == null) return null; else return Sign(parts, certificate); } /// /// Sign - certificate provided by caller /// /// list of parts to sign /// signer's certificate public PackageDigitalSignature Sign(IEnumerableparts, X509Certificate certificate) { // create unique signature name return Sign(parts, certificate, null); } /// /// Sign - certificate provided by caller /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null ///one of parts or relationships must be non-null and contain at least a single entry public PackageDigitalSignature Sign(IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors) { // use default signature Id return Sign(parts, certificate, relationshipSelectors, XTable.Get(XTable.ID.OpcSignatureAttrValue)); } /// /// Sign - certificate provided by caller /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null /// id for the new Signature - may be empty or null ///one of parts or relationships must be non-null and contain at least a single entry public PackageDigitalSignature Sign( IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId) { // Cannot both be null - need to check here because the similar check in the super-overload cannot // distinguish to this level. if (parts == null && relationshipSelectors == null) { throw new ArgumentException(SR.Get(SRID.NothingToSign)); } return Sign(parts, certificate, relationshipSelectors, signatureId, null, null); } /// /// Sign - caller specifies custom "Object" and/or SignedInfo "Reference" tags /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null /// id for the new Signature - may be empty or null /// references to custom object tags. The DigestMethod on each /// Reference will be ignored. The signature will use the globally defined HashAlgorithm /// obtained from the current value of the HashAlgorithm property. /// objects (signed or not) ///Thrown if any TransformMapping /// defines an empty or null transform for the ContentType of any Part being signed or if an unknown /// transform is encountered. ///Thrown if signatureId is non-null and violates the /// Xml Id schema (essentially - no leading digit is allowed). ///One of parts, relationships, signatureObjects and objectReferences must be /// non-null and contain at least a single entry. /// This and every other Sign overload makes use of the current state of the TransformMapping /// dictionary which defines a Transform to apply based on ContentType. The Opc specification /// only currently allows for two legal Transform algorithms: C14 and C14N. /// Note that the w3c Xml Signature standard does not allow for empty Manifest tags. /// Because the Opc specification requires the existence of a Package-specific Object /// tag and further specifies that this Object tag contain a Manifest and SignatureProperties /// tags, it follows that this Manifest tag must include at least one Reference tag. /// This means that every signature include at least one of a Part to sign (non-empty parts tag) /// or a Relationship to sign (non-empty relationshipSelectors) even if such a signature /// is only destined to sign signatureObjects and/or objectReferences. /// This overload provides support for generation of Xml signatures that require custom /// Object tags. For any provided Object tag to be signed, a corresponding Reference /// tag must be provided with a Uri that targets the Object tag using local fragment /// syntax. If the object had an ID of "myObject" the Uri on the Reference would /// be "#myObject". For unsigned objects, no reference is required. ////// Critical: calls X509Certificate.Handle which LinkDemands /// PublicOK: we don't store or return the handle /// [SecurityCritical] public PackageDigitalSignature Sign( IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId, IEnumerable signatureObjects, IEnumerable objectReferences) { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotSignReadOnlyFile)); VerifySignArguments(parts, certificate, relationshipSelectors, signatureId, signatureObjects, objectReferences); // substitute default id if none given if ((signatureId == null) || (signatureId == String.Empty)) { signatureId = "packageSignature"; // default } // Make sure the list reflects what's in the package. // Do this before adding the new signature part because we don't want it included until it // is fully formed (and delaying the add saves us having to remove it in case there is an // error during the Sign call). EnsureSignatures(); Uri newSignaturePartName = GenerateSignaturePartName(); if (_container.PartExists(newSignaturePartName)) throw new ArgumentException(SR.Get(SRID.DuplicateSignature)); // Pre-create origin part if it does not already exist. // Do this before signing to allow for signing the package relationship part (because a Relationship // is added from the Package to the Origin part by this call) and the Origin Relationship part in case this is // a Publishing signature and the caller wants the addition of more signatures to break this signature. PackageRelationship relationshipToNewSignature = OriginPart.CreateRelationship(newSignaturePartName, TargetMode.Internal, _originToSignatureRelationshipType); _container.Flush(); // ensure the origin relationship part is persisted so that any signature will include this newest relationship VerifyPartsExist(parts); // sign the data and optionally embed the certificate bool embedCertificateInSignaturePart = (_certificateEmbeddingOption == CertificateEmbeddingOption.InSignaturePart); // convert cert to version2 - more functionality X509Certificate2 exSigner = certificate as X509Certificate2; if (exSigner == null) exSigner = new X509Certificate2(certificate.Handle); //PRESHARP: Parameter to this public method must be validated: A null-dereference can occur here. // Parameter 'exSigner' to this public method must be validated: A null-dereference can occur here. //This is a false positive as the checks above can gurantee no null dereference will occur #pragma warning disable 6506 PackageDigitalSignature signature = null; PackagePart newSignaturePart = null; try { // create the new part newSignaturePart = _container.CreatePart(newSignaturePartName, XmlDigitalSignatureProcessor.ContentType.ToString()); // do the actual signing - only Xml signatures currently supported signature = XmlDigitalSignatureProcessor.Sign(this, newSignaturePart, parts, relationshipSelectors, exSigner, signatureId, embedCertificateInSignaturePart, signatureObjects, objectReferences); } catch (InvalidOperationException) { // bad hash algorithm - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } catch (System.IO.IOException) { // failure to open part - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } catch (System.Security.Cryptography.CryptographicException) { // failure to sign - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } // add to the list _signatures.Add(signature); // embed certificate if called for if (_certificateEmbeddingOption == CertificateEmbeddingOption.InCertificatePart) { // create the cert part // auto-generate a certificate name - will be the same for the same certificate Uri certificatePartName = PackUriHelper.CreatePartUri(new Uri( CertificatePart.PartNamePrefix + exSigner.SerialNumber + CertificatePart.PartNameExtension, UriKind.Relative)); // create the serialization helper class (side-effect of creating or opening the part) CertificatePart certPart = new CertificatePart(_container, certificatePartName); certPart.SetCertificate(exSigner); // establish a relationship newSignaturePart.CreateRelationship(certificatePartName, TargetMode.Internal, CertificatePart.RelationshipType); signature.SetCertificatePart(certPart); } #pragma warning restore 6506 _container.Flush(); // return to caller in case they need it return signature; } #endregion #region CounterSign /// /// CounterSign - prompts for certificate and embeds it based on current CertificateEmbeddingOption /// ///Set ParentWindow before this call if you want to make the certificate /// selection dialog modal to a particular window. Does not present the dialog if no suitable certificate /// could be found in the default certificate store. /// Signs all existing signature parts so that any change to these part(s) will invalidate the /// returned signature. ///Cannot CounterSign an unsigned package. ///null if no certificate could be located, or if the user cancels from the certificate selection dialog. public PackageDigitalSignature Countersign() { // Counter-sign makes no sense if we are not already signed // Check before asking for certificate if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // prompt for certificate X509Certificate certificate = PromptForSigningCertificate(ParentWindow); if (certificate == null) return null; else return Countersign(certificate); } ////// CounterSign - certificate provided /// /// signer's certificate ///Cannot CounterSign an unsigned package. ///certificate must be non-null. ///Signs all existing signature parts so that any change to these part(s) will invalidate the /// returned signature. public PackageDigitalSignature Countersign(X509Certificate certificate) { if (certificate == null) throw new ArgumentNullException("certificate"); // Counter-sign makes no sense if we are not already signed // Check before asking for certificate if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // sign all existing signatures Listsignatures = new List (_signatures.Count); for (int i = 0; i < _signatures.Count; i++) { signatures.Add(_signatures[i].SignaturePart.Uri); } // sign return Sign(signatures, certificate); } /// /// CounterSign - signature part name(s) specified by caller /// /// signer's certificate /// signature parts to sign ///Signs the given signature parts so that any change to these part(s) will invalidate the /// returned signature. ///Cannot CounterSign an unsigned package. ///signatures must be non-empty and cannot refer to parts other than signature parts. ///Both arguments must be non-null. public PackageDigitalSignature Countersign(X509Certificate certificate, IEnumerablesignatures) { if (certificate == null) throw new ArgumentNullException("certificate"); if (signatures == null) throw new ArgumentNullException("signatures"); // Counter-sign makes no sense if we are not already signed if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // Restrict signatures to be actual signature part references foreach (Uri uri in signatures) { PackagePart part = _container.GetPart(uri); if (!part.ValidatedContentType.AreTypeAndSubTypeEqual(XmlDigitalSignatureProcessor.ContentType)) throw new ArgumentException(SR.Get(SRID.CanOnlyCounterSignSignatureParts, signatures)); } return Sign(signatures, certificate); } #endregion /// /// verify all signatures - calls verify on each signature /// /// true to exit on first failure - false to continue ///register for invalid signature events public VerifyResult VerifySignatures(bool exitOnFailure) { VerifyResult result; EnsureSignatures(); // signed? if (_signatures.Count == 0) result = VerifyResult.NotSigned; else { // contract is to return a failure value, even if there are subsequent successes // defaulting to success here simplifies the logic for this result = VerifyResult.Success; // default for (int i = 0; i < _signatures.Count; i++) { VerifyResult temp = _signatures[i].Verify(); if (temp != VerifyResult.Success) { result = temp; // note failure if (InvalidSignatureEvent != null) InvalidSignatureEvent(this, new SignatureVerificationEventArgs(_signatures[i], temp)); if (exitOnFailure) break; } } } return result; } ////// Remove a signature /// /// signature to remove ///Caller should call Package.Flush() in order to persist changes. public void RemoveSignature(Uri signatureUri) { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotRemoveSignatureFromReadOnlyFile)); if (signatureUri == null) throw new ArgumentNullException("signatureUri"); // empty? if (!IsSigned) // calls EnsureSignatures for us return; // find the signature int index = GetSignatureIndex(signatureUri); if (index < 0) return; try { Debug.Assert(index < _signatures.Count); //After this signature is removed the total number of signatures remaining will //be _signatures.Count - 1. If this count is zero, then additional clean up needs //to be done, like removing the Origin part. InternalRemoveSignature(signatureUri, _signatures.Count - 1 /*since we are deleting one*/); // invalidate the signature itself _signatures[index].Invalidate(); } finally { _signatures.RemoveAt(index); // ensure it is actually removed from the list } } ////// Remove all signatures based on this origin /// ///also removes all certificate parts and the signature origin. Caller must call Flush() to persist changes. public void RemoveAllSignatures() { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotRemoveSignatureFromReadOnlyFile)); EnsureSignatures(); try { // Remove via known traversal - required to find all signatures (we may not know all signature content-types). for (int i = 0; i < _signatures.Count; i++) { PackagePart p = _signatures[i].SignaturePart; // Delete any Certificate part(s) targeted by this signature. We know that all of the // reference counts will reach zero because we are removing all signatures. foreach (PackageRelationship r in p.GetRelationshipsByType(CertificatePart.RelationshipType)) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) continue; // fail silently _container.DeletePart(PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri)); // will not throw if part not found } // delete signature part _container.DeletePart(p.Uri); // invalidate the signature itself _signatures[i].Invalidate(); } DeleteOriginPart(); } finally { // update internal variables _signatures.Clear(); } } ////// Obtain the PackageDigitalSignature referred to by the given Uri /// /// ID obtained from a PackageDigitalSignature object ///null if signature not found public PackageDigitalSignature GetSignature(Uri signatureUri) { if (signatureUri == null) throw new ArgumentNullException("signatureUri"); int index = GetSignatureIndex(signatureUri); if (index < 0) return null; else { Debug.Assert(index < _signatures.Count); return _signatures[index]; } } ////// Verify Certificate /// /// certificate to inspect ///certificate is invalid but the error code is not recognized ///the first error encountered when inspecting the certificate chain or NoError if the certificate is valid ////// Critical - The X509Chain.Build method has a LinkDemand for Unrestricted. /// PublicOK – VerifyCertificate has LinkDemand. /// [SecurityCritical] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static X509ChainStatusFlags VerifyCertificate(X509Certificate certificate) { if (certificate == null) throw new ArgumentNullException("certificate"); X509ChainStatusFlags status = X509ChainStatusFlags.NoError; // build the certificate chain X509Chain chain = new X509Chain(); bool valid = chain.Build(new X509Certificate2(certificate.Handle)); // inspect the results if (!valid) { X509ChainStatus[] chainStatus = chain.ChainStatus; for (int i = 0; i < chainStatus.Length; i++) { status |= chainStatus[i].Status; } } return status; } #endregion //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- ////// Get package - used by DigitalSignatureProcessors /// internal Package Package { get { return _container; } } //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- ////// PromptForSigningCertificate - invoked from Sign overloads if certificate is not provided by caller /// /// ///null if user cancels or no certificate could be located ////// Critical: calls X509Certificate2UI.SelectFromCollection which LinkDemands /// TreatAsSafe: UI can only display existing certificates, no spoofing /// [SecurityCritical, SecurityTreatAsSafe] static internal X509Certificate PromptForSigningCertificate(IntPtr hwndParent) { X509Certificate2 X509cert = null; // look for appropriate certificates X509Store store = new X509Store(StoreLocation.CurrentUser); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly); X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates; // narrow down the choices // timevalid collection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, true); // intended for signing (or no intent specified) collection = collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false); // remove certs that don't have private key // work backward so we don't disturb the enumeration for (int i = collection.Count - 1; i >= 0; i--) { if (!collection[i].HasPrivateKey) { collection.RemoveAt(i); } } // any suitable certificates available? if (collection.Count > 0) { // ask user to select collection = X509Certificate2UI.SelectFromCollection(collection, SR.Get(SRID.CertSelectionDialogTitle), SR.Get(SRID.CertSelectionDialogMessage), X509SelectionFlag.SingleSelection, hwndParent); if (collection.Count > 0) { X509cert = collection[0]; // return the first one } } return X509cert; } #region Private Members //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- ////// Predicate for use with List.Exists() /// private class StringMatchPredicate { public StringMatchPredicate(String id) { _id = id; } public bool Match(String id) { return (String.CompareOrdinal(_id, id) == 0); } private string _id; } ////// Verify Parts Exist before signing /// /// ///This call must be done after the signature Origin has been created to allow for /// callers to sign an Origin (or it's relationship part) for the first signature in the package. private void VerifyPartsExist(IEnumerableparts) { // check for missing parts if (parts != null) { foreach (Uri partUri in parts) { if (!_container.PartExists(partUri)) { // delete origin part if it was created and this is the first signature if (_signatures.Count == 0) DeleteOriginPart(); throw new ArgumentException(SR.Get(SRID.PartToSignMissing), "parts"); } } } } /// /// Verifies arguments to Sign() method - sub-function to reduce complexity in Sign() logic /// /// /// /// /// /// /// private void VerifySignArguments(IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId, IEnumerable signatureObjects, IEnumerable objectReferences) { if (certificate == null) throw new ArgumentNullException("certificate"); // Check for empty collections in order to provide negative feedback as soon as possible. if (EnumeratorEmptyCheck(parts) && EnumeratorEmptyCheck(relationshipSelectors) && EnumeratorEmptyCheck(signatureObjects) && EnumeratorEmptyCheck(objectReferences)) throw new ArgumentException(SR.Get(SRID.NothingToSign)); // check for illegal and/or duplicate id's in signatureObjects if (signatureObjects != null) { List ids = new List (); foreach (DataObject obj in signatureObjects) { // ensure they don't duplicate the reserved one if (String.CompareOrdinal(obj.Id, XTable.Get(XTable.ID.OpcAttrValue)) == 0) throw new ArgumentException(SR.Get(SRID.SignaturePackageObjectTagMustBeUnique), "signatureObjects"); // check for duplicates //if (ids.Contains(obj.Id)) if (ids.Exists(new StringMatchPredicate(obj.Id).Match)) throw new ArgumentException(SR.Get(SRID.SignatureObjectIdMustBeUnique), "signatureObjects"); else ids.Add(obj.Id); } } // ensure id is legal Xml id if ((signatureId != null) && (signatureId != String.Empty)) { try { // An XSD ID is an NCName that is unique. System.Xml.XmlConvert.VerifyNCName(signatureId); } catch (System.Xml.XmlException xmlException) { throw new ArgumentException(SR.Get(SRID.NotAValidXmlIdString, signatureId), "signatureId", xmlException); } } } /// /// Returns true if the given enumerator is null or empty /// /// may be null ///true if enumerator is empty or null private bool EnumeratorEmptyCheck(System.Collections.IEnumerable enumerable) { if (enumerable == null) return true; // null means empty // see if it's really a collection as this is more efficient than enumerating System.Collections.ICollection collection = enumerable as System.Collections.ICollection; if (collection != null) { return (collection.Count == 0); } else { // not a collection - do things the hard way foreach (Object o in enumerable) { return false; // if we get here - we're not empty } return true; // empty } } ////// Remove a signature - helper method /// /// signature to remove /// number of signatures that will remain /// after the remove operation. If this count becomes zero, then we can remove the /// origin part also from the package as there will be no remaining signatures /// in the package. ///Caller should call Package.Flush() in order to persist changes. private void InternalRemoveSignature(Uri signatureUri, int countOfSignaturesRemaining) { Debug.Assert(signatureUri != null); Debug.Assert(countOfSignaturesRemaining >= 0); // Remove origin if this operation will have removed the last signature in order to conform with Metro specification. // This will remove all relationships too so the code in the "else" clause becomes redundant and we can skip it. if (countOfSignaturesRemaining == 0) { DeleteOriginPart(); } else // there will be at least a single signature left after this remove, so we need to be more delicate in our surgery { SafeVisitRelationships( OriginPart.GetRelationshipsByType(_originToSignatureRelationshipType), DeleteRelationshipToSignature, signatureUri); } // delete the cert (if any) if it's reference count will become zero SafeVisitRelationships(_container.GetPart(signatureUri).GetRelationshipsByType(CertificatePart.RelationshipType), DeleteCertificateIfReferenceCountBecomesZeroVisitor); // delete the signature part _container.DeletePart(signatureUri); } // return true to continue private delegate bool RelationshipOperation(PackageRelationship r, Object context); ////// Visit relationships without disturbing the PackageRelationshipCollection iterator /// /// collection of relationships to visit /// function to call with each relationship in the list private void SafeVisitRelationships(PackageRelationshipCollection relationships, RelationshipOperation visit) { SafeVisitRelationships(relationships, visit, null); } ////// Visit relationships without disturbing the PackageRelationshipCollection iterator /// /// collection of relationships to visit /// function to call with each relationship in the list /// context object - may be null private void SafeVisitRelationships(PackageRelationshipCollection relationships, RelationshipOperation visit, Object context) { // make a local copy that will not be invalidated by any activity of the visitor function ListrelationshipsToVisit = new List (relationships); // now invoke the delegate for each member for (int i = 0; i < relationshipsToVisit.Count; i++) { // exit if visitor wants us to if (!visit(relationshipsToVisit[i], context)) break; } } /// /// Removes the certificate associated with the given signature if removing the signature would leave the /// certificate part orphaned. /// private bool DeleteCertificateIfReferenceCountBecomesZeroVisitor(PackageRelationship r, Object context) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri certificatePartName = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); if (CertificatePartReferenceCount(certificatePartName) == 1) // we are part of the calculation so one is the magic number _container.DeletePart(certificatePartName); // will not throw if part not found return true; } ////// Deletes any relationship that is of the type that relates a Package to the Digital Signature Origin /// /// /// ///private bool DeleteRelationshipOfTypePackageToOriginVisitor(PackageRelationship r, Object context) { Debug.Assert(Uri.Compare(r.SourceUri, PackUriHelper.PackageRootUri, UriComponents.SerializationInfoString, UriFormat.UriEscaped, StringComparison.Ordinal) == 0, "Logic Error: This visitor should only be called with relationships from the Package itself"); // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri targetUri = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); if (PackUriHelper.ComparePartUri(targetUri, _originPartName) == 0) _container.DeleteRelationship(r.Id); return true; } /// /// Deletes any relationship to the given signature from the signature origin /// /// relationship from origin /// signatureUri ///true private bool DeleteRelationshipToSignature(PackageRelationship r, Object signatureUri) { Uri uri = signatureUri as Uri; Debug.Assert(uri != null, "Improper use of delegate - context must be Uri"); // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); if (PackUriHelper.ComparePartUri(PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri), uri) == 0) { OriginPart.DeleteRelationship(r.Id); // don't break early in case there are redundant relationships } return true; } private void DeleteOriginPart() { try { // remove all relationships of the type "package-to-signature-origin" SafeVisitRelationships(_container.GetRelationshipsByType(_originRelationshipType), DeleteRelationshipOfTypePackageToOriginVisitor); _container.DeletePart(_originPartName); } finally { // reset state variables _originPartExists = false; _originSearchConducted = true; _originPart = null; } } ////// Lookup the index of the signature object in the _signatures array by the name of the part /// /// name of the signature part ///zero-based index or -1 if not found private int GetSignatureIndex(Uri uri) { EnsureSignatures(); for (int i = 0; i < _signatures.Count; i++) { if (PackUriHelper.ComparePartUri(uri, _signatures[i].SignaturePart.Uri) == 0) return i; } return -1; // not found } ////// Counts the number of signatures using the given certificate /// /// certificate to inspect private int CertificatePartReferenceCount(Uri certificatePartUri) { // count the number of signatures that reference this certificate part int count = 0; for (int i = 0; i < _signatures.Count; i++) { // for each signature, follow it's certificate link (if there) and compare the Uri if (_signatures[i].GetCertificatePart() != null) { // same Uri? if (PackUriHelper.ComparePartUri(certificatePartUri, _signatures[i].GetCertificatePart().Uri) == 0) ++count; } } return count; } ////// Generate guid-based signature name to reduce chances of conflict in merging scenarios /// ///private Uri GenerateSignaturePartName() { return PackUriHelper.CreatePartUri(new Uri(_defaultSignaturePartNamePrefix + Guid.NewGuid().ToString(_guidStorageFormatString, (IFormatProvider)null) + _defaultSignaturePartNameExtension, UriKind.Relative)); } // load signatures from container private void EnsureSignatures() { if (_signatures == null) { _signatures = new List (); // no signatures if origin not found if (OriginPartExists()) { // find all signatures from this origin (if any) PackageRelationshipCollection relationships = _originPart.GetRelationshipsByType( _originToSignatureRelationshipType); foreach (PackageRelationship r in relationships) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri signaturePartName = PackUriHelper.ResolvePartUri(_originPart.Uri, r.TargetUri); // throw if part does not exist if (!_container.PartExists(signaturePartName)) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); PackagePart signaturePart = _container.GetPart(signaturePartName); // ignore future signature types that we do not recognize if (signaturePart.ValidatedContentType.AreTypeAndSubTypeEqual (XmlDigitalSignatureProcessor.ContentType)) { // parse it PackageDigitalSignature signature = new PackageDigitalSignature(this, signaturePart); // add to the list _signatures.Add(signature); } } } } } /// /// Looks for part name of Origin by searching from the container root and following the metro origin part relationship /// ///side effect of assigning the _originPartName and _originPart if found ///true if found private bool OriginPartExists() { // only search once if (!_originSearchConducted) { try { Debug.Assert(!_originPartExists, "Logic Error: If OriginPartExists, OriginSearchConducted should be true."); PackageRelationshipCollection containerRelationships = _container.GetRelationshipsByType(_originRelationshipType); foreach (PackageRelationship r in containerRelationships) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); // resolve target (may be relative) Uri targetUri = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); // if part does not exist - we throw if (!_container.PartExists(targetUri)) throw new FileFormatException(SR.Get(SRID.SignatureOriginNotFound)); PackagePart p = _container.GetPart(targetUri); // inspect content type - ignore things we don't understand if (p.ValidatedContentType.AreTypeAndSubTypeEqual(_originPartContentType)) { // throw if more than one relationship to an origin part that we recognize if (_originPartExists) throw new FileFormatException(SR.Get(SRID.MultipleSignatureOrigins)); // overwrite default if some container is using some other name _originPartName = targetUri; _originPart = p; _originPartExists = true; } } } finally { _originSearchConducted = true; } } return _originPartExists; } //------------------------------------------------------ // // Private Properties // //----------------------------------------------------- private bool ReadOnly { get { return (_container.FileOpenAccess == FileAccess.Read); } } private PackagePart OriginPart { get { if (_originPart == null) { if (!OriginPartExists()) { // add if not found _originPart = _container.CreatePart(_originPartName, _originPartContentType.ToString()); _container.CreateRelationship(_originPartName, TargetMode.Internal, _originRelationshipType); } } return _originPart; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private CertificateEmbeddingOption _certificateEmbeddingOption; private Package _container; private IntPtr _parentWindow; private static Uri _defaultOriginPartName = PackUriHelper.CreatePartUri(new Uri("/package/services/digital-signature/origin.psdsor", UriKind.Relative)); private Uri _originPartName = _defaultOriginPartName; private PackagePart _originPart; private String _hashAlgorithmString = _defaultHashAlgorithm; private String _signatureTimeFormat = XmlSignatureProperties.DefaultDateTimeFormat; private List_signatures; private Dictionary _transformDictionary; private bool _originSearchConducted; // don't look more than once for Origin part private bool _originPartExists; // was the part found? private ReadOnlyCollection _signatureList; // lazy-init cached return value for Signatures property private static readonly ContentType _originPartContentType = new ContentType("application/vnd.openxmlformats-package.digital-signature-origin"); private static readonly String _guidStorageFormatString = @"N"; // N - simple format without adornments private static readonly String _defaultHashAlgorithm = SignedXml.XmlDsigSHA1Url; private static readonly String _originRelationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"; private static readonly String _originToSignatureRelationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature"; private static readonly String _defaultSignaturePartNamePrefix = "/package/services/digital-signature/xml-signature/"; private static readonly String _defaultSignaturePartNameExtension = ".psdsxs"; #endregion Private Members } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: // This class provides api's to add/remove/verify signatures on an MMCF container. // // History: // 03/22/2004: BruceMac: Initial Implementation // //----------------------------------------------------------------------------- // Allow use of presharp warning numbers [6506] unknown to the compiler #pragma warning disable 1634, 1691 using System; using System.Collections.Generic; using System.Windows; // For Exception strings - SRID using System.Text; // for StringBuilder using System.Diagnostics; // for Assert using System.Security; // for SecurityCritical tag using System.Security.Permissions; // for LinkDemand using System.Security.Cryptography.Xml; // for SignedXml using System.Security.Cryptography.X509Certificates; // for X509Certificate using MS.Internal.IO.Packaging; // for internal helpers using System.Collections.ObjectModel; // for ReadOnlyCollection<> using MS.Internal; // for ContentType namespace System.IO.Packaging { ////// Options for storing the signing Certificate /// public enum CertificateEmbeddingOption : int { ////// Embed certificate in its own PackagePart (or share if same cert already exists) /// InCertificatePart = 0, // embed the certificate in its own, possibly-shared part ////// Embed certificate within the signature PackagePart /// InSignaturePart = 1, // embed the certificate within the signature ////// Do not embed /// NotEmbedded = 2, // do not embed the certificate at all } ////// Type of the handler that is invoked if signature validation is non-success. /// /// signature /// event arguments - containing the result ///true to continue verifying other signatures, false to abandon effort public delegate void InvalidSignatureEventHandler(object sender, SignatureVerificationEventArgs e); ////// Signature Verification Event Args - information about a verification event /// public class SignatureVerificationEventArgs : EventArgs { //----------------------------------------------------- // // Public Members // //----------------------------------------------------- ////// Signature being processed /// public PackageDigitalSignature Signature { get { return _signature; } } ////// Result of Verification /// public VerifyResult VerifyResult { get { return _result; } } //------------------------------------------------------ // // Internal Members // //----------------------------------------------------- internal SignatureVerificationEventArgs(PackageDigitalSignature signature, VerifyResult result) { // verify arguments if (signature == null) throw new ArgumentNullException("signature"); if (result < VerifyResult.Success || result > VerifyResult.NotSigned) throw new System.ArgumentOutOfRangeException("result"); _signature = signature; _result = result; } //------------------------------------------------------ // // Private Members // //------------------------------------------------------ private PackageDigitalSignature _signature; private VerifyResult _result; } ////// PackageDigitalSignatureManager /// public sealed class PackageDigitalSignatureManager { #region Public Members //----------------------------------------------------- // // Public Events // //------------------------------------------------------ ////// Event to subscribe to for signature validation activities /// public event InvalidSignatureEventHandler InvalidSignatureEvent; //----------------------------------------------------- // // Public Properties // //----------------------------------------------------- ////// Does this container hold digital signatures? /// ///true if signatures exist ///this does not evaluate the signatures - they may be invalid even if this returns true public bool IsSigned { get { EnsureSignatures(); return (_signatures.Count > 0); } } ////// Signatures in container /// ///read only list of immutable signatures found in the container public ReadOnlyCollectionSignatures { get { // ensure signatures are loaded from origin EnsureSignatures(); // Return a read-only collection referring to them. // This list will be automatically updated when the underlying collection is changed. if (_signatureList == null) _signatureList = new ReadOnlyCollection (_signatures); return _signatureList; } } /// /// ContentType - Transform mapping dictionary /// ///Dictionary of transform Uri's indexed by ContentType. /// Contains a single transform to be applied /// before hashing any Part encountered with that ContentType public DictionaryTransformMapping { get { return _transformDictionary; } } /// /// Handle of parent window to use when displaying certificate selection dialog /// ////// not necessary if certificates are provided in calls to sign public IntPtr ParentWindow { get { return _parentWindow; } set { _parentWindow = value; } } ////// Hashalgorithm to use when creating/verifying signatures /// ////// defaults to SHA1 public String HashAlgorithm { get { return _hashAlgorithmString; } set { if (value == null) throw new ArgumentNullException("value"); if (value == String.Empty) throw new ArgumentException(SR.Get(SRID.UnsupportedHashAlgorithm), "value"); _hashAlgorithmString = value; } } ////// How to embed certificates when Signing /// ///public CertificateEmbeddingOption CertificateOption { get { return _certificateEmbeddingOption; } set { if ((value < CertificateEmbeddingOption.InCertificatePart) || (value > CertificateEmbeddingOption.NotEmbedded)) throw new ArgumentOutOfRangeException("value"); _certificateEmbeddingOption = value; } } /// /// How to format the SignatureTime in new signatures /// ///Legal formats specified in Opc book and reproduced here: /// YYYY-MM-DDThh:mm:ss.sTZD /// YYYY-MM-DDThh:mm:ssTZD /// YYYY-MM-DDThh:mmTZD /// YYYY-MM-DD /// YYYY-MM /// YYYY /// /// where: /// Y = year, M = month integer (leading zero), D = day integer (leading zero), /// hh = 24hr clock hour /// mm = minutes (leading zero) /// ss = seconds (leading zero) /// .s = tenths of a second /// public String TimeFormat { get { return _signatureTimeFormat; } set { if (value == null) throw new ArgumentNullException("value"); if (XmlSignatureProperties.LegalFormat(value)) _signatureTimeFormat = value; else throw new FormatException(SR.Get(SRID.BadSignatureTimeFormatString)); } } //----------------------------------------------------- // // Public Fields // //------------------------------------------------------ ////// Name of signature origin part /// ////// This value may vary by Package because the name is not formally defined. While this /// implementation will generally use the same default value, the value returned by this property will reflect /// whatever origin is already present in the current Package (if any) which may vary between implementations. /// public Uri SignatureOrigin { get { OriginPartExists(); // force search for OriginPart in case it is different from default return _originPartName; } } ////// Type of default signature origin relationship /// ///static public String SignatureOriginRelationshipType { get { return _originRelationshipType; } } /// /// Default hash algorithm /// ///static public String DefaultHashAlgorithm { get { return _defaultHashAlgorithm; } } //----------------------------------------------------- // // Public Methods // //------------------------------------------------------ /// /// Create a new PackageDigitalSignature manager /// /// container to work with ///based on the default origin ///package is null public PackageDigitalSignatureManager(Package package) { if (package == null) throw new ArgumentNullException("package"); _parentWindow = IntPtr.Zero; _container = package; // initialize the transform dictionary with defaults _transformDictionary = new Dictionary(4); _transformDictionary[PackagingUtilities.RelationshipPartContentType.ToString()] = SignedXml.XmlDsigC14NTransformUrl; // relationship parts _transformDictionary[XmlDigitalSignatureProcessor.ContentType.ToString()] = SignedXml.XmlDsigC14NTransformUrl; // xml signature } #region Sign /// /// Sign - prompts for certificate and embeds it /// /// list of parts to sign ///Set ParentWindow before this call if you want to make the certificate /// selection dialog modal to a particular window. Does not prompt for certificates if none could be located in the default certificate store. ///null if no certificate could be located, or if the user cancels from the certificate selection dialog. public PackageDigitalSignature Sign(IEnumerableparts) { X509Certificate certificate = PromptForSigningCertificate(ParentWindow); if (certificate == null) return null; else return Sign(parts, certificate); } /// /// Sign - certificate provided by caller /// /// list of parts to sign /// signer's certificate public PackageDigitalSignature Sign(IEnumerableparts, X509Certificate certificate) { // create unique signature name return Sign(parts, certificate, null); } /// /// Sign - certificate provided by caller /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null ///one of parts or relationships must be non-null and contain at least a single entry public PackageDigitalSignature Sign(IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors) { // use default signature Id return Sign(parts, certificate, relationshipSelectors, XTable.Get(XTable.ID.OpcSignatureAttrValue)); } /// /// Sign - certificate provided by caller /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null /// id for the new Signature - may be empty or null ///one of parts or relationships must be non-null and contain at least a single entry public PackageDigitalSignature Sign( IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId) { // Cannot both be null - need to check here because the similar check in the super-overload cannot // distinguish to this level. if (parts == null && relationshipSelectors == null) { throw new ArgumentException(SR.Get(SRID.NothingToSign)); } return Sign(parts, certificate, relationshipSelectors, signatureId, null, null); } /// /// Sign - caller specifies custom "Object" and/or SignedInfo "Reference" tags /// /// list of parts to sign - may be empty or null /// signer's certificate /// relationshipSelectors that hold information about /// the relationships to be signed - may be empty or null /// id for the new Signature - may be empty or null /// references to custom object tags. The DigestMethod on each /// Reference will be ignored. The signature will use the globally defined HashAlgorithm /// obtained from the current value of the HashAlgorithm property. /// objects (signed or not) ///Thrown if any TransformMapping /// defines an empty or null transform for the ContentType of any Part being signed or if an unknown /// transform is encountered. ///Thrown if signatureId is non-null and violates the /// Xml Id schema (essentially - no leading digit is allowed). ///One of parts, relationships, signatureObjects and objectReferences must be /// non-null and contain at least a single entry. /// This and every other Sign overload makes use of the current state of the TransformMapping /// dictionary which defines a Transform to apply based on ContentType. The Opc specification /// only currently allows for two legal Transform algorithms: C14 and C14N. /// Note that the w3c Xml Signature standard does not allow for empty Manifest tags. /// Because the Opc specification requires the existence of a Package-specific Object /// tag and further specifies that this Object tag contain a Manifest and SignatureProperties /// tags, it follows that this Manifest tag must include at least one Reference tag. /// This means that every signature include at least one of a Part to sign (non-empty parts tag) /// or a Relationship to sign (non-empty relationshipSelectors) even if such a signature /// is only destined to sign signatureObjects and/or objectReferences. /// This overload provides support for generation of Xml signatures that require custom /// Object tags. For any provided Object tag to be signed, a corresponding Reference /// tag must be provided with a Uri that targets the Object tag using local fragment /// syntax. If the object had an ID of "myObject" the Uri on the Reference would /// be "#myObject". For unsigned objects, no reference is required. ////// Critical: calls X509Certificate.Handle which LinkDemands /// PublicOK: we don't store or return the handle /// [SecurityCritical] public PackageDigitalSignature Sign( IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId, IEnumerable signatureObjects, IEnumerable objectReferences) { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotSignReadOnlyFile)); VerifySignArguments(parts, certificate, relationshipSelectors, signatureId, signatureObjects, objectReferences); // substitute default id if none given if ((signatureId == null) || (signatureId == String.Empty)) { signatureId = "packageSignature"; // default } // Make sure the list reflects what's in the package. // Do this before adding the new signature part because we don't want it included until it // is fully formed (and delaying the add saves us having to remove it in case there is an // error during the Sign call). EnsureSignatures(); Uri newSignaturePartName = GenerateSignaturePartName(); if (_container.PartExists(newSignaturePartName)) throw new ArgumentException(SR.Get(SRID.DuplicateSignature)); // Pre-create origin part if it does not already exist. // Do this before signing to allow for signing the package relationship part (because a Relationship // is added from the Package to the Origin part by this call) and the Origin Relationship part in case this is // a Publishing signature and the caller wants the addition of more signatures to break this signature. PackageRelationship relationshipToNewSignature = OriginPart.CreateRelationship(newSignaturePartName, TargetMode.Internal, _originToSignatureRelationshipType); _container.Flush(); // ensure the origin relationship part is persisted so that any signature will include this newest relationship VerifyPartsExist(parts); // sign the data and optionally embed the certificate bool embedCertificateInSignaturePart = (_certificateEmbeddingOption == CertificateEmbeddingOption.InSignaturePart); // convert cert to version2 - more functionality X509Certificate2 exSigner = certificate as X509Certificate2; if (exSigner == null) exSigner = new X509Certificate2(certificate.Handle); //PRESHARP: Parameter to this public method must be validated: A null-dereference can occur here. // Parameter 'exSigner' to this public method must be validated: A null-dereference can occur here. //This is a false positive as the checks above can gurantee no null dereference will occur #pragma warning disable 6506 PackageDigitalSignature signature = null; PackagePart newSignaturePart = null; try { // create the new part newSignaturePart = _container.CreatePart(newSignaturePartName, XmlDigitalSignatureProcessor.ContentType.ToString()); // do the actual signing - only Xml signatures currently supported signature = XmlDigitalSignatureProcessor.Sign(this, newSignaturePart, parts, relationshipSelectors, exSigner, signatureId, embedCertificateInSignaturePart, signatureObjects, objectReferences); } catch (InvalidOperationException) { // bad hash algorithm - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } catch (System.IO.IOException) { // failure to open part - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } catch (System.Security.Cryptography.CryptographicException) { // failure to sign - revert changes // guarantees proper cleanup including removal of Origin if appropriate // Note: _signatures.Count reflects the number of signatures that were // existing before this sign method was called. So we want to leave those // untouched and clean up what we added in this method prior to the // exception. If the count is zero, we will also delete the origin part. InternalRemoveSignature(newSignaturePartName, _signatures.Count); _container.Flush(); // actually persist the revert throw; } // add to the list _signatures.Add(signature); // embed certificate if called for if (_certificateEmbeddingOption == CertificateEmbeddingOption.InCertificatePart) { // create the cert part // auto-generate a certificate name - will be the same for the same certificate Uri certificatePartName = PackUriHelper.CreatePartUri(new Uri( CertificatePart.PartNamePrefix + exSigner.SerialNumber + CertificatePart.PartNameExtension, UriKind.Relative)); // create the serialization helper class (side-effect of creating or opening the part) CertificatePart certPart = new CertificatePart(_container, certificatePartName); certPart.SetCertificate(exSigner); // establish a relationship newSignaturePart.CreateRelationship(certificatePartName, TargetMode.Internal, CertificatePart.RelationshipType); signature.SetCertificatePart(certPart); } #pragma warning restore 6506 _container.Flush(); // return to caller in case they need it return signature; } #endregion #region CounterSign /// /// CounterSign - prompts for certificate and embeds it based on current CertificateEmbeddingOption /// ///Set ParentWindow before this call if you want to make the certificate /// selection dialog modal to a particular window. Does not present the dialog if no suitable certificate /// could be found in the default certificate store. /// Signs all existing signature parts so that any change to these part(s) will invalidate the /// returned signature. ///Cannot CounterSign an unsigned package. ///null if no certificate could be located, or if the user cancels from the certificate selection dialog. public PackageDigitalSignature Countersign() { // Counter-sign makes no sense if we are not already signed // Check before asking for certificate if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // prompt for certificate X509Certificate certificate = PromptForSigningCertificate(ParentWindow); if (certificate == null) return null; else return Countersign(certificate); } ////// CounterSign - certificate provided /// /// signer's certificate ///Cannot CounterSign an unsigned package. ///certificate must be non-null. ///Signs all existing signature parts so that any change to these part(s) will invalidate the /// returned signature. public PackageDigitalSignature Countersign(X509Certificate certificate) { if (certificate == null) throw new ArgumentNullException("certificate"); // Counter-sign makes no sense if we are not already signed // Check before asking for certificate if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // sign all existing signatures Listsignatures = new List (_signatures.Count); for (int i = 0; i < _signatures.Count; i++) { signatures.Add(_signatures[i].SignaturePart.Uri); } // sign return Sign(signatures, certificate); } /// /// CounterSign - signature part name(s) specified by caller /// /// signer's certificate /// signature parts to sign ///Signs the given signature parts so that any change to these part(s) will invalidate the /// returned signature. ///Cannot CounterSign an unsigned package. ///signatures must be non-empty and cannot refer to parts other than signature parts. ///Both arguments must be non-null. public PackageDigitalSignature Countersign(X509Certificate certificate, IEnumerablesignatures) { if (certificate == null) throw new ArgumentNullException("certificate"); if (signatures == null) throw new ArgumentNullException("signatures"); // Counter-sign makes no sense if we are not already signed if (!IsSigned) throw new InvalidOperationException(SR.Get(SRID.NoCounterSignUnsignedContainer)); // Restrict signatures to be actual signature part references foreach (Uri uri in signatures) { PackagePart part = _container.GetPart(uri); if (!part.ValidatedContentType.AreTypeAndSubTypeEqual(XmlDigitalSignatureProcessor.ContentType)) throw new ArgumentException(SR.Get(SRID.CanOnlyCounterSignSignatureParts, signatures)); } return Sign(signatures, certificate); } #endregion /// /// verify all signatures - calls verify on each signature /// /// true to exit on first failure - false to continue ///register for invalid signature events public VerifyResult VerifySignatures(bool exitOnFailure) { VerifyResult result; EnsureSignatures(); // signed? if (_signatures.Count == 0) result = VerifyResult.NotSigned; else { // contract is to return a failure value, even if there are subsequent successes // defaulting to success here simplifies the logic for this result = VerifyResult.Success; // default for (int i = 0; i < _signatures.Count; i++) { VerifyResult temp = _signatures[i].Verify(); if (temp != VerifyResult.Success) { result = temp; // note failure if (InvalidSignatureEvent != null) InvalidSignatureEvent(this, new SignatureVerificationEventArgs(_signatures[i], temp)); if (exitOnFailure) break; } } } return result; } ////// Remove a signature /// /// signature to remove ///Caller should call Package.Flush() in order to persist changes. public void RemoveSignature(Uri signatureUri) { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotRemoveSignatureFromReadOnlyFile)); if (signatureUri == null) throw new ArgumentNullException("signatureUri"); // empty? if (!IsSigned) // calls EnsureSignatures for us return; // find the signature int index = GetSignatureIndex(signatureUri); if (index < 0) return; try { Debug.Assert(index < _signatures.Count); //After this signature is removed the total number of signatures remaining will //be _signatures.Count - 1. If this count is zero, then additional clean up needs //to be done, like removing the Origin part. InternalRemoveSignature(signatureUri, _signatures.Count - 1 /*since we are deleting one*/); // invalidate the signature itself _signatures[index].Invalidate(); } finally { _signatures.RemoveAt(index); // ensure it is actually removed from the list } } ////// Remove all signatures based on this origin /// ///also removes all certificate parts and the signature origin. Caller must call Flush() to persist changes. public void RemoveAllSignatures() { if (ReadOnly) throw new InvalidOperationException(SR.Get(SRID.CannotRemoveSignatureFromReadOnlyFile)); EnsureSignatures(); try { // Remove via known traversal - required to find all signatures (we may not know all signature content-types). for (int i = 0; i < _signatures.Count; i++) { PackagePart p = _signatures[i].SignaturePart; // Delete any Certificate part(s) targeted by this signature. We know that all of the // reference counts will reach zero because we are removing all signatures. foreach (PackageRelationship r in p.GetRelationshipsByType(CertificatePart.RelationshipType)) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) continue; // fail silently _container.DeletePart(PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri)); // will not throw if part not found } // delete signature part _container.DeletePart(p.Uri); // invalidate the signature itself _signatures[i].Invalidate(); } DeleteOriginPart(); } finally { // update internal variables _signatures.Clear(); } } ////// Obtain the PackageDigitalSignature referred to by the given Uri /// /// ID obtained from a PackageDigitalSignature object ///null if signature not found public PackageDigitalSignature GetSignature(Uri signatureUri) { if (signatureUri == null) throw new ArgumentNullException("signatureUri"); int index = GetSignatureIndex(signatureUri); if (index < 0) return null; else { Debug.Assert(index < _signatures.Count); return _signatures[index]; } } ////// Verify Certificate /// /// certificate to inspect ///certificate is invalid but the error code is not recognized ///the first error encountered when inspecting the certificate chain or NoError if the certificate is valid ////// Critical - The X509Chain.Build method has a LinkDemand for Unrestricted. /// PublicOK – VerifyCertificate has LinkDemand. /// [SecurityCritical] [SecurityPermissionAttribute(SecurityAction.LinkDemand, Unrestricted = true)] public static X509ChainStatusFlags VerifyCertificate(X509Certificate certificate) { if (certificate == null) throw new ArgumentNullException("certificate"); X509ChainStatusFlags status = X509ChainStatusFlags.NoError; // build the certificate chain X509Chain chain = new X509Chain(); bool valid = chain.Build(new X509Certificate2(certificate.Handle)); // inspect the results if (!valid) { X509ChainStatus[] chainStatus = chain.ChainStatus; for (int i = 0; i < chainStatus.Length; i++) { status |= chainStatus[i].Status; } } return status; } #endregion //------------------------------------------------------ // // Internal Properties // //----------------------------------------------------- ////// Get package - used by DigitalSignatureProcessors /// internal Package Package { get { return _container; } } //------------------------------------------------------ // // Internal Methods // //----------------------------------------------------- ////// PromptForSigningCertificate - invoked from Sign overloads if certificate is not provided by caller /// /// ///null if user cancels or no certificate could be located ////// Critical: calls X509Certificate2UI.SelectFromCollection which LinkDemands /// TreatAsSafe: UI can only display existing certificates, no spoofing /// [SecurityCritical, SecurityTreatAsSafe] static internal X509Certificate PromptForSigningCertificate(IntPtr hwndParent) { X509Certificate2 X509cert = null; // look for appropriate certificates X509Store store = new X509Store(StoreLocation.CurrentUser); store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly); X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates; // narrow down the choices // timevalid collection = collection.Find(X509FindType.FindByTimeValid, DateTime.Now, true); // intended for signing (or no intent specified) collection = collection.Find(X509FindType.FindByKeyUsage, X509KeyUsageFlags.DigitalSignature, false); // remove certs that don't have private key // work backward so we don't disturb the enumeration for (int i = collection.Count - 1; i >= 0; i--) { if (!collection[i].HasPrivateKey) { collection.RemoveAt(i); } } // any suitable certificates available? if (collection.Count > 0) { // ask user to select collection = X509Certificate2UI.SelectFromCollection(collection, SR.Get(SRID.CertSelectionDialogTitle), SR.Get(SRID.CertSelectionDialogMessage), X509SelectionFlag.SingleSelection, hwndParent); if (collection.Count > 0) { X509cert = collection[0]; // return the first one } } return X509cert; } #region Private Members //----------------------------------------------------- // // Private Methods // //----------------------------------------------------- ////// Predicate for use with List.Exists() /// private class StringMatchPredicate { public StringMatchPredicate(String id) { _id = id; } public bool Match(String id) { return (String.CompareOrdinal(_id, id) == 0); } private string _id; } ////// Verify Parts Exist before signing /// /// ///This call must be done after the signature Origin has been created to allow for /// callers to sign an Origin (or it's relationship part) for the first signature in the package. private void VerifyPartsExist(IEnumerableparts) { // check for missing parts if (parts != null) { foreach (Uri partUri in parts) { if (!_container.PartExists(partUri)) { // delete origin part if it was created and this is the first signature if (_signatures.Count == 0) DeleteOriginPart(); throw new ArgumentException(SR.Get(SRID.PartToSignMissing), "parts"); } } } } /// /// Verifies arguments to Sign() method - sub-function to reduce complexity in Sign() logic /// /// /// /// /// /// /// private void VerifySignArguments(IEnumerableparts, X509Certificate certificate, IEnumerable relationshipSelectors, String signatureId, IEnumerable signatureObjects, IEnumerable objectReferences) { if (certificate == null) throw new ArgumentNullException("certificate"); // Check for empty collections in order to provide negative feedback as soon as possible. if (EnumeratorEmptyCheck(parts) && EnumeratorEmptyCheck(relationshipSelectors) && EnumeratorEmptyCheck(signatureObjects) && EnumeratorEmptyCheck(objectReferences)) throw new ArgumentException(SR.Get(SRID.NothingToSign)); // check for illegal and/or duplicate id's in signatureObjects if (signatureObjects != null) { List ids = new List (); foreach (DataObject obj in signatureObjects) { // ensure they don't duplicate the reserved one if (String.CompareOrdinal(obj.Id, XTable.Get(XTable.ID.OpcAttrValue)) == 0) throw new ArgumentException(SR.Get(SRID.SignaturePackageObjectTagMustBeUnique), "signatureObjects"); // check for duplicates //if (ids.Contains(obj.Id)) if (ids.Exists(new StringMatchPredicate(obj.Id).Match)) throw new ArgumentException(SR.Get(SRID.SignatureObjectIdMustBeUnique), "signatureObjects"); else ids.Add(obj.Id); } } // ensure id is legal Xml id if ((signatureId != null) && (signatureId != String.Empty)) { try { // An XSD ID is an NCName that is unique. System.Xml.XmlConvert.VerifyNCName(signatureId); } catch (System.Xml.XmlException xmlException) { throw new ArgumentException(SR.Get(SRID.NotAValidXmlIdString, signatureId), "signatureId", xmlException); } } } /// /// Returns true if the given enumerator is null or empty /// /// may be null ///true if enumerator is empty or null private bool EnumeratorEmptyCheck(System.Collections.IEnumerable enumerable) { if (enumerable == null) return true; // null means empty // see if it's really a collection as this is more efficient than enumerating System.Collections.ICollection collection = enumerable as System.Collections.ICollection; if (collection != null) { return (collection.Count == 0); } else { // not a collection - do things the hard way foreach (Object o in enumerable) { return false; // if we get here - we're not empty } return true; // empty } } ////// Remove a signature - helper method /// /// signature to remove /// number of signatures that will remain /// after the remove operation. If this count becomes zero, then we can remove the /// origin part also from the package as there will be no remaining signatures /// in the package. ///Caller should call Package.Flush() in order to persist changes. private void InternalRemoveSignature(Uri signatureUri, int countOfSignaturesRemaining) { Debug.Assert(signatureUri != null); Debug.Assert(countOfSignaturesRemaining >= 0); // Remove origin if this operation will have removed the last signature in order to conform with Metro specification. // This will remove all relationships too so the code in the "else" clause becomes redundant and we can skip it. if (countOfSignaturesRemaining == 0) { DeleteOriginPart(); } else // there will be at least a single signature left after this remove, so we need to be more delicate in our surgery { SafeVisitRelationships( OriginPart.GetRelationshipsByType(_originToSignatureRelationshipType), DeleteRelationshipToSignature, signatureUri); } // delete the cert (if any) if it's reference count will become zero SafeVisitRelationships(_container.GetPart(signatureUri).GetRelationshipsByType(CertificatePart.RelationshipType), DeleteCertificateIfReferenceCountBecomesZeroVisitor); // delete the signature part _container.DeletePart(signatureUri); } // return true to continue private delegate bool RelationshipOperation(PackageRelationship r, Object context); ////// Visit relationships without disturbing the PackageRelationshipCollection iterator /// /// collection of relationships to visit /// function to call with each relationship in the list private void SafeVisitRelationships(PackageRelationshipCollection relationships, RelationshipOperation visit) { SafeVisitRelationships(relationships, visit, null); } ////// Visit relationships without disturbing the PackageRelationshipCollection iterator /// /// collection of relationships to visit /// function to call with each relationship in the list /// context object - may be null private void SafeVisitRelationships(PackageRelationshipCollection relationships, RelationshipOperation visit, Object context) { // make a local copy that will not be invalidated by any activity of the visitor function ListrelationshipsToVisit = new List (relationships); // now invoke the delegate for each member for (int i = 0; i < relationshipsToVisit.Count; i++) { // exit if visitor wants us to if (!visit(relationshipsToVisit[i], context)) break; } } /// /// Removes the certificate associated with the given signature if removing the signature would leave the /// certificate part orphaned. /// private bool DeleteCertificateIfReferenceCountBecomesZeroVisitor(PackageRelationship r, Object context) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri certificatePartName = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); if (CertificatePartReferenceCount(certificatePartName) == 1) // we are part of the calculation so one is the magic number _container.DeletePart(certificatePartName); // will not throw if part not found return true; } ////// Deletes any relationship that is of the type that relates a Package to the Digital Signature Origin /// /// /// ///private bool DeleteRelationshipOfTypePackageToOriginVisitor(PackageRelationship r, Object context) { Debug.Assert(Uri.Compare(r.SourceUri, PackUriHelper.PackageRootUri, UriComponents.SerializationInfoString, UriFormat.UriEscaped, StringComparison.Ordinal) == 0, "Logic Error: This visitor should only be called with relationships from the Package itself"); // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri targetUri = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); if (PackUriHelper.ComparePartUri(targetUri, _originPartName) == 0) _container.DeleteRelationship(r.Id); return true; } /// /// Deletes any relationship to the given signature from the signature origin /// /// relationship from origin /// signatureUri ///true private bool DeleteRelationshipToSignature(PackageRelationship r, Object signatureUri) { Uri uri = signatureUri as Uri; Debug.Assert(uri != null, "Improper use of delegate - context must be Uri"); // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); if (PackUriHelper.ComparePartUri(PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri), uri) == 0) { OriginPart.DeleteRelationship(r.Id); // don't break early in case there are redundant relationships } return true; } private void DeleteOriginPart() { try { // remove all relationships of the type "package-to-signature-origin" SafeVisitRelationships(_container.GetRelationshipsByType(_originRelationshipType), DeleteRelationshipOfTypePackageToOriginVisitor); _container.DeletePart(_originPartName); } finally { // reset state variables _originPartExists = false; _originSearchConducted = true; _originPart = null; } } ////// Lookup the index of the signature object in the _signatures array by the name of the part /// /// name of the signature part ///zero-based index or -1 if not found private int GetSignatureIndex(Uri uri) { EnsureSignatures(); for (int i = 0; i < _signatures.Count; i++) { if (PackUriHelper.ComparePartUri(uri, _signatures[i].SignaturePart.Uri) == 0) return i; } return -1; // not found } ////// Counts the number of signatures using the given certificate /// /// certificate to inspect private int CertificatePartReferenceCount(Uri certificatePartUri) { // count the number of signatures that reference this certificate part int count = 0; for (int i = 0; i < _signatures.Count; i++) { // for each signature, follow it's certificate link (if there) and compare the Uri if (_signatures[i].GetCertificatePart() != null) { // same Uri? if (PackUriHelper.ComparePartUri(certificatePartUri, _signatures[i].GetCertificatePart().Uri) == 0) ++count; } } return count; } ////// Generate guid-based signature name to reduce chances of conflict in merging scenarios /// ///private Uri GenerateSignaturePartName() { return PackUriHelper.CreatePartUri(new Uri(_defaultSignaturePartNamePrefix + Guid.NewGuid().ToString(_guidStorageFormatString, (IFormatProvider)null) + _defaultSignaturePartNameExtension, UriKind.Relative)); } // load signatures from container private void EnsureSignatures() { if (_signatures == null) { _signatures = new List (); // no signatures if origin not found if (OriginPartExists()) { // find all signatures from this origin (if any) PackageRelationshipCollection relationships = _originPart.GetRelationshipsByType( _originToSignatureRelationshipType); foreach (PackageRelationship r in relationships) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); Uri signaturePartName = PackUriHelper.ResolvePartUri(_originPart.Uri, r.TargetUri); // throw if part does not exist if (!_container.PartExists(signaturePartName)) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); PackagePart signaturePart = _container.GetPart(signaturePartName); // ignore future signature types that we do not recognize if (signaturePart.ValidatedContentType.AreTypeAndSubTypeEqual (XmlDigitalSignatureProcessor.ContentType)) { // parse it PackageDigitalSignature signature = new PackageDigitalSignature(this, signaturePart); // add to the list _signatures.Add(signature); } } } } } /// /// Looks for part name of Origin by searching from the container root and following the metro origin part relationship /// ///side effect of assigning the _originPartName and _originPart if found ///true if found private bool OriginPartExists() { // only search once if (!_originSearchConducted) { try { Debug.Assert(!_originPartExists, "Logic Error: If OriginPartExists, OriginSearchConducted should be true."); PackageRelationshipCollection containerRelationships = _container.GetRelationshipsByType(_originRelationshipType); foreach (PackageRelationship r in containerRelationships) { // don't resolve if external if (r.TargetMode != TargetMode.Internal) throw new FileFormatException(SR.Get(SRID.PackageSignatureCorruption)); // resolve target (may be relative) Uri targetUri = PackUriHelper.ResolvePartUri(r.SourceUri, r.TargetUri); // if part does not exist - we throw if (!_container.PartExists(targetUri)) throw new FileFormatException(SR.Get(SRID.SignatureOriginNotFound)); PackagePart p = _container.GetPart(targetUri); // inspect content type - ignore things we don't understand if (p.ValidatedContentType.AreTypeAndSubTypeEqual(_originPartContentType)) { // throw if more than one relationship to an origin part that we recognize if (_originPartExists) throw new FileFormatException(SR.Get(SRID.MultipleSignatureOrigins)); // overwrite default if some container is using some other name _originPartName = targetUri; _originPart = p; _originPartExists = true; } } } finally { _originSearchConducted = true; } } return _originPartExists; } //------------------------------------------------------ // // Private Properties // //----------------------------------------------------- private bool ReadOnly { get { return (_container.FileOpenAccess == FileAccess.Read); } } private PackagePart OriginPart { get { if (_originPart == null) { if (!OriginPartExists()) { // add if not found _originPart = _container.CreatePart(_originPartName, _originPartContentType.ToString()); _container.CreateRelationship(_originPartName, TargetMode.Internal, _originRelationshipType); } } return _originPart; } } //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ private CertificateEmbeddingOption _certificateEmbeddingOption; private Package _container; private IntPtr _parentWindow; private static Uri _defaultOriginPartName = PackUriHelper.CreatePartUri(new Uri("/package/services/digital-signature/origin.psdsor", UriKind.Relative)); private Uri _originPartName = _defaultOriginPartName; private PackagePart _originPart; private String _hashAlgorithmString = _defaultHashAlgorithm; private String _signatureTimeFormat = XmlSignatureProperties.DefaultDateTimeFormat; private List_signatures; private Dictionary _transformDictionary; private bool _originSearchConducted; // don't look more than once for Origin part private bool _originPartExists; // was the part found? private ReadOnlyCollection _signatureList; // lazy-init cached return value for Signatures property private static readonly ContentType _originPartContentType = new ContentType("application/vnd.openxmlformats-package.digital-signature-origin"); private static readonly String _guidStorageFormatString = @"N"; // N - simple format without adornments private static readonly String _defaultHashAlgorithm = SignedXml.XmlDsigSHA1Url; private static readonly String _originRelationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/origin"; private static readonly String _originToSignatureRelationshipType = "http://schemas.openxmlformats.org/package/2006/relationships/digital-signature/signature"; private static readonly String _defaultSignaturePartNamePrefix = "/package/services/digital-signature/xml-signature/"; private static readonly String _defaultSignaturePartNameExtension = ".psdsxs"; #endregion Private Members } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- XmlRawWriter.cs
- DbDeleteCommandTree.cs
- SigningCredentials.cs
- RectAnimationBase.cs
- StdValidatorsAndConverters.cs
- manifestimages.cs
- TextCompositionManager.cs
- PointHitTestParameters.cs
- ConfigUtil.cs
- LogicalExpr.cs
- DateTimeEditor.cs
- MenuEventArgs.cs
- DefaultCommandExtensionCallback.cs
- DataGridViewComboBoxColumn.cs
- ObjectIDGenerator.cs
- HostedTransportConfigurationBase.cs
- DataBinding.cs
- SystemException.cs
- HttpHandlerActionCollection.cs
- TextBlock.cs
- MetadataPropertyvalue.cs
- BindStream.cs
- ComponentDispatcher.cs
- MimeBasePart.cs
- DeriveBytes.cs
- X509Certificate2.cs
- ArithmeticException.cs
- CategoryValueConverter.cs
- BamlLocalizableResourceKey.cs
- HtmlTableCell.cs
- ItemsPanelTemplate.cs
- ToolBarButton.cs
- GeneralTransform2DTo3DTo2D.cs
- DataGridViewRowsAddedEventArgs.cs
- ListItemConverter.cs
- PeerDefaultCustomResolverClient.cs
- XmlNodeChangedEventArgs.cs
- MissingMemberException.cs
- InstanceLockException.cs
- IndicFontClient.cs
- ToolStripItemEventArgs.cs
- OlePropertyStructs.cs
- Pair.cs
- ExtendedProtectionPolicyTypeConverter.cs
- ClonableStack.cs
- EditorZone.cs
- TableProviderWrapper.cs
- ProviderBase.cs
- OutputCacheSettingsSection.cs
- UserControl.cs
- SiteOfOriginContainer.cs
- DataGridViewComboBoxEditingControl.cs
- DtdParser.cs
- JavascriptCallbackMessageInspector.cs
- Exceptions.cs
- Marshal.cs
- BaseProcessor.cs
- PipelineComponent.cs
- Sequence.cs
- ToolStripItemClickedEventArgs.cs
- FlowDocument.cs
- XmlCollation.cs
- FrameworkElement.cs
- DetailsViewRow.cs
- SystemWebExtensionsSectionGroup.cs
- VisualTreeHelper.cs
- DrawingCollection.cs
- XmlSignificantWhitespace.cs
- EditorZone.cs
- DateTimeAutomationPeer.cs
- precedingsibling.cs
- ServicePointManagerElement.cs
- SerializerProvider.cs
- StatusBarItemAutomationPeer.cs
- EffectiveValueEntry.cs
- QuaternionAnimation.cs
- LongTypeConverter.cs
- DataObjectPastingEventArgs.cs
- TextLineResult.cs
- DataTableReaderListener.cs
- OleDbConnection.cs
- WebEvents.cs
- TaiwanLunisolarCalendar.cs
- Rectangle.cs
- EntityClientCacheEntry.cs
- MulticastNotSupportedException.cs
- TreeNodeStyle.cs
- CngAlgorithmGroup.cs
- LocationSectionRecord.cs
- ReturnEventArgs.cs
- DiagnosticEventProvider.cs
- KeySplineConverter.cs
- MasterPage.cs
- CodeConstructor.cs
- PageParser.cs
- SessionPageStatePersister.cs
- InvalidWMPVersionException.cs
- OptimisticConcurrencyException.cs
- StringSorter.cs
- processwaithandle.cs