Signing sections added via custom filter
From: Stewart Bourke (stewartbourke_at_eircom.net)
Date: 05/26/04
- Next message: Graham Allwood: "Re: PasswordOption.SendNone"
- Previous message: casey chesnut: "Re: wse 2.0 messaging with CE.NET"
- Messages sorted by: [ date ] [ thread ]
Date: 26 May 2004 07:12:03 -0700
Vs2003 .net, c#, wse1
First, apologies for the long post, but I have had to include some
soap messages...
I need to digitally sign a webservice call, having added a custom
filter to add a section to the soap header. I have managed to add the
custom section to a soap message with a custom filter. My problem now
is that I need to create a digest reference within the wse:security
section of the message, and I am not sure how to do it.
1. How can I remove the wsu reference? In my code, I have removed
all the filters, except the security and my cusom filter
2. Because I added a custom filter to add the 'Operation' section in
the soap header, it does not appear to have a digect calculated for
it. The 'correct' message has two 'Digest' references, whereas my
message only has one - how can I tell the application to generate
digests for both sections.
3. Me soap message has a huge ID reference:
<soap:Body wsu:Id="Id-9c18c809-de51-4d73-b748-67a8eb0a634c"
Whereas the 'correct' message has a simple one
<soap:Body id="MsgBody"> - without the wsu
How can I remove the wsu: before the 'Id'?
Also, can I control the format of the Id value - i.e. set
id='MsgBody'?
I have provided my (incorrect) soap message, and the correct one as
supplied by the service provider.
I have also provided some code snippets from the application.
I know it is a long message, but I would appreciate if anybody could
offer any assistance...
Regards,
Stewart Bourke
Message 1 - code generated from my application:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<wsse:Security soap:mustUnderstand="1"
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
<wsse:BinarySecurityToken ValueType="wsse:X509v3"
EncodingType="wsse:Base64Binary"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
wsu:Id="SecurityToken-ea6945eb-1414-4bc9-99f2-fab488315237">MIICOTCCAaagAwIBAgIQgQWWUbaPm6tO71vvsclQPzAJBgUrDgMCHQUAMFAxFjAUBgNVBAMTDUFkbWluaXN0cmF0b3IxDDAKBgNVBAcTA0VGUzEoMCYGA1UECxMfRUZTIEZpbGUgRW5jcnlwdGlvbiBDZXJ0aWZpY2F0ZTAgFw0wMzEyMTAxMDQ0MjlaGA8yMTAzMTExNjEwNDQyOVowUDEWMBQGA1UEAxMNQWRtaW5pc3RyYXRvcjEMMAoGA1UEBxMDRUZTMSgwJgYDVQQLEx9FRlMgRmlsZSBFbmNyeXB0aW9uIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEB
QUAA4GNADCBiQKBgQCbcO3b2QbGaPds6El98lEhN5HBvj8lCuqFcGL84WCZwn/qKc0uj6aWKw43AcqQegX2RchnZDd3iKj97U7Du67E+ikqUihtBGlFElpmk4AjeO6khZoTSPWE0A+OAFkZt37OTmFYiS0yx7p/JYWkz8zKLmu7Cgmh94sbcrWtDGjq9QIDAQABoxowGDAWBgNVHSUEDzANBgsrBgEEAYI3CgMEATAJBgUrDgMCHQUAA4GBAAcQ5jV3X9sPdaV/xx1ZjJyWhAZOptXlLfU2Y8EMiJlT/KhuAe1eyz6dtCNNtkWL2mq5gpzwZzrQJ4i+RsCLz0oQbdGKDMCrLdnQfzxH9/xvjucHmkDXKxzt0DhMtEVmgB+eHwOFVeVZQIM9EFWWk
eZbWRbmFr7O4iIwFCGjYXE</wsse:BinarySecurityToken>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<SignatureMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#Id-9c18c809-de51-4d73-b748-67a8eb0a634c">
<Transforms>
<Transform
Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</Transforms>
<DigestMethod
Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>OUDOeSEz7Dj6b4vSi6knUP3ZF6g=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>fNwBrI7xj491nvN83VJc10w1m9/72tLP+YZ9iEVJfdPkG97VR1SV+BjlcStOHxDAtJbVDuD3+//brHnJbfxf8rqN6rSd3EQESvAJuR/PkJ340hadpcJoloXOtNwyQZW39RIsmBTDWwvLQy1Qe+XkWDpV3mU2UGHONl/lCNiWh/U=</SignatureValue>
<KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference
URI="#SecurityToken-ea6945eb-1414-4bc9-99f2-fab488315237" />
</wsse:SecurityTokenReference>
</KeyInfo>
</Signature>
</wsse:Security>
<Operation id="MsgOperation"
xmlns="http://www.ros.ie/schemas/inbox/">Inbox/List</Operation>
</soap:Header>
<soap:Body wsu:Id="Id-9c18c809-de51-4d73-b748-67a8eb0a634c"
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<DocumentSearch xmlns="http://www.ros.ie/schemas/inbox/" />
</soap:Body>
</soap:Envelope>
Message 2: What the message should look like...
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/04/secext">
<wsse:BinarySecurityToken valueType="wsse:X509v3"
encodingType="wsse:Base64Binary" id="X509Token">
MIIEZzCcA9cgwaABQfd86afd2g...
</wsse:BinarySecurityToken>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod>Algorithm="http://www.w3.org/2001/10/xml-enc-c14n#"/>
</ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"/>
-- First digest reference is the MsgOperation section in the header..
<ds:Reference URI="#MsgOperation">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>DJbchm5gk...</ds:DigestValue>
</ds:Reference>
-- Second digest reference is the MsgBody section in the header..
<ds:Reference URI="#MsgBody">
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<ds:DigestValue>DJbchm5gk...</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>LyLsF0pi4wPu...</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#X509Token"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
<Operation xmlns="http://www.ros.ie/schemas/inbox/"
id="MsgOperation">Inbox/Document/Retrieve</Operation>
</soap:Header>
<soap:Body id="MsgBody">
<DocumentSelection xmlns="http://www.ros.ie/schemas/inbox/"
prn="12G"/>
</soap:Body>
</soap:Envelope>
============================================
Code:
....
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox txtMessage;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox cboCertsEncrypt;
private System.Windows.Forms.Button btnEcho;
private System.Windows.Forms.CheckBox chkEncrypt;
private System.Windows.Forms.ComboBox cboCertsSign;
private System.Windows.Forms.CheckBox chkSigned;
private DocumentDescription[] DocList;
private System.Windows.Forms.RichTextBox richTextBox1;
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
Microsoft.Web.Services.SoapInputFilterCollection inputFilters =
Microsoft.Web.Services.Configuration.WebServicesConfiguration.FilterConfiguration.InputFilters;
Microsoft.Web.Services.SoapOutputFilterCollection outputFilters =
Microsoft.Web.Services.Configuration.WebServicesConfiguration.FilterConfiguration.OutputFilters;
// remove the unused input filters
inputFilters.Remove(typeof(Microsoft.Web.Services.Referral.ReferralInputFilter));
inputFilters.Remove(typeof(Microsoft.Web.Services.Routing.RoutingInputFilter));
inputFilters.Remove(typeof(Microsoft.Web.Services.Timestamp.TimestampInputFilter));
// remove the unused output filters
outputFilters.Remove(typeof(Microsoft.Web.Services.Referral.ReferralOutputFilter));
outputFilters.Remove(typeof(Microsoft.Web.Services.Routing.RoutingOutputFilter));
outputFilters.Remove(typeof(Microsoft.Web.Services.Timestamp.TimestampOutputFilter));
outputFilters.Remove(typeof(Microsoft.Web.Services.Security.SecurityOutputFilter));
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
..... removed lots of setup for space reasons
from here...
this.Text = "X509 Client";
this.Load += new System.EventHandler(this.Form1_Load);
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
private void btnEcho_Click(object sender, System.EventArgs e)
{
// create the reference and make the call
try
{
// create the proxy class
RevenueOnlineServiceWse proxy = new RevenueOnlineServiceWse();
proxy.Pipeline.OutputFilters.Add(new
CustomOutputFilter());
proxy.Pipeline.OutputFilters.Add(new SecurityOutputFilter());
// open the correct certificate store
X509CertificateStore certStore =
X509CertificateStore.CurrentUserStore(X509CertificateStore.MyStore);
certStore.OpenRead();
// get the certificate and create the security token
X509Certificate certSignCertificate =
certStore.FindCertificateBySubjectString(cboCertsSign.Text)[0];
X509SecurityToken secSignToken = new
X509SecurityToken(certSignCertificate);
// add public key to message
proxy.RequestSoapContext.Security.Tokens.Add(secSignToken);
// create the signing details and add to the message
Signature certSignature = new Signature(secSignToken);
proxy.RequestSoapContext.Security.Elements.Add(certSignature);
// close the certificate store
certStore.Close();
// make the call
proxy.RequestSoapContext["Operation"] =
"Inbox/List";
DocumentSearch DocSrch;
DocSrch = new DocumentSearch();
taxtype tt;
tt = taxtype.Transit;
DocSrch.taxtype = tt;
DocList = proxy.InboxList(DocSrch);
}
catch (Exception error)
{
MessageBox.Show(error.Message, "Error!!");
}
}
private void Form1_Load(object sender, System.EventArgs e)
{
X509CertificateStore certStore;
int cntr=0;
// loop through the local certificate store and add to the signing
list
certStore = X509CertificateStore.CurrentUserStore(X509CertificateStore.MyStore);
certStore.OpenRead();
foreach(X509Certificate certCertificate in certStore.Certificates)
{
// can we sign with this key
if(certCertificate.SupportsDigitalSignature == true && cntr++ > 0)
{
cboCertsSign.Items.Add(GetCommonName(certCertificate.GetName()));
}
}
// close the open store
certStore.Close();
// loop through the local certificate store and add to the
encrypting list
certStore = X509CertificateStore.CurrentUserStore(X509CertificateStore.TrustStore);
certStore.Open();
foreach(X509Certificate certCertificate in certStore.Certificates)
{
// can we encrypt to this key
if(certCertificate.SupportsDataEncryption == true)
{
cboCertsEncrypt.Items.Add(GetCommonName(certCertificate.GetName()));
}
}
// close the store
certStore.Close();
// select the first entry
if(cboCertsSign.Items.Count != 0) cboCertsSign.SelectedIndex = 0;
if(cboCertsEncrypt.Items.Count != 0) cboCertsEncrypt.SelectedIndex
= 0;
}
private static string GetCommonName(string strName)
{
int intStart, intEnd;
string strReturn = strName;
// find the "CN=" tag
intStart = strName.IndexOf("CN=");
if(intStart != - 1)
{
// skip the "CN=" tag
intStart += 3;
// find the next "," after the "CN=" tag
intEnd = strName.IndexOf(",",intStart);
// split the string (on found position or EOF)
if(intEnd == -1)
{
strReturn = strName.Substring(intStart);
}
else
{
strReturn = strName.Substring(intStart, intEnd-intStart);
}
}
// return the string
return strReturn;
}
}
public class CustomOutputFilter : SoapOutputFilter
{
const string CustomHeaderName = "Operation";
const string CustomHeaderUri = "http://www.ros.ie/schemas/inbox";
const string CustomHeaderEchoAttributeName = "id";
public override void ProcessMessage(SoapEnvelope envelope)
{
//
// Look for any data stuffed in the SoapEnvelope's context that we
care about
//
string echoText = envelope.Context["Operation"] as string;
if (echoText != null)
{
//
// Create a new SOAP Header or retrieves a reference
// to an existing one.
//
XmlElement soapHeader = envelope.CreateHeader();
//
// Create a new CustomHeader and add it to the message
//
soapHeader.AppendChild(CreateCustomHeader(soapHeader, echoText));
}
}
XmlElement CreateCustomHeader(XmlElement header, string echoText)
{
XmlDocument document = header.OwnerDocument;
XmlElement customHeader = document.CreateElement("", "Operation",
"http://www.ros.ie/schemas/inbox/");
customHeader.InnerText = "Inbox/List";
customHeader.SetAttribute("id", "", "MsgOperation");
return customHeader;
}
}
}
- Next message: Graham Allwood: "Re: PasswordOption.SendNone"
- Previous message: casey chesnut: "Re: wse 2.0 messaging with CE.NET"
- Messages sorted by: [ date ] [ thread ]
Relevant Pages
|