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