protected void CreateToken(SoapEnvelope soap, X509Certificate2 certificateSignature, XmlElement nodeKeyInfo)
        {
            SecurityTokenReference tokenRef          = new SecurityTokenReference();
            XmlElement             tokenXmlReference = tokenRef.GetXml(soap);

            var nodeX509Data = CreateNode(tokenXmlReference, Constants.DATA);

            var nodeX509IssuerSerial = CreateNode(nodeX509Data, Constants.ISSUER_SERIAL);

            nodeX509Data.AppendChild(nodeX509IssuerSerial);

            var nodeX509IssuerName = CreateNode(nodeX509IssuerSerial, Constants.ISSUER_NAME);

            nodeX509IssuerName.InnerText = certificateSignature.Issuer;

            var nodeX509SerialNumber = CreateNode(nodeX509IssuerSerial, Constants.SERIAL_NUMBER);

            nodeX509SerialNumber.InnerText = Convert.ToString(Convert.ToInt64(certificateSignature.SerialNumber, 16));

            nodeX509IssuerSerial.AppendChild(nodeX509IssuerName);
            nodeX509IssuerSerial.AppendChild(nodeX509SerialNumber);

            tokenXmlReference.AppendChild(nodeX509Data);

            nodeKeyInfo.AppendChild(tokenXmlReference);
        }
