Securing Caché Web Services
Adding Digital Signatures
[Back] [Next]
   
Server:docs2
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes how to add digital signatures to SOAP messages sent by Caché web services and web clients. It discusses the following topics:

Typically you perform both encryption and signing. This chapter describes signing alone, for simplicity. For information on combining encryption and signing, see the chapter Combining Encryption and Signing.”
The chapter Using Derived Key Tokens for Encryption and Signing describes an alternative way to add digital signatures to SOAP messages.
Overview of Digital Signatures
You use digital signatures to detect message alteration or to simply validate that a certain part of a message was really generated by the entity which is listed. As with the traditional manually written signature, a digital signature is an addition to the document that can be created only by the creator of that document and that cannot easily be forged.
Caché support for digital signatures on SOAP messages is based on WS-Security 1.1. In turn, WS-Security follows the XML Signature specification. According to the latter specification, to sign an XML document:
  1. You use a digest function to compute the hashed value of one or more parts of the document.
  2. You concatenate the digest values.
  3. You use your private key to encrypt the concatenated digest. (This is the computation that only you can perform.)
  4. You create the <Signature> element, which includes the following information:
The chapter Using Derived Key Tokens for Encryption and Signing describes an alternative way to add digital signatures to SOAP messages. The details of the messages themselves vary, but the general process is the same and follows the XML Signature specification: You generate a digest of the signed parts, encrypt the digest, and include a <Signature> element with information that enables the recipient to validate the signature and decrypt the encrypted digest.
Adding a Digital Signature
To digitally sign a SOAP message, you can use the basic procedure here or the variations described in the following parts of the chapter.
First, the following figure summarizes the process:
In detail, the process is as follows:
  1. Optionally include the %soap.inc include file, which defines macros you might need to use.
  2. If you want to sign any security header elements, create those security header elements. For example:
     set utoken=##class(%SOAP.Security.UsernameToken).Create("_SYSTEM","SYS")
  3. Create an instance of %SYS.X509Credentials, as described in Retrieving Credential Sets Programmatically,” earlier in this book. This Caché credential set must contain your own certificate, and you must provide the private key password, if it has not already been loaded. For example:
     Set x509alias = "servercred" 
     Set pwd = "mypassword" 
     Set credset = ##class(%SYS.X509Credentials).GetByAlias(x509alias,mypassword)
    
  4. Create a binary security token that contains the certificate associated with that credential set. To do so, call the CreateX509Token() class method of %SOAP.Security.BinarySecurityToken. For example:
     set bst=##class(%SOAP.Security.BinarySecurityToken).CreateX509Token(credset)
    This method returns an instance of %SOAP.Security.BinarySecurityToken that represents the <BinarySecurityToken> header element.
  5. Add this token to the WS-Security header element. To do so, call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the method argument, use the token you just created. For example:
     do ..SecurityOut.AddSecurityElement(bst)
  6. Create the <Signature> element based on the binary security token. To do so, call the CreateX509() class method of %XML.Security.Signature. For example:
     set dsig=##class(%XML.Security.Signature).CreateX509(bst)
    This method returns an instance of %XML.Security.Signature that represents the <Signature> header element. The <Signature> element applies to a default set of parts of the message; you can specify a different set of parts.
    Formally, this method has the following signature:
    classmethod CreateX509(credentials As %SYS.X509Credentials = "", 
                           signatureOptions As %Integer, 
                           referenceOption As %Integer, 
                           Output status As %Status) as %XML.Security.Signature
    Where:
  7. Add the digital signature to the WS-Security header element. To do so, call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the argument, specify the signature object created in the previous step. For example:
     do ..SecurityOut.AddSecurityElement(dsig)
  8. Send the SOAP message. See the general comments in Adding Security Header Elements,” earlier in this book.
