SAP Cloud Integration (CPI) offers easy to use iFlow steps to secure messages with encryption or signing. But how to decrypt a message outside of CPI?
For your convenience, this blog post helps to make OpenSSL work together with CPI.
With other words it shows which commands to use in OpenSSL to process messages encrypted in CPI, etc

Example:
We encrypt a message in CPI, then send it to an SFTP receiver.
So what to do with such a unreadable file, in order to make it readable?
Solution:
Follow this blog post to decrypt it with OpenSSL

Note that there are no explanations here, as everything was explained in previous blog posts.
This blog posts rather serves as reference for OpenSSL commands, prepared for CPI.

Following scenarios are covered:
Encryption
encrypt in CPI with PKCS #7 / CMS Encryptor and decrypt with OpenSSL
encrypt locally with OpenSSL and decrypt in CPI with PKCS #7 / CMS Decryptor
Digital Signature
sign in CPI with PKCS #7 / CMS Signer and verify with OpenSSL
sign with OpenSSL and verify in CPI with PKCS #7 / CMS Verifyer

Content

Prerequisites
Preparation
Key Pair
Encryption
Encrypt in CPI and decrypt with OpenSSL
Encrypt with OpenSSL and decrypt in CPI
Digital Signature
Sign in CPi and verify with OpenSSL
Sign with OpenSSL and verify with CPI
View CMS Structure

Prerequisites

To understand what’s happening and to prepare Integration Flows, please refer to my previous blog posts:

Understanding the PKCS #7 / CMS standard
Understanding the PKCS #7 / CMS Encryptor
Understanding the PKCS #7 / CMS Signer

And refer to this glossary if any piece of info is missing.

Preparation

To follow this tutorial, we need OpenSSL and access to a CPI tenant.

Install OpenSSL

OpenSSL is the most commonly used tool (and library) for security-related operations, dealing with certificates, keys, converting, etc etc
Basically, it consists of libraries (for “c”) and a command line tool.

If you have GIT installed, you can just open the git bash which contains openssl.
Otherwise, follow these instructions to install OpenSSL under Windows:

Download openssl starting from here.
Afterwards it might be required to add the openssl.exe to the PATH.
If you get this error:
Unable to load config info from /usr/local/ssl/openssl.cnf
You need to set an environment variable.
e.g. on command line:

set OPENSSL_CONF=c:/tools/openssl/openssl.cfg

Note:
For windows, the config-file extension .cnf has to be adjusted to .cfg
A template .cnf file can be found in GIT installation folder.

Create iFlow
For the CPI part of the tutorial, we create very simple iFlows, with the goal to avoid specific prerequisites like SFTP server.
As such. our iFlows take some hard-coded input in a Content Modifier, perform the cryptographic operations and write the result into a data store.
Detailed description can be found here.

Key Pair

For the cryptographic operations, we need a key pair, including certificate.
As we need it in both environments (CPI and locally), we generate it with OpenSSL and upload it to the CPI Keystore (instead of generating it in CPI).

1. Create key pair and certificate

Below req command creates a key pair and a self-signed certificate in one step.

openssl req -x509 -newkey rsa -nodes -keyout privkey.pem -out cert.pem -subj “/CN=myowncert”

Note:
When copy- and pasting the command under windows, it might be required to clean the formatted quotation marks.

Info:
The req command is typically used for CSRs (certificate signing requests) according to PKCS #10, but it supports parameters for generating certificates as well.
-x509 this flag is responsible for generating a certificate.
-newkey generates a private key with algorithm “RSA”. We don’t specify the key size here, we can rely on the default, which is 2048.
-nodes not encrypt the private key.
-out the name of the generated certificate. The file extension can be chosen as of our taste.
-subj here we can pass the attributes of the certificate, like CN (common name) in our example. Other attributes may be specified here, but we leave them, to make it more simple.

Optional: view content of certificate

Below x509 command prints the content of the certificate:

openssl x509 -text -in cert.pem

The x509 command is used for certificate operations.
Above command prints the content of the specified file.
We can see e.g. the “Common Name” that we’ve specified above.

2. Create p12/pfx file

