예제 #1
0
        /// <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 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);
            }
        }
예제 #3
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);
            }
        }
        /// <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);
            }
        }