Support Article
Cannot open encrypted emails-Your digital ID cannot be found
SA-18689
Summary
Emails encrypted and sent by Pega cannot be viewed. The instructions given in the PDN article were followed. The link to the PDN article is given below.
https://pdn.pega.com/how-send-encrypted-email
The Email Recipient’s Certificate, needed to encrypt the outgoing message, is uploaded to Pega within a JKS keystore rule.
The Email Recipient has installed the corresponding Key Pair needed to decrypt the incoming email on Email Client.
The Certificate was referenced correctly in Data-Admin-Security-Keystore.pyEmailCertificateMap decision table rule.
However, there were no issues with non-encrypted emails sent by Pega.
Error Messages
The PegaRules logs display an error similar to this:
//
294 [http-bio-7170-exec-1] [ STANDARD] [ ] [ GCSAppli:01.01.01] (Admin_Security_Keystore.Action) ERROR prpc_host|xx.xx.xx.xx [email protected]gcs - getCertificate: Could not get certificate and key from keystore:
java.lang.NullPointerException
//
Microsoft Outlook displays the following error when the encrypted Email is opened:

Mozilla Thunderbird displays the following error when the encrypted Email is opened:

Steps to Reproduce
Assume that an encrypted email is sent using Pega from ‘[email protected]<mailhost>’ to ‘[email protected]<mailhost>’.
- Obtain Bob’s Certificate.
- Create a new Java Keystore File (JKS).
- Import Bob’s Certificate into the JKS file, and make a note of the Certificate Alias.
- Save the JKS, and set a password.
- Create a new Pega Keystore Rule by navigating to Create>Security>Keystore.
- Upload the JKS file to the Pega Keystore Rule, set the password, and save the rule.
- Create pyEmailCertificateMap decision table rule in Data-Admin-Security-Keystore class in a local ruleset by navigating to Create>Decision>Decision Table.
- Enter Bob’s email address under Email Address column.
- Enter the name of Pega Keystore rule under Keystore Instance column.
- Enter the name of Certificate Alias under Keystore Alias column.
- Create a Wrapper Activity to call SendEmailNotification out-of-the-box activity. Setup requires parameters for sending email from Alice to Bob (see below), and ensure EncryptMessage is checked.
- Run the Activity to send a test email.
- Log into Email Client (as Bob). The received Email Message cannot be decrypted.
Example Rule Screenshots are given below.
Root Cause
There is an issue within the Activity “Data-Admin-Security-Keystore.getCertificate|Pega-IntegrationEngine:07-10-01” : wherein the required Certificate is not returned to the calling ‘SendEmailNotification’.
There is a secondary issue in that despite the failure of the ‘getCertificate’ to obtain the certificate, the ‘SendEmailNotification’ still sends out an email – but the end-user will not be able to decrypt it.
Resolution
Perform the following local-changes:
Copy getCertificate activity to a Local unlocked Ruleset and make the following changes.



1. Add in a Debug logging statement to call out the local-change. Add SendToTracer as well.

2. Add in a WHEN/JUMP step around a Log-Message step to exit the Activity if the Keystore Name cannot be found.



Ensure Enable conditions are checked for When and Jump.
3. Create a new page, OBJ-OPEN the Keystore:
Note the presence of a Jump here, ensure it is enabled (and set up the corresponding Get label later).