Beispiel #2
0
        /// <summary>
        /// Retrieves a certificate from the Personal Certificate Store in Windows.
        /// </summary>
        /// <param name="sujetoCertificado"></param>
        /// <returns></returns>
        static void Encriptar(ref XmlDocument document, string elementoParaEncriptar, X509Certificate2 certificadopublico, ref XmlElement securityNode)
        {
            RSACryptoServiceProvider rsaAlgorithm = (RSACryptoServiceProvider)certificadopublico.PublicKey.Key; //llave publica usada para encriptar.


            //Ahora creamos un BinarySecurityToken que será el certificado x509 de la clave pública
            //se usa para que el receptor sepa qué certificado se usó para encriptar.
            XmlElement binarySecurityTokenNode = document.CreateElement("wsse", "BinarySecurityToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

            //El atributo EncodingType dice cómo el Token está codificado, en este caso, Base64Binary.
            binarySecurityTokenNode.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
            //El atributo ValueType indica qué es el BinarySecurityToken, en este caso un Certificado X509v3.
            binarySecurityTokenNode.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");

            binarySecurityTokenNode.SetAttribute("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", XmlElementsIds.PublicKeyBinarySecurityTokenUri);
            XmlAttribute attribute = binarySecurityTokenNode.GetAttributeNode("Id");

            attribute.Prefix = "wsu";
            binarySecurityTokenNode.InnerText = Convert.ToBase64String(certificadopublico.GetRawCertData());


            //Creamos una llave simétrica la cuál servirá para codificar la información. //AES-128-CBC
            AesManaged algoritmosimetrico = new AesManaged()
            {
                Padding = PaddingMode.ISO10126,
                KeySize = 128,
                Mode    = CipherMode.CBC,
            };

            System.Security.Cryptography.Xml.EncryptedKey encryptedKey = new System.Security.Cryptography.Xml.EncryptedKey();
            encryptedKey.EncryptionMethod = new System.Security.Cryptography.Xml.EncryptionMethod(EncryptedXml.XmlEncRSAOAEPUrl);
            encryptedKey.AddReference(new DataReference("#ED-31"));
            SecurityTokenReference securityTokenReference = new SecurityTokenReference();

            securityTokenReference.Reference = XmlElementsIds.PublicKeyBinarySecurityTokenUri;
            securityTokenReference.ValueType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
            KeyInfo ekkeyInfo = new KeyInfo();

            ekkeyInfo.AddClause(new KeyInfoNode(securityTokenReference.GetXml()));
            encryptedKey.KeyInfo    = ekkeyInfo;
            encryptedKey.CipherData = new CipherData(EncryptedXml.EncryptKey(algoritmosimetrico.Key, rsaAlgorithm, true));



            securityNode.PrependChild(document.ImportNode(encryptedKey.GetXml(), true));
            securityNode.PrependChild(binarySecurityTokenNode);



            //Crear un XmlElement a través del nombre del Tag que se encuentra en el documento Xml especificado.
            XmlElement elementoParaEncriptarXML = document.GetElementsByTagName(elementoParaEncriptar)[0] as XmlElement;



            //Creamos una instancia de la clase EncryptedXml y usarla para encriptar
            //el XmlElement: elementoParaEncriptarXML; usando la llave simétrica que acabamos de
            //crear.
            EncryptedXml xmlEncriptado = new EncryptedXml();

            //Encriptamos el Body (elementoParaEncriptarXML) usando el algoritmo simétrico AES-128-CBC y lo dejamos ahí.
            byte[] elementoEncriptado = xmlEncriptado.EncryptData(elementoParaEncriptarXML, algoritmosimetrico, false);


            //Ahora creamos una instancia de la clase EncryptedData que representa
            //un elemento <EncryptedData> en el documento XML.
            System.Security.Cryptography.Xml.EncryptedData encryptedData = new System.Security.Cryptography.Xml.EncryptedData()
            {
                Type = EncryptedXml.XmlEncElementContentUrl,
                Id   = "ED-31",

                //Le asignamos otra propiedad a este elemento <EncryptedData> que es un EncryptionMethod
                //para que el receptor sepa que algoritmo usar para descifrar
                EncryptionMethod = new System.Security.Cryptography.Xml.EncryptionMethod(EncryptedXml.XmlEncAES128Url) //Aes-128-cbc o Rjindael.
            };
            encryptedData.CipherData = new CipherData(elementoEncriptado);

            /* Para descencriptar: Funciona, es para testear si puedo desencriptar los datos.
             * var lmao= xmlEncriptado.DecryptData(encryptedData, algoritmosimetrico);
             * var decrypted = Encoding.UTF8.GetString(lmao);
             */

            //Reemplazamos el elemento quotationCarGenericRq sin encriptar del documento XML con el elemento <EncryptedData> (que contiene el Body y sus contenidos encriptados) básicamente.
            //totalmente lleno.
            EncryptedXml.ReplaceElement(elementoParaEncriptarXML, encryptedData, false);
        }
Beispiel #3
0
        /// <summary>
        /// Firmar y Encriptar el Documento XML usando un Certificado x509.
        /// </summary>
        /// <param name="xmldoc">el documento XML a firmar y encriptar.</param>
        /// <param name="certificado">el certificado para poder firmar el XML</param>
        /// <param name="certificadopublico">el certificado publico para poder encriptar</param>
        /// <returns></returns>
        private static XmlDocument FirmaryEncriptarSoapRequest(XmlDocument xmldoc, X509Certificate2 certificadoPrivado, X509Certificate2 certificadopublico)
        {
            #region Firmar
            //añadir las referencias de espacios de nombres para asegurarnos de que podamos trabajar contra
            //cualquier documento elemento XML sin importar el nombramiento de los Tags siempre y cuando sepamos sus Namespaces.
            XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmldoc.NameTable);
            namespaceManager.AddNamespace("wsse", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            namespaceManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            namespaceManager.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");

            //Seleccionar el Header para agregarle elementos.
            XmlElement headerNode = xmldoc.DocumentElement.SelectSingleNode("//soapenv:Header", namespaceManager) as XmlElement;
            //Creamos el nodo de seguridad <Security>
            XmlElement securityNode = xmldoc.CreateElement("wsse", "Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            securityNode.SetAttribute("xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            securityNode.SetAttribute("mustUnderstand", "http://schemas.xmlsoap.org/soap/envelope/", "1");
            XmlAttribute mustUnderstandSecurityAttribute = securityNode.GetAttributeNode("mustUnderstand");
            mustUnderstandSecurityAttribute.Prefix = "soapenv";



            #region Preparar elementos a ser firmados


            //Ahora vamos a crear otro BinarySecurityToken

            //Ahora creamos un BinarySecurityToken que será el certificado x509 de la clave privada
            //Con este BinarySecurityToken se espera que el receptor pueda verificar el Digest de la firma que se
            //genera con este BinarySecurityToken.
            //este BinarySecurityToken es firmado también.

            XmlElement binarySecurityTokenNode2 = xmldoc.CreateElement("wsse", "BinarySecurityToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
            //El atributo EncodingType dice cómo el Token está codificado, en este caso, Base64Binary.
            binarySecurityTokenNode2.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
            //El atributo ValueType indica qué es el BinarySecurityToken, en este caso un Certificado X509v3.
            binarySecurityTokenNode2.SetAttribute("ValueType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3");

            binarySecurityTokenNode2.SetAttribute("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", XmlElementsIds.PrivateKeyBinarySecurityTokenUri);
            XmlAttribute attribute2 = binarySecurityTokenNode2.GetAttributeNode("Id");
            attribute2.Prefix = "wsu";
            binarySecurityTokenNode2.InnerText = Convert.ToBase64String(certificadoPrivado.GetRawCertData());

            //Creamos una estampa de tiempo, la cuál será firmada también:

            Timestamp timestamp = new Timestamp();
            timestamp.TtlInSeconds = 5000;

            //El body también será firmado, pero todavía no tiene los atributos requeridos para que pueda ser firmado
            //Aquí se los agrego.

            //Ahora vamos a ponerle un Id.
            XmlElement body = xmldoc.DocumentElement.SelectSingleNode("//soapenv:Body", namespaceManager) as XmlElement;
            body.SetAttribute("xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
            body.SetAttribute("Id", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", XmlElementsIds.BodyId);
            var bodyId = body.GetAttributeNode("Id");
            bodyId.Prefix = "wsu";

            #endregion

            #region Agregar elementos a ser firmados al nodo Security



            securityNode.AppendChild(timestamp.GetXml(xmldoc));
            securityNode.AppendChild(binarySecurityTokenNode2);
            //agregar
            headerNode.AppendChild(securityNode);
            //el body ya existe, y no pertenece al nodo security.

            #endregion

            //Al momento de computar la firma, la clase SignedXml buscará las referencias previamente puestas, (las busca por los Id de cada uno
            //de los elementos a ser firmados.
            //y firmará los elementos que las referencias han referenciado
            //valga la redundancia.

            #region Crear firma XML


            //Ahora vamos a agregar un elemento Signature, que representa la firma digital.

            SignedXml signedXml = new SignedXmlWithId(xmldoc);

            signedXml.Signature.Id = "SIG-3";
            //la canonicalización indica como se deben interpretar los espacios en blanco y similares
            //porque el valor de firma puede cambiar inclusive cuando hayan espacios u otros caracteres-
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
            //cual fue el algoritmo usado para firmar.
            signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;

            //Cada una de las referencias apunta a un Id, que deberán tener los elementos
            //a ser firmados.


            System.Security.Cryptography.Xml.Reference reference = new System.Security.Cryptography.Xml.Reference
            {
                Uri = "#" + XmlElementsIds.PrivateKeyBinarySecurityTokenUri
            };
            reference.AddTransform(new XmlDsigExcC14NTransform(""));
            reference.DigestMethod = SignedXml.XmlDsigSHA1Url;

            System.Security.Cryptography.Xml.Reference reference2 = new System.Security.Cryptography.Xml.Reference
            {
                Uri = "#" + timestamp.Id
            };
            reference2.AddTransform(new XmlDsigExcC14NTransform("wsse lib soapenv"));
            reference2.DigestMethod = SignedXml.XmlDsigSHA1Url;

            System.Security.Cryptography.Xml.Reference reference3 = new System.Security.Cryptography.Xml.Reference
            {
                Uri = "#" + XmlElementsIds.BodyId
            };
            reference3.AddTransform(new XmlDsigExcC14NTransform("lib"));
            reference3.DigestMethod = SignedXml.XmlDsigSHA1Url;


            signedXml.SignedInfo.AddReference(reference);
            signedXml.SignedInfo.AddReference(reference2);
            signedXml.SignedInfo.AddReference(reference3);
            signedXml.SigningKey = certificadoPrivado.PrivateKey; //la clave privada para firmar.

            //La Keyinfo representa un identificador de un Token de seguridad.
            //en el caso de las firmas, identifica cómo encontrar el token que se usó para firmar.
            KeyInfo keyInfoInsideSignature = new KeyInfo();
            keyInfoInsideSignature.Id = "KI-D313N3M1G0";

            //en este caso Una referencia a un token de seguridad.
            SecurityTokenReference securityTokenReferenceInsideSignature = new SecurityTokenReference();
            securityTokenReferenceInsideSignature.Id        = "STR-SecurityTokenReference";
            securityTokenReferenceInsideSignature.ValueType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
            securityTokenReferenceInsideSignature.Reference = XmlElementsIds.PrivateKeyBinarySecurityTokenUri; //El BinarySecurityToken que contiene el Certificado x509v3 usado para la firma (usando su clave privada)
            KeyInfoClause keyInfoClauseInsideSignature = new KeyInfoNode(securityTokenReferenceInsideSignature.GetXml());
            keyInfoInsideSignature.AddClause(keyInfoClauseInsideSignature);

            signedXml.KeyInfo = keyInfoInsideSignature;


            signedXml.ComputeSignature();

            //revisar que la firma sea válida.(para propósitos de desarrollo)
            bool    firstcheck    = signedXml.CheckSignature(certificadoPrivado, true);
            XmlNode signatureNode = signedXml.GetXml(); //Finalmente ya obtenemos un elemento <signature> totalmente formado y listo para ser anexado al nodo <security>
            #endregion


            securityNode.AppendChild(signatureNode);



            #endregion

            #region Encriptar

            //Ahora vamos a obtener el certificado público, y usar su clave para encriptar el contenido del body

            Encriptar(ref xmldoc, "lib:quotationCarGenericRq", certificadopublico, ref securityNode);

            #endregion

            //Devolver un XML Firmado y Encriptado.
            #region testing, se puede dejar comentado:
            //HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://wsqa.libertycolombia.com.co:8443/soa-infra/services/GenericAuto/GenericAutoQuotation/GenericAutoQuotationMediator_ep");
            //req.Headers.Add("SOAPAction", "urn:quotationCarGeneric");
            //req.Method = "POST";
            //req.UserAgent = "Apache-HttpClient/4.1.1 (java 1.5)";
            //req.ContentType = "text/xml;charset=\"utf-8\"";
            //req.Host = "wsqa.libertycolombia.com.co:8443";

            ////XmlDocument xmldoctest = new XmlDocument();
            ////xmldoctest.Load(@"C:\Users\CarlosAlbertoFiguere\Desktop\test.xml");

            //using (Stream stream = req.GetRequestStream())
            //{
            //    using (StreamWriter streamWriter = new StreamWriter(stream))
            //    {
            //        streamWriter.Write(xmldoc.OuterXml);

            //    }

            //}
            //try
            //{
            //    WebResponse lol = req.GetResponse();
            //    string response = (new StreamReader(lol.GetResponseStream())).ReadToEnd();

            //}
            //catch (WebException wex)
            //{
            //    string response = (new StreamReader(wex.Response.GetResponseStream())).ReadToEnd();
            //}
            #endregion

            return(xmldoc);
        }