Example
This example shows a web service that signs its response messages.
To make this example work in your own environment, first do the following:
Class DSig.DivideWS Extends %SOAP.WebService
{

///  Name of the Web service.
Parameter SERVICENAME = "DigitalSignatureDemo";

///  SOAP namespace for the Web service
Parameter NAMESPACE = "http://www.myapp.org";

/// use in documentation
Method Divide(arg1 As %Numeric = 2, arg2 As %Numeric = 8) As %Numeric [ WebMethod ]
{
 Do ..SignResponses()
 Try {
  Set ans=arg1 / arg2
  }Catch{
    Do ..ApplicationError("division error")
  }
 Quit ans
}

/// use in documentation
/// signs and includes a binary security token
Method SignResponses()
{
 //Add timestamp because that's commonly done
 Set ts=##class(%SOAP.Security.Timestamp).Create()
 Do ..SecurityOut.AddSecurityElement(ts)

 //access previously stored server certificate & private key file
 //no need to use private key file password, because that has been saved
 Set x509alias = "servercred" 
 Set cred = ##class(%SYS.X509Credentials).GetByAlias(x509alias)
 set bst=##class(%SOAP.Security.BinarySecurityToken).CreateX509Token(cred)
 do ..SecurityOut.AddSecurityElement(bst)

 //Create WS-Security Signature object
 Set signature=##class(%XML.Security.Signature).CreateX509(bst)
 
 //Add WS-Security Signature object to the outbound message
 Do ..SecurityOut.AddSecurityElement(signature)
 Quit
}


///  Create our own method to produce application specific SOAP faults.
Method ApplicationError(detail As %String)
{
    Set fault=##class(%SOAP.Fault).%New()
    Set fault.faultcode=$$$FAULTServer
    Set fault.detail=detail
    Set fault.faultstring="Application error"
    // ReturnFault must be called to send the fault to the client.
    // ReturnFault will not return here.
    Do ..ReturnFault(fault)
}


}
Other Ways to Use the Certificate with the Signature
In the basic procedure discussed in the previous section, you use a <BinarySecurityToken> contains a certificate in serialized, base-64–encoded format. Instead of including the certificate, you can use information that identifies the certificate. Or you can contain the certificate within a signed SAML assertion. This section discusses these variations.
Variation: Using Information That Identifies the Certificate
Instead of including a certificate in the message, you can include information that identifies the certificate. The recipient uses this information to retrieve the certificate from the appropriate location. To do so, use the steps in the previous section, with the following changes:
Example
This example is a variation of the earlier example in this chapter.
Method SignResponses()
{
 //Add timestamp because that's commonly done
 Set ts=##class(%SOAP.Security.Timestamp).Create()
 Do ..SecurityOut.AddSecurityElement(ts)

 //access previously stored server certificate & private key file
 //no need to use private key file password, because that has been saved
 Set x509alias = "servercred" 
 Set cred = ##class(%SYS.X509Credentials).GetByAlias(x509alias)

 //Create WS-Security Signature object
 Set signature=##class(%XML.Security.Signature).CreateX509(cred)
 
 //Add WS-Security Signature object to the outbound message
 Do ..SecurityOut.AddSecurityElement(signature)
 Quit
}
In this case, the web service sends response messages like the following:
<?xml version="1.0" encoding="UTF-8" ?>
<SOAP-ENV:Envelope [parts omitted]>
  <SOAP-ENV:Header>
    <Security xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <Timestamp xmlns="[parts omitted]oasis-200401-wss-wssecurity-utility-1.0.xsd" 
                 wsu:Id="Timestamp-48CEE53E-E6C3-456C-9214-B7D533B2663F">
        <Created>2010-03-19T14:35:06Z</Created>
        <Expires>2010-03-19T14:40:06Z</Expires>
      </Timestamp>
      <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-sha256"></SignatureMethod>
            <Reference URI="#Timestamp-48CEE53E-E6C3-456C-9214-B7D533B2663F">
              <Transforms>
                <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>waSMFeYMruQn9XHx85HqunhMGIA=</DigestValue>
            </Reference>
            <Reference URI="#Body-73F08A5C-0FFD-4FE9-AC15-254423DBA6A2">
              <Transforms>
                <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>wDCqAzy5bLKKF+Rt0+YV/gxTQws=</DigestValue>
            </Reference>
          </SignedInfo>
          <SignatureValue>j6vtht/[parts omitted]trCQ==</SignatureValue>
          <KeyInfo>
            <SecurityTokenReference 
            xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
              <KeyIdentifier EncodingType="[parts omitted]#Base64Binary" 
                             ValueType="[parts omitted]#ThumbprintSHA1">
                   WeCnU2sMyOXfHH8CHTLjNTQQnGQ=
              </KeyIdentifier>
            </SecurityTokenReference>
          </KeyInfo>
        </Signature>
      </Security>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body wsu:Id="Body-73F08A5C-0FFD-4FE9-AC15-254423DBA6A2">
      [omitted]
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Variation: Using a Signed SAML Assertion
To add a digital signature that uses the certificate in a signed SAML assertion, do the following:
  1. Optionally include the %soap.inc include file, which defines macros you might need to use.
  2. If you want to sign any security header elements, create those security header elements. For example:
     set utoken=##class(%SOAP.Security.UsernameToken).Create("_SYSTEM","SYS")
  3. Create a signed SAML assertion with a <SubjectConfirmation> element that uses the Holder-of-key method . See Creating and Adding SAML Tokens,” later in this book.
  4. Create the <Signature> element. When you do, use the signed SAML assertion as the first argument to the CreateX509() class method. For example:
     set signature=##class(%XML.Security.EncryptedKey).CreateX509(signedassertion)
  5. Add the digital signature to the WS-Security header element. To do so, call the AddSecurityElement() method of the SecurityOut property of your web client or web service. For the argument, specify the signature object created in the previous step. For example:
     do ..SecurityOut.AddSecurityElement(dsig)
  6. Send the SOAP message. See the general comments in Adding Security Header Elements,” earlier in this book.
