Security is at the core of the Globus ToolkitTM. Grid security infrastructure (GSI) enables secure authentication and communication over computer networks. It provides services such as mutual authentication and single sign-on, and is based on proven standards such as public key encryption, X.509 certificates, and the Secure Sockets Layer (SSL).
The purpose of this article is to address compatibility issues that arise when writing Web-enabled grid applications using IBM's WebSphere® Application Server. These issues are related specifically to the Grid security infrastructure JavaTM crypto extensions used by GSI to implement a variety of security services.
Globus Toolkit security libraries
Globus Toolkit 3.0 (GT3) uses a totally new security library provided by the Java CoG Kit 1.1. This new security library is based on GSS-API and is implemented entirely with open-source SSL and certificate processing libraries. When writing Web-enabled Grid applications for the Websphere platform that require the manipulation of X.509 certificates and proxies (also called Globus credentials), conflicts will arise. These conflicts are due to Websphere's use of IBM JCE as the default security provider, whereas GT3 will attempt to use it's own security extensions provided by The Legion of the Bouncy Castle and an SSLv3/TLS implementation, licensed by Claymore Systems.
1. Create proxies from default certificates with WebSphere
We will start by writing a simple JSP page to create a Globus credential, also known as proxy, as shown in Listing 1.
Listing 1. A JSP file to create a Globus credential
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
import= "java.util.Properties,
java.io.*,
java.security.cert.*,
org.globus.gsi.*,
org.globus.gsi.bc.*,
org.apache.log4j.*"
%>
<%!
public synchronized GlobusCredential gridProxyInit(InputStream inUserCert, InputStream inUserKey ,
String pwd, int bits, int hours)
throws IOException, java.security.GeneralSecurityException
{
X509Certificate userCert = CertUtil.loadCertificate(inUserCert);
OpenSSLKey key = new BouncyCastleOpenSSLKey(inUserKey);
System.out.println("gridProxyInit: User Cert=" + userCert +
" User key encrypted=" + key.isEncrypted());
if (key.isEncrypted()) {
try {
key.decrypt(pwd);
} catch(java.security.GeneralSecurityException e) {
throw new
java.security.GeneralSecurityException("Wrong password or other security error");
}
}
System.out.println("gridProxyInit: User Priv key : " + key.getPrivateKey());
java.security.PrivateKey userKey = key.getPrivateKey();
BouncyCastleCertProcessingFactory factory =
BouncyCastleCertProcessingFactory.getDefault();
return factory.createCredential(new X509Certificate[] {userCert},
userKey,
bits,
hours * 3600, GSIConstants.GSI_2_PROXY, null);
}
%>
<%
Logger.getRootLogger().setLevel(Level.DEBUG);
String action = (request.getParameter("ACTION") != null)
? request.getParameter("ACTION") : "INIT";
String pwd = request.getParameter("txtPWD");
String bits = request.getParameter("ST");
String hours = request.getParameter("LIFETIME");
String Msg = request.getParameter("MSG");
String subject = "N/A"; // generated proxy subject
String issuer = "N/A";
String strength = "N/A"; // proxy strength
String sTimeLeft = "N/A"; // proxy time left
// Used to load certs from db
boolean proxyReady = false; // is the proxy ready?
// Init
if ( ! action.equalsIgnoreCase("INIT") ) {
}
try {
if ( action.equalsIgnoreCase("CREATE") ) {
String path = System.getProperty("user.home") + "/.globus/cog.properties";
org.globus.common.CoGProperties props = new org.globus.common.CoGProperties();
props.load(path);
String certPath = props.getProperty("usercert");
String keyPath = props.getProperty("userkey");
System.out.println("test-proxy.jsp::CREATE pwd=" + pwd + " bits=" + bits + " hours=" + hours);
System.out.println("test-proxy.jsp::Cert path:" + certPath + "\nKey path: " + keyPath);
// create a globus cred. Certs read from def locs
InputStream inCert = new FileInputStream(certPath);
InputStream inKey = new FileInputStream(keyPath);
int stren = Integer.parseInt(bits);
int life = Integer.parseInt(hours);
// create globus proxy
GlobusCredential cred = gridProxyInit(inCert , inKey, pwd , stren, life);
subject = cred.getSubject();
issuer = cred.getIssuer();
strength = new Integer(cred.getStrength()).toString();
sTimeLeft = org.globus.util.Util.formatTimeSec(cred.getTimeLeft()); //
// save proxy in def location
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cred.save(bos);
System.out.println("grid-proxy.jsp::Saving proxy into db\n" + bos.toString());
proxyReady = true;
Msg ="Proxy created.";
}
}
catch ( Exception e ) {
e.printStackTrace();
response.sendRedirect("test-proxy.jsp?MSG=GridProxyInit+Error:" + e.getMessage());
}
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="../../theme/Master.css" rel="stylesheet" type="text/css">
<TITLE>test-proxy.jsp</TITLE>
<STYLE>
TABLE, lengend {
font-family: Verdana, Arial;
font-size: 12px;
}
</STYLE>
<SCRIPT LANGUAGE=javascript>
<!--
var proxyReady = <%=proxyReady%>;
function OnLoad() {
var f = document.F1;
if ( document.all && proxyReady ) {
f.btnCreate.disabled = true;
f.txtPWD.disabled = true;
}
}
function showMsg(msg){
window.status = msg;
}
// fires when create btn is pressed
function Proxy_OnSubmit() {
var action = "test-proxy.jsp?ACTION=CREATE";
var f = document.F1;
if ( f.txtPWD.value == "" ) {
alert("All fields are required");
f.txtCN.focus();
return false;
}
//alert("action=" + action + "\nSubmit vals. cert=" + cert + " key=" + key);
showMsg("Working. Please wait...");
if ( document.all )
document.F1.btnCreate.disabled = true; // IE only
document.F1.action = action;
document.F1.submit(); // submit
}
//-->
</SCRIPT>
</HEAD>
<BODY onload="OnLoad()">
<H1>Grid Proxy Init</H1>
<B>Cetificates will be loaded from default locations</B>
<hr>
<% if ( Msg != null ) { %>
<br>
<font color=red><%=Msg%></font>
<% } %>
<FORM method="POST" name="F1" onsubmit="return Proxy_OnSubmit()">
<FIELDSET>
<LEGEND>Proxy Options</LEGEND>
<TABLE width="100%">
<tr class="smallfont">
<TD class="smallfont">Lifetime</TD>
<TD class="smallfont">
<INPUT type="radio" name="LIFETIME" value="12" checked="true">12 h
<INPUT type="radio" name="LIFETIME" value="24">24 h
<INPUT type="radio" name="LIFETIME" value="168">1 week
<INPUT type="radio" name="LIFETIME" value="720">1 month
</TD>
</tr>
<tr class="smallfont">
<TD class="smallfont">Strength</TD>
<TD class="smallfont">
<INPUT type="radio" name="ST" value="512" checked="true">512
<INPUT type="radio" name="ST" value="1024">1024
<INPUT type="radio" name="ST" value="2048">2048
<INPUT type="radio" name="ST" value="4096">4096
</TD>
</tr>
</TABLE>
</FIELDSET>
<TABLE width="100%">
<TR>
<td class="smallfont">Pass Phrase</td>
<td class="smallfont">
<INPUT name="txtPWD" type="password" maxlength="20">
</td>
</TR>
<TR>
<TD> </TD>
<td>
<INPUT name="btnCreate" type="submit" value="Create" align="right">
</td>
</TR>
</TABLE>
<FIELDSET>
<LEGEND>Proxy Info</LEGEND>
<TABLE width="100%">
<TR class="smallfont">
<td class="smallfont">CN</td>
<td class="smallfont">
<font color=red></font>
</td>
</TR>
<TR>
<td class="smallfont">Subject</td>
<td class="smallfont"><%=subject%>
</td>
</TR>
<TR>
<td class="smallfont">Issuer</td>
<td class="smallfont"><%=issuer%>
</td>
</TR>
<TR>
<td class="smallfont">Time left</td>
<td class="smallfont"><%=sTimeLeft%>
</td>
</TR>
<TR>
<td class="smallfont">Strength</td>
<td class="smallfont"><%=strength%>
</td>
</TR>
</TABLE>
</FIELDSET>
<br>
</FORM>
</BODY>
</HTML> |
To successfully compile this JSP file in WebSphere Studio V5.x, make sure
the following JAR files are in your WEB-INF/lib folder:
- cog-jglobus.jar
- cryptix-ans1.jar
- cryptix32.jar
- jce-jdk13-117.jar
- jgss.jar
- log4j-core.jar
- puretls.jar.
All of the above files are included on the GT3 distribution.
2. Configure local certificates for testing
You must configure local certificates to be used by this JSP file, or even
by the Java CoG Kit. The file cog.properties must be present under your
home .globus folder. Thus, if your are logged in to your win32 system as
"Administrator" then you must create: C:\Documents and Settings\Administrator\.globus\cog.properties.
Sample contents of this file are shown is Listing 2:
Listing 2. cog.properties file
#Tue Aug 26 11:46:58 EDT 2003 usercert=C\:\\Documents and Settings\\Administrator\\.globus\\usercert.pem userkey=C\:\\Documents and Settings\\Administrator\\.globus\\userkey.pem proxy=C\:\\DOCUME~1\\ADMINI~1\\LOCALS~1\\Temp\\x509up_u_vladimir cacert=C\:\\Documents and Settings\\Administrator\\.globus\\simpleCA\\cacert.pem |
The cog.properties file will be setup automatically if you download and install the Java CoG Kit from the Globus Web site. With these pieces in place, the JSP file will look something like Figure
1 in your Web browser.
Figure 1. Proxy init test

