001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.net.http; 020 021 022import java.io.IOException; 023import java.io.InputStream; 024import java.io.OutputStream; 025import java.security.GeneralSecurityException; 026import java.security.KeyStore; 027import java.security.KeyStoreException; 028import java.security.NoSuchAlgorithmException; 029import java.security.cert.CertificateException; 030import java.security.cert.X509Certificate; 031 032import javax.net.ssl.SSLContext; 033import javax.net.ssl.SSLSocket; 034import javax.net.ssl.SSLSocketFactory; 035import javax.net.ssl.TrustManager; 036import javax.net.ssl.TrustManagerFactory; 037import javax.net.ssl.X509TrustManager; 038 039import lucee.commons.io.IOUtil; 040import lucee.commons.io.res.Resource; 041 042public class CertificateInstaller { 043 044 private String host; 045 private int port; 046 private char[] passphrase; 047 private Resource source; 048 private TrustManagerFactory tmf; 049 private SavingTrustManager tm; 050 private SSLContext context; 051 private KeyStore ks; 052 053 054 public CertificateInstaller(Resource source,String host, int port) throws IOException, KeyStoreException, GeneralSecurityException { 055 this(source,host,port,"changeit".toCharArray()); 056 } 057 058 public CertificateInstaller(Resource source,String host, int port, char[] passphrase) throws IOException, KeyStoreException, GeneralSecurityException { 059 this.source=source; 060 this.host=host; 061 this.port=port; 062 this.passphrase=passphrase; 063 064 065 ks=null; 066 InputStream in = source.getInputStream(); 067 try{ 068 ks = KeyStore.getInstance(KeyStore.getDefaultType()); 069 ks.load(in, passphrase); 070 } 071 finally{ 072 IOUtil.closeEL(in); 073 } 074 075 context = SSLContext.getInstance("SSL"); 076 tmf = 077 TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 078 tmf.init(ks); 079 X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; 080 tm = new SavingTrustManager(defaultTrustManager); 081 context.init(null, new TrustManager[] {tm}, null); 082 083 checkCertificate(); 084 085 if (tm.chain == null) 086 throw new IOException("Could not obtain server certificate chain"); 087 088 089 090 } 091 092 public void installAll() throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { 093 for(int i=0;i<tm.chain.length;i++){ 094 install(i); 095 } 096 } 097 098 public void install(int index) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException { 099 100 X509Certificate cert = tm.chain[index]; 101 String alias = host + "-" + (index + 1); 102 ks.setCertificateEntry(alias, cert); 103 104 OutputStream os = source.getOutputStream(); 105 try{ 106 ks.store(os, passphrase); 107 } 108 finally{ 109 IOUtil.closeEL(os); 110 } 111/* 112 System.out.println(); 113 System.out.println(cert); 114 System.out.println(); 115 System.out.println 116 ("Added certificate to keystore 'jssecacerts' using alias '" 117 + alias + "'"); 118*/ 119 } 120 121 /** 122 * checks if a certificate is installed for given host:port 123 * @param context 124 * @param host 125 * @param port 126 * @return 127 */ 128 public IOException checkCertificate() { 129 SSLSocketFactory factory = context.getSocketFactory(); 130 //System.out.println("Opening connection to " + host + ":" + port + "..."); 131 132 try { 133 SSLSocket socket = (SSLSocket)factory.createSocket(host, port); 134 socket.setSoTimeout(10000); 135 socket.startHandshake(); 136 socket.close(); 137 return null; 138 } 139 catch (IOException e) { 140 return e; 141 } 142 } 143 144 public void printCertificates() { 145 System.out.println("Server sent " + tm.chain.length + " certificate(s):"); 146 for (int i = 0; i < tm.chain.length; i++) { 147 X509Certificate cert = tm.chain[i]; 148 System.out.println 149 (" " + (i + 1) + " Subject " + cert.getSubjectDN()); 150 System.out.println(" Issuer " + cert.getIssuerDN()); 151 System.out.println(); 152 } 153 } 154 155 public X509Certificate[] getCertificates() { 156 return tm.chain; 157 } 158 159 160 161 private static class SavingTrustManager implements X509TrustManager { 162 163 private final X509TrustManager tm; 164 private X509Certificate[] chain; 165 166 SavingTrustManager(X509TrustManager tm) { 167 this.tm = tm; 168 } 169 170 public X509Certificate[] getAcceptedIssuers() { 171 throw new UnsupportedOperationException(); 172 } 173 174 public void checkClientTrusted(X509Certificate[] chain, String authType) 175 throws CertificateException { 176 throw new UnsupportedOperationException(); 177 } 178 179 public void checkServerTrusted(X509Certificate[] chain, String authType) 180 throws CertificateException { 181 this.chain = chain; 182 tm.checkServerTrusted(chain, authType); 183 } 184 } 185 186}