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