Skip to main content

Using Derived Key Tokens for Encryption and Signing

InterSystems IRIS supports the <DerivedKeyToken> element as defined by WS-SecureConversation 1.4. You can create and use the <DerivedKeyToken> element for encryption and signing, as an alternative to the approaches described in the previous three topics.

Typically you perform both encryption and signing. This topic describes these tasks separately, for simplicity. For information on combining encryption and signing, see Combining Encryption and Signing.

Overview

The <DerivedKeyToken> element is intended to carry information that the sender and the recipient can independently use to generate the same symmetric key. These parties can use that symmetric key to encrypt, sign, or perform both actions on the indicated parts of the SOAP message.

To generate and use a <DerivedKeyToken>, you do the following:

  1. You generate a symmetric key for temporary use.

  2. You encrypt the symmetric key with the public key of the entity to whom you are sending the message. This creates an <EncryptedKey> element.

    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.

  3. You compute a new symmetric key from the original symmetric key, via the P_SHA1 algorithm.

    This creates an <DerivedKeyToken> element that refers to the <EncryptedKey> element.

  4. You use the new symmetric key to encrypt or sign.

    It is considered good practice to use different symmetric key for these activities, so that there is minimal data for analysis.

  5. You include the <EncryptedKey> element and the <DerivedKeyToken> in the message.

In InterSystems IRIS, a derived key token could also be based on another derived key token.

Creating and Adding a <DerivedKeyToken>

For reference, this section describes a common activity needed in later sections. It describes how to create a <DerivedKeyToken> and add it to the WS-Security header. You can use the following procedure or the variations described in the subsections.

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

  2. Obtain the credential set of the entity to whom you are sending the message. See Retrieving Credential Sets Programmatically.

    For example:

     Set x509alias = "servernopassword" 
     Set credset = ##class(%SYS.X509Credentials).GetByAlias(x509alias)
    
  3. Create an encrypted key based on the credential set. To do so, call the CreateX509() class method of %XML.Security.EncryptedKeyOpens in a new tab and specify the second argument as $$$SOAPWSEncryptNone. For example:

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

    This method generates a symmetric key 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 credential set.

    When you create an encrypted key to use as a basis for a derived key, always specify $$$SOAPWSEncryptNone or "" as the second argument for CreateX509().

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

  5. 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)
  6. Create the derived key token based on the encrypted key. To do so, call the Create() method of %SOAP.WSSC.DerivedKeyTokenOpens in a new tab. This method takes two arguments:

    1. The encrypted key to use as a basis.

    2. A reference option that specifies how the derived key refers to that encrypted key. In this basic procedure, use $$$SOAPWSReferenceEncryptedKey

    For example:

     set refopt=$$$SOAPWSReferenceEncryptedKey
     set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(enckey,refopt)

    This method returns an instance of %SOAP.WSSC.DerivedKeyTokenOpens in a new tab that represents the <DerivedKeyToken> element.

  7. Add the <DerivedKeyToken> 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 %SOAP.WSSC.DerivedKeyTokenOpens in a new tab.

    For example:

     do ..SecurityOut.AddSecurityElement(dkenc)
  8. Send the SOAP message. See the general comments in Adding Security Header Elements.

Variation: Creating an Implied <DerivedKeyToken>

You can also create an implied <DerivedKeyToken>, which is a shortcut technique for referencing a <DerivedKeyToken>. In this technique:

  • The <DerivedKeyToken> is not included in the message.

  • Within the element that uses the <DerivedKeyToken>, the <SecurityTokenReference> element specifies the Nonce attribute, which contains the value of the nonce used for the <DerivedKeyToken>. This indicates to the message recipient that the derived key token is implied and is derived from the referenced token.

To create an implied <DerivedKeyToken>, use the general procedure described previously, with two changes:

  1. Set the Implied property to 1, for the derived key token instance.

    For example:

     set dkt.Implied=1
  2. Do not add the <DerivedKeyToken> element to the WS-Security header element.

Use the <DerivedKeyToken> in exactly the same way as if you had included it in the message.

