/// <summary> /// Gets a list of digest values from a signature element. /// </summary> /// <param name="signatureElem">Signature element.</param> /// <returns>Map that contains reference Uri to digest values.</returns> public IDictionary <string, byte[]> GetDigestValues(XmlElement signatureElem) { ArgumentUtils.CheckNotNull(signatureElem, "signatureElem"); if (!XmlUtils.CheckElement(signatureElem, SignatureElement, SignedXml.XmlDsigNamespaceUrl)) { throw new XspException("Element is not a 'ds:Signature' element"); } // Load the signature SignedXml signedXml = new SignedXml(signatureElem.OwnerDocument); signedXml.LoadXml(signatureElem); IDictionary <string, byte[]> digestValues = new Dictionary <string, byte[]>(); // Iterate through each reference and add it to the map foreach (Reference signatureRef in signedXml.SignedInfo.References) { // Check the URI value is set if (signatureRef.Uri == null || signatureRef.Uri.Length == 0) { throw new XspException("Signature reference does not contain a URI"); } // Check the digest value exists if (signatureRef.DigestValue == null) { throw new XspException("Signature reference does not contain a digest value"); } digestValues.Add(signatureRef.Uri, signatureRef.DigestValue); } return(digestValues); }
/// <summary> /// Signs Xml data with a certificate and creates a signed payload container. /// </summary> /// <param name="payloadDoc">Document to sign.</param> /// <param name="certificate">Certificate used to sign with.</param> /// <returns>Signed container.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument Create(XmlDocument payloadDoc, X509Certificate2 certificate) { ArgumentUtils.CheckNotNull(payloadDoc, "payloadDoc"); ArgumentUtils.CheckNotNull(certificate, "certificate"); return(Create(payloadDoc, new X509Certificate2Collection(certificate))); }
/// <summary> /// Checks a list of signatures. /// </summary> /// <param name="signatureElems">Signature elements.</param> /// <param name="certificateVerifier">Certificate verifier.</param> public void Check(IList <XmlElement> signatureElems, ICertificateVerifier certificateVerifier) { ArgumentUtils.CheckNotNullNorEmpty(signatureElems, "signatureElems"); ArgumentUtils.CheckNotNull(certificateVerifier, "certificateVerifier"); // Check each signature foreach (XmlElement signatureElem in signatureElems) { if (!XmlUtils.CheckElement(signatureElem, SignatureElement, SignedXml.XmlDsigNamespaceUrl)) { throw new XspException("Element is not a 'ds:Signature' element"); } // Get the certificate from the 'KeyInfo' of the signature X509Certificate2 certificate = GetCertificate(signatureElem); // Verify the signature if (!XmlSecurityUtils.Verify(signatureElem, certificate)) { throw new XspException("Could not validate the signature"); } // Verify the certificate certificateVerifier.Verify(certificate); } }
/// <summary> /// Decrypts an encrypted container document returning the payload. /// </summary> /// <param name="encryptedPayloadDoc">Encrypted container to decrypt.</param> /// <param name="certificate">Certificate to decrypt with.</param> /// <returns>Decrypted payload.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument GetData(XmlDocument encryptedPayloadDoc, X509Certificate2 certificate) { ArgumentUtils.CheckNotNull(encryptedPayloadDoc, "encryptedPayloadDoc"); ArgumentUtils.CheckNotNull(certificate, "certificate"); return(GetData(encryptedPayloadDoc.DocumentElement, certificate)); }
/// <summary> /// Constructor that sets the Xml namespace and the signed /// profile service implementation. /// </summary> /// <param name="signedPayloadXmlNs">Xml namespace of the /// signed payload. /// </param> /// <param name="signedProfileService">Implementation of the signed /// profile service.</param> public SignedContainerProfileService(string signedPayloadXmlNs, IXmlSignatureProfileService signedProfileService) { ArgumentUtils.CheckNotNull(signedPayloadXmlNs, "signedPayloadXmlNs"); ArgumentUtils.CheckNotNull(signedProfileService, "signedProfileService"); this.signedPayloadXmlNs = signedPayloadXmlNs; this.signedProfileService = signedProfileService; }
/// <summary> /// Encrypts Xml data using multiple certificates and creates an encrypted /// payload container. /// </summary> /// <param name="payloadDoc">Payload to encrypt.</param> /// <param name="certificates">Certificates to encrypt with.</param> /// <returns>Encrypted container Xml document.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument Create(XmlDocument payloadDoc, X509Certificate2Collection certificates) { ArgumentUtils.CheckNotNull(payloadDoc, "payloadDoc"); ArgumentUtils.CheckNotNull(certificates, "certificates"); CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates"); return(Create(payloadDoc, certificates, null)); }
/// <summary> /// Checks a signature. /// </summary> /// <param name="signatureElem">Signature element.</param> /// <param name="certificateVerifier">Certificate verifier.</param> public void Check(XmlElement signatureElem, ICertificateVerifier certificateVerifier) { ArgumentUtils.CheckNotNull(signatureElem, "signatureElem"); ArgumentUtils.CheckNotNull(certificateVerifier, "certificateVerifier"); IList <XmlElement> signatureElems = new List <XmlElement>(); signatureElems.Add(signatureElem); Check(signatureElems, certificateVerifier); }
/// <summary> /// Decrypts an element using the cipher key. /// </summary> /// <param name="encryptedDataElem">Element to decrypt.</param> /// <param name="cipherKey">Cipher key.</param> public void Decrypt(XmlElement encryptedDataElem, byte[] cipherKey) { ArgumentUtils.CheckNotNull(encryptedDataElem, "encryptedDataElem"); ArgumentUtils.CheckNotNull(cipherKey, "cipherKey"); IList <XmlElement> dataElems = new List <XmlElement>(); dataElems.Add(encryptedDataElem); Decrypt(dataElems, cipherKey); }
/// <summary> /// Constructor that sets the Xml namespace and the encrypted /// profile service implementation. /// </summary> /// <param name="encryptedPayloadXmlNs">Xml namespace of the /// encrypted payload. /// </param> /// <param name="encryptedProfileService">Implementation of the encrypted /// profile service.</param> public EncryptedContainerProfileService(string encryptedPayloadXmlNs, IXmlEncryptionProfileService encryptedProfileService) { ArgumentUtils.CheckNotNull(encryptedPayloadXmlNs, "encryptedPayloadXmlNs"); ArgumentUtils.CheckNotNull(encryptedProfileService, "encryptedProfileService"); this.encryptedPayloadXmlNs = encryptedPayloadXmlNs; this.encryptedProfileService = encryptedProfileService; }
/// <summary> /// Signs an element. /// </summary> /// <param name="elementToAddToSigTo"></param> /// <param name="elementToSign"></param> /// <param name="certificates"></param> public void Sign(XmlElement elementToAddToSigTo, XmlElement elementToSign, X509Certificate2Collection certificates) { ArgumentUtils.CheckNotNull(elementToAddToSigTo, "elementToAddToSigTo"); ArgumentUtils.CheckNotNull(elementToSign, "elementToSign"); CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates"); IList <XmlElement> elementsToSign = new List <XmlElement>(); elementsToSign.Add(elementToSign); Sign(elementToAddToSigTo, elementsToSign, certificates); }
/// <summary> /// Decrypts an element. /// </summary> /// <param name="encryptedKeyElems"></param> /// <param name="encryptedDataElem"></param> /// <param name="certificate"></param> public void Decrypt(IList <XmlElement> encryptedKeyElems, XmlElement encryptedDataElem, X509Certificate2 certificate) { ArgumentUtils.CheckNotNullNorEmpty(encryptedKeyElems, "encryptedKeyElems"); ArgumentUtils.CheckNotNull(encryptedDataElem, "encryptedDataElem"); ArgumentUtils.CheckNotNull(certificate, "certificate"); IList <XmlElement> encryptedDataElems = new List <XmlElement>(); encryptedDataElems.Add(encryptedDataElem); Decrypt(encryptedKeyElems, encryptedDataElems, certificate); }
/// <summary> /// Gets a list of digest values. /// </summary> /// <param name="containerDoc">Signed container.</param> /// <returns>List of digest values.</returns> public IList <byte[]> GetDigestValues(XmlDocument containerDoc) { ArgumentUtils.CheckNotNull(containerDoc, "containerDoc"); // Check the document is a signed container if (!XmlUtils.CheckElement(containerDoc.DocumentElement, SignedPayloadElement, this.signedPayloadXmlNs)) { throw new ArgumentException("Document is not a signed container"); } // Create the namespace manager for executing XPath statements XmlNamespaceManager namespaceManager = CreateXmlNamespaceManager( containerDoc); // Get the list of signature elements IList <XmlElement> signatureElems = XPathUtils.GetElements(containerDoc, "/sp:signedPayload/sp:signatures/ds:Signature", namespaceManager); if (signatureElems.Count == 0) { throw new XspException("No 'ds:Signature' elements were found within the " + "'sp:signatures' element"); } // Iterate through each signature to get the digest IList <byte[]> digestList = new List <byte[]>(); foreach (XmlElement signatureElem in signatureElems) { // Extract the digest from the signature IDictionary <string, byte[]> digestValues = this.signedProfileService.GetDigestValues(signatureElem); if (digestValues.Keys.Count == 0) { throw new XspException("Signature contains no refences"); } if (digestValues.Keys.Count > 1) { throw new XspException("Signature contains more than one reference"); } // Get the first value from the values list as there is only one IEnumerator <byte[]> digestEnumerator = digestValues.Values.GetEnumerator(); digestEnumerator.MoveNext(); digestList.Add(digestEnumerator.Current); } return(digestList); }
/// <summary> /// Signs a list of elements. /// </summary> /// <param name="elementToAddToSigTo"></param> /// <param name="elementsToSign"></param> /// <param name="certificate"></param> public void Sign(XmlElement elementToAddToSigTo, IList <XmlElement> elementsToSign, X509Certificate2 certificate) { ArgumentUtils.CheckNotNull(elementToAddToSigTo, "elementToAddToSigTo"); ArgumentUtils.CheckNotNullNorEmpty(elementsToSign, "elementsToSign"); ArgumentUtils.CheckNotNull(certificate, "certificate"); X509Certificate2Collection certificates = new X509Certificate2Collection( certificate); Sign(elementToAddToSigTo, elementsToSign, certificates); }
/// <summary> /// Encrypts an element. /// </summary> /// <param name="elementToAddEncKeysTo"></param> /// <param name="elementToEncrypt"></param> /// <param name="certificates"></param> public void Encrypt(XmlElement elementToAddEncKeysTo, XmlElement elementToEncrypt, X509Certificate2Collection certificates) { ArgumentUtils.CheckNotNull(elementToAddEncKeysTo, "elementToAddEncKeysTo"); ArgumentUtils.CheckNotNull(elementToEncrypt, "elementToEncrypt"); CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates"); IList <XmlElement> elementsToEncrypt = new List <XmlElement>(); elementsToEncrypt.Add(elementToEncrypt); Encrypt(elementToAddEncKeysTo, elementsToEncrypt, certificates); }
/// <summary> /// Gets the signing certificate. /// </summary> /// <param name="signatureElem">Signature element.</param> /// <returns>Certificate used to create the signature.</returns> public X509Certificate2 GetSigningCertificate(XmlElement signatureElem) { ArgumentUtils.CheckNotNull(signatureElem, "signatureElem"); if (!XmlUtils.CheckElement(signatureElem, SignatureElement, SignedXml.XmlDsigNamespaceUrl)) { throw new XspException("Element is not a 'ds:Signature' element"); } // Get the certificate from the signature return(GetCertificate(signatureElem)); }
/// <summary> /// Encrypts a list of elements. /// </summary> /// <param name="elementToAddEncKeysTo"></param> /// <param name="elementsToEncrypt"></param> /// <param name="certificate"></param> public void Encrypt(XmlElement elementToAddEncKeysTo, IList <XmlElement> elementsToEncrypt, X509Certificate2 certificate) { ArgumentUtils.CheckNotNull(elementToAddEncKeysTo, "elementToAddEncKeysTo"); ArgumentUtils.CheckNotNullNorEmpty(elementsToEncrypt, "elementsToEncrypt"); ArgumentUtils.CheckNotNull(certificate, "certificate"); X509Certificate2Collection certificates = new X509Certificate2Collection(); certificates.Add(certificate); Encrypt(elementToAddEncKeysTo, elementsToEncrypt, certificates); }
/// <summary> /// Decrypts an encrypted container Xml element, returning the payload. /// </summary> /// <param name="encryptedPayloadElem">Encrypted container to decrypt.</param> /// <param name="certificate">Certificate to decrypt with.</param> /// <returns>Decrypted payload.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument GetData(XmlElement encryptedPayloadElem, X509Certificate2 certificate) { ArgumentUtils.CheckNotNull(encryptedPayloadElem, "encryptedPayloadElem"); ArgumentUtils.CheckNotNull(certificate, "certificate"); // Check the root element belongs to the right namespace if (!XmlUtils.CheckElement(encryptedPayloadElem, EncryptedPayloadElement, this.encryptedPayloadXmlNs)) { throw new ArgumentException("Document is not an encrypted container"); } // Clone the source element so it is not modified XmlElement clonePayloadElem = XmlUtils.Clone(encryptedPayloadElem); // Create a namespace manager for XPath XmlNamespaceManager namespaceManager = CreateXmlNamespaceManager( clonePayloadElem.OwnerDocument); // Get the 'xenc:EncryptedData' element XmlElement encryptedDataElem = XPathUtils.GetElement(clonePayloadElem, "/ep:encryptedPayload/ep:encryptedPayloadData/xenc:EncryptedData", namespaceManager); if (encryptedDataElem == null) { throw new XspException("Encrypted data was not found within the container"); } // Get the 'xenc:EncryptedKey' element list IList <XmlElement> keyElems = XPathUtils.GetElements(clonePayloadElem, "/ep:encryptedPayload/ep:keys/xenc:EncryptedKey", namespaceManager); if (keyElems.Count == 0) { throw new XspException("No encrypted keys found within the container"); } // Decrypt the data this.encryptedProfileService.Decrypt(keyElems, encryptedDataElem, certificate); // Get the payload element XmlElement payloadElem = XPathUtils.GetElement(clonePayloadElem, "/ep:encryptedPayload/ep:encryptedPayloadData/*[1]", namespaceManager); // Return the payload element within a new Xml document return(XmlUtils.CreateXmlDocument(payloadElem)); }
/// <summary> /// Encrypts Xml data using multiple certificates and creates an encrypted /// payload container. /// </summary> /// <param name="payloadDoc">Payload to encrypt.</param> /// <param name="certificates">Certificates to encrypt with.</param> /// <param name="cipherKey">The cipher to use when encrypting the payload.</param> /// <returns>Encrypted container Xml document.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument Create(XmlDocument payloadDoc, X509Certificate2Collection certificates, byte[] cipherKey) { ArgumentUtils.CheckNotNull(payloadDoc, "payloadDoc"); ArgumentUtils.CheckNotNull(certificates, "certificates"); CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates"); // Create an empty Xml document to hold the elements XmlDocument containerDoc = XmlUtils.CreateXmlDocument(); // Create the 'ep:encryptedPayload' element XmlElement rootElem = containerDoc.CreateElement(EncryptedPayloadElement, this.encryptedPayloadXmlNs); containerDoc.AppendChild(rootElem); // Create the 'ep:keys' element XmlElement keysElem = containerDoc.CreateElement(KeysElement, this.encryptedPayloadXmlNs); // Add the 'ep:keys' element to the 'ep:encryptedPayload' element rootElem.AppendChild(keysElem); // Create the 'ep:encryptedPayloadData' element XmlElement dataElem = containerDoc.CreateElement(EncryptedPayloadDataElement, this.encryptedPayloadXmlNs); // Add the 'ep:encryptedPayloadData' element to the 'ep:encryptedPayload' // element rootElem.AppendChild(dataElem); // Add the payload to the data element XmlNode payloadNode = containerDoc.ImportNode(payloadDoc.DocumentElement, true); dataElem.AppendChild(payloadNode); // Perform the encryption List <XmlElement> elementsToEncrypt = new List <XmlElement>(); elementsToEncrypt.Add((XmlElement)payloadNode); this.encryptedProfileService.Encrypt(keysElem, elementsToEncrypt, certificates, cipherKey); // Return the created container return(containerDoc); }
/// <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> /// Checks the signatures in a signed payload container and also verifies the /// certificates with the certificate verifier callback. /// </summary> /// <param name="containerDoc">Signed payload container.</param> /// <param name="certificateVerifier">Certificate verifier.</param> /// <exception cref="XspException">Thrown on error.</exception> public void Check(XmlDocument containerDoc, ICertificateVerifier certificateVerifier) { ArgumentUtils.CheckNotNull(containerDoc, "containerDoc"); ArgumentUtils.CheckNotNull(certificateVerifier, "certificateVerifier"); // Check the container is valid CheckSignedContainer(containerDoc); // Get all the signatures in the container IList <XmlElement> signatureElems = XPathUtils.GetElements(containerDoc, "/sp:signedPayload/sp:signatures/ds:Signature", CreateXmlNamespaceManager(containerDoc)); // Check all the signatures verify this.signedProfileService.Check(signatureElems, certificateVerifier); }
/// <summary> /// Decrypts an encrypted container document returning the payload. /// </summary> /// <param name="encryptedPayloadDoc">Encrypted container to decrypt.</param> /// <param name="cipherKey">The cipher key to use to decrypt the document.</param> /// <returns>Decrypted payload.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument GetData(XmlDocument encryptedPayloadDoc, byte[] cipherKey) { ArgumentUtils.CheckNotNull(encryptedPayloadDoc, "encryptedPayloadDoc"); ArgumentUtils.CheckNotNull(cipherKey, "cipherKey"); XmlElement docElement = encryptedPayloadDoc.DocumentElement; // Check the root element belongs to the right namespace if (!XmlUtils.CheckElement(docElement, EncryptedPayloadElement, this.encryptedPayloadXmlNs)) { throw new ArgumentException("Document is not an encrypted container"); } // Clone the source element so it is not modified XmlElement clonePayloadElem = XmlUtils.Clone(docElement); // Create a namespace manager for XPath XmlNamespaceManager namespaceManager = CreateXmlNamespaceManager( clonePayloadElem.OwnerDocument); // Get the 'xenc:EncryptedData' element XmlElement encryptedDataElem = XPathUtils.GetElement(clonePayloadElem, "/ep:encryptedPayload/ep:encryptedPayloadData/xenc:EncryptedData", namespaceManager); if (encryptedDataElem == null) { throw new XspException("Encrypted data was not found within the container"); } // Decrypt the element with the cipher key this.encryptedProfileService.Decrypt(encryptedDataElem, cipherKey); // Get the payload element XmlElement payloadElem = XPathUtils.GetElement(clonePayloadElem, "/ep:encryptedPayload/ep:encryptedPayloadData/*[1]", namespaceManager); // Return the payload element within a new Xml document return(XmlUtils.CreateXmlDocument(payloadElem)); }
/// <summary> /// Extracts the payload from the signed payload container. /// </summary> /// <param name="containerDoc">Signed payload container.</param> /// <returns>Payload.</returns> /// <exception cref="XspException">Thrown on error.</exception> public XmlDocument GetData(XmlDocument containerDoc) { ArgumentUtils.CheckNotNull(containerDoc, "containerDoc"); // Check the document is a signed container if (!XmlUtils.CheckElement(containerDoc.DocumentElement, SignedPayloadElement, this.signedPayloadXmlNs)) { throw new ArgumentException("Document is not a signed container"); } // Create an Xml namespace manager for XPathing XmlNamespaceManager namespaceManager = CreateXmlNamespaceManager( containerDoc); // Get the data from the container XmlElement payloadDataElem = XPathUtils.GetElement(containerDoc, "/sp:signedPayload/sp:signedPayloadData/*[1]", namespaceManager); return(XmlUtils.CreateXmlDocument(payloadDataElem)); }
/// <summary> /// Returns a list of certificates from the signed container. /// </summary> /// <param name="containerDoc">Signed container.</param> /// <returns>List of certificates.</returns> public IList <X509Certificate2> GetSigningCertificates(XmlDocument containerDoc) { ArgumentUtils.CheckNotNull(containerDoc, "containerDoc"); // Check the document is a signed container if (!XmlUtils.CheckElement(containerDoc.DocumentElement, SignedPayloadElement, this.signedPayloadXmlNs)) { throw new ArgumentException("Document is not a signed container"); } // Create the namespace manager for executing XPath statements XmlNamespaceManager namespaceManager = CreateXmlNamespaceManager( containerDoc); // Get the list of signature elements IList <XmlElement> signatureElems = XPathUtils.GetElements(containerDoc, "/sp:signedPayload/sp:signatures/ds:Signature", namespaceManager); if (signatureElems.Count == 0) { throw new XspException("No 'ds:Signature' elements were found " + "within the 'sp:signatures' element"); } IList <X509Certificate2> certs = new List <X509Certificate2>(); foreach (XmlElement signatureElem in signatureElems) { // Add each certificate X509Certificate2 cert = this.signedProfileService.GetSigningCertificate(signatureElem); certs.Add(cert); } return(certs); }
/// <summary> /// Decrypts a list of elements using the cipher key. /// </summary> /// <param name="encryptedDataElems">Elements to decrypt.</param> /// <param name="cipherKey">Cipher key.</param> public void Decrypt(IList <XmlElement> encryptedDataElems, byte[] cipherKey) { ArgumentUtils.CheckNotNullNorEmpty(encryptedDataElems, "encryptedDataElems"); ArgumentUtils.CheckNotNull(cipherKey, "cipherKey"); // Decrypt the encrypted key RijndaelManaged sessionKey = new RijndaelManaged(); sessionKey.Key = cipherKey; // Decrypt each of the encrypted data elements using the decrypted key foreach (XmlElement encryptedDataElem in encryptedDataElems) { // Decrypt the data byte[] decryptedData = XmlSecurityUtils.Decrypt(encryptedDataElem, sessionKey); XmlDocument containerDoc = encryptedDataElem.OwnerDocument; // Replace the encrypted data with the decrypted data within the container EncryptedXml encryptedXml = new EncryptedXml(containerDoc); encryptedXml.ReplaceData(encryptedDataElem, decryptedData); } }
/// <summary> /// Encrypts a list of elements. /// </summary> /// <param name="elementToAddEncKeysTo"></param> /// <param name="elementsToEncrypt"></param> /// <param name="certificates"></param> /// <param name="cipherKey"></param> public void Encrypt(XmlElement elementToAddEncKeysTo, IList <XmlElement> elementsToEncrypt, X509Certificate2Collection certificates, byte[] cipherKey) { ArgumentUtils.CheckNotNull(elementToAddEncKeysTo, "elementToAddEncKeysTo"); ArgumentUtils.CheckNotNullNorEmpty(elementsToEncrypt, "elementsToEncrypt"); CertificateUtils.CheckNotNullOrEmpty(certificates, "certificates"); // Check all the elements to encrypt are not the same as the element // to add the keys to and check they belong to the same document. foreach (XmlElement elementToEncrypt in elementsToEncrypt) { if (elementToEncrypt == elementToAddEncKeysTo) { throw new XspException( "Cannot add keys to an element that is being encrypted"); } if (elementToAddEncKeysTo.OwnerDocument != elementToEncrypt.OwnerDocument) { throw new XspException( "Elements to encrypt must belong to the same document as the " + "keys element"); } if (XmlUtils.IsDescendant(elementToEncrypt, elementToAddEncKeysTo)) { throw new XspException( "Element the keys are added to cannot be a child element of an " + "element to encrypt"); } } // Get the container document XmlDocument containerDoc = elementToAddEncKeysTo.OwnerDocument; // Create a random session key RijndaelManaged sessionKey = new RijndaelManaged(); sessionKey.KeySize = 256; if (cipherKey != null) { sessionKey.Key = cipherKey; } IList <string> referenceIdList = new List <string>(); foreach (XmlElement elementToEncrypt in elementsToEncrypt) { // Generate a unique reference identifier string referenceId = "_" + Guid.NewGuid().ToString(); // Add it to the reference list referenceIdList.Add(referenceId); // Create the encrypted data EncryptedData encryptedData = XmlSecurityUtils.Encrypt( sessionKey, elementToEncrypt, referenceId); // Replace the original element with the encrypted data EncryptedXml.ReplaceElement(elementToEncrypt, encryptedData, false); } foreach (X509Certificate2 certificate in certificates) { // Create the encrypted key EncryptedKey encryptedKey = XmlSecurityUtils.CreateEncryptedKey( sessionKey, certificate, referenceIdList); // Import the encrypted key element into the container document XmlNode encryptedKeyElem = containerDoc.ImportNode(encryptedKey.GetXml(), true); elementToAddEncKeysTo.AppendChild(encryptedKeyElem); } }
/// <summary> /// Decrypts a list of elements. /// </summary> /// <param name="encryptedKeyElems">List of encrypted key elements.</param> /// <param name="encryptedDataElems">List of encrypted data elements.</param> /// <param name="certificate">Certificate to use for key decryption.</param> public void Decrypt(IList <XmlElement> encryptedKeyElems, IList <XmlElement> encryptedDataElems, X509Certificate2 certificate) { ArgumentUtils.CheckNotNullNorEmpty(encryptedKeyElems, "encryptedKeyElems"); ArgumentUtils.CheckNotNullNorEmpty(encryptedDataElems, "encryptedDataElems"); ArgumentUtils.CheckNotNull(certificate, "certificate"); // Check the certificate has a private key if (certificate.PrivateKey == null) { throw new XspException("Certificate with subject '" + certificate.Subject + "' does not contain a private key"); } XmlDocument containerDoc = encryptedKeyElems[0].OwnerDocument; // Check the 'encryptedKeyElems' elements foreach (XmlElement encryptedKeyElem in encryptedKeyElems) { // Check they are all 'xenc:EncryptedKey' elements if (!XmlUtils.CheckElement(encryptedKeyElem, EncryptedKeyTag, EncryptedXml.XmlEncNamespaceUrl)) { throw new XspException("Element within the keys list is not " + "an 'xenc:EncryptedKey'"); } // Check they all belong to the same document if (encryptedKeyElem.OwnerDocument != containerDoc) { throw new XspException("All 'xenc:EncryptedKey' elements " + "must belong to the same document"); } } // Check the 'encryptedDataElems' elements foreach (XmlElement encryptedDataElem in encryptedDataElems) { // Check they are all 'xenc:EncryptedData' elements if (!XmlUtils.CheckElement(encryptedDataElem, EncryptedDataTag, EncryptedXml.XmlEncNamespaceUrl)) { throw new XspException("Element within the encrypted data list is " + "not an 'xenc:EncryptedData' element."); } // Check they all belong to the same document if (encryptedDataElem.OwnerDocument != containerDoc) { throw new XspException("All 'xenc:EncryptedData' elements " + "must belong to the same document"); } } // Attempt to find the matching encrypted key for the certificate EncryptedKey encryptedKey = null; foreach (XmlElement encryptedKeyElem in encryptedKeyElems) { EncryptedKey currentEncryptedKey = new EncryptedKey(); currentEncryptedKey.LoadXml(encryptedKeyElem); // Check if the subject key identifier specified within the // 'KeyInfo' of the encrypted key matches the certificate if (MatchesCertificate(currentEncryptedKey, certificate)) { encryptedKey = currentEncryptedKey; break; } } // Check if a key was found if (encryptedKey == null) { throw new KeyMismatchException( "Could not find a matching encrypted key for certificate '" + certificate.Subject + "'."); } // Decrypt the encrypted key RijndaelManaged sessionKey = new RijndaelManaged(); sessionKey.Key = XmlSecurityUtils.DecryptEncryptedKey( encryptedKey, certificate.PrivateKey); // Decrypt each of the encrypted data elements using the decrypted key foreach (XmlElement encryptedDataElem in encryptedDataElems) { // Decrypt the data byte[] decryptedData = XmlSecurityUtils.Decrypt( encryptedDataElem, sessionKey); // Replace the encrypted data with the decrypted data within the container EncryptedXml encryptedXml = new EncryptedXml(containerDoc); encryptedXml.ReplaceData(encryptedDataElem, decryptedData); } }
/// <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); } }