Java tutorial
/* Copyright 2006 VPAC * * This file is part of Grix. * Grix is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * Grix is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with Grix; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.vpac.grix.model.certificate; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintStream; import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.PublicKey; import java.util.ArrayList; import org.apache.log4j.Logger; import org.bouncycastle.asn1.DERSet; import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.jce.PKCS10CertificationRequest; import org.bouncycastle.util.encoders.Base64; import org.globus.gsi.CertUtil; import org.globus.util.PEMUtils; import org.vpac.common.exceptions.MissingInformationException; import org.vpac.grix.control.utils.GrixProperty; /** * A certification request similar/compatible with the one created by openssl * e.g.: openssl req -newkey rsa:1024 -config ./apacgrid-openssl.cnf -out * usercert-request.pem * * @author Markus Binsteiner * */ public class CertificationRequest { static final Logger myLogger = Logger.getLogger(CertificationRequest.class.getName()); private final String signatureAlgorithm; private GlobusKeyPair keypair; private String c = ""; private String o = ""; private String ou = ""; private String cn = ""; private String email = ""; private X509Name dn = null; /** * Creates a certification request with the specified Subject. Generates a * RSA keypair. The private key has to be stored by the user manually. * * @param c * the country * @param o * the organization * @param ou * the organization unit * @param cn * the name of the applicant * @param email * the email address of the applicant * @param passphrase * the passphrase to encrypt the private key * @throws GeneralSecurityException * @throws MissingInformationException * @throws */ public CertificationRequest(String c, String o, String ou, String cn, String email, int keysize, String signature_algorithm, boolean hostcert) throws GeneralSecurityException, MissingInformationException { this.c = c; this.o = o; this.ou = ou; this.cn = cn; this.email = email; createDN(hostcert); this.keypair = GlobusKeyPair.globusKeyPairFactory(keysize); this.signatureAlgorithm = signature_algorithm; } /** * Creates a certification request with the specified Subject. Generates a * RSA keypair. The private key has to be stored by the user manually. * * @param c * the country * @param o * the organization * @param ou * the organization unit * @param cn * the name of the applicant * @param passphrase * the passphrase to encrypt the private key * @throws GeneralSecurityException * @throws MissingInformationException * @throws */ public CertificationRequest(String c, String o, String ou, String cn, int keysize, String signature_algorithm, boolean hostcert) throws GeneralSecurityException, MissingInformationException { this.c = c; this.o = o; this.ou = ou; this.cn = cn; createDN(hostcert); this.keypair = GlobusKeyPair.globusKeyPairFactory(keysize); this.signatureAlgorithm = signature_algorithm; } /** * Creates a certification request without user details. Only sets the * signature algorithm and creates a keypair. * * @throws GeneralSecurityException * @throws * * @throws SecurityProviderException */ public CertificationRequest(int keysize, String signature_algorithm) throws GeneralSecurityException { this.keypair = GlobusKeyPair.globusKeyPairFactory(keysize); this.signatureAlgorithm = signature_algorithm; } /** * Broken!!! This constructor does not read the public key in the .pem file * It just parses the subject line and fills the dn fields. * * @param file * the certificate request with a subject line containing the DN * @param signature_algorithm * the algorithm for the private key. Use * GrixProperty.getString("signature.algorithm"); * @param hostcert * whether the certification request was for a hostcert or not * @throws IOException * @throws MissingInformationException */ public CertificationRequest(File file, String signature_algorithm, boolean hostcert) throws IOException, MissingInformationException { this.signatureAlgorithm = signature_algorithm; BufferedReader input = null; try { input = new BufferedReader(new FileReader(file)); String line = null; // not declared within while loop while ((line = input.readLine()) != null) { if (line.startsWith("/C=")) { parseDN(line, hostcert); } } } finally { try { if (input != null) { // flush and close both "input" and its underlying // FileReader input.close(); } } catch (Exception e) { // e.printStackTrace(); myLogger.error(e); } } } private void parseDN(String line, boolean hostcert) throws MissingInformationException { this.c = line.substring(line.indexOf("/C=") + 3, line.indexOf("/O=")); this.o = line.substring(line.indexOf("/O=") + 3, line.indexOf("/OU=")); this.ou = line.substring(line.indexOf("/OU=") + 4, line.indexOf("/CN=")); // if (!hostcert){ if (line.indexOf("/Email") != -1) { this.cn = line.substring(line.indexOf("/CN=") + 4, line.indexOf("/Email=")); this.email = line.substring(line.indexOf("/Email=") + 7); } else { this.cn = line.substring(line.indexOf("/CN=") + 4, line.indexOf("/E=")); this.email = line.substring(line.indexOf("/E=") + 3); } // } else { // this.cn = line.substring( line.indexOf( "/CN=")+4 ); // } createDN(hostcert); } /** * Concatenates all the user information to a DN and stores the DN into the * X509Name field dn. * * @param hostcert * whether this is for a hostcert or not * @throws MissingInformationException */ public void createDN(boolean hostcert) throws MissingInformationException { ArrayList<String> missingInformation = new ArrayList<String>(); if (this.c.equals("")) missingInformation.add("C"); if (this.o.equals("")) missingInformation.add("O"); if (this.ou.equals("")) missingInformation.add("OU"); if (this.cn.equals("")) missingInformation.add("CN"); if (this.email.equals("")) missingInformation.add("EMAIL"); if (missingInformation.size() == 0) { if (!hostcert) { // user certificate this.dn = new X509Name( "C=" + c + ", O=" + o + ", OU=" + ou + ", CN=" + cn + ", emailAddress=" + email); } else { // host certificate this.dn = new X509Name( "C=" + c + ", O=" + o + ", OU=" + ou + ", CN=" + cn + ", emailAddress=" + email); } } else { throw new MissingInformationException("Could not create DN: not enough information available", missingInformation); } } /** * Creates a certification request with the specified// * PEMUtils.writeBase64(ps, "-----BEGIN CERTIFICATE REQUEST-----", // * encodedData, "-----END CERTIFICATE REQUEST-----"); Subject. * * @param dn * the subject (e.g. "C=AU, O=APACGrid, OU=VPAC, ..." * @param keypair * the GlobusKeyPair to use for the certification request. * @throws NoSuchPropertyException */ public CertificationRequest(GlobusKeyPair keypair) { this.signatureAlgorithm = GrixProperty.getString("signature.algorithm"); this.keypair = keypair; } /** * creates a encoded representation of the certification request. * * @return the certification request. */ public String getEncodedRequest() { String request_string = null; ByteArrayOutputStream out = new ByteArrayOutputStream(); // stolen from jglobus.jar: // nothing in it DERSet derset = new DERSet(); PublicKey pubkey = this.keypair.getPublicKey(); PrivateKey privkey = this.keypair.getPrivateKey().getPrivateKey(); PKCS10CertificationRequest request = null; try { // using the already implemented .getEncoded() function of // PKCS10CertificationRequest request = new PKCS10CertificationRequest(this.signatureAlgorithm, this.dn, pubkey, derset, privkey); PEMUtils.writeBase64(out, "-----BEGIN CERTIFICATE REQUEST-----", Base64.encode(request.getEncoded()), "-----END CERTIFICATE REQUEST-----"); request_string = out.toString(); out.close(); } catch (Exception e) { // TODO throw new SecurityProviderException("Could not write // certification request to file."); // e.printStackTrace(); myLogger.error(e); } return request_string; } /** * Writes the certification request to a PEM encoded file * * @param certReqFile * the file * @throws IOException * @throws Exception */ public void writeToPEMFile(File certReqFile) throws IOException { if (!certReqFile.getParentFile().exists()) if (!certReqFile.getParentFile().mkdirs()) throw new IOException("Could not create directory: " + certReqFile.getParent()); // if ( !certReqFile.canWrite() ) throw new // IOException("Can not write file: "+certReqFile.toString()); PrintStream ps = null; try { ps = new PrintStream(new FileOutputStream(certReqFile)); ps.print("\n\n" + "Please mail the following certificate request to " + GrixProperty.getString("CA_EMAIL_ADDRESS") + "\n" + "\n" + "==================================================================\n" + "\n" + "Certificate Subject:\n" + "\n" + CertUtil.toGlobusID(this.dn.toString()) + "\n" + "\n" + "The above string is known as your user certificate subject, and it \n" + "uniquely identifies this user.\n" + "\n" + "To install this user certificate, please save this e-mail message\n" + "into the following file.\n" + "\n" + "\n" + certReqFile.getAbsolutePath() + "\n" + "\n" + "\n" + " You need not edit this message in any way. Simply \n" + " save this e-mail message to the file.\n" + "\n" + "\n" + "If you have any questions about the certificate contact\n" + "the Certificate Authority at " + GrixProperty.getString("CA_EMAIL_ADDRESS") + "\n" + "\n" + getEncodedRequest()); } finally { if (ps != null) { ps.close(); } } } /** * @return the keypair */ public GlobusKeyPair getKeypair() { return keypair; } /** * @param keypair * the keypair to set */ public void setKeypair(GlobusKeyPair keypair) { this.keypair = keypair; } /** * @return the c */ public String getC() { return c; } /** * @param c * the c to set */ public void setC(String c) { this.c = c; } /** * @return the cn */ public String getCn() { return cn; } /** * @param cn * the cn to set */ public void setCn(String cn) { this.cn = cn; } /** * @return the dn */ public X509Name getDn() { return dn; } public String getDNwithoutEmail() { int index = dn.toString().indexOf(",E="); if (index == -1) index = dn.toString().indexOf(",Email="); return dn.toString().substring(0, index); } /** * @param dn * the dn to set */ public void setDn(X509Name dn) { this.dn = dn; } /** * @return the email */ public String getEmail() { return email; } /** * @param email * the email to set */ public void setEmail(String email) { this.email = email; } /** * @return the o */ public String getO() { return o; } /** * @param o * the o to set */ public void setO(String o) { this.o = o; } /** * @return the ou */ public String getOu() { return ou; } /** * @param ou * the ou to set */ public void setOu(String ou) { this.ou = ou; } }