Variation: Referencing the SHA1 Hash of an <EncryptedKey>

In this variation (available only on the web service), the sender does not include the <EncryptedKey> element in the message but instead references the SHA1 hash of the key. The web service can reference an <EncryptedKey> element received in the inbound message.

Use the preceding general procedure, with the following changes:

  • Steps 2–4 are optional.

  • Omit step 5 (do not add the <EncryptedKey>).

  • In step 6, when you use Create() to create the derived key token, to use the <EncryptedKey> received from the client, omit the first argument. Or, if you have created an <EncryptedKey>, use that as the first argument.

    Specify $$$SOAPWSReferenceEncryptedKeySHA1 for the second argument.

    For example, to use the first <EncryptedKey> element in the message received from the web client:

     set refopt=$$$SOAPWSReferenceEncryptedKeySHA1
     set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(,refopt)

Using a <DerivedKeyToken> for Encryption

To use a <DerivedKeyToken> for encryption, use the following procedure:

  1. If you want to encrypt one or more security header elements, create those security header elements.

  2. Create the <DerivedKeyToken> and add it to the WS-Security header, as described in Creating and Adding a <DerivedKeyToken.

    Note that this step also creates and adds the <EncryptedKey> element on which the <DerivedKeyToken> is based.

  3. For each element that you want to encrypt, create an <EncryptedData> element based on the element. To do so, call the Create() class method of %XML.Security.EncryptedDataOpens in a new tab. In this procedure, specify the following arguments:

    1. The derived key token.

    2. The item to encrypt. Omit this argument to encrypt the body.

    3. A macro that specifies how the <EncryptedData> element refers to the <DerivedKeyToken>. In this scenario, the only currently supported value is $$$SOAPWSReferenceDerivedKey.

    For example, to encrypt the <UsernameToken>:

     set refopt=$$$SOAPWSReferenceDerivedKey
     set encryptedData=##class(%XML.Security.EncryptedData).Create(dkenc,userToken,refopt) 

    Or, to encrypt the body:

     set refopt=$$$SOAPWSReferenceDerivedKey
     set encryptedData=##class(%XML.Security.EncryptedData).Create(dkenc,,refopt) 
  4. Create a <ReferenceList> element. To do so, call the %New() method of the %XML.Security.ReferenceListOpens in a new tab class. For example:

     set reflist=##class(%XML.Security.ReferenceList).%New() 
  5. Within this <ReferenceList>, create a <ReferenceList> that points to the <EncryptedData> elements. To do so, do the following for each <EncryptedData>:

    1. Call the Create() class method of %XML.Security.DataReferenceOpens in a new tab and specify the encrypted data instance as the argument. This method returns an instance of %XML.Security.DataReferenceOpens in a new tab.

    2. Call the AddReference() method of your reference list instance and specify the data reference instance as the argument.

    For example:

     set dataref=##class(%XML.Security.DataReference).Create(encdata)
     do reflist.AddReference(dataref)
     set dataref2=##class(%XML.Security.DataReference).Create(encdata2)
     do reflist.AddReference(dataref2)
  6. Add the <ReferenceList> 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 reference list instance.

    For example:

     do ..SecurityOut.AddSecurityElement(reflist)
  7. If you encrypted any security header elements, add them to the WS-Security header element. To do so, call the AddSecurityElement() method of the SecurityOut property of your web client or web service. In this case, two arguments are required:

    1. The security header element (not the %XML.Security.EncryptedDataOpens in a new tab that you generated from it).

    2. The reference list instance. The second argument specifies where to place the item specified by the first argument. If the arguments are A,B, then InterSystems IRIS ensures that A is after B. You specify this so that the recipient processes the reference list first and later processes the encrypted security header element that depends on it.

    For example:

     do client.SecurityOut.AddSecurityElement(userToken,reflist)

    If you encrypted only the SOAP body, the system automatically includes an <EncryptedData> element as the child of <Body>.

  8. Send the SOAP message. See the general comments in Adding Security Header Elements.