The output of this JSP will look similar to this:
Figure 2. Creating a Globus credential

So far so good: we have successfully created a Globus proxy from our Web application.
3. Create certificates and private keys
The JSP code in Listing 3 creates a user certificate and private key set.
Listing 3. Create a certificate and private key pair
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<%@ page
language="java"
contentType="text/html; charset=ISO-8859-1"
import= "java.util.*,
java.io.*,
java.security.*,
java.security.cert.*,
org.globus.gsi.*,
org.globus.gsi.bc.*,
org.apache.log4j.*,
COM.claymoresystems.cert.*,
cryptix.util.mime.*"
%>
<%!
/*
* Write bytes into a PEM string
*/
public static String writePEM (byte[] bytes, String hdr, String ftr)
throws IOException
{
ByteArrayOutputStream bos=new ByteArrayOutputStream();
Base64OutputStream b64os=new Base64OutputStream(bos);
b64os.write(bytes);
b64os.flush();
b64os.close();
ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
InputStreamReader irr=new InputStreamReader(bis);
BufferedReader r=new BufferedReader(irr);
StringBuffer buff = new StringBuffer();
String line;
buff.append(hdr);
while((line=r.readLine())!=null){
buff.append(line + "\n");
}
buff.append(ftr);
return buff.toString();
}
/* Create an X509 Name used for cert creation */
private static X509Name makeCertDN(String subject) throws Exception
{
Vector tdn = new Vector();
Vector elems = new Vector();
StringTokenizer st = new StringTokenizer(subject,",");
for (; st.hasMoreTokens() ;) {
String s = st.nextToken(); // [key=value]
if ( s.indexOf("=") == -1 )
throw new Exception("Invalid subject format: " + subject +
" Offending value: " + s);
String key = s.substring(0, s.indexOf("=")).trim();
String val = s.substring(s.indexOf("=") + 1).trim();
if ( val == null || val.equals(""))
throw new Exception("Invalid subject format: " + subject +
" Offending value: " + s);
String[] temp = {key, val};
tdn.addElement(temp);
}
// COM.claymoresystems.cert (puretls.jar)
return CertRequest.makeSimpleDN(tdn);
}
/* Cert/key creation */
public void generateSelfSignedCertAndKey(String subject, int bits,
String Pwd, StringWriter swKey, StringWriter swCert )
throws NoSuchAlgorithmException, Exception
{
X509Name _subject = makeCertDN(subject);
System.out.println("generateSelfSignedCertAndKey Cert subject: " +
_subject.getNameString() +
" Strength=" + bits + " Pwd=" + Pwd);
// Generate A Cert RQ
//StringWriter sw = new StringWriter(); // wil contain the priv key PEM
BufferedWriter bw = new BufferedWriter(swKey);
KeyPair kp = CertRequest.generateKey("RSA", bits, Pwd, bw, true);
// certs are valid for 1 year: 31536000 secs
byte[] certBytes = CertRequest.makeSelfSignedCert(kp, _subject, 31536000);
BufferedWriter bw1 = new BufferedWriter(swCert);
String _certPEM = writePEM(certBytes,
"-----BEGIN CERTIFICATE-----\n",
"-----END CERTIFICATE-----\n");
bw1.write(_certPEM);
System.out.println("CertKeyGenerator: Signed Cert RQ . signedUserCert\n" + _certPEM);
}
%>
<%
org.apache.log4j.Logger.getRootLogger().setLevel(org.apache.log4j.Level.DEBUG);
String action = (request.getParameter("ACTION") != null) ? request.getParameter("ACTION") : "INIT";
String Msg = request.getParameter("MSG");
try {
//Properties args = com.ibm.grid.ogsa.securityextension.gsi.GSIProperties.load();
String msg = "";
if ( action.equalsIgnoreCase("GENERATE") ) {
String cn = request.getParameter("txtCN");
String org = request.getParameter("txtORG");
String ou = request.getParameter("txtOU");
String pwd = request.getParameter("txtPWD");
String subject = "O=" + org + "," + "OU="+ ou + ",CN=" + cn;
System.out.println("Gen certs. Subject: " + subject);
StringWriter swCert = new StringWriter(); // wil contain cert PEM
StringWriter swKey = new StringWriter(); // wil contain the priv key PEM
generateSelfSignedCertAndKey(subject, 1024, pwd, swKey, swCert);
// Private key
System.out.println("Private key PEM\n" + swKey.toString());
// cert
System.out.println("Certificate PEM\n" + swCert.toString());
response.sendRedirect("test-creds.jsp?MSG=Certs+installed+successfully.");
}
}
catch ( Exception e0 ) {
e0.printStackTrace();
response.sendRedirect("test-creds.jsp?MSG=Error+ installing+certs:" + e0.getMessage());
}
catch ( InternalError e ) {
e.printStackTrace();
response.sendRedirect("test-creds.jsp?MSG=Error+ installing+certs:" + e.getMessage());
}
%>
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<META name="GENERATOR" content="IBM WebSphere Studio">
<META http-equiv="Content-Style-Type" content="text/css">
<LINK href="../../theme/Master.css" rel="stylesheet" type="text/css">
<TITLE>setup-gsi.jsp</TITLE>
<SCRIPT LANGUAGE=javascript>
<!--
function showMsg(msg){
window.status = msg;
}
function OnLoad() {
document.F1.txtCN.focus();
showMsg("Done");
}
// fires when create btn is pressed
function OnSubmit() {
var f = document.F1;
if ( f.txtCN.value == "" || f.txtPWD.value == "" || f.txtOU.value == "" ) {
alert("All fields are required");
f.txtCN.focus();
return false;
}
showMsg("Working. Please wait...");
if ( document.all )
document.F1.btnCreate.disabled = true; // IE only
document.F1.submit(); // submit
}
//-->
</SCRIPT>
</HEAD>
<BODY onload="OnLoad()">
<H1>Setup Certificate/Private key</H1>
<hr>
<% if ( Msg != null ) { %>
<br><font color=red><%=Msg%></font><br>
<% } %>
<B>All fileds are required</B>
<form name="F1" method="POST" action="test-creds.jsp?ACTION=GENERATE" onsubmit="return OnSubmit()">
<TABLE width="100%" class="smallfont">
<tr>
<td>Common Name</td>
<td width="40%">
<INPUT type="text" name="txtCN" size="20" maxlength="50">
</td>
<TD>Enter your name or email</TD>
</tr>
<tr>
<td>Organizational Unit</td>
<td>
<INPUT type="text" name="txtOU" size="20" maxlength="50">
</td>
<TD class="smallfont"></TD>
</tr>
<tr>
<td>Organization</td>
<td>
<INPUT type="text" name="txtORG" size="20" maxlength="50">
</td>
<TD class="smallfont">Organization</TD>
</tr>
<tr>
<td>Pass phrase</td>
<td>
<INPUT type="password" name="txtPWD" size="20" maxlength="50">
</td>
<TD class="smallfont">Password used to encrypt the private key</TD>
</tr>
</TABLE>
<hr>
<INPUT name="btnCreate" type="submit" name="Submit" value="Install Certs">
</form>
</BODY>
</HTML> |
This code will display like this on your Web browser:
Figure 3. Setting up certificate/private key

