SSL.java revision 6073:cea72c2bf071
1/* 2 * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 6894643 6913636 27 * @summary Test JSSE Kerberos ciphersuite 28 * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_SHA 29 * @run main/othervm SSL TLS_KRB5_WITH_RC4_128_MD5 30 * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_SHA 31 * @run main/othervm SSL TLS_KRB5_WITH_3DES_EDE_CBC_MD5 32 * @run main/othervm SSL TLS_KRB5_WITH_DES_CBC_SHA 33 * @run main/othervm SSL TLS_KRB5_WITH_DES_CBC_MD5 34 * @run main/othervm SSL TLS_KRB5_EXPORT_WITH_RC4_40_SHA 35 * @run main/othervm SSL TLS_KRB5_EXPORT_WITH_RC4_40_MD5 36 * @run main/othervm SSL TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA 37 * @run main/othervm SSL TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 38 */ 39import java.io.*; 40import java.net.InetAddress; 41import javax.net.ssl.*; 42import java.security.Principal; 43import java.util.Date; 44import sun.security.jgss.GSSUtil; 45import sun.security.krb5.PrincipalName; 46import sun.security.krb5.internal.ktab.KeyTab; 47 48public class SSL { 49 50 private static String krb5Cipher; 51 private static final int LOOP_LIMIT = 3; 52 private static int loopCount = 0; 53 private static volatile String server; 54 private static volatile int port; 55 56 // 0-Not started, 1-Start OK, 2-Failure 57 private static volatile int serverState = 0; 58 59 public static void main(String[] args) throws Exception { 60 61 krb5Cipher = args[0]; 62 63 KDC kdc = KDC.create(OneKDC.REALM); 64 // Run this after KDC, so our own DNS service can be started 65 try { 66 server = InetAddress.getLocalHost().getHostName().toLowerCase(); 67 } catch (java.net.UnknownHostException e) { 68 server = "localhost"; 69 } 70 71 kdc.addPrincipal(OneKDC.USER, OneKDC.PASS); 72 kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM); 73 KDC.saveConfig(OneKDC.KRB5_CONF, kdc); 74 System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF); 75 76 // Add 3 versions of keys into keytab 77 KeyTab ktab = KeyTab.create(OneKDC.KTAB); 78 PrincipalName service = new PrincipalName( 79 "host/" + server, PrincipalName.KRB_NT_SRV_HST); 80 ktab.addEntry(service, "pass1".toCharArray(), 1, true); 81 ktab.addEntry(service, "pass2".toCharArray(), 2, true); 82 ktab.addEntry(service, "pass3".toCharArray(), 3, true); 83 ktab.save(); 84 85 // and use the middle one as the real key 86 kdc.addPrincipal("host/" + server, "pass2".toCharArray()); 87 88 // JAAS config entry name ssl 89 System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF); 90 File f = new File(OneKDC.JAAS_CONF); 91 FileOutputStream fos = new FileOutputStream(f); 92 fos.write(( 93 "ssl {\n" + 94 " com.sun.security.auth.module.Krb5LoginModule required\n" + 95 " principal=\"host/" + server + "\"\n" + 96 " useKeyTab=true\n" + 97 " keyTab=" + OneKDC.KTAB + "\n" + 98 " isInitiator=false\n" + 99 " storeKey=true;\n};\n" 100 ).getBytes()); 101 fos.close(); 102 103 Context c; 104 final Context s = Context.fromJAAS("ssl"); 105 106 // There's no keytab file when server starts. 107 s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID); 108 109 Thread server = new Thread(new Runnable() { 110 public void run() { 111 try { 112 s.doAs(new JsseServerAction(), null); 113 } catch (Exception e) { 114 e.printStackTrace(); 115 serverState = 2; 116 } 117 } 118 }); 119 server.setDaemon(true); 120 server.start(); 121 122 while (serverState == 0) { 123 Thread.sleep(50); 124 } 125 126 if (serverState == 2) { 127 throw new Exception("Server already failed"); 128 } 129 130 // Now create the keytab 131 132 /* 133 // Add 3 versions of keys into keytab 134 KeyTab ktab = KeyTab.create(OneKDC.KTAB); 135 PrincipalName service = new PrincipalName( 136 "host/" + server, PrincipalName.KRB_NT_SRV_HST); 137 ktab.addEntry(service, "pass1".toCharArray(), 1); 138 ktab.addEntry(service, "pass2".toCharArray(), 2); 139 ktab.addEntry(service, "pass3".toCharArray(), 3); 140 ktab.save(); 141 142 // and use the middle one as the real key 143 kdc.addPrincipal("host/" + server, "pass2".toCharArray()); 144 */ 145 c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); 146 c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); 147 c.doAs(new JsseClientAction(), null); 148 149 // Add another version of key, make sure it can be loaded 150 Thread.sleep(2000); 151 ktab = KeyTab.getInstance(OneKDC.KTAB); 152 ktab.addEntry(service, "pass4".toCharArray(), 4, true); 153 ktab.save(); 154 kdc.addPrincipal("host/" + server, "pass4".toCharArray()); 155 156 c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); 157 c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); 158 c.doAs(new JsseClientAction(), null); 159 160 // Revoke the old key 161 /*Thread.sleep(2000); 162 ktab = KeyTab.create(OneKDC.KTAB); 163 ktab.addEntry(service, "pass5".toCharArray(), 5, false); 164 ktab.save(); 165 166 c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); 167 c.startAsClient("host/" + server, GSSUtil.GSS_KRB5_MECH_OID); 168 try { 169 c.doAs(new JsseClientAction(), null); 170 throw new Exception("Should fail this time."); 171 } catch (SSLException e) { 172 // Correct behavior. 173 }*/ 174 } 175 176 // Following codes copied from 177 // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/lab/part2.html#JSSE 178 private static class JsseClientAction implements Action { 179 public byte[] run(Context s, byte[] input) throws Exception { 180 SSLSocketFactory sslsf = 181 (SSLSocketFactory) SSLSocketFactory.getDefault(); 182 System.out.println("Connecting " + server + ":" + port); 183 SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(server, port); 184 185 // Enable only a KRB5 cipher suite. 186 String enabledSuites[] = {krb5Cipher}; 187 sslSocket.setEnabledCipherSuites(enabledSuites); 188 // Should check for exception if enabledSuites is not supported 189 190 BufferedReader in = new BufferedReader(new InputStreamReader( 191 sslSocket.getInputStream())); 192 BufferedWriter out = new BufferedWriter(new OutputStreamWriter( 193 sslSocket.getOutputStream())); 194 195 String outStr = "Hello There!\n"; 196 out.write(outStr); 197 out.flush(); 198 System.out.print("Sending " + outStr); 199 200 String inStr = in.readLine(); 201 System.out.println("Received " + inStr); 202 203 String cipherSuiteChosen = sslSocket.getSession().getCipherSuite(); 204 System.out.println("Cipher suite in use: " + cipherSuiteChosen); 205 Principal self = sslSocket.getSession().getLocalPrincipal(); 206 System.out.println("I am: " + self.toString()); 207 Principal peer = sslSocket.getSession().getPeerPrincipal(); 208 System.out.println("Server is: " + peer.toString()); 209 210 sslSocket.close(); 211 // This line should not be needed. It's the server's duty to 212 // forget the old key 213 //sslSocket.getSession().invalidate(); 214 return null; 215 } 216 } 217 218 private static class JsseServerAction implements Action { 219 public byte[] run(Context s, byte[] input) throws Exception { 220 SSLServerSocketFactory sslssf = 221 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 222 SSLServerSocket sslServerSocket = 223 (SSLServerSocket) sslssf.createServerSocket(0); // any port 224 port = sslServerSocket.getLocalPort(); 225 System.out.println("Listening on " + port); 226 serverState = 1; 227 228 // Enable only a KRB5 cipher suite. 229 String enabledSuites[] = {krb5Cipher}; 230 sslServerSocket.setEnabledCipherSuites(enabledSuites); 231 // Should check for exception if enabledSuites is not supported 232 233 while (loopCount++ < LOOP_LIMIT) { 234 System.out.println("Waiting for incoming connection..."); 235 236 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 237 238 System.out.println("Got connection from client " 239 + sslSocket.getInetAddress()); 240 241 BufferedReader in = new BufferedReader(new InputStreamReader( 242 sslSocket.getInputStream())); 243 BufferedWriter out = new BufferedWriter(new OutputStreamWriter( 244 sslSocket.getOutputStream())); 245 246 String inStr = in.readLine(); 247 System.out.println("Received " + inStr); 248 249 String outStr = inStr + " " + new Date().toString() + "\n"; 250 out.write(outStr); 251 System.out.println("Sending " + outStr); 252 out.flush(); 253 254 String cipherSuiteChosen = 255 sslSocket.getSession().getCipherSuite(); 256 System.out.println("Cipher suite in use: " + cipherSuiteChosen); 257 Principal self = sslSocket.getSession().getLocalPrincipal(); 258 System.out.println("I am: " + self.toString()); 259 Principal peer = sslSocket.getSession().getPeerPrincipal(); 260 System.out.println("Client is: " + peer.toString()); 261 262 sslSocket.close(); 263 } 264 return null; 265 } 266 } 267} 268