package com.sap.pi.afm.pkcs7;
/**
*--------------------------------------------------------------
* @autor: Rogério Coimbra de Oliveira.
* Purpose: To sign data in the PKCS # 7 pattern and Base64 base.
* Version: 001 (create)
*--------------------------------------------------------------
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Local;
import javax.ejb.LocalHome;
import javax.ejb.Remote;
import javax.ejb.RemoteHome;
import javax.ejb.Stateless;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import sun.misc.BASE64Encoder;
import com.sap.aii.af.lib.mp.module.Module;
import com.sap.aii.af.lib.mp.module.ModuleContext;
import com.sap.aii.af.lib.mp.module.ModuleData;
import com.sap.aii.af.lib.mp.module.ModuleException;
import com.sap.aii.af.lib.mp.module.ModuleHome;
import com.sap.aii.af.lib.mp.module.ModuleLocal;
import com.sap.aii.af.lib.mp.module.ModuleLocalHome;
import com.sap.aii.af.lib.mp.module.ModuleRemote;
import com.sap.engine.interfaces.keystore.KeystoreManager;
import com.sap.engine.interfaces.messaging.api.Message;
import com.sap.engine.interfaces.messaging.api.MessageKey;
import com.sap.engine.interfaces.messaging.api.PublicAPIAccessFactory;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditAccess;
import com.sap.engine.interfaces.messaging.api.auditlog.AuditLogStatus;
import com.sap.engine.interfaces.messaging.api.exception.InvalidParamException;
import com.sap.security.api.ssf.ISsfData;
import com.sap.security.core.server.ssf.SsfDataPKCS7;
import com.sap.security.core.server.ssf.SsfInvalidAlgException;
import com.sap.security.core.server.ssf.SsfInvalidKeyException;
import com.sap.security.core.server.ssf.SsfProfileKeyStore;
/**
* Session Bean implementation class SignaturePKCS7
*/
@Stateless(name = "SignaturePKCS7Bean")
@Local(value = { ModuleLocal.class })
@Remote(value = { ModuleRemote.class })
@LocalHome(value = ModuleLocalHome.class)
@RemoteHome(value = ModuleHome.class)
public class SignaturePKCS7 implements Module {
private AuditAccess audit;
private byte[] content;
private Message msg;
MessageKey msgKey;
private String aliasPrivateKey;
private boolean base64Encode;
private boolean formatPKCS7;
private boolean applySignature;
private String pwdPrivateKey;
private String aliasKeyStore;
private String mdAlg;
private int incCerts;
private boolean detached;
private boolean paramMandatoryEmpty;
private static final String PARAM_ALIAS_PRIVATE_KEY = "aliasPrivateKey";
private static final String PARAM_BASE64_ENCODE = "base64Encode";
private static final String PARAM_APPLY_SIGNATURE = "applySignature";
private static final String PARAM_PWD_PRIVATE_KEY = "pwdPrivateKey";
private static final String PARAM_ALIAS_KEY_STORE = "aliasKeyStore";
private static final String PARAM_MD_ALG = "mdAlg";
private static final String PARAM_INC_CERTS = "incCerts";
private static final String PARAM_DETACHED = "detached";
private static final String PARAM_FORMAT_PKCS7 = "formatPKCS7";
@Override
public ModuleData process(ModuleContext moduleContext,
ModuleData inputModuleData) throws ModuleException {
//Load message:
this.msg = (Message) inputModuleData.getPrincipalData();
this.msgKey = this.msg.getMessageKey();
//Loads the contents of the incoming message:
this.content = msg.getDocument().getContent();
//Load configuration parameters:
this.loadParameters(moduleContext);
if (this.applySignature && !this.paramMandatoryEmpty) {
//Sign the file digitally in PKCS # 7 standard:
content = this.signPKCS7(content);
}
if (this.base64Encode) {
if (this.formatPKCS7) {
//Encode data in Base64 and non-standard format PKCS7:
content = this.formatPKCS7(this.encodeBase64(content)).getBytes();
} else {
// Encode data in Base64:
content = this.encodeBase64(content).getBytes();
}
}
//Update output:
try {
msg.getDocument().setContent(content);
} catch (InvalidParamException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
inputModuleData.setPrincipalData(msg);
return inputModuleData;
}
@PostConstruct
public void initializeResources() {
try {
this.audit = PublicAPIAccessFactory.getPublicAPIAccess()
.getAuditAccess();
} catch (Exception e) {
throw new RuntimeException("Error initializing resources: "
+ e.getMessage());
}
}
@PreDestroy
public void releaseResources() {
this.audit.flushAuditLogEntries(this.msgKey);
}
private void loadParameters(ModuleContext moduleContext)
throws ModuleException {
//Determine the data must be signed:
if (moduleContext.getContextData(PARAM_APPLY_SIGNATURE) != null
&& !moduleContext.getContextData(PARAM_APPLY_SIGNATURE)
.isEmpty()) {
this.applySignature = Boolean.valueOf(moduleContext
.getContextData(PARAM_APPLY_SIGNATURE));
} else {
this.applySignature = true;
}
if (this.applySignature) {
//Private key or digital certificate name:
if (moduleContext.getContextData(PARAM_ALIAS_PRIVATE_KEY) == null
|| moduleContext.getContextData(PARAM_ALIAS_PRIVATE_KEY)
.isEmpty()) {
this.paramMandatoryEmpty = true;
audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR,
"Parameter " + PARAM_ALIAS_PRIVATE_KEY
+ " required when the "
+ PARAM_APPLY_SIGNATURE
+ " is equal to \"true\"");
} else {
this.aliasPrivateKey = moduleContext
.getContextData(PARAM_ALIAS_PRIVATE_KEY);
}
//Private key password:
if (moduleContext.getContextData(PARAM_PWD_PRIVATE_KEY) != null
&& !moduleContext.getContextData(PARAM_PWD_PRIVATE_KEY)
.isEmpty()) {
this.pwdPrivateKey = moduleContext
.getContextData(PARAM_PWD_PRIVATE_KEY);
} else {
this.pwdPrivateKey = null;
}
//Key Store Name:
if (moduleContext.getContextData(PARAM_ALIAS_KEY_STORE) != null
&& !moduleContext.getContextData(PARAM_ALIAS_KEY_STORE)
.isEmpty()) {
this.aliasKeyStore = moduleContext
.getContextData(PARAM_ALIAS_KEY_STORE);
} else {
this.aliasKeyStore = "DEFAULT";
}
//Digital signature algorithm:
if (moduleContext.getContextData(PARAM_MD_ALG) != null
&& !moduleContext.getContextData(PARAM_MD_ALG).isEmpty()) {
this.mdAlg = moduleContext.getContextData(PARAM_MD_ALG);
} else {
this.mdAlg = SsfDataPKCS7.ALG_SHA;
}
//Determines how the certificate should be included in the content:
if (moduleContext.getContextData(PARAM_INC_CERTS) != null
&& !moduleContext.getContextData(PARAM_INC_CERTS).isEmpty()) {
try {
this.incCerts = Integer.valueOf(moduleContext
.getContextData(PARAM_INC_CERTS));
} catch (NumberFormatException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
} else {
this.incCerts = 1;
}
// Determines whether signed content should be included with signature:
if (moduleContext.getContextData(PARAM_DETACHED) != null
&& !moduleContext.getContextData(PARAM_DETACHED).isEmpty()) {
this.detached = Boolean.valueOf(moduleContext
.getContextData(PARAM_DETACHED));
} else {
this.detached = false;
}
}
//Determines whether content should be formatted in the PKCS7 standard:
if (moduleContext.getContextData(PARAM_FORMAT_PKCS7) != null
&& !moduleContext.getContextData(PARAM_FORMAT_PKCS7).isEmpty()) {
this.formatPKCS7 = Boolean.valueOf(moduleContext
.getContextData(PARAM_FORMAT_PKCS7));
} else {
this.formatPKCS7 = false;
}
//Determines whether content should be encoded for Base64:
if (moduleContext.getContextData(PARAM_BASE64_ENCODE) != null
&& !moduleContext.getContextData(PARAM_BASE64_ENCODE).isEmpty()) {
this.base64Encode = Boolean.valueOf(moduleContext
.getContextData(PARAM_BASE64_ENCODE));
} else {
this.base64Encode = true;
}
//Generates audit logs:
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_APPLY_SIGNATURE + ") loaded: "
+ this.applySignature);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_ALIAS_PRIVATE_KEY + ") loaded: "
+ this.aliasPrivateKey);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_PWD_PRIVATE_KEY + ") loaded!" );
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_ALIAS_KEY_STORE + ") loaded: " + this.aliasKeyStore);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_MD_ALG + ") loaded: " + this.mdAlg);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_INC_CERTS + ") loaded: " + this.incCerts);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_DETACHED + ") loaded: " + this.detached);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS, "Parameter ("
+ PARAM_BASE64_ENCODE + ") loaded: " + this.base64Encode);
}
private byte[] signPKCS7(byte[] content) throws ModuleException {
SsfProfileKeyStore profile;
//Loads data to be signed:
InputStream stream = new ByteArrayInputStream(content);
ISsfData data = null;
try {
data = new SsfDataPKCS7(stream);
} catch (IOException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
//Get sign-up profile from Key Storage:
InitialContext ctx = null;
try {
ctx = new InitialContext();
} catch (NamingException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
Object o = null;
try {
o = (Object) ctx.lookup("keystore");
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS,
"Context \"Keystore\" loaded!");
} catch (NamingException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
KeystoreManager manager = (KeystoreManager) o;
KeyStore keyStore = null;
try {
keyStore = manager.getKeystore(this.aliasKeyStore);
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS,
"Private Key Loaded Successfully:" + this.aliasKeyStore
+ ".");
} catch (RemoteException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
try {
profile = new SsfProfileKeyStore(keyStore, this.aliasPrivateKey,
this.pwdPrivateKey);
} catch (KeyStoreException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
try {
//Sign data in default PKCS # 7:
boolean res = data.sign(profile, this.mdAlg, this.incCerts,
this.detached);
audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS,
"Data signed successfully: Format \"PKCS#7\".");
if (!res) {
// Failed to sign data:
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR,
"Failed to sign file!");
throw new ModuleException("Failed to sign file!");
}
} catch (SsfInvalidKeyException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
} catch (SsfInvalidAlgException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
//Get signed data:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
data.writeTo(baos);
} catch (IOException e) {
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.ERROR, e
.getMessage());
throw new ModuleException(e.getMessage(), e);
}
return baos.toByteArray();
}
private String encodeBase64(byte[] content) throws ModuleException {
String encoded = new BASE64Encoder().encode(content).trim();
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS,
"Data encoded successfully: Base64.");
return encoded;
}
private String formatPKCS7(String encoded) throws ModuleException {
final String bgn_sign = "-----BEGIN PKCS7-----";
final String end_sign = "-----END PKCS7-----";
String formated;
//Format string encoded in BASE64 in the PKCS7 pattern:
formated = bgn_sign + "\r\n" + encoded + "\r\n" + end_sign;
this.audit.addAuditLogEntry(msgKey, AuditLogStatus.SUCCESS,
"Successfully formatted data: PKCS7 standard.");
return formated;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<ejb-j2ee-engine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ejb-j2ee-engine_3_0.xsd">
<enterprise-beans>
<enterprise-bean>
<ejb-name>SignaturePKCS7Bean</ejb-name>
<jndi-name>SignPKCS7</jndi-name>
</enterprise-bean>
</enterprise-beans>
</ejb-j2ee-engine>
<?xml version="1.0" encoding="UTF-8"?>
<application-j2ee-engine xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="application-j2ee-engine.xsd">
<reference reference-type="hard">
<reference-target target-type="service" provider-name="sap.com">engine.security.facade</reference-target>
</reference>
<reference reference-type="hard">
<reference-target target-type="library" provider-name="sap.com">engine.j2ee14.facade</reference-target>
</reference>
<reference reference-type="hard">
<reference-target target-type="service" provider-name="sap.com">com.sap.aii.af.svc.facade</reference-target>
</reference>
<reference reference-type="hard">
<reference-target target-type="interface" provider-name="sap.com">com.sap.aii.af.ifc.facade</reference-target>
</reference>
<reference reference-type="hard">
<reference-target target-type="library" provider-name="sap.com">com.sap.aii.af.lib.facade</reference-target>
</reference>
<reference reference-type="hard">
<reference-target target-type="library" provider-name="sap.com">com.sap.base.technology.facade</reference-target>
</reference>
<fail-over-enable xsi:type="fail-over-enableType_disable"
mode="disable" />
</application-j2ee-engine>
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
7 | |
4 | |
4 | |
3 | |
3 | |
3 | |
3 | |
3 | |
2 | |
2 |