For example, the following client-side code encrypts both the SOAP body and the <UsernameToken>:

  // Create UsernameToken
  set userToken=##class(%SOAP.Security.UsernameToken).Create("_SYSTEM","SYS")
 
  // get credentials for encryption
  set cred = ##class(%SYS.X509Credentials).GetByAlias("servercred") 

  // get EncryptedKey element to encrypt <UsernameToken)
  // $$$SOAPWSEncryptNone means that this key does not encrypt the body
  set enckey=##class(%XML.Security.EncryptedKey).CreateX509(cred,$$$SOAPWSEncryptNone)
  //add to WS-Security Header
  do client.SecurityOut.AddSecurityElement(enckey)

  // get derived key to use for encryption
  // second argument specifies how the derived key 
  // refers to the key on which it is based
  set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(enckey,
     $$$SOAPWSReferenceEncryptedKey)
  //add to WS-Security Header
  do client.SecurityOut.AddSecurityElement(dkenc)
  
  // create <EncryptedData> element to contain <UserToken>
  set encdata=##class(%XML.Security.EncryptedData).Create(dkenc,userToken,
     $$$SOAPWSReferenceDerivedKey)
  
  // create <EncryptedData> element to contain SOAP body
  set encdata2=##class(%XML.Security.EncryptedData).Create(dkenc,"",
     $$$SOAPWSReferenceDerivedKey)

  // create <ReferenceList> with <DataReference> elements that
  // point to these two <EncryptedData> elements
  set reflist=##class(%XML.Security.ReferenceList).%New()
  set dataref=##class(%XML.Security.DataReference).Create(encdata)
  do reflist.AddReference(dataref)
  set dataref2=##class(%XML.Security.DataReference).Create(encdata2)
  do reflist.AddReference(dataref2)

  // add <ReferenceList> to WS-Security header
  do client.SecurityOut.AddSecurityElement(reflist)
  // add encrypted <UserName> to security header;
  // 2nd argument specifies position
  do client.SecurityOut.AddSecurityElement(userToken,reflist)

  // encrypted SOAP body is handled automatically

The client sends 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">
      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#" 
                  Id="Id-658202BF-239A-4A8C-A100-BB25579F366B">
        <EncryptionMethod Algorithm="[parts omitted]#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">
            <KeyIdentifier EncodingType="[parts omitted]#Base64Binary" 
                           ValueType="[parts omitted]#ThumbprintSHA1">5afOHv1w7WSXwDyz6F3WdM1r6cM=
            </KeyIdentifier>
          </SecurityTokenReference>
        </KeyInfo>
        <CipherData>
          <CipherValue>tFeKrZKw[parts omitted]r+bx7KQ==</CipherValue>
        </CipherData>
      </EncryptedKey>
      <DerivedKeyToken xmlns="[parts omitted]ws-secureconversation/200512" 
                    xmlns:wsc="[parts omitted]ws-secureconversation/200512" 
                    wsu:Id="Enc-943C6673-E3F3-48E4-AA24-A7F82CCF6511">
        <SecurityTokenReference xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
           <Reference URI="#Id-658202BF-239A-4A8C-A100-BB25579F366B"></Reference>
        </SecurityTokenReference>
        <Nonce>GbjRvVNrPtHs0zo/w9Ne0w==</Nonce>
      </DerivedKeyToken>
      <ReferenceList xmlns="http://www.w3.org/2001/04/xmlenc#">
        <DataReference URI="#Enc-358FB189-81B3-465D-AFEC-BC28A92B179C"></DataReference>
        <DataReference URI="#Enc-9EF5CCE4-CF43-407F-921D-931B5159672D"></DataReference>
      </ReferenceList>
      <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" 
                  Id="Enc-358FB189-81B3-465D-AFEC-BC28A92B179C" 
                  Type="http://www.w3.org/2001/04/xmlenc#Element">
        <EncryptionMethod Algorithm="[parts omitted]#aes256-cbc"></EncryptionMethod>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
           <SecurityTokenReference xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <Reference URI="#Enc-943C6673-E3F3-48E4-AA24-A7F82CCF6511"></Reference>
           </SecurityTokenReference>
        </KeyInfo>
        <CipherData>
          <CipherValue>e4//6aWGqo1dIQ7ZAF[parts omitted]KZcj99N78A==</CipherValue>
        </CipherData>
      </EncryptedData>
    </Security>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" 
                   Id="Enc-9EF5CCE4-CF43-407F-921D-931B5159672D" 
                   Type="http://www.w3.org/2001/04/xmlenc#Content">
        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc">
        </EncryptionMethod>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <SecurityTokenReference xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <Reference URI="#Enc-943C6673-E3F3-48E4-AA24-A7F82CCF6511"></Reference>
          </SecurityTokenReference>
        </KeyInfo>
        <CipherData>
          <CipherValue>Q3XxuNjSan[parts omitted]x9AD7brM4</CipherValue>
        </CipherData>
    </EncryptedData>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

