/// <summary>
        /// Signs Xml data with multiple certificates and creates a signed payload container.
        /// </summary>
        /// <param name="payloadDoc">Document to sign.</param>
        /// <param name="certificates">List of certificates used to sign with.</param>
        /// <returns>Signed container.</returns>
        /// <exception cref="XspException">Thrown on error.</exception>
        public XmlDocument Create(XmlDocument payloadDoc,
                                  X509Certificate2Collection certificates)
        {
            ArgumentUtils.CheckNotNull(payloadDoc, "payloadDoc");
            CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates");

            // Create the container
            XmlDocument containerDoc = XmlUtils.CreateXmlDocument();

            // Create the 'sp:signedPayload' root element of the container
            XmlElement rootElem =
                containerDoc.CreateElement(SignedPayloadElement,
                                           this.signedPayloadXmlNs);

            containerDoc.AppendChild(rootElem);

            // Create the 'sp:signatures' element
            XmlElement signaturesElem =
                containerDoc.CreateElement(SignaturesElement,
                                           this.signedPayloadXmlNs);

            // Add the 'sp:signatures' to the 'sp:signedPayload' element
            rootElem.AppendChild(signaturesElem);

            // Create the 'sp:signedPayloadData' element
            XmlElement dataElem =
                containerDoc.CreateElement(SignedPayloadDataElement,
                                           this.signedPayloadXmlNs);

            // Add the data element 'sp:signedPayloadData' to 'sp:signedPayload' element
            rootElem.AppendChild(dataElem);

            // Add the payload data
            XmlNode payloadNode = containerDoc.ImportNode(payloadDoc.DocumentElement, true);

            dataElem.AppendChild(payloadNode);

            // Add an 'id' attribute to the data element for use as a signing reference
            // Make sure reference starts with an alpha char - 'Malformed message' error if starts with number
            string referenceId = "Id_" + Guid.NewGuid().ToString();

            XmlUtils.AddIdAttribute(dataElem, referenceId);

            this.signedProfileService.Sign(signaturesElem, dataElem, certificates);

            return(containerDoc);
        }
Пример #2
0
        /// <summary>
        /// Signs a list of elements.
        /// </summary>
        /// <param name="elementToAddToSigTo"></param>
        /// <param name="elementsToSign"></param>
        /// <param name="certificates"></param>
        public void Sign(XmlElement elementToAddToSigTo,
                         IList <XmlElement> elementsToSign, X509Certificate2Collection certificates)
        {
            ArgumentUtils.CheckNotNull(elementToAddToSigTo, "elementToAddToSigTo");
            ArgumentUtils.CheckNotNullNorEmpty(elementsToSign, "elementsToSign");
            CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates");

            // Get the owner document
            XmlDocument containerDoc = elementToAddToSigTo.OwnerDocument;

            // Check each certificate has a private key
            foreach (X509Certificate2 cert in certificates)
            {
                if (cert.PrivateKey == null)
                {
                    throw new XspException("Certificate with subject '" +
                                           cert.Subject + "' does not contain a private key");
                }
            }

            // Check the 'elementsToSign' elements
            foreach (XmlElement elementToSign in elementsToSign)
            {
                // Check an element to sign is not the same as the element where the
                // signature will be added
                if (elementToSign == elementToAddToSigTo)
                {
                    throw new XspException("Cannot add the signature to an " +
                                           "element being signed");
                }

                // Check if all elements have the same owner document
                if (elementToSign.OwnerDocument != containerDoc)
                {
                    throw new XspException("Element to sign must belong to the same " +
                                           "document to where the signature is being added");
                }

                // Check the element to add the signature to is not a descendant
                // of an element being signed
                if (XmlUtils.IsDescendant(elementToSign, elementToAddToSigTo))
                {
                    throw new XspException("Element to add the signature to cannot be " +
                                           "a descendant of an element being signed");
                }
            }

            // Create the reference list for signing
            IList <string> referenceList = new List <string>();

            foreach (XmlElement elementToSign in elementsToSign)
            {
                // Check if the element has an existing 'id' attribute
                string         referenceId  = null;
                IList <string> elemIdValues = GetIdValues(elementToSign);
                if (elemIdValues.Count == 0)
                {
                    // There is no 'id' element on the attribute so create one and add it
                    // Make sure reference starts with an alpha char - 'Malformed message' error if starts with number
                    referenceId = "Id_" + Guid.NewGuid().ToString();
                    XmlUtils.AddIdAttribute(elementToSign, referenceId);
                }
                else
                {
                    // Set the signature reference 'id' to the existing one
                    referenceId = elemIdValues[0];
                }

                referenceList.Add(referenceId);
            }

            // Sign all the elements
            foreach (X509Certificate2 certificate in certificates)
            {
                // Create the signature for the element
                XmlElement signatureElem = XmlSecurityUtils.Sign(
                    containerDoc, certificate, referenceList);

                // Append each created signature
                elementToAddToSigTo.AppendChild(signatureElem);
            }
        }