We need a container to upload both private key and certificate to CPI keystore.

The reason is:
As we’re using both Encryptor and Signer, we also need both, private key and certificate (which includes the public key)
For the Encryptor, it would be enough to upload the certificate via “Add->Certificate” only.

To create a container, we use the pkcs12 command of OpenSSL.
The pkcs#12 standard defines a binary format to store certificates (etc), protected with password and thus suitable for import/export.

openssl pkcs12 -export -out myownstore.p12 -inkey privkey.pem -in cert.pem -passout pass:abcd

Info:
The pkcs12 command uses 2 input parameters to specify the certificate and private key that should be stored in the .p12 result file.
-export is used to generate a .p12 file (instead of operating on an existing one).
-passout allows us to specify a password, as the PKCS #12 standard supports password to protect the stored private key.
-out we specify the result file with the usual .p12 file extension. Another frequent file extension would be .pfx.

Optional: view content of p12 file

We can use below command to view the certificate and private key stored in the .p12 file.
Below command includes the private key and writes the required password in the console (can be passed as file as well)

openssl pkcs12 -in myownstore.p12 -info -nodes -passin pass:abcd

Info:
-info prints the contained encoded certificate and private key.
-nodes to view the private key unencrypted.

3. Upload to CPI Keystore

In your CPI dashboard, go to “Monitoring” -> “Keystore” and choose “Add”->”Keystore”.
Browse for the .p12 file and enter the password, as provided in the command: “abcd”.
CPI displays a warning, because it couldn’t find a trusted CA in the certificate chain.
As we’ve self-signed our certificate during test phase, this is ok for us.
Remember the Alias name (“myownstore”) for later use.

Encryption

When talking about “encryption”, we have to understand that the CPI Encryptor processes messages based on the CMS standard. Such a message can only be decrypted with a tool that supports CMS.
Reason:
The CMS standard describes a “hybrid” approach: the content is encrypted with symmetric key, generated on the fly, and the key is afterwards encrypted with asymmetric key.
As such, tools or libraries for “normal” encryption cannot be used in conjunction with CPI.
To be more precise: only the CMS-type “EnvelopedData” is supported by both CPI and OpenSSL.

Note:
Other encryption option in CPI, the PGP Encryptor, is currently not in scope of this blog post.

Encrypt in CPI and decrypt with OpenSSL

We create an iFlow with the following elements:

  • Start Timer set to “Run Once”.
  • Content Modifier with some arbitrary text in the Message Body.
  • PKCS #7 / CNS Encryptor with “myownstore” as Public Key Alias and default settings (“Enveloped Data Only”, no “Base64”).
  • Datastore Write Operation with an arbitrary name.

After deploy and successful execution of the iFlow, we download the encrypted message from the Datastore.
We extract the “body” file of the zip into the same folder that contains our certificate and private key.

To decrypt, we use the cms command of OpenSSL, which implements the CMS standard.
(same standard as used by CPI).

The cms  command requires the private key to decrypt a content that was encrypted with the corresponding public key.
The result is written to the file specified via -out

openssl cms -decrypt -in body -out decrypted.txt -inkey privkey.pem -inform DER

Info:
The -inform DER parameter is required, because we’re decrypting a binary file, not base64 encoded.
Alternatively, the PEM and SMIME formats for input are supported.

Result:
We can see the plaintext content of the message in the decrypted.txt file.

Note about the formats:
There are 3 options to use with the cms -decrypt command and that can be passed via -inform  parameter.
The format must match the format of the given encrypted input file.
These are the 3 formats supported by OpenSSL:

1. SMIME
The default format for en/decryption with openssl cms command is SMIME (no -inform param required).
This format contains a MIME-header like this:

MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64

The content can be encrypted or base64-encoded.

If we want to decrypt a CPI-message with a tool that supports only SMIME format, we could manually add this header, as a workaround.
Note: blank line is required after header
Note: if payload is binary, make sure to use header without transfer-encoding set to base64

2. PEM
This format can be set with -inform PEM during decryption.
Prerequisite:
In CPI iFlow, the base64 flag must be enabled for the Encryptor.
Decrypting binary format with -inform PEM doesn’t work, according to the PEM spec.
However, if your decryption tool supports only PEM, there’s again a simple workaround:
Manually add BEGIN and END at beginning and end, like this:

