SAML 1.1 Malformed Reference in C# - c#

I am trying to build a SAML Assertion in C# for a web service i am trying to connect to. I am using SamlAssertion and X509 Cert as SigningCredentials
This generates a SamlSecurityToken, i then serialize. When i try to validate the signature i get a error message saying the
Malformed reference element.
Code to Serialize
var result = new StringBuilder();
using (var writer = XmlWriter.Create(result))
{
var serializer = new WSSecurityTokenSerializer(SecurityVersion.WSSecurity11, true);
serializer.WriteToken(writer, obj); //Obj is the SamlSecurityToken
}
var xml = result.ToString();
Signature generated:
<Signature
xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></SignatureMethod>
<Reference URI="#_caeceed6-7006-4354-a398-75a8e4c52818">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
<DigestValue>SOME VALUE</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>SOME VALUE</SignatureValue>
</Signature>
This is almost as the example i got from the web service provider. Part of the example:
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="code ds kind rw saml samlp typens #default xsd xsi"></ec:InclusiveNamespaces>
</ds:Transform>
The example and the generated XML looks almost the same, except some prefixes and the InclusiveNamespaces tag.
I have also seen examples where people use SignedXml instead of the WSSecurityTokenSerializer, why is that? more control over the generated XML? Or can i not use the WSSecurityTokenSerializer to create the token?

I created a class based on the example posted by Thuan to return the correct element, i had to overrid the SignedXml class with a custom search for AssertionID to return the correct element to validate.
public class SignedSamlXml : SignedXml
{
public SignedSamlXml()
{
}
public SignedSamlXml(XmlDocument doc)
: base(doc)
{
}
public override XmlElement GetIdElement(XmlDocument document, string idValue)
{
var idElement = base.GetIdElement(document, idValue);
if (idElement == null)
{
var attributes = document.SelectNodes("//#AssertionID");
if (attributes == null) return null;
foreach (XmlAttribute attr in attributes)
{
if (attr.Value == idValue)
{
return attr.OwnerElement;
}
}
}
return idElement;
}
}

Related

SAML Authentication Requested ( Invalid Signature Error)

