private PackageDigitalSignature Sign(
            IEnumerable<Uri>                            parts, 
            IEnumerable<PackageRelationshipSelector>    relationshipSelectors, 
            X509Certificate2                            signer, 
            String                                      signatureId,
            bool                                        embedCertificate,
            IEnumerable<System.Security.Cryptography.Xml.DataObject> signatureObjects,
            IEnumerable<System.Security.Cryptography.Xml.Reference> objectReferences)
        {
            // don't overwrite
            Debug.Assert(SignaturePart.GetStream().Length == 0, "Logic Error: Can't sign when signature already exists");

            // grab hash algorithm as this may change in the future
            _hashAlgorithmName = _manager.HashAlgorithm;

            // keep the signer if indicated
            if (_manager.CertificateOption == CertificateEmbeddingOption.NotEmbedded)
                _lookForEmbeddedCert = false;       // don't bother parsing
            else
                _certificate = signer;              // save some parsing

            // we only release this key if we obtain it
            AsymmetricAlgorithm key = null;
            bool ownKey = false;
            if (signer.HasPrivateKey)
            {
                key = signer.PrivateKey;
            }
            else
            {
                ownKey = true;
                key = GetPrivateKeyForSigning(signer);
            }

            try
            {
                _signedXml = new CustomSignedXml();
                _signedXml.SigningKey = key;
                _signedXml.Signature.Id = signatureId;
                
                // put it in the XML
                if (embedCertificate)
                {
                    _signedXml.KeyInfo = GenerateKeyInfo(key, signer);
                }

                // Package object tag
                // convert from string to class and ensure we dispose
                using (HashAlgorithm hashAlgorithm = GetHashAlgorithm(_hashAlgorithmName))
                {
                    // inform caller if hash algorithm is unknown
                    if (hashAlgorithm == null)
                        throw new InvalidOperationException(SR.Get(SRID.UnsupportedHashAlgorithm));

                    _signedXml.AddObject(GenerateObjectTag(hashAlgorithm, parts, relationshipSelectors, signatureId));
                }

                // add reference from SignedInfo to Package object tag
                Reference objectReference = new Reference(XTable.Get(XTable.ID.OpcLinkAttrValue));
                objectReference.Type = XTable.Get(XTable.ID.W3CSignatureNamespaceRoot) + "Object";
                objectReference.DigestMethod = _hashAlgorithmName;
                _signedXml.AddReference(objectReference);

                // add any custom object tags
                AddCustomObjectTags(signatureObjects, objectReferences);

                // compute the signature
                SignedXml xmlSig = _signedXml;

                (new PermissionSet(PermissionState.Unrestricted)).Assert();
                try
                {
                    xmlSig.ComputeSignature();
                }
                finally
                {
                    PermissionSet.RevertAssert();
                }

                // persist
                UpdatePartFromSignature(_signedXml.Signature);
            }
            finally
            {
                if (key != null && ownKey)
                    ((IDisposable)key).Dispose();
            }

            // create the PackageDigitalSignature object
            _signature = new PackageDigitalSignature(_manager, this);
            return _signature;
        }
        //------------------------------------------------------
        //
        //  Private Properties
        //
        //------------------------------------------------------
        /// <summary>
        /// Helper class
        /// </summary>
        private SignedXml EnsureXmlSignatureParsed()
        {
            // lazy init
            if (_signedXml == null)
            {
                _signedXml = new CustomSignedXml();

                // Load the XML
                XmlDocument xmlDocument = new XmlDocument();
                xmlDocument.PreserveWhitespace = true;
                using (Stream s = SignaturePart.GetStream())
                {
                    using (XmlTextReader xmlReader = new XmlTextReader(s))
                    {
                        //Prohibit DTD from the markup as per the OPC spec
                        xmlReader.ProhibitDtd = true;

                        //This method expects the reader to be in ReadState.Initial.
                        //It will make the first read call.
                        PackagingUtilities.PerformInitailReadAndVerifyEncoding(xmlReader);

                        //If the reader.ReadState is ReadState.Initial, then XmlDocument with perform the
                        //first xmlReader.Read() and start loading from that node/tag. 
                        //If the reader.ReadState is ReadState.Intermediate, then XmlDocument, will start
                        //loading from that location itself.
                        //Note: Since in the above method we perform only the first read and will have not 
                        //moved the reader state further down in the markup, we should be okay, and 
                        //xmlDocument.Load will load from the very begining as intended.
                        xmlDocument.Load(xmlReader);

                        // W3C spec allows for Signature tag to appear as an island and inherently allows
                        // for multiple Signature tags within the same XML document.
                        // OPC restricts this to a single, root-level Signature tag.  However, Signature
                        // tags are allowed to exist within the non-OPC Object tags within an OPC signature.
                        // This is common for XAdES signatures and must be explicitly allowed.
                        XmlNodeList nodeList = xmlDocument.ChildNodes;
                        if (nodeList == null || nodeList.Count == 0 || nodeList.Count > 2)
                            throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
                        
                        XmlNode node = nodeList[0];
                        if (nodeList.Count == 2)
                        {
                            // First node must be the XmlDeclaration <?xml...>
                            if (nodeList[0].NodeType != XmlNodeType.XmlDeclaration)
                                throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));

                            // Second node must be in the w3c namespace, and must be the <Signature> tag
                            node = nodeList[1];
                        }

                        if ((node.NodeType != XmlNodeType.Element) ||
                           (String.CompareOrdinal(node.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0) ||
                           (String.CompareOrdinal(node.LocalName, XTable.Get(XTable.ID.SignatureTagName)) != 0))
                        {
                            throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
                        }

                        // instantiate the SignedXml from the xmlDoc
                        _signedXml.LoadXml((XmlElement)node);
                    }
                }
            }

            // As per the OPC spec, only two Canonicalization methods can be specified            
            if (!IsValidXmlCanonicalizationTransform(_signedXml.SignedInfo.CanonicalizationMethod))
                throw new XmlException(SR.Get(SRID.UnsupportedCanonicalizationMethod));

            // As per OPC spec, signature ID must be NCName
            if (_signedXml.Signature.Id != null)
            {
                try
                {
                    System.Xml.XmlConvert.VerifyNCName(_signedXml.Signature.Id);
                }
                catch (System.Xml.XmlException)
                {
                    throw new XmlException(SR.Get(SRID.PackageSignatureCorruption));
                }
            }

            return _signedXml;
        }