-----BEGIN CMS-----
MIAGCSqGSIb3DQEHA6CAMIIBkQIBADGCATwwggE4AgEAMCAwE . . .
-----END CMS-----

 

3. DER
If we use the parameter -inform DER to decrypt a message received from CPI, then no workaround is required, as shown above.
Prerequisite:
In CPI iFlow, the base64 flag must not be enabled for he Encryptor.

Encrypt with OpenSSL and decrypt in CPI

In this chapter we encrypt a text file locally with OpenSSL on command line.
Then we decrypt it in CPI with the PKCS #7 / CMS Decryptor.

First of all, we create a text file with name orig.txt and arbitrary plaintext content.
Then we encrypt it with the cms command and -encrypt operation option:

openssl cms -encrypt -aes256 -outform DER -in orig.txt -out encry.enc cert.pem

Info:
The command takes an input file with the original plaintext content.
It writes the CMS-based encrypted message to the output file.
The operation is done according to the CMS type EnvelopedData.

-aes256 the algorithm to use for (symmetric) encryption.
-outform this param is used to specify one of the 3 formats. We choose DER, which is used in CPI.
cert.pem the certificate with public key to be used for (asymmetric) encryption.

Note:
The result is a binary file that could be understood by the CPI decryptor.
This file could be copied to an SFTP server used as sender in CPI.
However, our iFlow is as simple as possible, to enable users who don’t have an SFTP server.
So we manually copy and paste our encrypted file into the iFlow.
There’s just a little problem with this approach: we cannot copy binary content into the iFlow.
The solution for this problem: base64 encoding.
Although there are workarounds like using different output format, we’re happy to add this step for our learning.

The enc command of OpenSSL is simple, it takes a binary input file and writes the base64-encoded result to the -out file:

openssl enc -base64 -in encry.enc -out encry.b64

Info:

-base64 specifies the encoding for the enc command.

Result:
The encrypted file is now base64 encoded and can be easily processed further.

Design Integration Flow

We create an iFlow with the following elements:

  • Start Timer set to “Run Once”.
  • Content Modifier: we copy the content of encry.b64 into in the Message Body.
  • PKCS #7 / CNS Decryptor with “Enveloped Data Only” and with “Base64” enabled.
  • Datastore Write Operation with an arbitrary name.

After deploy, we download the decrypted message from Datastore and view our plaintext content in the “body”.

Digital Signature

When talking about “digital signature”, we have to understand that the CPI Signer processes messages based on the CMS standard. Such a message can only be verified with a tool that supports CMS.
To be more precise: only the CMS-type SignedData is supported by CPI PKCS #7 / CMS Signer (and Verifier).

Note:
Other signing options in CPI are currently not in scope of this blog post.

Sign in CPi and verify with OpenSSL

In this chapter we’re creating the CMS-based Signature in an iFlow in CPI, then we verify it locally with OpenSSL.

We create an iFlow with the following elements:

  • Start Timer set to “Run Once”.
  • Content Modifier with some arbitrary text in the Message Body.
  • PKCS #7 / CNS Signer with “myownstore” as Private Key Alias and default settings,  “include…” is enabled, “Base64” not enabled.
  • Datastore Write Operation with an arbitrary name.

After deploy and successful execution of the iFlow, we download the message from Datastore.
We extract the “body” file of the zip into the same folder that contains our certificate and private key.

To verify, we use the cms command of OpenSSL, which implements the CMS standard.

openssl cms -verify -noverify -inform DER -in body -out verified

Info:
-inform this option is required because CPI writes binary file (not the default SMIME format).
-noverify this option is required, because we’re using a self-signed certificate.

Note:
The command doesn’t require certificate, because we configured the Signer in CPI to include it in the message.

Result:
Success message is printed to the console.
The output file specified above contains the original plaintext message content.
It has been verified by OpenSSL, so we can rely on the fact that the content is correct and has not been altered by any hacker.

Sign with OpenSSL and verify with CPI