I am creating signed SAML Request using below code and the certificates are cross checked to be same however getting invalid signature error on IDP , Please suggest
public XmlDocument SignXML(XmlDocument xml)
{
X509Certificate2 cert = new X509Certificate2(#"" + SPCertificateLocation, SPCertificatePassword);// , X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
// set key, signing algorithm, and canonicalization method
var signedXml = new SignedXml(xml.DocumentElement) { SigningKey = cert.GetRSAPrivateKey() };
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
//signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
// sign whole document using "SAML style" transforms
var reference = new Reference { Uri = string.Empty };
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data(cert);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// create signature
signedXml.ComputeSignature();
// get signature XML element and add it as a child of the root element
//signedXml.GetXml();
//XmlElement xmlSignature = signedXml.GetXml();
//AssignNameSpacePrefixToElementTree(xmlSignature, "ds");
// Add prefix "ds:" to signature
XmlElement signature = signedXml.GetXml();
SetPrefix("ds", signature);
// Load modified signature back
signedXml.LoadXml(signature);
// this is workaround for overcoming a bug in the library
signedXml.SignedInfo.References.Clear();
// Recompute the signature
signedXml.ComputeSignature();
string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);
// Replace value of the signature with recomputed one
ReplaceSignature(signature, recomputedSignature);
// Append the signature to the XML document.
xml.DocumentElement.InsertAfter(xml.ImportNode(signature, true), xml.DocumentElement.FirstChild);
//xml.DocumentElement?.AppendChild(signedXml.GetXml());
return xml;
}
The code converts the XML correctly into signature enabled XML however it is showing unable to verify the authenticity of signature
<saml2p:AuthnRequest ID="_3a6d2566-68a1-4afc-a784-c125bd94173f" Version="2.0" ForceAuthn="false" IssueInstant="2022-05-09T08:26:33Z" Destination="https://auth.pingone.com/172e7894-5cbe-456b-b451-d2585aeab74f/saml20/idp/sso" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://localhost:20630/CASCC/SamlConsume" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:20630</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><ds:DigestValue>EZBisrHSVKE2zS15roaUFG0EnP3ZobisulcQXw0fO18=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>uyniiynlIP6z/g6U4qzWKdmeD8sP7majYwqDhy5n2nTDJyE8MEdaIhEJssIDeuc+VAILueMhzRV/mC4uiAZ5kgAYDa0LYnaO3673dCvuFJPgQxKbJUWYSTnfY89x/VYXsFm6kKgR2pxyGgq4VYGK9W/vvpIi+PKkYwCKtjjb8LKin/zoCPAA7UecMS9mxPeJ/ntdEfjIGTwBcoETsFRRNdVToTdVtQJjc4LBa/5FnJbGNRKFIdRDqx+wr7IbaT+08o5yl+UI2Qogly8JxeOPolVUr94rLXKyY1/n2nkXr+5LoY/sRomoCNJ11wLsMUEmg11j4J3bB93FGtlnmpwm4Q==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIEFzCCAv+gAwIBAgIUeUS7jZnkZLcxjRUQ5uhqrAI7z2gwDQYJKoZIhvcNAQELBQAwgZoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEPMA0GA1UEBwwGQm9zdG9uMRQwEgYDVQQKDAtDb21tYW5kQ29tbTEUMBIGA1UECwwLQ29tbWFuZENvbW0xFDASBgNVBAMMC0NvbW1hbmRDb21tMSswKQYJKoZIhvcNAQkBFhxha2Fwb29yQGNvbW1hbmRjb21wYW5pZXMuY29tMB4XDTIyMDQxNTExNDk1MloXDTIzMDQxNTExNDk1MlowgZoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEPMA0GA1UEBwwGQm9zdG9uMRQwEgYDVQQKDAtDb21tYW5kQ29tbTEUMBIGA1UECwwLQ29tbWFuZENvbW0xFDASBgNVBAMMC0NvbW1hbmRDb21tMSswKQYJKoZIhvcNAQkBFhxha2Fwb29yQGNvbW1hbmRjb21wYW5pZXMuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyTHXlPSUCzHLGXkoSkuXTh2/oONTe+5TcswtFTnq6VDZnZ3m1tNs2EWcOXq6lVjSlfaqByCHUSGa0O54qMAD2WdZjTv08GQS1uYtJhjQvi58P32ost2LBEKYhtyaw8fen81OwJq+tiDHCw8xrx/z610rHGQVRrSojmqC6zLOclkQmrfpAhC2L+enovxfl6xW0FzYJETFYv/jW0ACcaZJBtFb7AfYDlCzvajUQ+dGTpZE1/0UOGdOTNjbMezGxFDyndcJ4ZLQItbG0cE3c1fEQkU06OYgPoOeXGsHM2w1R498oS/pk1ZLB1LtDUfKl7PVmjJGoytCi38Huft/95u0JQIDAQABo1MwUTAdBgNVHQ4EFgQUawg+tyAVohufNTVu7RXqPtu+B4MwHwYDVR0jBBgwFoAUawg+tyAVohufNTVu7RXqPtu+B4MwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAPom0ZUQx3OWXlO7R5Goyv7cEepq+Nikd82chqzUvwhXW5Azb3xsC+cgh0srjYlrRC9QJk7m43yQE1xa0DM4aKi/rA/l9rLJpXfjQj+97V0SA8JMrCxbcxdN+v2mN1vp8xprJ2i+nPtCBPqLM2XA0kUQ44zeygCm+L78zElYu79r3YF6ObzA9D3/Fa794zFWqI/1ggmOdI4T3kzUgFxv1YMTYZ8rgWcICVs1mSU2zkT5ScJq0NJPENR0jpzFHzirzIJUgnAcOWnCnzyCKDgpJI/+9yJNzLaR97LHk12cVfQMuBvLcchRian08sZ/J4a440h54bB9EByp+853rUpHhVQ==</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature></saml2p:AuthnRequest>
As #timothy suggested i added the Id = "#" + Id
and below is the XML generated
<saml2p:AuthnRequest ID="_35ab8f46-0ba1-4a29-a153-b02e97bf1397" Version="2.0" ForceAuthn="false" IssueInstant="2022-05-10T09:25:33Z" Destination="https://auth.pingone.com/172e7894-5cbe-456b-b451-d2585aeab74f/saml20/idp/sso" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="http://localhost:20630/CASCC/SamlConsume" xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">http://localhost:20630</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><ds:Reference URI="#_35ab8f46-0ba1-4a29-a153-b02e97bf1397"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><ds:DigestValue>0iGmT3qeJrHVXJveUe5AboRo65hxD25OjVpbbxWvbUo=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>InYJ2yGLSnL9Q2BVaWBfABpcpiViFgZH6XnvhYU0I67sPI/KTb6g39MZMBM4XiUDNTpjGXHcZn9c2elh+NnVAx/SPX8R0Yjq7dKiVe+Zz6BFKk0DCSA9Q2APFCk2uJZVlvKza3tIjoxrBvQuxZcNZxsMOUm8LEWnhQ3ElgN7pisHj5AiAzc/VluPIl21BG+tTolV/Ab7bg+B7YdBwK4++QEyK0R7dsYoZex+NsLf1+zel1xWg2PbZgTXOi4PXFB9RvIPXDUtfMPCSOUQRUdgbI6GeV5X+ZWCGOs0m0FnnZD7hL1WR1sWOcHUgY0DSIpgtToJintjx0f5HphidWZF9/sjP+zR9QEOtkcBMYl9JacO5tbNp49fZSVuuqN2pMxcSCE2BmPdoWw1t/CHrKFOzOfNyNQsvauP2UpufQQt+lxUePpvE7VZNuXYQ+hGv74FkBpy6NU58x3agqOP0NeMsyrT+R0AOSTCXWqzfogYIOR9t/mOFMTohKJqjPXB7H2+LrlOcmQM/+HHUf21F4KP6w2ujbFESOgCZmoyou0gBDEAtT4xbYvwnplZwSbYaKHQQhunyzesfqtdF8bY9+0jVsfj0+e7tzofoURb+d6HMtbJxDnIg4VUzmI2QHEUhNJzT1nAS2cbVieP/kGzmLQ9TKGhYdTUnWVa16oXZz+qkeo=</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIFqDCCA5ACFAQ5F+2NYAb4N/enCOaeA/V2IVPYMA0GCSqGSIb3DQEBCwUAMIGNMQswCQYDVQQGEwJVUzELMAkGA1UECAwCVVMxCzAJBgNVBAcMAk5ZMRQwEgYDVQQKDAtDb21tYW5kQ29tbTEUMBIGA1UECwwLQ29tbWFuZENvbW0xCzAJBgNVBAMMAkNDMSswKQYJKoZIhvcNAQkBFhxha2Fwb29yQGNvbW1hbmRjb21wYW5pZXMuY29tMB4XDTIyMDUwOTEyMDcyNVoXDTIzMDUwOTEyMDcyNVowgZIxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJVUzELMAkGA1UEBwwCTlkxFDASBgNVBAoMC0NvbW1hbmRDb21tMRQwEgYDVQQLDAtDb21tYW5kQ29tbTEQMA4GA1UEAwwHQ29tbWFuZDErMCkGCSqGSIb3DQEJARYcYWthcG9vckBjb21tYW5kY29tcGFuaWVzLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKoMSbgGecTY5d6bNjCEnpX2YxY+QRNDT0v/zGpO23PZlt+fuaYHr+b0hP3R/3cCxVTmd36o6MNASjT/slq8aFTdk49sW/zwICNa5AtjRRBVHGOmNYz/ntbo1KIQzC1faoGg+1CiTBL/vflQN4EWMyKGg/GfyIeKLODmOzzx41U5Y/Bv22X8bMmnFgYtwBMh2c7X0hNysqUmkc81sJ5cDgcwNbU4tu+sLslxI+1iOmmDtZBfcYmn+5vU4lFy8XZIODqN0eWpOyvH+a6r6rhAe9vIPwjWv2oh1Ktw0HE3b4JIgk/Vk4YvHKeSTjeC0biue7EF1c0sexOac5KpRhaWNxY4tmHY0dxKT1I21ls7TFd1x9E9A+n5Ff+INb9O4V0OmTrJUiXHZ44vpOi2kv1zbf2lSVFXwF6fhcb1KqxP2XQUMr7Fs6P5JUuH9h1AB5Kf7pjcrza7jjWU3LFRQzwISnJZNV+g1f62VM1S3AHpn1YFaI49Kpn9k5kuqWgGPUlIJq+9tWIy19lL6D3vzYI4yzZR4sGp8NcdSlKR8FgMgfB3bU4DtP85agoEOQ5C2DKV8No3jLVEJ8qFMhn/kLzcDy9oWF7ZVQGUmYuNo0q5T9O4dXcX0alXx0PS9UKJwfw23sGfUenwLI9HZEAqK5f3UEaDnfFmhxlajIAMj2hPldODAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAL4Fr2RzIH0O4VJRgYQr1ASeSghzijkhSHpjmL3fCEVrS7WvYtgKr3gXC5tQ/8i3Immh2aqMmbmq1gk/885frCMW76e0I1ZRfSw0ktUa04WlftVLeg9lzqPEmNKwaxzSudcR+WdEnLKrm3DHXltXqXw2yuDzy1SWGeyfZ+Lq62geahBkGWn5YoQqsxbmvhFDZNtDvinUI0GsbmTEsv9oxdWGGfl0spg6y0cO5WW/8fTh6Jrpk2RjOWcx7wUChQbv/Wu4WH9S7g78/F5HSy5hQ2PTg/CVtFXt/zScj6pxXb0Uov4/PXE7zHyLPUqtOxgasov4FurDJZaxUVNE5hu9OVLiHmw0jyU0t6myON+B4+a6I2xeWDBe1EQJyK2G22yISN6o4UILD3YL3gnl/xZoe/64sKP59RU0Gxv3pyYTpCtp+DYR8xYWzN8hVG0KHlxSypkh0TwQ7a4H4x5LOXZ5Qinr1qHgjgJY9LCAYHfvX6i+pctsd+na8ZUEPKZH/ARFz1LDx0RS5RbZhsnyn7GkpJZEuUUeS+aOYkuFLlvBopcKnP8KmKXjjRmrhHaNhPhnK8cJgai377uNk87xUt2WnMankROZajIK+7M6xMTq5WgmmDPE16o6zp+mdn5I8RzglelDFtgCAf9Hz2vupH4v8fcg772fzIf277zZpl8RZc36</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature></saml2p:AuthnRequest>
However when i try to validate it using https://tools.chilkat.io/xmlDsigVerify.cshtml
I get valid signature but https://console.pingone.com/ says invalid signature so may be certificates is the one i suggest it is blocking something please suggest
My Latest code looks like
public XmlDocument SignXML(XmlDocument xml)
{
X509Certificate2 cert = new X509Certificate2(#"" + SPCertificateLocation, SPCertificatePassword);// , X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
// set key, signing algorithm, and canonicalization method
var signedXml = new SignedXml(xml.DocumentElement) { SigningKey = cert.GetRSAPrivateKey() };
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
//signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
// sign whole document using "SAML style" transforms
var reference = new Reference { Uri = "#"+_id };
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data(cert);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// create signature
signedXml.ComputeSignature();
// get signature XML element and add it as a child of the root element
//signedXml.GetXml();
//XmlElement xmlSignature = signedXml.GetXml();
//AssignNameSpacePrefixToElementTree(xmlSignature, "ds");
// Add prefix "ds:" to signature
XmlElement signature = signedXml.GetXml();
SetPrefix("ds", signature);
// Load modified signature back
signedXml.LoadXml(signature);
// this is workaround for overcoming a bug in the library
signedXml.SignedInfo.References.Clear();
//var reference2 = new Reference { Uri = "#" + _id };
//reference2.AddTransform(new XmlDsigEnvelopedSignatureTransform());
//reference2.AddTransform(new XmlDsigExcC14NTransform());
//signedXml.AddReference(reference2);
// Recompute the signature
signedXml.ComputeSignature();
string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);
// Replace value of the signature with recomputed one
ReplaceSignature(signature, recomputedSignature);
// Append the signature to the XML document.
xml.DocumentElement.InsertAfter(xml.ImportNode(signature, true), xml.DocumentElement.FirstChild);
//xml.DocumentElement?.AppendChild(signedXml.GetXml());
return xml;
}
I was able to validate your XML with perl's XML::Sig after a few changes that I had to make to XML::Sig since it does not currently support SignedInfo without an ID.
https://tools.chilkat.io/xmlDsigVerify.cshtml also validates it fine so the issue is likely in your validation code that you did not show.

