/* 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.plugins.openca; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.log4j.Logger; import org.vpac.grix.control.utils.GrixProperty; import org.vpac.grix.control.utils.UserProperty; import org.vpac.grix.exceptions.certificate.UnableToUploadCertificationRequestException; import org.vpac.grix.external.ClientHttpRequest; import org.vpac.grix.model.certificate.CertificationRequest; /** * This class is used to download a certificate from an openca server via * http(s). * * @author Markus Binsteiner * */ public class OpenCA { static final Logger myLogger = Logger.getLogger(OpenCA.class.getName()); private static void installTrustManager() { // TODO try better way to create https connection. maybe using // hostname verifier // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection .setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { } } /** * Initializes this plugin. */ // public static void init() { // // if (UnlimitedStrengthPolicyManager.maxRSAKeysize() >= GrixProperty // .getInt("OPENCA_SERVER_KEYSIZE")) { // myLogger // .debug("Able to communicate with the openca server. That's good."); // UserProperty.setProperty("ABLE_TO_COMMUNICATE_WITH_OPENCA_SERVER", // "yes"); // } else { // myLogger // .debug("Not able to communicate with the openca server because of java policy restrictions. That's not good."); // UserProperty.setProperty("ABLE_TO_COMMUNICATE_WITH_OPENCA_SERVER", // "no"); // } // // } /** * Checks whether the certification request with the specified * request_serial number is processed by the CA. * * @param request_serial * the request serial * @return true if ready to download, false if not */ public static boolean checkStatusOfRequest(String request_serial) { installTrustManager(); URL url = null; try { url = new URL(GrixProperty.getString("openca.base.url") + "?cmd=lists;action=newReqs"); } catch (MalformedURLException e) { // TODO Auto-generated catch block/ throw exception // e.printStackTrace(); myLogger.error(e); } String result = readPage(url); if (result == null) { myLogger.debug("Could not read OpenCA page... returning \"ready\" nontheless."); // TODO throw exception return true; } if (result.indexOf(request_serial) != -1) { // found, means not processed yet myLogger.debug("Request serial found, this means the request is not processed yet."); return false; } else { while ((url = containsNextPage(result)) != null) { myLogger.debug("Next page url: " + url.toString()); result = readPage(url); if (result == null) { myLogger.debug("Could not read OpenCA page... returning \"ready\" nontheless."); return true; // TODO throw exception } if (result.indexOf(request_serial) != -1) { myLogger.debug("Request serial found on this page, this means the request is not processed yet."); return false; // still on list => not processed } } myLogger.debug("Request processed."); return true; } } private static String readPage(URL url) { StringBuffer result = new StringBuffer(); BufferedReader reader = null; try { reader = new BufferedReader(new InputStreamReader(url.openStream())); String line = null; while ((line = reader.readLine()) != null) { result.append(line); result.append(System.getProperty("line.separator")); } } catch (IOException ex) { myLogger.debug("Cannot retrieve contents of: " + url); return null; } finally { try { reader.close(); } catch (Exception e) { // TODO Auto-generated catch block // e.printStackTrace(); myLogger.error(e); return null; } } return result.toString(); } private static URL containsNextPage(String page_body) { if (page_body.indexOf(">>") != -1) { int startLink = page_body .lastIndexOf("Extra References  <a href=") + 32; int endLink = page_body.indexOf(">></a>  ", startLink) - 1; String url_string = page_body.substring(startLink, endLink); if ((startLink = url_string.lastIndexOf("<</a>")) != -1) { startLink = url_string.indexOf("<a href=", startLink) + 9; url_string = url_string.substring(startLink); } URL url = null; try { url = new URL(GrixProperty.getString("openca.base.url") + url_string); } catch (MalformedURLException e) { // TODO Auto-generated catch block // e.printStackTrace(); myLogger.error(e); return null; } return url; } else return null; } /** * Download the certificate via https. This installs a trust-manager that * does not validate certificate chains. This may be altered in the future, * although I don't think it is really a security concern in our case. * * @return The base64 encoded certificate as a string. * @throws Exception */ public static String downloadCertificate(String c, String o, String ou, String cn, String email) throws Exception { if (email == null) email = "*"; // TODO check this: // cn = "*"; String value4 = "*"; Object[] post_options_pre = { // "value_1", cn, "value_1", "*", "value_2", email, "value_3", "*CN=" + cn + // "*OU="+ou+ //because of possible change of organisation on ca // side "*O=" + o + "*C=" + c + "*", "value_4", value4, "value_5", "", "name_3", "DN", "name_5", "KEY", "name_1", "CN", "cmd", "search", "dataType", "CERTIFICATE", "name_4", "ROLE", "pcounter", "5", "name_2", "EMAILADDRESS" }; // Object[] post_options_pre = { // "value_1", cn, // "value_2", email, // "value_3", "*", // "value_4", "*", // "value_5", "", // "name_1", "CN", // "name_2", "EMAILADDRESS", // "name_3", "DN", // "name_4", "ROLE", // "cmd", "search", // "pcounter", "5" // }; String certificate = null; installTrustManager(); URL url_pre = new URL("https://ca.apac.edu.au/cgi-bin/pub/pki"); InputStream serverinput_pre = ClientHttpRequest.post(url_pre, post_options_pre); BufferedInputStream bufin_pre = new BufferedInputStream(serverinput_pre); myLogger.debug("parsing html..."); BufferedReader br_pre = new BufferedReader(new InputStreamReader( bufin_pre)); String line_pre; int serial = -1; StringBuffer result_pre = new StringBuffer(); myLogger.debug("Search answer: "); // search for the serial number of the certificate if there are multiple // then use the last one found while ((line_pre = br_pre.readLine()) != null) { // result_pre = result_pre.append( line_pre ); // result_pre = result_pre.append( "\n" ); myLogger.debug(line_pre); String searchString = GrixProperty .getString("openca.server.keyword.start"); String searchString_end = GrixProperty .getString("openca.server.keyword.end"); int pos = line_pre.indexOf(searchString); if (pos != -1) { serial = new Integer(line_pre.subSequence( pos + searchString.length(), line_pre.indexOf(searchString_end, pos + 1)).toString()); } } bufin_pre.close(); if (serial == -1) { myLogger.debug("Serial not found. Can't download certificate."); return null; } myLogger.debug("Serial found: " + serial); URL url = new URL(GrixProperty.getString("openca.base.url")); Object[] post_options = { "format_sendcert", "pem", "Submit", "Download", "GET_PARAMS_CMD", "", "cmd", "sendcert", "dataType", "VALID_CERTIFICATE", "name", "PUBLIC", "key", serial, "HIDDEN_key", serial, "passwd", "", "signature", "", "format", "", "text", "", "new_dn", "", "dn", "" }; InputStream serverinput = ClientHttpRequest.post(url, post_options); BufferedInputStream bufin = new BufferedInputStream(serverinput); myLogger.debug("pasing xhtml..."); BufferedReader br = new BufferedReader(new InputStreamReader(bufin)); String line; StringBuffer result = new StringBuffer(); while ((line = br.readLine()) != null) { result = result.append(line); result = result.append("\n"); } certificate = result.toString(); bufin.close(); myLogger.debug("Answer from server: \n\n" + certificate); return certificate; } /** * Uploads a user certification request onto an OpenCA server via http(s) * post. * * @param cert_req * The certificationRequest * @return a String array consisting of string[0]=short message, * string[1]=long message(e.g. server answer) * @throws Exception */ public static String[] uploadCertificationRequest( CertificationRequest cert_req, String department, String telephone) throws Exception { return uploadCertificationRequest(cert_req, false, cert_req.getCn(), cert_req.getEmail(), department, telephone); } /** * Uploads a certification request onto an OpenCA server via http(s) post. * * @param cert_req * The certificationRequest * @param email * The email address of the user (used for hostcerts, because * these don't contain email addresses) * @param hostCert * whether this request is for a hostcert or not * @return a String array consisting of string[0]=short message, * string[1]=long message(e.g. server answer) * @throws Exception */ public static String[] uploadCertificationRequest( CertificationRequest cert_req, boolean hostCert, String name, String email, String department, String telephone) throws Exception { String result = null; String additional_attribute_department = department; String loa = ""; String request = cert_req.getEncodedRequest(); String additional_attribute_telephone = telephone; String cmd = "pkcs10_req"; String passwd1 = ""; String passwd2 = ""; String additional_attribute_email = email; // cert_req.getEmail(); String ra = cert_req.getOu(); // TODO translate String operation = "server-confirmed-form"; String role = "Web Server"; if (!hostCert) role = "User"; String additional_attribute_requestercn = name;// cert_req.getCn(); Object[] post_options = { "ADDITIONAL_ATTRIBUTE_DEPARTMENT", additional_attribute_department, "loa", loa, "request", request, // "request", "-----BEGIN CERTIFICATE // REQUEST-----\nMIIBuDCCASECAQAwXXXeDELMAkGA1UEBhMCQVUxETAPBgNVBAoTCEFQQUNHcmlkMQ0w\nCwYDVQQLEwRWUEFDMScwJQYDVQQDEx5QbGVhc2UgZGVsZXRlIG1lIHN0cmFpZ2h0\nIGF3YXkxHjAcBgkqhkiG9w0BCQEWD21hcmt1c0B2cGFjLm9yZzCBnzANBgkqhkiG\n9w0BAQEFAAOBjQAwgYkCgYEAtqPqSqO3fHUs/3b95musvjeIYZ1zTFk9R1KF5MfL\n1ica/Uf/XGqzPfNA2WeRHE1cE2wRjImRO8Z2IYFwo1Wu5aSGPiOodi/Qymuw29NP\n20sO4USWJk/womBRhQATUPmAgQdJp4WMJPvditfdkzyrWnYemOXKot4Xiidj01/R\n2XkCAwEAAaAAMA0GCSqGSIb3DQEBBAUAA4GBAGO4C/8ybRLZ9rDTIE3+QmthiSGs\n4rewkiiTLar2thR/+rrpOA6RwjmGZEotZBY195wSmpmAPpTypmvehDqRgiXCqLWe\nFqrbRZKFsHRPf4iSZTPiw4zyNi3lOOZX6IyI+PadR6BNXJeFK0K1XLogmzRNZmtA\nRLc2sqwMIglFNIzJ\n-----END // CERTIFICATE REQUEST-----", "ADDITIONAL_ATTRIBUTE_TELEPHONE", additional_attribute_telephone, "cmd", cmd, "passwd1", passwd1, "ADDITIONAL_ATTRIBUTE_EMAIL", additional_attribute_email, "ra", ra, "passwd2", passwd2, "operation", operation, "role", role, "ADDITIONAL_ATTRIBUTE_REQUESTERCN", additional_attribute_requestercn }; installTrustManager(); URL url = new URL(GrixProperty.getString("openca.base.url")); InputStream serverinput = ClientHttpRequest.post(url, post_options); // BufferedInputStream bufin = new BufferedInputStream( serverinput ); myLogger.debug("parsing xhtml..."); // Don't know whether clean html or not // result = Utils.getCleanXHTML( bufin ); StringBuffer answer = new StringBuffer(); BufferedReader buff = new BufferedReader(new InputStreamReader( serverinput)); char[] buf = new char[1024]; int numRead = 0; while ((numRead = buff.read(buf)) != -1) { String readData = String.valueOf(buf, 0, numRead); answer.append(readData); buf = new char[1024]; } buff.close(); serverinput.close(); // TODO dodgy but I don't know how else to do it. try { int index = answer.indexOf("serial") + 7; if (index == -1 || answer.indexOf("error") != -1 || answer.indexOf("Error") != -1) { // means: not successful myLogger.error("Could not upload certification request."); throw new UnableToUploadCertificationRequestException("OpenCA", new Exception(answer.toString())); } int index_end = answer.indexOf(" ", index); String req_serial = answer.substring(index, index_end); UserProperty.setProperty("REQUEST_SERIAL", req_serial); } catch (RuntimeException e) { // TODO Auto-generated catch block // e.printStackTrace(); myLogger.error(e); throw e; } myLogger.debug("Answer from server: \n\n" + answer); return new String[] { "Upload successful", answer.toString() }; } }