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