How to: Verify Digital Signatures of SOAP Messages Signed by an X.509 Certificate

WSE validates that a digital signature is cryptographically correct, however user code or Policy should be used to verify that a signature exists and that the signature applies to the expected set of XML elements. Signature validation is done by WSE prior to recipient code executes when WSE is configured to run with the recipient.

To configure WSE to validate digital signatures for incoming SOAP messages

  1. For each certification authority (CA) that the SOAP message recipient intends to trust X.509 certificates to be issued from, install the CA certificate chain into the certificate store that WSE is configured to retrieve X.509 certificates from.

    For example, if a SOAP message recipient intends to trust X.509 certificates issued by Microsoft, the CA certificate chain for Microsoft must be installed in the certificate store from which WSE is set up to look for X.509 certificates. The certificate store that WSE looks in is controlled by the <x509> Element configuration element. Windows ships with a set of default certificate chains for trusted certification authorities, so you might not need to install the certificate chain for all certification authorities.

    1. Export the CA certificate chain.
      Exactly how this is done depends on the CA. However, if the CA is running Microsoft Certificate Services, select the Download a CA certificate, certificate chain, or CRL option, and thenchoose Download CA certificate.
    2. Import the CA certificate chain.
      Open the Certificates snap-in of the MMC, and then select the Trusted Root Certification Authorities folder for the certificate store from which WSE is configured to retrieve X.509 certificates. Right-click the Certificates folder contained within the Trusted Root Certification Authorities folder, point to All Tasks, click Import, and then provide the file exported in step a.
      For information about configuring which certificate store WSE is configured to retrieve X.509 certificates from, see <x509> Element. For information about using the Certificates snap-in of the MMC, see Managing X.509 Certificates.
  2. Start Visual Studio .NET 2003.

  3. On the File menu, point to New, and then click Project.

  4. Select Visual C# Projects in the Project Types pane.

  5. Select ASP.NETWeb Service in the Templates pane.

  6. In the Location box, enter the name of the Web server and the name of the project, and then click OK.

    The project is added to the solution. The Component Designer for Service1.asmx appears in the development environment.

  7. Add a reference to the Microsoft.Web.Services2 assembly.

    1. In Solution Explorer, right-click References, and then select Add Reference.
    2. Click the .NET tab, select Microsoft.Web.Services2.dll, and then click Select.
    3. Click OK.
  8. In the Web.config file for the Web service, include an <add> Element for <soapExtensionTypes> (WSE for Microsoft .NET) element in the <soapExtensionTypes> section.

  9. When the SOAP message recipient is a Web service client, this configuration entry is not required. Instead, the base class that the proxy class derives from must be changed to derive from the WebServicesClientProtocol class.

    The following code example shows the configuration entry that must be placed in the Web.config file for WSE to run with a Web service. The type attribute of the <add> element for <soapExtensionTypes> section must be on one line, even though the following sample shows it split across multiple lines for readability.

    <configuration>
       <system.web>
          <webServices>
             <soapExtensionTypes>
                <add type="Microsoft.Web.Services2.WebServicesExtension, 
                   Microsoft.Web.Services2,Version=2.0.0.0, Culture=neutral, 
                   PublicKeyToken=31bf3856ad364e35" 
                   priority="1" group="0"/>
             </soapExtensionTypes>
          </webServices>
       </system.web>
    </configuration>
    

