Skip to main content

Encrypting the SOAP Body

This topic describes how to encrypt the body of SOAP messages sent by InterSystems IRIS web services and web clients.

The topics Encrypting Security Header Elements and Using Derived Key Tokens for Encryption and Signing describe how to encrypt security header elements as well as other ways to encrypt the SOAP body.

Overview of Encryption

InterSystems IRIS support for encryption of SOAP messages is based on WS-Security 1.1. In turn, WS-Security follows the XML Encryption specification. According to the latter specification, to encrypt an XML document:

  1. You generate a symmetric key for temporary use.

  2. You use this to encrypt the document (or selected parts of the document).

    You replace those parts of the document with <EncryptedData> elements that contain the encrypted version of the contents.

  3. You encrypt the symmetric key with the public key of the entity to whom you are sending the document.

    You can obtain the public key from an X.509 certificate contained in a request message from that entity. Or you can obtain it ahead of time.

  4. You include the encrypted symmetric key within an <EncryptedKey> element in the same document. The <EncryptedKey> element provides, directly or indirectly, information that enables the recipient to determine the key to use to decrypt this element.

    This information can be contained within the <EncryptedKey> element, or the <EncryptedKey> element can include a direct reference to a binary security token that contains an X.509 certificate or a signed SAML assertion. In the latter case, the security token must be added to the message before the <Signature> element is added.

The document can include multiple <EncryptedKey> elements, applicable to different encrypted parts of the document.

Other topics describe other ways to encrypt parts of SOAP messages. The details of the messages themselves vary, but the general process is the same and follows the XML Encryption specification: You generate and use symmetric keys, encrypt the symmetric key, and include the encrypted symmetric key in the messages.

Encrypting the SOAP Body

To encrypt the body of SOAP messages, you can use the basic procedure here or the variations described in the subsections. First, the following figure summarizes the process:

Using credentials in an inbound message, the steps are to create the security objects and then add them to the header.

In detail, the process is as follows:

  1. Optionally include the %soap.inc include file, which defines macros you might need to use.

  2. Obtain a credential set that contains the public key of the entity that will receive the SOAP messages, typically from the inbound message that you have received. See Retrieving Credential Sets Programmatically.

    For example:

     set credset=..SecurityIn.Signature.X509Credentials

    Be sure to check the type of the returned object to see if it is an instance of %SYS.X509CredentialsOpens in a new tab, as discussed in Retrieving Credential Sets Programmatically.

  3. 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.BinarySecurityTokenOpens in a new tab. For example:

     set bst=##class(%SOAP.Security.BinarySecurityToken).CreateX509Token(credset)

    This method returns an instance of %SOAP.Security.BinarySecurityTokenOpens in a new tab that represents the <BinarySecurityToken> header element.

  4. 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)
  5. Create the encrypted key based on the binary security token. To do so, call the CreateX509() class method of %XML.Security.EncryptedKeyOpens in a new tab. For example:

     set enckey=##class(%XML.Security.EncryptedKey).CreateX509(bst)

    This method generates a symmetric key, uses it to encrypt the SOAP body, and returns an instance of %XML.Security.EncryptedKeyOpens in a new tab which represents the <EncryptedKey> header element. This header element contains the symmetric key, encrypted by the public key contained in the given binary security token.

  6. Optionally modify the encrypted key instance to use different algorithms. See Specifying the Block Encryption Algorithm and Specifying the Key Transport Algorithm.

  7. Add the <EncryptedKey> element 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 element to add, specify your instance of %XML.Security.EncryptedKeyOpens in a new tab.

    For example:

     do ..SecurityOut.AddSecurityElement(enckey)

    This step also adds an <EncryptedData> element as the child of the <Body> element.

  8. Send the SOAP message. The SOAP body is encrypted and the WS-Security header is included.

    The WS-Security header includes the <BinarySecurityToken> and <EncryptedKey> elements.

    See the general comments in Adding Security Header Elements.

Variation: Using Information That Identifies the Certificate

