Example #1
0
        /// <summary>
        /// Tries to verify the signature(s) of the elements in the specified document.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="signature">Required parameter if the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Detached</c>; otherwise the parameter is ignored.</param>
        /// <returns><see langword="true" /> if the signature verification succeeds, otherwise <see langword="false" />.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// document
        /// or
        /// signature
        /// </exception>
        public bool TryVerifySignature(
            XmlDocument document,
            XmlDocument signature = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }
            if (signature == null && SignatureLocation == SignatureLocation.Detached)
            {
                throw new ArgumentNullException(nameof(signature));
            }

            var signedXml = new SignedXmlWithId(document, IdAttributeNames);

            if (SignatureLocation != SignatureLocation.Detached)
            {
                signature = document;
            }

            var signatureElement = signature.GetElementsByTagName(_xmlSignatureLocalName)
                                   .OfType <XmlElement>()
                                   .FirstOrDefault();

            if (signatureElement == null)
            {
                return(false);
            }

            signedXml.LoadXml(signatureElement);

            return(signedXml.CheckSignature(Asymmetric));
        }
Example #2
0
        /// <summary>
        /// Signs the XML <paramref name="document" /> or only the elements specified by the <paramref name="xmlPath" />.
        /// </summary>
        /// <param name="document">The document to be signed.</param>
        /// <param name="xmlPath">The XML path selecting the XML elements to be signed.
        /// Can be <see langword="null" />, empty or consisted of whitespace characters only (see the remarks below).
        /// The parameter is ignored if the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Enveloping</c>.</param>
        /// <param name="namespaceManager">The namespace manager which can resolve the namespace prefixes used in the XPath expression in <paramref name="xmlPath" />.
        /// Can be <see langword="null" /> if <paramref name="xmlPath" /> is <see langword="null" /> or no name-space prefixes are used.
        /// The parameter is ignored if the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Enveloping</c>.</param>
        /// <param name="documentLocation">Specifies the location (URI) of the document if the property <see cref="SignatureLocation" /> is set to
        /// <see cref="SignatureLocation" /><c>.Detached</c> and <paramref name="xmlPath" /> specifies the whole document (e.g. is <see langword="null" />);
        /// otherwise the parameter is ignored. Can be <see langword="null" /> in any case.</param>
        /// <returns>If the property <see cref="SignatureLocation" /> is set to:
        /// <list type="bullet"><item><see cref="SignatureLocation" /><c>.Enveloped</c>: the method returns the modified <paramref name="document" /> with added signature element.
        /// Also if the <paramref name="xmlPath" /> selects one or more descending elements they will be modified too by adding
        /// an extra attribute that would look like this: <c>xml:id="signed0"</c>.
        /// </item><item><see cref="SignatureLocation" /><c>.Enveloping</c>: the method returns an XmlDocument of the signature which includes the root element of the <paramref name="document" />;
        /// </item><item><see cref="SignatureLocation" /><c>.Detached</c>: the method returns an XmlDocument containing the signature with a reference to the document location.
        /// </item></list></returns>
        /// <exception cref="System.ArgumentNullException">document</exception>
        /// <remarks><para>
        /// If the parameter <paramref name="xmlPath" /> is <see langword="null" />, empty or consist of whitespace characters only,
        /// the whole document will be signed as if the parameter was set to <c>"/"</c>.
        /// </para>
        /// <para>
        /// If the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Enveloped</c> (the default) and the parameter
        /// <paramref name="xmlPath" /> specifies the document node (e.g. <see langword="null" />), a signature element will be appended next to the children of the root element.
        /// If <paramref name="xmlPath" /> selects one or more elements of the document, each one will be represented in the inserted signature by a <c>Reference</c> element
        /// (XPath <c>"/Signature/SignedInfo/Reference"</c>) with its corresponding URI (<c>"/Signature/SignedInfo/Reference/@URI"</c>) and
        /// digest (<c>"/Signature/SignedInfo/Reference/DigestValue"</c>). The URI will be in the form "#xxxxx" and will refer to the signed element's
        /// <c>xml:Id</c> attribute. If the element does not have one, the signer will create and add a new <c>Id</c> that will look like this: <c>xml:id="signed0"</c>.
        /// </para>
        /// <para></para>
        /// <para>
        /// If the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Enveloping</c> the parameter <paramref name="xmlPath" /> will be ignored,
        /// the root element of the document will be signed and inserted in the element of the generated XML signature at XPath <c>"/Signature/Object"</c>.
        /// </para>
        /// <para>
        /// If the property <see cref="SignatureLocation" /> is set to <see cref="SignatureLocation" /><c>.Detached</c> and the path specifies the whole document
        /// (e.g. <see langword="null" />) the URI of the reference element of the signature (at XPath <c>"/Signature/SignedInfo/Reference/@URI"</c>)
        /// will contain the value of the parameter <paramref name="documentLocation" /> if specified or "".
        /// If the <paramref name="xmlPath" /> selects node(s) other than the document itself, the <paramref name="documentLocation" /> will be ignored and the reference URI(s) will point
        /// to the signed elements in the form "#xxxxx". If the elements do not have attributes specifying unique identifiers of type <c>xml:Id</c> they will be added in the
        /// respective elements of the <paramref name="document" />.
        /// </para></remarks>
        public XmlDocument Sign(
            XmlDocument document,
            string xmlPath = null,
            XmlNamespaceManager namespaceManager = null,
            Uri documentLocation = null)
        {
            if (document == null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            var signer = new SignedXmlWithId(document, IdAttributeNames)
            {
                SigningKey = Asymmetric
            };

            signer.SignedInfo.CanonicalizationMethod = _canonicalizationMethod;
            signer.SignedInfo.SignatureMethod        = _signatureMethod;

            if (IncludeKeyInfo)
            {
                signer.KeyInfo = new KeyInfo();
                signer.KeyInfo.AddClause(new RSAKeyValue((RSA)Asymmetric));
            }

            foreach (var reference in GetReferences(signer, document, xmlPath, namespaceManager, documentLocation))
            {
                signer.AddReference(reference);
            }

            signer.ComputeSignature();

            var         xmlSignature    = signer.GetXml();
            XmlDocument returnedDoc     = null;
            XmlNode     signatureParent = null;

            switch (SignatureLocation)
            {
            case SignatureLocation.Enveloped:
                returnedDoc     = document;
                signatureParent = returnedDoc.DocumentElement;
                break;

            case SignatureLocation.Enveloping:
            case SignatureLocation.Detached:
                returnedDoc     = new XmlDocument();
                signatureParent = returnedDoc;
                break;
            }

            signatureParent.AppendChild(
                returnedDoc.ImportNode(xmlSignature, true));

            return(returnedDoc);
        }