To use Policy to require incoming SOAP messages be signed using an X.509 certificate and that it signed the required XML elements

  1. Add a <Policy> Element (WSE for Microsoft .NET) (1) element to the policy file for the application. Add the <Policy> Element (WSE for Microsoft .NET) (1) element as a child element of the <policies> Element element.

    Use the <Policy> Element (WSE for Microsoft .NET) (1) element to define criteria that a SOAP message must meet. The criteria are specified as child elements of the <Policy> element. The Id attribute is used to name the policy assertion, which is used by the <request> Element (WSE for Microsoft .NET), <response> Element (WSE for Microsoft .NET), and <fault> Element elements to refer to a policy assertion when applying the policy to an endpoint.

    The following code example defines a policy assertion named policy-c0a22319-6b89-49ff-9b82-bdbac5f04618.

    <wsp:Policy wsu:Id="policy-c0a22319-6b89-49ff-9b82-bdbac5f04618"
      xmlns:wsp="https://schemas.xmlsoap.org/ws/2002/12/policy"
      xmlns:wsa="https://schemas.xmlsoap.org/ws/2004/03/addressing" >
    
  2. Add an <Integrity> Element child element to the <Policy> Element (WSE for Microsoft .NET) (1) element.

    Use the <Integrity> Element element to define digital signature requirements. The requirements are specified in child elements.

    The following code example specifies that there are digital signature requirements.

    <wsp:Policy wsu:Id="policy-c0a22319-6b89-49ff-9b82-bdbac5f04618"
       xmlns:wsp="https://schemas.xmlsoap.org/ws/2002/12/policy"
       xmlns:wsa="https://schemas.xmlsoap.org/ws/2004/03/addressing" >
      <wssp:Integrity wsp:Usage="wsp:Required" xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">
    
  3. Add a <TokenInfo> Element child element to the <Integrity> Element element.

    Use the <TokenInfo> Element element to define security token requirements for the digital signature.

    The following code example specifies that there are security token requirements for the digital signature.

                  <wssp:Integrity wsp:Usage="wsp:Required"
                    xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">
                    <wssp:TokenInfo>
    
    
  4. Add a <SecurityToken> Element child element to the <TokenInfo> Element element.

    Use the <SecurityToken> Element element to define security token requirements for the digital signature.

    The following code example specifies that there are security token requirements for the digital signature.

    <wssp:TokenInfo>
      <wssp:SecurityToken>
    
  5. Add a <TokenType> Element child element to the <SecurityToken> Element element and set its value to http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3.

    Use the <TokenType> Element element to specify the type of security token that must be used to create the digital signature.

    The following code example specifies that an X509SecurityToken must have been used to digitally sign the SOAP message.

    <wssp:SecurityToken>
      <wssp:TokenType xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3</wssp:TokenType>
    
  6. Optionally, add a <Claims> Element child element to the <SecurityToken> Element element.

    Use the <Claims> Element element to specify requirements specific to an X.509 certificate. The requirements are specified in <Role> Element or <SubjectName> Element child elements.

    The following code example specifies that there are specific requirements on the X.509 certificate used to digitally sign the SOAP message.

    <wssp:SecurityToken>
      <wssp:Claims>
    
  7. Optionally, add a <SubjectName> Element child element to the <Claims> Element element.

    Use the <SubjectName> Element element to specify that the digital signature must have been created using an X.509 certificate with a specific subject name.

    Note

    When the <SubjectName> element is used to specify the subject name for an X.509 certificate, the value of the element is formatted differently than what appears in the MMC. The value that must be placed in the <SubjectName> element maps to the Subject field that appears on the Details tab of the Certificates snap-in within the MMC. If you copy the value of the Subject field from the MMC, the value has to be reversed prior to placement in the <SubjectName> element. For example, if the value of the Subject field is CN=WSE2QuickStartServer, O=Coho Winery, L=Woodinville, S=WA, C=US, the value that must be added to the <SubjectName> element is C=US, S=WA, L=Woodinville, O=Contoso, CN=Coho Winery.

    The following code example specifies that the digital signature must have been created with the X.509 certificate that has a subject name of CN=WSE2QuickStartClient.

    <wssp:Claims>
      <wssp:SubjectName>CN=WSE2QuickStartClient</wssp:SubjectName>
    
  8. Optionally, add a <TokenIssuer> Element (WSE for Microsoft .NET) (1) child element to the <SecurityToken> Element element.

    Use the <TokenIssuer> Element (WSE for Microsoft .NET) (1) element to specify the certification authority that issued the X.509 certificate.

    Note

    The value of the <TokenIssuer> element is formatted differently than what appears in the MMC. The value that must be placed in the <TokenIssuer> element maps to the Issuer field that appears on the Details tab of the Certificates snap-in within the MMC. If you copy the value of the Issuer field from the MMC, the value has to be reversed prior to placement in the <TokenIssuer> element. For example, if the value of the Issuer field is CN=CertServer DC=corp DC=contoso DC=com, the value that must be added to the <TokenIssuer> element is DC=com DC=contoso DC=corp CN=CertServer.

    The following code example specifies that SOAP messages must have been digitally signed using X.509 certificates issued by the DC=com DC=contoso DC=corp CN=CertServer certification authority.

    <wssp:SecurityToken>
      <wssp:TokenIssuer>DC=com DC=contoso DC=corp CN=CertServer</wssp:TokenIssuer>
    
  9. Add a <MessageParts> Element for <Integrity> Element element to the <Integrity> Element element.

    Use the <MessageParts> element to specify the XML elements that must be signed.

    The following code example specifies that the <Body> element and the To, Action, MessageID, and From headers are signed.

    <wssp:MessageParts Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">
      wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
    </wssp:MessageParts>
    
  10. Specify that the XML elements that must be signed, exist in incoming SOAP messages.

    1. Add a <MessagePredicate> Element child element to the <Policy> Element (WSE for Microsoft .NET) (1) element in the policy file for the application.
      When using policy to require digital signatures on incoming SOAP messages, always use the <MessagePredicate> element. The <MessagePredicate> element ensures that the XML elements that must be signed actually exist in the SOAP message. Just adding an <Integrity> Element element to a policy file specifies that a digital signature must exist, if the XML elements specified in the <Integrity> element exist in the SOAP messages. If the SOAP message does not contain the XML elements specified in the <Integrity> element, the SOAP message satisfies the requirements of the policy and is allowed to access the Web service. To remedy this potential problem, add a <MessagePredicate> element specifying the XML elements that must exist in the incoming SOAP message.
      Set the Dialect attribute value to "https://schemas.xmlsoap.org/2002/12/wsse#part".

    2. Specify the parts of the message that must exist by listing them, separated by spaces, as the value of the <MessagePredicate> Element element.
      The following code example specifies that the <Body> element and the To, Action, MessageID, and From headers exist in the SOAP message.

      <wsp:MessagePredicate 
        Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">
        wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
      </wsp:MessagePredicate>
      
  11. Add an <endpoint> Element element to the <mappings> Element element.

    Use the <endpoint> Element element to apply a policy assertion to an endpoint.

    The following code example sets the default policy for all SOAP messages to the policy-c0a22319-6b89-49ff-9b82-bdbac5f04618 policy assertion.

    <mappings xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy">
      <endpoint uri="https://localhost/X509SignPolicyService/X509SigningService.asmx">
        <defaultOperation>
          <request policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
          <response policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
          <fault policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        </defaultOperation>
      </endpoint>
    </mappings>
    