A <BinarySecurityToken> contains a certificate in serialized, base-64–encoded format. You can omit this token and instead use information that identifies the certificate; the recipient uses this information to retrieve the certificate from the appropriate location. To do so, use the preceding steps, with the following changes:

  • Skip steps 3 and 4. That is, do not add a <BinarySecurityToken>.

  • In step 5 (creating the encrypted key), use the credential set from step 1 (rather than a binary security token) as the first argument to CreateX509(). For example:

     set enckey=##class(%XML.Security.EncryptedKey).CreateX509(credset,,referenceOption)

    For the third argument (referenceOption), you can specify how the <Signature> element uses the certificate.

    If you specify a credential set as the first argument (as we are doing in this variation), the default for referenceOption is $$$SOAPWSReferenceThumbprint. Optionally specify a value as described in the subsection. You can use any value except $$$SOAPWSReferenceDirect.

Reference Options for X.509 Certificates

The section A Brief Look at the WS-Security Header shows one way in which certificates are used in SOAP messages. In the example there, the digital signature consists of two header elements:

  • A <BinarySecurityToken> element, which carries the certificate in serialized, base-64–encoded form.

  • A <Signature> element, which carries the signature and which includes a direct reference to the binary security token.

There are other possible forms of reference. For example, the <Signature> could instead include a thumbprint of the certificate, and the <BinarySecurityToken> is not needed in the message in this case.

When you create an encrypted key, digital signature, or SAML assertion, you can specify the referenceOption argument, which controls how the newly created element uses the certificate (or more, specifically, the key material) contained in the credentials.

For reference, this argument can have any of the following values. These values are macros defined in the %soap.inc include file:

$$$SOAPWSReferenceDirect

The element includes a direct reference to the binary security token. Specifically, a <KeyInfo> element is created with a <SecurityTokenReference> subelement with a <Reference> subelement whose URI attribute is a local reference to the <BinarySecurityToken>. In order to use this option, you must be sure to also add the security token to the WS-Security header; details are given in the relevant sections.

$$$SOAPWSReferenceThumbprint

The element includes the SHA-1 thumbprint of the X.509 certificate.

$$$SOAPWSReferenceKeyIdentifier

The element includes the SubjectKeyIdentifier of the X.509 certificate.

$$$SOAPWSReferenceIssuerSerial

The element includes a <KeyInfo> element with a <SecurityTokenReference> child with an <X509Data> child that contains an <X509IssuerSerial> element.

$$$KeyInfoX509Certificate

The element includes a <KeyInfo> element with an <X509Data> child that contains an <X509Certificate> element. This usage is not recommended by the WS-Security specification for the <Signature> and <EncryptedKey> elements, but may be used for the <Assertion> element.

$$$KeyInfoX509IssuerSerial

The element includes a <KeyInfo> element with an <X509Data> child that contains an <X509IssuerSerial> element. This usage is not recommended by the WS-Security specification for the <Signature> and <EncryptedKey> elements, but may be used for the <Assertion> element.

$$$KeyInfoX509SKI

The element includes a <KeyInfo> element with an X509Data> child that contains an <X509SKI> element. This usage is not recommended by the WS-Security specification for the <Signature> and <EncryptedKey> elements, but may be used for the <Assertion> element.

$$$KeyInfoX509SubjectName

The element includes a <KeyInfo> element with an <X509Data> child that contains an <X509SubjectName> element. This usage is not recommended by the WS-Security specification for the <Signature> and <EncryptedKey> elements, but may be used for the <Assertion> element.

$$$KeyInfoRSAKey

The element includes a <KeyInfo> element with a <KeyValue> child that contains an <RSAKeyValue> element. This usage is not recommended by the WS-Security specification for the <Signature> and <EncryptedKey> elements, but may be used for the <Assertion> element.

Variation: Using a Signed SAML Assertion

To encrypt using the public key contained in the certificate in a signed SAML assertion, do the following:

  1. Skip steps 1–4 in the preceding steps.

  2. Create a signed SAML assertion with a <SubjectConfirmation> element that uses the Holder-of-key method . See Creating and Adding SAML Tokens.

  3. Create the <EncryptedKey> element. When you do so, use the signed SAML assertion as the first argument to the CreateX509() class method. For example:

     set enckey=##class(%XML.Security.EncryptedKey).CreateX509(signedassertion)
  4. Continue with step 5 in the preceding steps.

Message Encryption Examples

In this example, the web client (not shown) sends a signed request message and the web service sends an encrypted response.

The web service obtains the public key from the client certificate in the signature of the request message and uses that to add an <EncryptedKey> element in its response, which is encrypted. The <EncryptedKey> element is encrypted with the client’s public key and it contains the symmetric key used to encrypt the response message body.

The web service is as follows:

Class XMLEncr.DivideWS Extends %SOAP.WebService
{

Parameter SECURITYIN = "REQUIRE";

Parameter SERVICENAME = "XMLEncryptionDemo";

Parameter NAMESPACE = "http://www.myapp.org";

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

Method EncryptBody()
{
  //Retrieve X.509 certificate from the signature of the inbound request
  Set clientsig = ..SecurityIn.Signature
  Set clientcred = clientsig.X509Credentials
  set bst=##class(%SOAP.Security.BinarySecurityToken).CreateX509Token(clientcred)
  do ..SecurityOut.AddSecurityElement(bst)
  
  //generate a symmetric key, encrypt that with the public key of
  //the certificate contained in the token, and create an 
  //<EncryptedKey> element with a direct reference to the token (default)
  Set enc=##class(%XML.Security.EncryptedKey).CreateX509(bst)
  
  //add the <EncryptedKey> element to the security header
  Do ..SecurityOut.AddSecurityElement(enc)
}

///  Create our own method to produce application specific SOAP faults.
Method ApplicationError(detail As %String)
{
    //details omitted
}

}

This 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">
            <BinarySecurityToken wsu:Id="SecurityToken-4EC1997A-AD6B-48E3-9E91-8D50C8EA3B53" 
                                 EncodingType="[parts omitted]#Base64Binary" 
                                 ValueType="[parts omitted]#X509v3">
                         MIICnDCCAYQ[parts omitted]ngHKNhh
            </BinarySecurityToken>
            <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
               <EncryptionMethod Algorithm="[parts omitted]xmlenc#rsa-oaep-mgf1p">
                  <DigestMethod xmlns="http://www.w3.org/2000/09/xmldsig#" 
                                Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">
               </DigestMethod>
               </EncryptionMethod>
               <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
                  <SecurityTokenReference 
                        xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
                     <Reference URI="#SecurityToken-4EC1997A-AD6B-48E3-9E91-8D50C8EA3B53" 
                                ValueType="[parts omitted]#X509v3"></Reference>
                  </SecurityTokenReference>
               </KeyInfo>
               <CipherData>
                  <CipherValue>WtE[parts omitted]bSyvg==</CipherValue>
               </CipherData>
               <ReferenceList>
                  <DataReference URI="#Enc-143BBBAA-B75D-49EB-86AC-B414D818109F"></DataReference>
               </ReferenceList>
            </EncryptedKey>
         </Security>  
      </SOAP-ENV:Header>  
      <SOAP-ENV:Body>
         <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" 
                        Id="Enc-143BBBAA-B75D-49EB-86AC-B414D818109F" 
                        Type="http://www.w3.org/2001/04/xmlenc#Content">
            <EncryptionMethod Algorithm="[parts omitted]#aes128-cbc"></EncryptionMethod>
            <CipherData>
               <CipherValue>MLwR6hvKE0gon[parts omitted]8njiQ==</CipherValue>
            </CipherData>
         </EncryptedData>
      </SOAP-ENV:Body>
   </SOAP-ENV:Envelope>

Specifying the Block Encryption Algorithm

By default, the message itself is encrypted with $$$SOAPWSaes128cbc. You can specify a different algorithm. To do so, set the Algorithm property of your instance of %XML.Security.EncryptedKeyOpens in a new tab.

Possible values are $$$SOAPWSaes128cbc (the default), $$$SOAPWSaes192cbc and $$$SOAPWSaes256cbc

For example:

 set enckey.Algorithm=$$$SOAPWSaes256cbc

This information is also applicable when you create an <EncryptedKey> in other scenarios, as described elsewhere.

Specifying the Key Transport Algorithm

The key transport algorithm is the public key encryption algorithm used for the symmetric keys (see https://www.w3.org/TR/xmlenc-core/Opens in a new tab). By default, this is $$$SOAPWSrsaoaep. You can instead use $$$SOAPWSrsa15. To do so, call the SetEncryptionMethod() method of your instance of %XML.Security.EncryptedKeyOpens in a new tab, created in the previous step. The argument to this method can be either $$$SOAPWSrsaoaep (the default) or $$$SOAPWSrsa15

For example:

 do enckey.SetEncryptionMethod($$$SOAPWSrsa15)

This information is also applicable when you create an <EncryptedKey> in other scenarios, as described elsewhere.

FeedbackOpens in a new tab