In this chapter we create a digital signature of a text file with OpenSSL.
Then we verify it in CPI with PKCS #7 / CMS Verifier.

First of all, we create a text file with name orig.txt and arbitrary plaintext content.
Then we sign it with the cms command and -sign operation option:

openssl cms -sign -outform DER -signer cert.pem -inkey privkey.pem -in orig.txt -out signature.enc

Info:
The command creates a CMS-based digital signature using the given private key.
It adds the certificate to the CMS-package.
-outform DER the generated signature file needs to be in DER form, to be understood by CPI.

Result:
This creates an external digital signature, without the content.
With other words, we’re operating on a so-called “Detached Mode”

Note:
Again, we need to base64-encode the generated binary file, such that we can copy it into the content modifier in the iFlow.

openssl enc -base64 -in signature.enc -out signature.b64

Design Integration Flow

We create an iFlow with Verifier and configure it for “Detached Mode”.
Means, the Verifier expects that
– the actual content of the message is in the body.
– the CMS-package with the “external Signature” is contained in the special exchange property with name SapCmsSignedData

In our case, we try to simulate a real scenario with our simple iFlow.
We copy the base64-encoded CMS-package into the Message Body of a Content Modifier.
So afterwards, we have to move it to the special Exchange Property, in a second Content Modifier.
The original content from orig.txt is copied into the Message Body of the second Content Modifier.

So we create an iFlow as follows:

  • Start Timer set to “Run Once”.
  • 1st Content Modifier:
    We copy the content of signature.b64 into in the Message Body.
  • 2nd Content Modifier:
    We create an Exchange Property with following info:
    Name: “SapCmsSignedData”
    Source Type: “Expression”
    Value: “${in.body}”
    This has the effect of moving the previous Message Body (the signature) into it.
    Finally, we manually copy the content of orig.txt into in the Message Body.
  • PKCS #7 / CNS Verifier with Public key as “myownstore” and “Header is Base64” enabled.
    Make sure that “Body is Base64” is NOT enabled.
  • Datastore Write Operation with an arbitrary name.

After deploy, we download the verified message from Datastore and view our plaintext content in the “body”.

View CMS Structure

Some of the OpenSSL cms commands support viewing the structure of the generated CMS package.
This is interesting to understand the CMS standard and mechanism.
So let’s view it.

As an example, we encrypt a file with OpenSSL.
Then we decrypt it with OpenSSL.
Then we print the CMS-structure while decrypting.

First step: encrypt our existing orig file:

openssl cms -encrypt -aes256 -outform DER -in orig.txt -out encry.enc cert.pem

Second step: optionally run the normal decrypt command, just to remember:

openssl cms -decrypt -in encry.enc -out decrypted.txt -inkey privkey.pem -inform DER

Third step: Add the 2 required options to view the structure of the encrypted input file:

openssl cms -decrypt -in encry.enc -out cmsStructure.txt -inkey privkey.pem -inform DER -cmsout -print

Summary

In this blog post we’ve learned that the CMS-based iFlow steps can seamlessly work in conjunction with open-source tools like OpenSSL.
We’ve learned which configuration settings are required on both sides, CPI and OpenSSL, to make them work together.
We’ve also learned how to use the “detached mode” of the CMS-based signing (datatype “SignedData”).

Links

Blogs on the cryptographic support of CPI:
Understanding the PKCS #7 / CMS standard
Understanding the PKCS #7 / CMS Encryptor
Understanding the PKCS #7 / CMS Signer
And the Security Glossary Blog.

OpenSSL
Official list of unofficial binaries download page
Docu home
Manual: https://www.openssl.org/docs/manmaster/man1/
cms: https://www.openssl.org/docs/manmaster/man1/openssl-cms.html
req: https://www.openssl.org/docs/manmaster/man1/openssl-req.html
pkcs12: https://www.openssl.org/docs/manmaster/man1/openssl-pkcs12.html
x509: https://www.openssl.org/docs/manmaster/man1/openssl-x509.html

SAP Help Portal
Docu for PKCS#7/CMS Encryptor
Docu for PCKS#7/CMS Signer
Docu for Message-Level Security

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x