To use code to require incoming SOAP messages be signed using an X.509 certificate and that it signed the required XML elements

  1. Add a Web service method that processes the X.509 certificate.

    1. In Solution Explorer, right-click Service1.asmx, and then click View Code.

    2. Add the Imports or using directives to Service1.asmx.cs as shown in the following code example.

      Imports Microsoft.Web.Services2
      Imports Microsoft.Web.Services2.Security
      Imports Microsoft.Web.Services2.Security.Tokens
      
      using Microsoft.Web.Services2;
      using Microsoft.Web.Services2.Security;
      using Microsoft.Web.Services2.Security.Tokens;
      
    3. In the Service1 class, add code to verify that the <Body> element of the SOAP request was signed using an X.509 certificate.
      The following code example adds a Web service method named sayHello that verifies the request was made using SOAP and calls the method named IsMessageSigned defined in the next step.

      <WebMethod()>  _
      Public Function sayHello() As String
          Dim requestContext As SoapContext = _
            RequestSoapContext.Current
          ' Verify that a SOAP request was received.  
          If requestContext Is Nothing Then
              Throw New ApplicationException( "Either a non-SOAP " + _
                "request was received or WSE is not properly " + _
                "installed for the Web application hosting the " + _
                "Web service.")
          End If
          If Not IsMessageSigned(requestContext) Then
              Throw New ApplicationException("The request is not signed.")
          End If
          Return "Hello"
      End Function
      
      [WebMethod]
      public string sayHello () 
      {
          SoapContext requestContext = RequestSoapContext.Current;
          // Verify that a SOAP request was received.  
          if (requestContext == null)
          {
              throw new ApplicationException( "Either a non-SOAP " +
                "request was received or WSE is not properly " +
                "installed for the Web application hosting the " +
                "Web service.");
          }
          // Check if the Soap Message is Signed.
          if (!IsMessageSigned(requestContext))
          {
              throw new ApplicationException(
                "The request is not signed.");
                  }
          return "Hello";
      }
      
  2. Define a method to get the X.509 certificate that is used to sign the SOAP message.

    1. In Solution Explorer, right-click Service1.asmx, and then click View Code.

    2. In the Service1 class, add the code shown in the following code example.
      The following code example verifies that a digital signature exists for a SoapContext and that it signed the <Body> element.

      Private Function IsMessageSigned(ByVal context As SoapContext) As Boolean
          Dim element As ISecurityElement
          For Each element In context.Security.Elements
              If (TypeOf (element) Is MessageSignature) Then
                  ' The SoapContext contains a Signature element. 
                  Dim sign As MessageSignature = element
                  If ((sign.SignatureOptions And _
                       SignatureOptions.IncludeSoapBody) <> 0) Then
                      ' The SOAP body is signed.
                      Return True
                  End If
              End If
          Next
          Return False
      End Function 
      
      private bool IsMessageSigned(SoapContext context)
      {
          foreach (ISecurityElement element in context.Security.Elements)
          {
              if (element is MessageSignature)
              {
                  // The given context contains a Signature element.
                  MessageSignature sig = element as MessageSignature;
                  if ((sig.SignatureOptions & 
                       SignatureOptions.IncludeSoapBody) != 0)
                  {
                      // The SOAP Body is signed.
                      return true;
                  }
              }
          }
          return false;
      }
      