For another example, the following web service receives an <EncryptedKey> in the inbound message and uses it to generate a <DerivedKeyToken> that it uses to encrypt parts of the response:

  // create <DerivedKeyToken> based on first <EncryptedKey> in inbound message;
  // refer to it with SHA1 thumbprint
  set refopt=$$$SOAPWSReferenceEncryptedKeySHA1
  set dkenc=##class(%SOAP.WSSC.DerivedKeyToken).Create(,refopt)
  do ..SecurityOut.AddSecurityElement(dkenc)
  
  // create <EncryptedData> element to contain SOAP body
  set encdata=##class(%XML.Security.EncryptedData).Create(dkenc,"",
     $$$SOAPWSReferenceDerivedKey)
  
  // create <ReferenceList> with <DataReference> elements that
  // point to the <EncryptedData> elements
  set reflist=##class(%XML.Security.ReferenceList).%New()
  set dataref=##class(%XML.Security.DataReference).Create(encdata)
  do reflist.AddReference(dataref)

  // add <ReferenceList> to WS-Security header
  do ..SecurityOut.AddSecurityElement(reflist)

This web service sends messages like the following:

<SOAP-ENV:Envelope [parts omitted]>  
   <SOAP-ENV:Header>
      <Security xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
         <DerivedKeyToken xmlns="[parts omitted]ws-secureconversation/200512" 
                          xmlns:wsc="[parts omitted]ws-secureconversation/200512" 
                          wsu:Id="Enc-D69085A9-9608-472D-85F3-44031586AB35">
            <SecurityTokenReference xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd" 
                               s01:TokenType="[parts omitted]#EncryptedKey" 
                               xmlns:s01="h[parts omitted]oasis-wss-wssecurity-secext-1.1.xsd">
               <KeyIdentifier EncodingType="[parts omitted]#Base64Binary" 
                              [parts omitted]#EncryptedKeySHA1">
                     U8CEWXdUPsIk/r8JT+2KdwU/gSw=
               </KeyIdentifier>
            </SecurityTokenReference>
            <Nonce>nJWyIJUcXXLd4k1tbNg10w==</Nonce>
         </DerivedKeyToken>
         <ReferenceList xmlns="http://www.w3.org/2001/04/xmlenc#">
            <DataReference URI="#Enc-0FF09175-B594-4198-9850-57D40EB66DC3"></DataReference>
         </ReferenceList>
      </Security>  
   </SOAP-ENV:Header>  
   <SOAP-ENV:Body>
      <EncryptedData xmlns="http://www.w3.org/2001/04/xmlenc#" 
                     Id="Enc-0FF09175-B594-4198-9850-57D40EB66DC3" 
                     Type="http://www.w3.org/2001/04/xmlenc#Content">
         <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc">
         </EncryptionMethod>
         <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SecurityTokenReference xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
               <Reference URI="#Enc-D69085A9-9608-472D-85F3-44031586AB35"></Reference>
            </SecurityTokenReference>
         </KeyInfo>
         <CipherData>
            <CipherValue>NzI94WnuQU4uBO[parts omitted]xHZpJSA==</CipherValue>
         </CipherData>
      </EncryptedData>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Using a <DerivedKeyToken> for Signing

