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 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 then choose 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 2005.

  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.NET Web 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.Services3 assembly.

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

    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 <soapServerProtocolFactory> Element section must be on one line, even though the following sample shows it split across multiple lines for readability.

    <configuration>
       <system.web>
            <webServices>
                <soapServerProtocolFactory type="Microsoft.Web.Services3.WseProtocolFactory, Microsoft.Web.Services3, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> 
            </webServices>
        </system.web>
       </system.web>
    </configuration>
    

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

  1. Create a custom policy assertion.

    For more details about creating custom policy assertions, see How to: Create a Custom Policy Assertion that Secures SOAP Messages.

  2. In the input SOAP filter for the client or the Web service that receives the signed SOAP messages, override the ValidateMessageSecurity method.

    The following code example overrides the ValidateMessageSecurity method for the Web service input SOAP filter.

    Public Overrides Sub ValidateMessageSecurity(ByVal envelope As SoapEnvelope, ByVal security As Security)
    
    public override void  ValidateMessageSecurity(SoapEnvelope envelope, Security security)
    {
    
  3. Verify that the incoming SOAP message is signed using a X509SecurityToken security token.

    The following code example verifies that the request was signed using a X509SecurityToken security token.

    Dim IsSigned As Boolean = False
    Dim element As ISecurityElement
    For Each element In security.Elements
        If (TypeOf (element) Is MessageSignature) Then
            ' The SoapContext contains a Signature element. 
            Dim sig As MessageSignature = element
            Dim expectedOptions As SignatureOptions = SignatureOptions.IncludeTimestamp Or _
                                                      SignatureOptions.IncludeSoapBody Or _
                                                      SignatureOptions.IncludeTo Or _
                                                      SignatureOptions.IncludeAction Or _
                                                      SignatureOptions.IncludeMessageId
            If ((sig.SignatureOptions And expectedOptions) = expectedOptions) Then
                ' The SOAP body and the WS-Addressing headers are signed.
                If (TypeOf sig.SigningToken Is X509SecurityToken) Then
                    ' The SOAP message is signed by a X509SecurityToken.
                    IsSigned = True
                End If
            End If
        End If
    Next
    If (Not IsSigned) Then
        Throw New SecurityFault("Message did not meet security requirements.")
    
    bool IsSigned = false;
    foreach (ISecurityElement element in security.Elements)
    {
        if (element is MessageSignature)
        {
            // The given context contains a Signature element.
            MessageSignature sig = element as MessageSignature;
            SignatureOptions expectedOptions = SignatureOptions.IncludeTimestamp |
                                               SignatureOptions.IncludeSoapBody |
                                               SignatureOptions.IncludeTo |
                                               SignatureOptions.IncludeAction |
                                               SignatureOptions.IncludeMessageId;
            if ((sig.SignatureOptions & expectedOptions) == expectedOptions)
            {
                // The SOAP body and the WS-Addressing headers are signed.
                if (sig.SigningToken is X509SecurityToken)
                    // The SOAP message is signed by a X509SecurityToken.
                    IsSigned = true;
            }
        }
    }
    if (!IsSigned)
        throw new SecurityFault("Message did not meet security requirements.");
    

Example

The following code example verifies that incoming SOAP messages are signed using a X509SecurityToken security token.

Dim IsSigned As Boolean = False
Dim element As ISecurityElement
For Each element In security.Elements
    If (TypeOf (element) Is MessageSignature) Then
        ' The SoapContext contains a Signature element. 
        Dim sig As MessageSignature = element
        Dim expectedOptions As SignatureOptions = SignatureOptions.IncludeTimestamp Or _
                                                  SignatureOptions.IncludeSoapBody Or _
                                                  SignatureOptions.IncludeTo Or _
                                                  SignatureOptions.IncludeAction Or _
                                                  SignatureOptions.IncludeMessageId
        If ((sig.SignatureOptions And expectedOptions) = expectedOptions) Then
            ' The SOAP body and the WS-Addressing headers are signed.
            If (TypeOf sig.SigningToken Is X509SecurityToken) Then
                ' The SOAP message is signed by a X509SecurityToken.
                IsSigned = True
            End If
        End If
    End If
Next
If (Not IsSigned) Then
    Throw New SecurityFault("Message did not meet security requirements.")
bool IsSigned = false;
foreach (ISecurityElement element in security.Elements)
{
    if (element is MessageSignature)
    {
        // The given context contains a Signature element.
        MessageSignature sig = element as MessageSignature;
        SignatureOptions expectedOptions = SignatureOptions.IncludeTimestamp |
                                           SignatureOptions.IncludeSoapBody |
                                           SignatureOptions.IncludeTo |
                                           SignatureOptions.IncludeAction |
                                           SignatureOptions.IncludeMessageId;
        if ((sig.SignatureOptions & expectedOptions) == expectedOptions)
        {
            // The SOAP body and the WS-Addressing headers are signed.
            if (sig.SigningToken is X509SecurityToken)
                // The SOAP message is signed by a X509SecurityToken.
                IsSigned = true;
        }
    }
}
if (!IsSigned)
    throw new SecurityFault("Message did not meet security requirements.");

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
Brokered Authentication - X.509 PKI
X.509 Technical Supplement