Java tutorial
/* * Swift Parallel Scripting Language (http://swift-lang.org) * Code from Java CoG Kit Project (see notice below) with modifications. * * Copyright 2005-2014 University of Chicago * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // ---------------------------------------------------------------------- // This code is developed as part of the Java CoG Kit project // The terms of the license can be found at http://www.cogkit.org/license // This message may not be removed or altered. // ---------------------------------------------------------------------- /** * Copyright (c) 2003, National Research Council of Canada * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, merge, * publish, distribute, and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice(s) and this licence appear in all copies of the Software or * substantial portions of the Software, and that both the above copyright notice(s) and this * license appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE * FOR ANY CLAIM, OR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL * DAMAGES, OR ANY DAMAGES WHATSOEVER (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWSOEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Except as contained in this notice, the name of a copyright holder shall NOT be used in * advertising or otherwise to promote the sale, use or other dealings in this Software * without specific prior written authorization. Title to copyright in this software and any * associated documentation will at all times remain with copyright holders. */ package org.globus.cog.security.cert.request; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.PrivateKey; import java.security.cert.X509Certificate; import org.bouncycastle.asn1.DERConstructedSet; import org.bouncycastle.asn1.x509.X509Name; import org.bouncycastle.jce.PKCS10CertificationRequest; import org.bouncycastle.util.encoders.Base64; import org.globus.common.CoGProperties; import org.globus.gsi.CertUtil; import org.globus.gsi.GSIConstants; import org.globus.gsi.GlobusCredential; import org.globus.gsi.OpenSSLKey; import org.globus.gsi.bc.BouncyCastleCertProcessingFactory; import org.globus.gsi.bc.BouncyCastleOpenSSLKey; import org.globus.gsi.gssapi.GlobusGSSCredentialImpl; import org.globus.util.PEMUtils; import org.globus.util.Util; import org.ietf.jgss.GSSCredential; import cryptix.util.core.Hex; /** * GridCertRenewalRequest Command Line Client * @author Jean-Claude Cote */ public class GridCertRenewalRequest { public static final String usage = "\n" + "\ngrid-cert-request [-help] [ options ...]" + "\n-help" + "\n-usage " + "\nDisplays usage. " + "\n" + "\n-version " + "\nDisplays version. " + "\n" + "\n-debug " + "\nDisplays extra information (if problems occur). " + "\n" + "\n-nopassphrase " + "\nSignals that the new key will not be protected by a passphrase. " + "\n" + "\n-oldcert file " + "\nLocation of the certificate that is about to expire. If not set, $HOME/.globus/usercert.pem " + "\n" + "\n-oldkey file " + "\nLocation of the private key to the certificate that is about to expire. If not set, $HOME/.globus/userkey.pem" + "\n" + "\n-newkey file " + "\nLocation of the replacement key that is generated by grid-cert-renew. If not set, $HOME/.globus/userkey_new.pem is assumed. " + "\n" + "\n-newcertreq file " + "\nLocation of the certificate renewal request. If not set, $HOME/.globus/usercert_renew_request.pem is assumed. " + "\n" + "\n-force" + "\nReplaces any existing renewal request" + "\n" + "\nchallenge " + "\nChallenge text string, as instructed in the CA renewal notification message. This is the only required argument. " + "\n"; private static GlobusGSSCredentialImpl cred = null; private static String chalenge = ""; private static String newPrivKeyLoc = ""; private static String userCertRenewFile = ""; private static String oldPassword = ""; private static boolean noPswd = false; private static String userCertFile = ""; private static String userKeyFile = ""; private static boolean force = false; private static String version = "1.0"; private static boolean verbose = false; public static void main(String[] args) { boolean bOk = parseCmdLine(args); if (bOk) { CertUtil.init(); // Get default location of cert. CoGProperties props = CoGProperties.getDefault(); // If cert file loc not specified use default. if (userCertFile.length() == 0) { userCertFile = props.getUserCertFile(); } // If key file loc not specified use default. if (userKeyFile.length() == 0) { userKeyFile = props.getUserKeyFile(); } // If renwal cert loc not specified if (userCertRenewFile.length() == 0) { userCertRenewFile = props.getUserCertFile().substring(0, props.getUserCertFile().length() - 4) + "_renew_request.pem"; } // If new key loc not specified if (newPrivKeyLoc.length() == 0) { newPrivKeyLoc = props.getUserKeyFile().substring(0, props.getUserKeyFile().length() - 4) + "_new.pem"; } // Check not to overwrite any of these files. if (force == false) { boolean bFileExists = false; File f = new File(userCertRenewFile); if (f.exists()) { System.out.println(userCertRenewFile + " exists"); bFileExists = true; } f = new File(newPrivKeyLoc); if (f.exists()) { System.out.println(newPrivKeyLoc + " exists"); bFileExists = true; } if (bFileExists) { System.out.println("If you wish to overwrite, run the script again with -force."); bOk = false; } } } GlobusGSSCredentialImpl cred = null; if (bOk) { // Get password from user. String oldPassword = Util.getInput("Enter private key pass phrase: "); // Generate a proxy, and keypair from current cert and key int credLifetimeSeconds = 300; // life time of proxy 5 min. cred = createNewProxy(oldPassword, credLifetimeSeconds, 1024); if (cred == null) { bOk = false; } } String newPrivateKeyPassword = ""; if (bOk && !noPswd) { // Get password from user. bOk = false; int attempts = 0; while (bOk == false && attempts < 3) { newPrivateKeyPassword = Util.getInput("Enter new private key pass phrase: "); String password2 = Util.getInput("Verify password enter new private key pass phrase: "); if (newPrivateKeyPassword.compareTo(password2) != 0) { System.out.println("Verify failure"); } else { if (newPrivateKeyPassword.length() < 4) { System.out.println("phrase is too short, needs to be at least 4 chars"); } else { bOk = true; } } attempts++; } } if (bOk) { try { genRenewRequest(cred, newPrivateKeyPassword, chalenge, newPrivKeyLoc, userCertRenewFile); } catch (GeneralSecurityException e) { e.printStackTrace(); bOk = false; } catch (IOException e) { e.printStackTrace(); bOk = false; } } } protected static boolean parseCmdLine(String[] args) { boolean bOk = true; if (args.length == 0) { System.out.println(usage); bOk = false; } else { for (int i = 0; i < args.length && bOk; i++) { if (args[i].equalsIgnoreCase("-version")) { System.out.println(version); } else if (args[i].equalsIgnoreCase("-help") || args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("-?")) { System.out.println(usage); bOk = false; } else if (args[i].equalsIgnoreCase("-nopw") || args[i].equalsIgnoreCase("-nodes") || args[i].equalsIgnoreCase("-nopassphrase")) { // no password noPswd = true; } else if (args[i].equalsIgnoreCase("-verbose")) { verbose = true; } else if (args[i].equalsIgnoreCase("-oldcert")) { userCertFile = args[++i]; } else if (args[i].equalsIgnoreCase("-oldkey")) { userKeyFile = args[++i]; } else if (args[i].equalsIgnoreCase("-newkey")) { newPrivKeyLoc = args[++i]; } else if (args[i].equalsIgnoreCase("-newcertreq")) { userCertRenewFile = args[++i]; } else if (args[i].equalsIgnoreCase("-force")) { // overwrite existing credentials force = true; } else { // if last arg if (i == args.length - 1) { chalenge = args[i]; } else { System.out.println("Error: argument #" + i + "(" + args[i] + ") : unknown"); } } } } return bOk; } protected static GlobusGSSCredentialImpl createNewProxy(String keyPassword, int lifetime, int bits) { X509Certificate userCert = null; PrivateKey userKey = null; CertUtil.init(); try { OpenSSLKey key = new BouncyCastleOpenSSLKey(userKeyFile); if (key.isEncrypted()) { key.decrypt(keyPassword); } userKey = key.getPrivateKey(); } catch (IOException e) { System.out.println("Error: Failed to load key: " + userKeyFile); System.out.println("Make sure you have a valide private key installed."); e.printStackTrace(); return null; } catch (GeneralSecurityException e) { System.out.println("Error: Wrong grid pass phrase!"); e.printStackTrace(); return null; } try { userCert = CertUtil.loadCertificate(userCertFile); } catch (IOException e) { System.out.println("Error: Failed to load cert: " + userCertFile); System.out.println("Make sure you have a valide certificate installed."); e.printStackTrace(); return null; } catch (GeneralSecurityException e) { System.out.println("Error: Unable to load user certificate: " + e.getMessage()); e.printStackTrace(); return null; } BouncyCastleCertProcessingFactory factory = BouncyCastleCertProcessingFactory.getDefault(); boolean limited = false; int proxyType = (limited) ? GSIConstants.DELEGATION_LIMITED : GSIConstants.DELEGATION_FULL; try { GlobusCredential proxy = factory.createCredential(new X509Certificate[] { userCert }, userKey, bits, lifetime, proxyType); return new GlobusGSSCredentialImpl(proxy, GSSCredential.INITIATE_ONLY); } catch (Exception e) { System.out.println("Failed to create a proxy: " + e.getMessage()); e.printStackTrace(); return null; } } /** * The renewal request method is based on the Grid Canada's renew.sh script. * * @param newPrivateKeyPassword * @param chalenge * @param newPrivKeyLoc * @param userCertRenewFile * @return */ public static void genRenewRequest(GlobusGSSCredentialImpl cred, String newPrivateKeyPassword, String chalenge, String newPrivKeyLoc, String userCertRenewFile) throws GeneralSecurityException, IOException { File fTempDigest = null; try { // Extract the private key, encrypt it in new passphrase and save it as new user key // $OPENSSL rsa -des3 -in $TMPPROXY -out $RENEWALKEY OpenSSLKey key = new BouncyCastleOpenSSLKey(cred.getPrivateKey()); if (newPrivateKeyPassword.length() != 0) { key.encrypt(newPrivateKeyPassword); } key.writeTo(new File(newPrivKeyLoc).getAbsolutePath()); // set read only permissions Util.setFilePermissions(newPrivKeyLoc, 600); // copy proxy cert signed by user // $OPENSSL x509 -in $TMPPROXY >> $RENEWALREQ PrintStream ps = null; X509Certificate cert = null; byte[] data = null; X509Certificate[] certs = cred.getCertificateChain(); cert = certs[0]; data = cert.getEncoded(); ps = new PrintStream(new FileOutputStream(userCertRenewFile)); ////// part 1 ///// ps.print(toCertPEM(data)); // generate a digest which can not be copied // $OPENSSL x509 -in $TMPPROXY > $TMPPROXY.d // echo X$1 >> $TMPPROXY.d // $OPENSSL dgst < $TMPPROXY.d >> $RENEWALREQ fTempDigest = File.createTempFile("digest-", ".pem"); PrintStream psDigest = new PrintStream(new FileOutputStream(fTempDigest)); psDigest.print(toCertPEM(data)); psDigest.println("X" + chalenge); psDigest.close(); FileInputStream inDigest = null; inDigest = new FileInputStream(fTempDigest); int digestSize = inDigest.available(); byte[] digestData = new byte[digestSize]; inDigest.read(digestData, 0, digestSize); MessageDigest md = MessageDigest.getInstance("MD5"); int le = md.getDigestLength(); byte[] digest = md.digest(digestData); /////// part 2 /////// ps.println(Hex.toString(digest).toLowerCase()); // generate a cert req signed by the new key. // $OPENSSL x509 -in $TMPPROXY -x509toreq -signkey $RENEWALKEY >> $RENEWALREQ // Generate a certificate request. X509Name name = new X509Name(cert.getIssuerDN().getName()); DERConstructedSet derSet = new DERConstructedSet(); PKCS10CertificationRequest request = null; request = new PKCS10CertificationRequest("MD5WithRSA", name, cert.getPublicKey(), derSet, key.getPrivateKey()); /////// part 3 ///// ps.println("Certificate Request:"); ps.println(" Data:"); ps.print(cert.toString()); ps.print(toCertReqPEM(request.getEncoded())); ps.close(); } finally { if (fTempDigest != null) { fTempDigest.delete(); } } } /** * Converts to PEM encoding. */ static private String toCertPEM(byte[] data) { byte[] enc_data = Base64.encode(data); String header = "-----BEGIN CERTIFICATE-----"; ByteArrayOutputStream out = new ByteArrayOutputStream(); try { PEMUtils.writeBase64(out, header, enc_data, "-----END CERTIFICATE-----"); } catch (IOException e) { } return new String(out.toByteArray()); } /** * Converts to PEM encoding. */ static private String toCertReqPEM(byte[] data) { byte[] enc_data = Base64.encode(data); String header = "-----BEGIN CERTIFICATE REQUEST-----"; ByteArrayOutputStream out = new ByteArrayOutputStream(); try { PEMUtils.writeBase64(out, header, enc_data, "-----END CERTIFICATE REQUEST-----"); } catch (IOException e) { } return new String(out.toByteArray()); } }