Example

The following code example is a policy file specifying that all incoming SOAP messages must be signed using an X.509 certificate with a subject name of CN=WSE2QuickStartClient.

Note

This code example is designed to demonstrate WSE features and is not intended for production use.

<?xml version="1.0" encoding="utf-8"?>
<policyDocument xmlns="https://schemas.microsoft.com/wse/2003/06/Policy">
  <mappings xmlns:wse="https://schemas.microsoft.com/wse/2003/06/Policy">
    <endpoint uri="https://localhost/X509SignPolicyService/X509SigningService.asmx">
      <defaultOperation>
        <request policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        <response policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
        <fault policy="#policy-c0a22319-6b89-49ff-9b82-bdbac5f04618" />
      </defaultOperation>
    </endpoint>
  </mappings>
  <policies xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <!-- This policy ensures that the message is signed with an X.509
         certificate. -->
    <wsp:Policy wsu:Id="policy-c0a22319-6b89-49ff-9b82-bdbac5f04618"
      xmlns:wsp="https://schemas.xmlsoap.org/ws/2002/12/policy"
      xmlns:wsa="https://schemas.xmlsoap.org/ws/2004/03/addressing" >
      
      <wsp:MessagePredicate 
        Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">
            wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)
      </wsp:MessagePredicate>
      
      <wssp:Integrity wsp:Usage="wsp:Required" xmlns:wssp="https://schemas.xmlsoap.org/ws/2002/12/secext">        <wssp:TokenInfo>          <!-- The SecurityToken element within the TokenInfo element               describes the requirements for the certificate which               must be used for the signature described by the               Integrity assertion.           -->          <wssp:SecurityToken>            <wssp:TokenType>http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3</wssp:TokenType>            <wssp:Claims>                <wssp:SubjectName>CN=WSE2QuickStartClient</wssp:SubjectName>            </wssp:Claims>          </wssp:SecurityToken>        </wssp:TokenInfo>        <wssp:MessageParts Dialect="https://schemas.xmlsoap.org/2002/12/wsse#part">            wsp:Body() wsp:Header(wsa:To) wsp:Header(wsa:Action) wsp:Header(wsa:MessageID) wsp:Header(wsa:From)        </wssp:MessageParts>      </wssp:Integrity>
    </wsp:Policy>
  </policies>
</policyDocument>

See Also

Tasks

How to: Sign a SOAP Message Using an X.509 Certificate

Concepts

Digitally Signing a SOAP Message

Other Resources

Managing X.509 Certificates