Applying a Digital Signature to Specific Message Parts
By default, when you create and add a digital signature to the WS-Security header element, the signature is applied to the SOAP body, the <Timestamp> element in the header (if present), and any WS-Addressing header elements.
To specify the parts to which the signature applies, use any of the procedures described earlier with one variation: When you create the signature, use the second argument (signatureOptions) to specify the message parts to sign. Specify this argument as a binary combination of any of the following macros (which are contained in the %soap.inc file):
To combine macros, use plus (+) and minus (-) signs. For example:
$$$SOAPWSIncludeSoapBody+$$$SOAPWSIncludeTimestamp
Note:
These options apply both to the CreateX509() and the Create() methods; the latter is discussed in the chapter Using Derived Key Tokens for Encryption and Signing.”
For example:
 set ts=##class(%SOAP.Security.Timestamp).Create()
 do ..SecurityOut.AddSecurityElement(ts)
 set x509alias = "servercred" 
 set cred = ##class(%SYS.X509Credentials).GetByAlias(x509alias)
 
 set parts=$$$SOAPWSIncludeSoapBody + $$$SOAPWSIncludeTimestamp
 set signature=##class(%XML.Security.Signature).CreateX509(cred,parts)
Specifying the Digest Method
By default, the digest value for the signature is computed via the SHA-1 algorithm, and the <Signature> element in the security header includes something like this:
   <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod>
   <DigestValue>waSMFeYMruQn9XHx85HqunhMGIA=</DigestValue>
You can specify a different digest method for the signature. To do so, call the SetDigestMethod() method of your instance of %XML.Security.Signature. For the argument, use one of the following macros (which are contained in the %soap.inc file):
For example:
 do sig.SetDigestMethod($$$SOAPWSsha256)
Specifying the Signature Method
By default, the signature value is computed via the RSA-SHA256 algorithm, and the <Signature> element in the security header includes something like this:
   <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha256"></SignatureMethod>
...
   <SignatureValue>J+gACmdjkJxaq2hJqA[parts omitted]</SignatureValue>
You can specify a different algorithm for the signature method. To do so, call the SetSignatureMethod() method of your instance of %XML.Security.Signature. For the argument, use one of the following macros (which are contained in the %soap.inc file):
For example:
 do sig.SetSignatureMethod($$$SOAPWSrsasha512)
Note that you can modify the default signature algorithm. To do so, access the Management Portal, click System Administration, then Security, then System Security, and then System-wide Security Parameters. The option to specify the default signature algorithm is labeled Default signature hash.
Specifying the Canonicalization Method for <KeyInfo>
By default, the <KeyInfo> element is canonicalized with Exclusive XML Canonicalization, and the <KeyInfo> element includes the following:
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
To instead canonicalize this element with Inclusive XML Canonicalization, do the following:
 Set sig.SignedInfo.CanonicalizationMethod.Algorithm=$$$SOAPWSc14n
Where sig is the instance of %XML.Security.Signature.
In this case, <KeyInfo> contains the following:
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315">
Adding Signature Confirmation
The WS-Security 1.1 <SignatureConfirmation> feature enables a web client to ensure that a received SOAP message was generated in response to the original request sent by the web client. The client request is typically signed but does not have to be. In this mechanism, the web service adds a <SignatureConfirmation> element to the security header element, and the web client can check that <SignatureConfirmation> element.
For a web service, to add a <SignatureConfirmation> element to the security header element:
  1. Call the WSAddSignatureConfirmation() method of the web service. For the argument, specify the main signature of the security header element. For example:
     do ..WSAddSignatureConfirmation(sig)
  2. Send the SOAP message as usual. See the general comments in Adding Security Header Elements,” earlier in this book.
This method adds WS-Security 1.1 <SignatureConfirmation> elements to the outbound message. It adds a <SignatureConfirmation> element to the SecurityOut property for each <Signature> received in SecurityIn.
If SecurityIn does not include a signature, then a <SignatureConfirmation> element is added with no Value attribute, as required by WS-Security 1.1.
For information on validating <SignatureConfirmation> elements, see Checking the Signature Confirmation,” later in this book.