When attempting to create a certificate/private key, the following exception will be thrown by Websphere:
Listing 4. Exception thrown by security provider collisons between Websphere and GT3
java.lang.InternalError: java.security.NoSuchAlgorithmException: class configured for Cipher:
com.ibm.crypto.provider.DESedeCipher is not a subclass of xjava.security.Cipher
at COM.claymoresystems.crypto.PEMData.writePEMObject(PEMData.java:172)
at COM.claymoresystems.crypto.EAYEncryptedPrivateKey.writePrivateKey(EAYEncryptedPrivateKey.java:83)
at COM.claymoresystems.cert.CertRequest.generateKey(CertRequest.java:102)
at jsp.article._test_2D_creds_jsp_0.generateSelfSignedCertAndKey(_test_2D_creds_jsp_0.java:108)
at jsp.article._test_2D_creds_jsp_0._jspService(_test_2D_creds_jsp_0.java:210) |
By taking a closer look at the message:
class configured for Cipher: com.ibm.crypto.provider.DESedeCipher is not
a subclass of xjava.security.Cipher;
and the stack trace, we can assume that the internals of the Java CoG APIs are trying to use IBM's JCE as the default provider, which is incorrect, since the security provider should be Cryptix/Bouncy Castle. This problem arises when creating a private key. To fix the problem, the security provider Java code will need to be modified.
4. Change GT3 security providers to work with WebSphere
With the problem identified, the solution consists of a change to a few lines of code of the puretls.jar and cryptix32.jar source code. To do this, you will need to download the source from the
Web sites, change the code and repackage the JAR files. The actual code
changes that need to be made are listsed in the table below. For information
on downloading the source, see the References section.
Table 1: Overview of changes to the GT3 security providers
| JAR file | Class/Line | Original | Update | Comments |
| Puretls.jar | PEMData.javaLine 155 | Cipher ciph = Cipher.getInstance(algorithm); ((FeedbackCipher)ciph) .setInitializationVector(iv); | Cipher ciph = Cipher.getInstance(algorithm,"Cryptix"); | This change will force the use of Cryptix as the security provider |
| Cryptix32.jar | Cipher.javaLine 480 | cipherName = IJCE.getStandardName (cipherName, "Cipher"); | cipherName = CryptixProperties.getProperty ("Alg.Alias.Cipher." + cipherName); | The method: IJCE. getStandardName Has been deprecated and wrongfully returns the Cipher name under Websphere (For ciphers such as DES-EDE3) |
This article provides a useful insight to the GT3 security providers and their compatibility with WebSphere Application Server V4 and V5. If you find yourself writing Web-enabled Grid applications and need to manipulate or create certificates, keys and proxies, the information here will help you resolve incompatibilities you may encounter between the GT3 and Websphere containers.
Vladimir Silva was born in Quito, Ecuador. He received a System's Analyst degree from
the Polytechnic Institute of the Army in 1994. In the same year, he came
to the United States as an exchange student pursuing a career in Computer
Science at Middle Tennessee State University. After graduation, he joined
the IBM "Web-Ahead" technology think tank. His interests include
Grid computing, Neural Nets, and artificial intelligence. He also holds
numerous IT certifications including OCP, MCSD, and MCP. To contact Vladimir,
or to obtain the modified versions of puretls.jar and cryptix32.jar described in this article.
Comments (Undergoing maintenance)