4. An error handler for bad keystore:
This is jumped over by Step 3 unless there is a problem with the OBJ-OPEN.
It is a Java Step comprised of the following code, and this will terminate the Activity if the keystore cannot be opened.
---cut here---
// need to wrap the Exception throw in order for the Activity to compile
if (true)
{
throw new PRRuntimeException("Unable to open Keystore record called " + tools.getParamValue("KeystoreInstance"));
}
---cut here---
5. This step looks for the certificate in the keystore.
Ensure its label is set to Get.
The Java code is given below.
---cut here---
String keystoreFile = myStepPage.getString("pyFileSource");
String keystorePassword = myStepPage.getString("pyKeystorePassword");
final String keystoreRecordName = myStepPage.getString("pyKeystore");
final String aliasProvided = tools.getParamValue("KeystoreAlias");
String keyAlias = aliasProvided;
String certAlias = aliasProvided;
String type = myStepPage.getString("pyKeystoreType");
final ParameterPage pp = tools.getParameterPage();
// objects returned
java.security.Key myKey = null;
java.security.cert.Certificate [] certChain = null;
if (keystoreFile.length() < 1)
{
throw new PRRuntimeException("getCertificate: No Keystore has been uploaded to " + keystoreRecordName + "Keystore.");
}
byte[] buffer = Base64Util.decodeToByteArray(keystoreFile);
java.io.ByteArrayInputStream bis = new java.io.ByteArrayInputStream(buffer);
//get certificate
try
{
/// Adds the BouncyCastle provider.
// Doesn't matter if the provider has been added before, will not add duplicates
try
{
java.security.Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
catch (Exception e)
{
oLog.error("getCertificate: Failed adding BouncyCastle Security provider: \n" + e.toString());
throw e;
}
/// Load keyStore file
java.security.KeyStore keyStore = null;
char keyStorePassArray [] = null;
try
{
if (type.equals("jks") || type.equals("JKS"))
{
keyStore = java.security.KeyStore.getInstance("JKS");
}else
{
if (oLog.isDebugEnabled())
{
oLog.debug("assuming non-JKS keystore is PKCS12");
}
keyStore = java.security.KeyStore.getInstance("PKCS12", "BC");
}
if (keystorePassword.length() > 0)
{
if (oLog.isDebugEnabled())
{
oLog.debug("decrypting keystore password");
}
keyStorePassArray = tools.getPRCrypto().decrypt(keystorePassword).toCharArray();
}
keyStore.load(bis, keyStorePassArray);
}catch (Exception e)
{
oLog.error("getCertificate: Unable to instantiate Java Keystore from record: " + keystoreRecordName + ": \n" + e.toString());
throw e;
}
if (keyStore == null)
{
throw new PRRuntimeException("getCertificate: Unable to instantiate Java Keystore from record: " + keystoreRecordName);
}
// Search for Key (Pair) first, certificate second.
// Select the first available Key in the keystore if no alias provided
java.util.Enumeration en = keyStore.aliases();
if (! en.hasMoreElements() )
{
throw new PRRuntimeException("getCertificate: Keystore in record is empty: " + keystoreRecordName);
}
while(keyAlias.length() < 1 && en.hasMoreElements())
{
String elementName = en.nextElement().toString();
if(! keyStore.isKeyEntry(elementName) )
{
// is probably a cert entry - not a key
continue;
}
if (oLog.isInfoEnabled())
{
oLog.info("Using Key with Alias: " + elementName);
}
keyAlias = elementName;
}
if(keyAlias.length() < 1)
{
oLog.warn("getCertificate: No suitable Key found in KeyStore: " + keystoreRecordName);
}
else
{
oLog.debug("Attempting to key with alias: " + keyAlias);
// extract the key from the keystore
try
{
myKey = keyStore.getKey(keyAlias, keyStorePassArray);
}catch( Exception e)
{
oLog.error("Exception in getCertificate: Could not extract Key \"" + keyAlias + "\" from KeyStore \"" + keystoreRecordName + "\": \n" + e.toString());
throw e;
}
if (myKey != null)
{
if (oLog.isInfoEnabled())
{
oLog.info("\tKey Algorithm: " + myKey.getAlgorithm());
oLog.info("\tKey Format: " + myKey.getFormat());
}
certAlias = keyAlias;
}
}
// make sure certAlias is non-empty
java.util.Enumeration allAliases = keyStore.aliases();
while(certAlias.length() < 1 && allAliases.hasMoreElements())
{
String elementName = allAliases.nextElement().toString();
if(! keyStore.isCertificateEntry(elementName))
{
// is probably a cert entry - not a key
continue;
}
if (oLog.isInfoEnabled())
{
oLog.info("Using Cert with Alias: " + elementName);
}
certAlias = elementName;
}
// get the certificate array out of the keystore
certChain = keyStore.getCertificateChain(certAlias);
if (certChain == null)
{
// get the single certificate with this alias, construct our own array
java.security.cert.Certificate cert = keyStore.getCertificate(certAlias);
if (cert != null)
{
certChain = new java.security.cert.Certificate[1];
certChain[0] = cert;
}
else { throw new PRRuntimeException("No Certificate with an alias of '"+keyAlias+"' found in keystore; cannot encrypt" ); }
}
// add certificate chain and key to parameter page
pp.putObject("CertificateKey", myKey);
pp.putObject("CertificateChain", certChain);
}
catch (PRRuntimeException pegaException)
{
throw pegaException;
}
catch (Exception e)
{
throw new PRRuntimeException("getCertificate: Could not get certificate and/or key from keystore: \n", e);
}
---cut here---
NOTE: In case Certificate cannot be found, the Activity does not terminate.
It will instead report a (WARN) message to the logs and return a NULL pointer for the CERT.
In this scenario, a corrupt email will still be sent out. This behavior cannot be modified with this local-change.
This issue is due to defects in Pegasystems’ code or rules.
BUG-230566 "getCertificate Activity NPEs instead of errors"
BUG-230715 "Pega attempts to encrypt email with bad keystore, sends corrupt"
These BUGS will be addressed in a future version of PRPC.
Published February 25, 2016 - Updated October 8, 2020
Have a question? Get answers now.
Visit the Collaboration Center to ask questions, engage in discussions, share ideas, and help others.