To use a <DerivedKeyToken> for signing, use the following procedure:

  1. If you want to sign any security header elements, create those security header elements.

  2. Create the <DerivedKeyToken> and add it to the WS-Security header, as described in Creating and Adding a <DerivedKeyToken>.

    Note that this step also creates and adds the <EncryptedKey> element on which the <DerivedKeyToken> is based.

  3. Create the <Signature> element based on the derived key token. To do so, call the Create() class method of %XML.Security.SignatureOpens in a new tab. For example:

     set dsig=##class(%XML.Security.Signature).Create(dkt)

    This method returns an instance of %XML.Security.SignatureOpens in a new tab that represents the <Signature> header element. The signature value is computed via the HMAC-SHA1 digest algorithm, using the symmetric key implied by the <DerivedKeyToken>.

    The <Signature> element applies to a default set of parts of the message; you can specify a different set of parts.

  4. 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)

For example, the following client-side code signs the SOAP body:

 // get credentials
 set cred = ##class(%SYS.X509Credentials).GetByAlias("servercred") 

 // get EncryptedKey element that does not encrypt the body
 set enckey=##class(%XML.Security.EncryptedKey).CreateX509(cred,$$$SOAPWSEncryptNone)
 //add to WS-Security Header
 do client.SecurityOut.AddSecurityElement(enckey)

 // get derived key & add to header
 set dksig=##class(%SOAP.WSSC.DerivedKeyToken).Create(enckey,$$$SOAPWSReferenceEncryptedKey)
 //add to WS-Security Header
 do client.SecurityOut.AddSecurityElement(dksig)

 // create a signature and add it to the security header 
 set sig=##class(%XML.Security.Signature).Create(dksig,,$$$SOAPWSReferenceDerivedKey)
 do client.SecurityOut.AddSecurityElement(sig)

The client sends 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">
      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#" 
                   Id="Id-6188CA15-22BF-41EB-98B1-C86D4B242C9F">
        <EncryptionMethod Algorithm="[parts omitted]#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">
            <KeyIdentifier EncodingType="[parts omitted]#Base64Binary" 
                           ValueType="[parts omitted]#ThumbprintSHA1">5afOHv1w7WSXwDyz6F3WdM1r6cM=
            </KeyIdentifier>
          </SecurityTokenReference>
        </KeyInfo>
        <CipherData>
          <CipherValue>VKyyi[parts omitted]gMVfayVYxA==</CipherValue>
          </CipherData>
      </EncryptedKey>
      <DerivedKeyToken xmlns="[parts omitted]ws-secureconversation/200512" 
                       xmlns:wsc=[parts omitted]ws-secureconversation/200512" 
                       wsu:Id="Enc-BACCE807-DB34-46AB-A9B8-42D05D0D1FFD">
        <SecurityTokenReference 
             xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
           <Reference URI="#Id-6188CA15-22BF-41EB-98B1-C86D4B242C9F"></Reference>
        </SecurityTokenReference>
        <Offset>0</Offset>
        <Length>24</Length>
        <Nonce>IgSfZJ1jje710zadbPXf1Q==</Nonce>
      </DerivedKeyToken>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
          <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
          </CanonicalizationMethod>
          <SignatureMethod Algorithm="[parts omitted]#hmac-sha1"></SignatureMethod>
          <Reference URI="#Body-B08978B3-8BE8-4365-A352-1934D7C33D2D">
             <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>56gxpK1mSVW7DN5LUYRvqDbMt0s=</DigestValue>
           </Reference>
        </SignedInfo>
        <SignatureValue>aY4dKX17zDS2SF+BXlVTHcEituc=</SignatureValue>
        <KeyInfo>
          <SecurityTokenReference 
                xmlns="[parts omitted]oasis-200401-wss-wssecurity-secext-1.0.xsd">
              <Reference URI="#Enc-BACCE807-DB34-46AB-A9B8-42D05D0D1FFD"></Reference>
          </SecurityTokenReference>
        </KeyInfo>
      </Signature>
    </Security>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body wsu:Id="Body-B08978B3-8BE8-4365-A352-1934D7C33D2D">
    [omitted]
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

FeedbackOpens in a new tab