/// <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); }
/// <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); } }