Get digest value of SOAP Envelope XML (Web Services Security:SOAP Message Security 1.1)

I am trying to implement the signing of this SOAP-envelope document in C# with binary security token and X509 certificate to consume a service. This XML must comply with Web Services Security:SOAP Message Security 1.1(WS-Security 2004). I was able to properly do it in SOAPUI as well as in C# using Chilkat. Now I am trying to redo it manually but I cant get the same digest values.
If I understood correctly the procedure is:
A) Canonicalize the whole XML. In this case is canonicalized with xml-exc-c14n.
B) Digest the soapenv:Body element as it is indicated in the reference URI with the ID (#id-5157A8F91DFED0BF1516369837630694) with SHA-256 and obtain the base 64 of the hash.
But still not able to get the same hash (In this case, the correct value is sLXr8sDC07k7ln7y7kZ1SwCw5BU4z7o9jGA77PfjvHs while i get wrong SR0QiRYmF21SR2WG/v10zqa9vsSqNUi6p3jN8BQ/uT0=)
I will include the code I use for manual calculation, the starting XML , the final XML and the code I am using to get the digest value. I would like to know how to get the proper digestValues.
------------------------FINAL XML---------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:loc="http://administracion.gob.es/punto-unico-notificaciones/localiza" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Timestamp wsu:Id="TS-5157A8F91DFED0BF1516369837631526">
<wsu:Created>2022-03-04T13:48:25Z</wsu:Created>
<wsu:Expires>2022-03-04T13:53:25Z</wsu:Expires>
</wsu:Timestamp>
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-5157A8F91DFED0BF1516369837630331">..BinarySecurityTokenValue...</wsse:BinarySecurityToken>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="SIG-5157A8F91DFED0BF1516369837631235">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="wsa loc soapenv"/></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#id-5157A8F91DFED0BF1516369837630694">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="loc"/></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>sLXr8sDC07k7ln7y7kZ1SwCw5BU4z7o9jGA77PfjvHs=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>WH7BHRTk2X5q8oHVroXkhcCUEL/OEM+T/OfNjhWCrZ9UuFH6QSs6kWJ3MPmpbQ5IdAHD2fJJB9d9nH/5fAaQiez/VUVOK9xFOceNeLlz8uuO1AcSNEz5Bq+fB1dswTrxSei+1/df7byD/bYREt0l8In4Y0FfZ84CSEiSblZqkJS5b9W8P/mLlS2qA9CelahD+b3YCFa3qdWEosC467XD1LVNBRMBBUhvk/kPgmzsRO4HBl6u2y9xi+Xpyun70TFJ3WgxKIo+2seTA+o667iKfpRt2HICDOCGLWfVGWwMSAb8svhPSh18YMq2NOUyfxjmlkKx2lPV8UVOeZAaKuXikQ==</ds:SignatureValue>
<ds:KeyInfo Id="KI-5157A8F91DFED0BF1516369837630652"><wsse:SecurityTokenReference wsu:Id="STR-5157A8F91DFED0BF1516369837630663">
<wsse:Reference URI="#X509-5157A8F91DFED0BF1516369837630331" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature></wsse:Security>
<wsa:Action>https://administracionelectronica.gob.es/notifica/ws/lema/Localiza</wsa:Action>
<wsa:MessageID>uuid:4251a8a3-8e14-4218-844e-c9854a3fcff5</wsa:MessageID>
<wsa:To>https://se-dehuws.redsara.es/ws/v2/lema</wsa:To>
</soapenv:Header>
<soapenv:Body wsu:Id="id-5157A8F91DFED0BF1516369837630694" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<loc:Localiza>
<loc:nifTitular>A</loc:nifTitular>
<loc:nifDestintario>A</loc:nifDestintario>
<loc:opcionesLocaliza>
<loc:opcion tipo="dehu.paginador.pagina">1</loc:opcion>
</loc:opcionesLocaliza>
</loc:Localiza>
</soapenv:Body>
</soapenv:Envelope>
--------------------------START XML-------------------------------------------------------------
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:loc="http://administracion.gob.es/punto-unico-notificaciones/localiza">
<soapenv:Header/>
<soapenv:Body>
<loc:Localiza>
<loc:nifTitular>B87222014</loc:nifTitular>
<loc:nifDestintario>B87222014</loc:nifDestintario>
<loc:opcionesLocaliza>
<loc:opcion tipo="dehu.paginador.pagina">1</loc:opcion>
</loc:opcionesLocaliza>
</loc:Localiza>
</soapenv:Body>
</soapenv:Envelope>
---------------------------------C# CODE---------------------------------------------------------
string canon = CanonicalizeDsig(File.ReadAllText(#"PATHTOXMLFILE"));
XmlDocument x = new XmlDocument();
x.LoadXml(canon);
XmlNodeList j = x.GetElementsByTagName("soapenv:Body");
resultado1 = getDigest(j[0].OuterXml);
string getDigest(string mesg)
{
SHA256 sha256Hash = SHA256.Create();
byte[] mesgBytes = Encoding.UTF8.GetBytes(mesg);
byte[] hash = sha256Hash.ComputeHash(mesgBytes);
return Convert.ToBase64String(hash);
}
string CanonicalizeDsig(string input)
{
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = false;
try
{
doc.LoadXml(input);
XmlDsigExcC14NTransform trans = new XmlDsigExcC14NTransform();
trans.LoadInput(doc);
String c14NInput = new StreamReader((Stream)trans.GetOutput(typeof(Stream))).ReadToEnd();
return c14NInput;
}
catch (Exception ex)
{
return String.Empty;
}
}
The signature covers a node with Id="id-5157A8F91DFED0BF1516369837630694", see ds:Reference element:
<ds:Reference URI="#id-5157A8F91DFED0BF1516369837630694">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="loc"/></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>sLXr8sDC07k7ln7y7kZ1SwCw5BU4z7o9jGA77PfjvHs=</ds:DigestValue>
</ds:Reference>
While the provided document does not contain a node with that Id at all.
So either you need to include the Id to the parent element of the SOAP envelope, or (a better way) is to implement an enveloped signature format, by de-referencing the enveloping XML with a URI="" (empty URI) and adding an enveloped-signature transform before the canonicalization. E.g.:
<dsig:Reference URI="">
<dsig:Transforms xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<dsig:DigestValue>*some value*</dsig:DigestValue>
</dsig:Reference>
For more information about the de-reference model and enveloped-signatures please see XMLDSig specification.

Generating Username Token For Soap Request

I am trying to generate SOAP Username token using C# but without success
<wsse:UsernameToken wsu:Id='UsernameToken-1231231231123123'>
<wsse:Username>UserName</wsse:Username>
<wsse:Password Type='http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText'>Password</wsse:Password>
</wsse:UsernameToken>
the above one is the correct format for our SOAP endpoint but when i am trying to generate token using UsernameToken from namespace
Microsoft.Web.Services2.Security.Tokens
UsernameToken t;
t = new UsernameToken("UserName", "Password");
string usernameTokenSection1 = t.GetXml(new XmlDocument()).OuterXml.ToString();
I got this result which
is not working
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-cf96131b-1528-46a1-8f00-f61af616db91" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>Username</wsse:Username>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">+S3AH9NHRtOpgdxEwqIVIg==</wsse:Nonce><wsu:Created>2020-04-04T06:46:53Z</wsu:Created></wsse:UsernameToken>
the wsu:Id='UsernameToken-1231231231123123' attribute is Id property of UsernameToken
So, you do this :
UsernameToken t = new UsernameToken("UserName", "Password", PasswordOption.SendPlainText)
{
Id = "UsernameToken-1231231231123123"
};
Then you can parse it in XmlDocument or XDocument which would give you the ability to adjust the elements to fit your requirements.
you can parse it like this var doc = XDocument.Parse(usernameTokenSection1);
Now, using the parsed XML, you can adjust it to your requirements. For instance you can remove Nonce and Created elements like this :
var doc = XDocument.Parse(usernameTokenSection1);
XNamespace wsu = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
XNamespace wsse = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
doc.Root.Descendants(wsse + "Nonce").Remove();
doc.Root.Descendants(wsu + "Created").Remove();

How to make WCF Client conform to specific WS-Security - sign UsernameToken and SecurityTokenReference

I need to create a wcf client to call a service that I have no control over.
I have been given a wsdl and a working soapui project.
The service uses both a username/password and a x509 certificate.
UPDATE
I now understand what the problem is, but am still unsure what steps I need to take to be able to create the required message, so any help would be much appreciated.
I need to sign both the UsernameToken and the SecurityTokenReference.
The code I had to create the custom binding has been removed from this post as its no longer used. I no longer add a SecurityBindingElement to the binding, instead I add a new behaviour that writes the security element into the header.
So the security node is created from scratch by subclassing the SignedXml class, adding signing references and then calling ComputeSignature to create the Signature node within the Security header.
You need to pass the xml to sign into the SignedXml constructor for this to work. It is no problem passing in the UsernameToken and this appears to be signed correctly.
The problem is that the SecurityTokenReference is only created when ComputeSignature() is called, so I'm not able to add a signing Reference to this element, as it does not exist at the time it is required (within the overridden GetIdElement method of SignedXml which is called prior to ComputeSignature())
The code I'm using to create the signature block to insert into the Security header is as follows
string certificatePath = System.Windows.Forms.Application.StartupPath + "\\" + "Certs\\sign-and- enc.p12";
XmlDocument xd = new XmlDocument();
xd.LoadXml(xml);
// Set Certificate
System.Security.Cryptography.X509Certificates.X509Certificate2 cert = new X509Certificate2(certificatePath, "password");
MySignedXml signedXml = new MySignedXml(xd);
signedXml.SigningKey = cert.PrivateKey;
// Create a new KeyInfo object.
KeyInfo keyInfo = new KeyInfo();
keyInfo.Id = "";
MemoryStream keyInfoStream = new MemoryStream();
XmlWriter keyInfoWriter = XmlWriter.Create(keyInfoStream);
WSSecurityTokenSerializer.DefaultInstance.WriteKeyIdentifierClause(keyInfoWriter, new LocalIdKeyIdentifierClause("token_reference", typeof(X509SecurityToken)));
keyInfoWriter.Flush();
keyInfoStream.Position = 0;
XmlDocument keyInfoDocument = new XmlDocument();
keyInfoDocument.Load(keyInfoStream);
XmlAttribute attrib = keyInfoDocument.CreateAttribute("ValueType");
attrib.InnerText = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3";
keyInfoDocument.ChildNodes[1].ChildNodes[0].Attributes.Append(attrib);
KeyInfoNode keyInfoNode = new KeyInfoNode();
keyInfoNode.LoadXml(keyInfoDocument.DocumentElement);
keyInfo.AddClause(keyInfoNode);
// Add the KeyInfo object to the SignedXml object.
signedXml.KeyInfo = keyInfo;
// Need to use External Canonicalization method.
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "#UsernameToken-1";
XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
env.Algorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
reference.AddTransform(env);
reference.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
signedXml.AddReference(reference);
Reference reference2 = new Reference();
reference2.Uri = "#token_reference";
XmlDsigEnvelopedSignatureTransform env2 = new XmlDsigEnvelopedSignatureTransform();
env2.Algorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
reference2.AddTransform(env2);
reference2.DigestMethod = "http://www.w3.org/2000/09/xmldsig#sha1";
signedXml.AddReference(reference2);
// Add the Signature Id
signedXml.Signature.Id = "MYSIG_ID";
// Compute the signature.
signedXml.ComputeSignature();
XmlElement xmlDigitalSignature = signedXml.GetXml();
where the xml variable is the the UsernameToken xml string, and the MySignedXml class is a subclassed SignedXml with the GetIdElement method overridden (to try to find and correctly refreence the non-existant SecurityTokenReference)
I've spend days researching and testing this now, and unfortunately the company supplying the service isn't any help - but I need to use their service.
Full working soap message (soapUI project)
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:XXXXX">
<soapenv:Header xmlns:ebxml="http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/">
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="CertId-D05E596B5ABC341FEB13505090224061" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">MIIEnDCCBAWgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBxDELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxHjAcBgNVBAMTFWRldmNhLmIyYi5pcmQuZ292dC5uejEXMBUGA1UEKRMORGV2ZWxvcG1lbnQgQ0ExKDAmBgkqhkiG9w0BCQEWGWNocmlzLnNjaHVsdHpAaXJkLmdvdnQubnowHhcNMTEwOTE1MDIwNjIwWhcNMjEwOTEyMDIwNjIwWjCByTELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxJTAjBgNVBAMTHHNpZ24tYW5kLWVuYy5kZXYuaXJkLmdvdnQubnoxFTATBgNVBCkTDHNpZ24tYW5kLWVuYzEoMCYGCSqGSIb3DQEJARYZY2hyaXMuc2NodWx0ekBpcmQuZ292dC5uejCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAykyZHVnXjsG220zB3kNOsGBeGP2rdNbLlIqW1D8yZO1fcj3/RhRiqsopbUrb8AU1ClpfhbH2K68kg7V91VAY0qrwNxP+pPPo1vYKMU6pT38qJGQzffr+iV2BCJshZvSk9E7QSWO5mFNstdg19xc+5ST1Lgb3fefuRG2KZVxPx0sCAwEAAaOCAZUwggGRMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDQGCWCGSAGG+EIBDQQnFiVFYXN5LVJTQSBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0GA1UdDgQWBBSczRKXKPe3Sin7eFrVXfI7MXckzzCB+QYDVR0jBIHxMIHugBSLWxPSZd9otEj16vhLyovMCI9OMaGByqSBxzCBxDELMAkGA1UEBhMCTloxDTALBgNVBAgTBFdHVE4xEzARBgNVBAcTCldlbGxpbmd0b24xGDAWBgNVBAoTD0lSRFN0dWR5bGlua0IyQjEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxHjAcBgNVBAMTFWRldmNhLmIyYi5pcmQuZ292dC5uejEXMBUGA1UEKRMORGV2ZWxvcG1lbnQgQ0ExKDAmBgkqhkiG9w0BCQEWGWNocmlzLnNjaHVsdHpAaXJkLmdvdnQubnqCCQDL/qDdlx2j6DATBgNVHSUEDDAKBggrBgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADgYEAS4ZPIVVpgTOGN4XcIC3SiYlxF8wYg7qnUhH5wJsAD3VCKfj68j9FSJtdBWLlWvvRxEoDP2lZ0IbFl6Rjnl+2ibzFnyac2G1AVm5mwPrNKHBQJ9J5eDJi0iUVY7Wphz86tKnqj34GvlHPNXmrF7oGEcDhPwK0T8zRdE/pvKIUiJc=</wsse:BinarySecurityToken>
<ds:Signature Id="Signature-2" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#CertId-D05E596B5ABC341FEB13505090224061">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>3iVAUEAt8vAb7Ku+jf2gwSkSm0Q=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#UsernameToken-1">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>r4HLEAWJldJwmEmcAqV6Y8rnTPE=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>
YGh2I3VcukqjT0O7hKItiykWN5tlID18ZXRCwQjXriHmnVsO4wGcHjWfmhuNDecq+xRN+SjG8E7M
2Rx/5/BbFKbVlNOkQOSbSxIs1YT9GaThK16pMrX5KRkkJme1W3R0pGIIQh6gGRSUf79RZUIYxyVl
LqdIe561TXXDdtbt/6Q=
</ds:SignatureValue>
<ds:KeyInfo Id="KeyId-D05E596B5ABC341FEB13505090224372">
<wsse:SecurityTokenReference wsu:Id="STRId-D05E596B5ABC341FEB13505090224373" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Reference URI="#CertId-D05E596B5ABC341FEB13505090224061" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/></wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>XXXXXX</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">XXXXXXX</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
<ebxml:Messaging xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ebxml:UserMessage>
<ebxml:MessageInfo>
<ebxml:Timestamp>2002-02-02T14:18:02.0Z</ebxml:Timestamp>
<ebxml:MessageId>bf9433d9-c6e9-4c12-9c98-724008a09c21</ebxml:MessageId>
</ebxml:MessageInfo>
<ebxml:PartyInfo>
<ebxml:From>
<ebxml:PartyId type="identifier">Trading Partner X</ebxml:PartyId>
<ebxml:Role>Provider</ebxml:Role>
</ebxml:From>
<ebxml:To>
<ebxml:PartyId type="identifier">XXXXXXX</ebxml:PartyId>
<ebxml:Role>Requestor</ebxml:Role>
</ebxml:To>
</ebxml:PartyInfo>
<ebxml:CollaborationInfo>
<ebxml:AgreementRef>urn:XXXXXXXXX</ebxml:AgreementRef>
<ebxml:Service type="Web Service">urn:XXXXXXXX</ebxml:Service>
<ebxml:Action>customerInformation</ebxml:Action>
<ebxml:ConversationId>e302426a-b2d9-4ff1-a14b-fbbc2f40a017</ebxml:ConversationId>
</ebxml:CollaborationInfo>
</ebxml:UserMessage>
</ebxml:Messaging>
</soapenv:Header>
<soapenv:Body>
<urn:ConnectionTest>
<Message>Bonjour</Message>
</urn:ConnectionTest>
</soapenv:Body>
</soapenv:Envelope>
We were supplied with some documentation. The security section is copied below
The following security must be applied to each request in the following order:
A wsse:UsernameToken must be included and contain:
The Agent‟s Portal Username for the value of the wsse:Username element
The Agent‟s Portal Password for the value of the wsse:PasswordText (clear text) in the Password element
A Signature block:
Digital Signatures are created using x509 certificates. Each software provider is required to hold and protect a valid certificate and private key issued by [To Be Determined]. With each service request the software must:
Include the Certificate that matches the private key used for signing as a wsse:BinarySecurityToken and use it as the wsse:SecurityTokenReference for the Signature
Sign the wsse:BinarySecurityToken
Sign the wsse:UsernameToken
Use Canonicalization Method Algorithm: http://www.w3.org/2001/10/xml-exc-c14n#
Use Signature Method Algorithm: http://www.w3.org/2000/09/xmldsig#rsa-sha1
Use Digest Method Algorithm: http://www.w3.org/2000/09/xmldsig#sha1
Update
Image of the SoapUI configuration I was initially given
Finally sorted the problem today. In terms of terminology, it is not the SecurityTokenReference that I need to sign, but the Binary Security Token.
In order to do this I needed to hide the certificates for Initiator and Recipient and add a signed supporting token.
I went back to using configuration to create and sign the message, rather than trying to add the signature manually.
Other problem that would have stopped this from working is that I had an incorrect namespace on my custom 'Messaging' header, so be mindful of namespaces, I didn't think they would be as important as what they are.
The code to create the binding follows
private System.ServiceModel.Channels.Binding GetCustomBinding()
{
System.ServiceModel.Channels.AsymmetricSecurityBindingElement asbe = new AsymmetricSecurityBindingElement();
asbe.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
asbe.InitiatorTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
asbe.RecipientTokenParameters = new System.ServiceModel.Security.Tokens.X509SecurityTokenParameters { InclusionMode = SecurityTokenInclusionMode.Never };
asbe.MessageProtectionOrder = System.ServiceModel.Security.MessageProtectionOrder.SignBeforeEncrypt;
asbe.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
asbe.EnableUnsecuredResponse = true;
asbe.IncludeTimestamp = false;
asbe.SetKeyDerivation(false);
asbe.DefaultAlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Basic128Rsa15;
asbe.EndpointSupportingTokenParameters.Signed.Add(new UserNameSecurityTokenParameters());
asbe.EndpointSupportingTokenParameters.Signed.Add(new X509SecurityTokenParameters());
CustomBinding myBinding = new CustomBinding();
myBinding.Elements.Add(asbe);
myBinding.Elements.Add(new TextMessageEncodingBindingElement(MessageVersion.Soap11, Encoding.UTF8));
HttpsTransportBindingElement httpsBindingElement = new HttpsTransportBindingElement();
httpsBindingElement.RequireClientCertificate = true;
myBinding.Elements.Add(httpsBindingElement);
return myBinding;
}
When using the binding, I set the ClientCredentials UserName, ServiceCertificate and ClientCertificate, and all works as expected.
Using the code is as follows
using (CredentialingService.SOAPPortTypeClient client = GetCredentialingClient())
{
client.Open();
etc....
}
private static CredentialingService.SOAPPortTypeClient GetCredentialingClient()
{
CredentialingService.SOAPPortTypeClient client = new CredentialingService.SOAPPortTypeClient(GetCustomBinding(), new EndpointAddress(new Uri(Settings.AppSettings.B2BUrl), new DnsEndpointIdentity(Settings.AppSettings.B2BDNSEndpoint), new AddressHeaderCollection()));
client.Endpoint.Contract.ProtectionLevel = System.Net.Security.ProtectionLevel.None;
SetClientCredentialsSecurity(client.ClientCredentials);
return client;
}
where GetCustomBinding is specified in my post
SetClientCredentialsSecurity is where the certificate is set, and is as follows
private static void SetClientCredentialsSecurity(ClientCredentials clientCredentials)
{
clientCredentials.UserName.UserName = Settings.AppSettings.B2BUserName;
clientCredentials.UserName.Password = Settings.AppSettings.B2BPassword;
string directoryName = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
clientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BServerCertificateName));
clientCredentials.ClientCertificate.Certificate = new X509Certificate2(Path.Combine(directoryName, Settings.AppSettings.B2BClientCertificateName), Settings.AppSettings.B2BClientCertificatePassword);
}
Hopefully that makes it a bit clearer
Maybe it's because your certificate is not publicly valid. Try this:
System.Net.ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(delegate { return true; });
//...
using (var client = new SrvClient())
{
client.ClientCredentials.UserName.UserName = "usr";
client.ClientCredentials.UserName.Password = "psw";
//...
}

Sign SOAP using certificate (WSE)

I have a requirement that I must build a SOAP message and then sign it using an X509 cert before sending it to a service via POST. I have NO idea what type of service this is but I was given a SOAP example.
I tried to use the example on MSDN but it's limited and incomplete and I am not able to instantiate the Security object. But even if I could, how do I associate it with the SoapEnvelope?
http://msdn.microsoft.com/en-us/library/aa529277.aspx
The SOAP message is built via Xslt. I need to get it signed anyway I can. Having a hard time finding anything. any ideas?
I'm currently using the following code to sign the xml and then I inject it into the SOAP xml.
private static XmlElement EncryptMessage(XmlElement msgBody)
{
StoreName storeName = (StoreName)Enum.Parse(typeof(StoreName), "My");
StoreLocation storeLocation = (StoreLocation)Enum.Parse(typeof(StoreLocation), "LocalMachine");
X509Certificate2 cert = X509Helper.GetCertificate(storeName, storeLocation, "CN=Something");
SignedXml signedXml = new SignedXml(msgBody);
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
signedXml.SigningKey = cert.PrivateKey;
signedXml.KeyInfo.AddClause(new System.Security.Cryptography.Xml.KeyInfoX509Data(cert));
Reference tRef = new Reference("");
XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
tRef.AddTransform(env);
signedXml.AddReference(tRef);
signedXml.ComputeSignature();
XmlElement xmlDsig = signedXml.GetXml();
xmlDsig.SetAttribute("Id", "Signature-1");
return xmlDsig;
}
which returns
<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>iGDf7TGuTzLDv/PYYF7/DC7xcZs=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue xmlns="http://www.w3.org/2000/09/xmldsig#">nALPlzIs96AE6/oMeFLFgxNJEeExwbvVLQI5HmevtthSX8hppH6Wr3OSk6/GSBtfyw6x1rXZXVbiXLuZ5jxiOsFfz314gBhoRzAskIxEer2SVmJ3BGUknEj+8pAAWfHFd3S8I4xPDjXvNPKalPsos8SBIDGNztACuG/aTb8FfomtxeJuzuIxQMPzXcJmX3bc1Sm7vkfrImY0Ep6LgFhl7NH5cl9R51APoSyRAjAxgPSQ/B3cdYxKwRO4Xe0A3XmFhdVWbFz+IfZGoWWqol0pOlVjkyzagqaMKl6Qstg3qmoqwspiQ/sUcyl+BOqXUtOw8ItFNUhrCeHxp4Utq8Hlqg==</SignatureValue>
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>MIIDAjCCAeqgAwIBAgIQdTFx7HlggYRD6LNeHg9uITANBgkqhkiG9w0BAQUFADAqMSgwJgYDVQQDEx9kZGF2aXMtUEMuaW50cmFuZXQud2VibWV0cm8uY29tMB4XDTExMDExODIxNDAyNFoXDTEyMDExODAwMDAwMFowKjEoMCYGA1UEAxMfZGRhdmlzLVBDLmludHJhbmV0LndlYm1ldHJvLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALMTgt9dnWwPEquCzW0sfUvRN5VLqX8BGeT9IL3MSXT9jdY2fWHav6SNdoXGp2RnSmQnTjHoz7WRu0r8UHfV9H7W6bUwiE+Ek1mQcbTGM3v/MOzzpbK4OT/OexP8LLFV0DihtX3PHinaTIvczledUHj135hOF6q6YDgLg/XkYUiuXk2DzYSIFSTQ5cPgt7k7fYwpVPiqddU56djKov2xWbnJKmNyO7XbKQiHYUADvqem3WE4NcTHIwScmjXdLxrN3xKKhh+UFvRRXeMyV+I4yvHGRUx1ZSsJ7yvC8rMYWuq3n8GymYSXJyWZKzEKxISbl9RTeri4ToyghpEcqiQ0oBUCAwEAAaMkMCIwCwYDVR0PBAQDAgQwMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBBQUAA4IBAQAWlISMloQU+SmZ1vAvup6WngUUsWc27h/mkA2wO1/H8GfjiiUrS/BCIqL37L/x0uFw6uUF4v0qbK2/weuqKPCUYu676k4D9fuwdTLwZaoIclSrM7XWwcbp/m4IHzHuW3BZ+r4MWe0Jv49CDlVj5A2kT0FXDc+qemulPtP4OOb0f8UzBoPuWTM86rjjY290F1jUdtEtgY9EJWxNAC2AnIY2dxXBZZm5v3FBPcqXTQXxCAmMV9xXfGb6Rg2j8IiL04qJ/2y4u+G3VKjWRyqDvKQ293qO7JMAdDnBleRxgwPNTJ/B5R5UcRT5AAwqbSfUgmcZeJN1ZCWMEdX41oONzkJJ</X509Certificate>
</X509Data>
</KeyInfo>
Based on what I read here: http://www.trl.ibm.com/projects/xml/soap/wp/wp.html all I need is what I have so I can just inject it into the header.
You don't need WSE, you can sign the message by generating a signature from the body of the message. The code you're using is correct. Just change it to process the body of the message and then put the xml returned by your method int he header of the soap message. Also, it looks like you need to add a reference. The URL should be whatever the ID you gave the body.
I made it in the following way, first take the certificate and keep it in stock certificates, after we access the certificate from the store and sign the soap message
in this link you will find the same example and other similar
http://www.systemdeveloper.info/2013/11/digital-signature-in-c.html
This is an example of how I did it:
public static getDataResponse queryingData(string name)
{
proxy.BanWS conexion = new proxy.Banws();
//VALIDATION OF CONNECTION V3
X509Certificate2 elCert = new X509Certificate2(#"C:\portecle-1.5\12345.P12", "12345");
conexion.ClientCertificates.Add(elCert);
// Copy the certificate to the certificate store using ASPNET
// spent the path and password
X509Certificate2 certificate = new X509Certificate2(#"C:\portecle-1.5\12345.P12", "12345");
X509Store stores = new X509Store(StoreName.My, StoreLocation.CurrentUser);
stores.Open(OpenFlags.ReadWrite);
stores.Add(certificate);
stores.Close();
String sto = X509CertificateStore.MyStore;
// Open the Certificates Stores
X509CertificateStore store = X509CertificateStore.CurrentUserStore(sto);
store.OpenRead();
// We look for the certificate that we will use to perform the signature
String certname = "conticert";
Microsoft.Web.Services2.Security.X509.X509CertificateCollection certcoll = store.FindCertificateBySubjectString(certname);
if (certcoll.Count != 0)
{
Microsoft.Web.Services2.Security.X509.X509Certificate cert = certcoll[0];
SoapContext ctx = conexion.RequestSoapContext;
SecurityToken tok = new X509SecurityToken(cert);
ctx.Security.Timestamp.TtlInSeconds = 120;
ctx.Security.Tokens.Add(tok);
// We signed the request
ctx.Security.Elements.Add(new MessageSignature(tok));
}
//remote call
getDataResponse response = new getDataResponse();
response = conexion.getData(name);
return response;
}

Categories

Resources