test/jdk/sun/security/krb5/auto/SSL.java
branchJDK-8145252-TLS13-branch
changeset 56542 56aaa6cb3693
parent 56541 92cbbfc996f3
child 56543 2352538d2f6e
equal deleted inserted replaced
56541:92cbbfc996f3 56542:56aaa6cb3693
     1 /*
       
     2  * Copyright (c) 2009, 2018, 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 8005523 8025123 8194486
       
    27  * @summary Test JSSE Kerberos ciphersuite
       
    28  * @library /test/lib
       
    29  * @run main jdk.test.lib.FileInstaller TestHosts TestHosts
       
    30  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    31  *      TLS_KRB5_WITH_RC4_128_SHA
       
    32  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    33  *      TLS_KRB5_WITH_RC4_128_SHA unbound
       
    34  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    35  *      TLS_KRB5_WITH_RC4_128_SHA unbound sni
       
    36  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    37  *      TLS_KRB5_WITH_3DES_EDE_CBC_SHA
       
    38  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    39  *      TLS_KRB5_WITH_3DES_EDE_CBC_MD5
       
    40  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    41  *      TLS_KRB5_WITH_DES_CBC_SHA
       
    42  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    43  *      TLS_KRB5_WITH_DES_CBC_MD5
       
    44  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    45  *      TLS_KRB5_EXPORT_WITH_RC4_40_SHA
       
    46  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    47  *      TLS_KRB5_EXPORT_WITH_RC4_40_MD5
       
    48  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    49  *      TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA
       
    50  * @run main/othervm -Djdk.net.hosts.file=TestHosts SSL
       
    51  *      TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5
       
    52  */
       
    53 import java.io.*;
       
    54 import java.security.Permission;
       
    55 import javax.net.ssl.*;
       
    56 import java.security.Principal;
       
    57 import java.security.Security;
       
    58 import java.util.Date;
       
    59 import java.util.List;
       
    60 import java.util.ArrayList;
       
    61 import java.util.Locale;
       
    62 import javax.security.auth.kerberos.ServicePermission;
       
    63 import sun.security.jgss.GSSUtil;
       
    64 import sun.security.krb5.PrincipalName;
       
    65 import sun.security.krb5.internal.ktab.KeyTab;
       
    66 
       
    67 public class SSL extends SecurityManager {
       
    68 
       
    69     private static String krb5Cipher;
       
    70     private static final int LOOP_LIMIT = 3;
       
    71     private static int loopCount = 0;
       
    72     private static volatile String server;
       
    73     private static volatile int port;
       
    74     private static String sniHostname = null;
       
    75     private static String sniMatcherPattern = null;
       
    76 
       
    77     private static String permChecks = "";
       
    78 
       
    79     // 0-Not started, 1-Start OK, 2-Failure
       
    80     private static volatile int serverState = 0;
       
    81 
       
    82     @Override
       
    83     public void checkPermission(Permission perm, Object context) {
       
    84         checkPermission(perm);
       
    85     }
       
    86 
       
    87     public void checkPermission(Permission perm) {
       
    88         if (!(perm instanceof ServicePermission)) {
       
    89             return;
       
    90         }
       
    91         ServicePermission p = (ServicePermission)perm;
       
    92         // ServicePermissions required to create GSSName are ignored
       
    93         if (!p.getActions().isEmpty()) {
       
    94             permChecks = permChecks
       
    95                 + p.getActions().toUpperCase(Locale.US).charAt(0);
       
    96         }
       
    97     }
       
    98 
       
    99     public static void main(String[] args) throws Exception {
       
   100         // reset the security property to make sure that the algorithms
       
   101         // and keys used in this test are not disabled.
       
   102         Security.setProperty("jdk.tls.disabledAlgorithms", "");
       
   103 
       
   104         krb5Cipher = args[0];
       
   105 
       
   106         boolean unbound = args.length > 1;
       
   107 
       
   108         // Workaround for JDK-8161101, reference the class before
       
   109         // SecurityManager is set.
       
   110         System.out.println("Touching " + ServicePermission.class);
       
   111 
       
   112         System.setSecurityManager(new SSL());
       
   113 
       
   114         KDC kdc = KDC.create(OneKDC.REALM);
       
   115         server = "host." + OneKDC.REALM_LOWER_CASE;
       
   116 
       
   117         if (args.length > 2) {
       
   118             sniHostname = "test." + server;
       
   119             sniMatcherPattern = ".*";
       
   120         }
       
   121 
       
   122         kdc.addPrincipal(OneKDC.USER, OneKDC.PASS);
       
   123         kdc.addPrincipalRandKey("krbtgt/" + OneKDC.REALM);
       
   124         KDC.saveConfig(OneKDC.KRB5_CONF, kdc);
       
   125         System.setProperty("java.security.krb5.conf", OneKDC.KRB5_CONF);
       
   126 
       
   127         // Add 3 versions of keys into keytab
       
   128         KeyTab ktab = KeyTab.create(OneKDC.KTAB);
       
   129         String serviceName = null;
       
   130         if (sniHostname != null) {
       
   131             serviceName = "host/" + sniHostname;
       
   132         } else {
       
   133             serviceName = "host/" + server;
       
   134         }
       
   135         PrincipalName service = new PrincipalName(
       
   136             serviceName, PrincipalName.KRB_NT_SRV_HST);
       
   137         ktab.addEntry(service, "pass1".toCharArray(), 1, true);
       
   138         ktab.addEntry(service, "pass2".toCharArray(), 2, true);
       
   139         ktab.addEntry(service, "pass3".toCharArray(), 3, true);
       
   140         ktab.save();
       
   141 
       
   142         // and use the middle one as the real key
       
   143         kdc.addPrincipal(serviceName, "pass2".toCharArray());
       
   144 
       
   145 
       
   146         // JAAS config entry name ssl
       
   147         System.setProperty("java.security.auth.login.config", OneKDC.JAAS_CONF);
       
   148         File f = new File(OneKDC.JAAS_CONF);
       
   149         FileOutputStream fos = new FileOutputStream(f);
       
   150         fos.write((
       
   151                 "ssl {\n" +
       
   152                 "    com.sun.security.auth.module.Krb5LoginModule required\n" +
       
   153                 (unbound ?
       
   154                     "    principal=*\n" :
       
   155                     "    principal=\"" + serviceName + "\"\n") +
       
   156                 "    useKeyTab=true\n" +
       
   157                 "    keyTab=" + OneKDC.KTAB + "\n" +
       
   158                 "    isInitiator=false\n" +
       
   159                 "    storeKey=true;\n};\n"
       
   160                 ).getBytes());
       
   161         fos.close();
       
   162 
       
   163         Context c;
       
   164         final Context s = Context.fromJAAS("ssl");
       
   165 
       
   166         s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
       
   167 
       
   168         Thread server = new Thread(new Runnable() {
       
   169             public void run() {
       
   170                 try {
       
   171                     s.doAs(new JsseServerAction(), null);
       
   172                 } catch (Exception e) {
       
   173                     e.printStackTrace();
       
   174                     serverState = 2;
       
   175                 }
       
   176             }
       
   177         });
       
   178         server.setDaemon(true);
       
   179         server.start();
       
   180 
       
   181         while (serverState == 0) {
       
   182             Thread.sleep(50);
       
   183         }
       
   184 
       
   185         if (serverState == 2) {
       
   186             throw new Exception("Server already failed");
       
   187         }
       
   188 
       
   189         c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
       
   190         c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
       
   191         c.doAs(new JsseClientAction(), null);
       
   192 
       
   193         // Add another version of key, make sure it can be loaded
       
   194         Thread.sleep(2000);
       
   195         ktab = KeyTab.getInstance(OneKDC.KTAB);
       
   196         ktab.addEntry(service, "pass4".toCharArray(), 4, true);
       
   197         ktab.save();
       
   198         kdc.addPrincipal(serviceName, "pass4".toCharArray());
       
   199 
       
   200         c = Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false);
       
   201         c.startAsClient(serviceName, GSSUtil.GSS_KRB5_MECH_OID);
       
   202         c.doAs(new JsseClientAction(), null);
       
   203 
       
   204         // Permission checking check. Please note this is highly
       
   205         // implementation related.
       
   206         if (unbound) {
       
   207             // For unbound, server does not know what name to check.
       
   208             // Client checks "initiate", then server gets the name
       
   209             // and checks "accept". Second connection resume.
       
   210             if (!permChecks.equals("IA")) {
       
   211                 throw new Exception(permChecks);
       
   212             }
       
   213         } else {
       
   214             // For bound, JAAS checks "accept" once. Server checks again,
       
   215             // client then checks "initiate". Second connection resume.
       
   216             if (!permChecks.equals("AAI")) {
       
   217                 throw new Exception(permChecks);
       
   218             }
       
   219         }
       
   220     }
       
   221 
       
   222     // Following codes copied from
       
   223     // http://java.sun.com/javase/6/docs/technotes/guides/security/jgss/lab/part2.html#JSSE
       
   224     private static class JsseClientAction implements Action {
       
   225         public byte[] run(Context s, byte[] input) throws Exception {
       
   226             SSLSocketFactory sslsf =
       
   227                 (SSLSocketFactory) SSLSocketFactory.getDefault();
       
   228             System.out.println("Connecting " + server + ":" + port);
       
   229             SSLSocket sslSocket = (SSLSocket) sslsf.createSocket(server, port);
       
   230 
       
   231             // Enable only a KRB5 cipher suite.
       
   232             String enabledSuites[] = {krb5Cipher};
       
   233             sslSocket.setEnabledCipherSuites(enabledSuites);
       
   234             // Should check for exception if enabledSuites is not supported
       
   235 
       
   236             if (sniHostname != null) {
       
   237                 List<SNIServerName> serverNames = new ArrayList<>();
       
   238                 serverNames.add(new SNIHostName(sniHostname));
       
   239                 SSLParameters params = sslSocket.getSSLParameters();
       
   240                 params.setServerNames(serverNames);
       
   241                 sslSocket.setSSLParameters(params);
       
   242             }
       
   243 
       
   244             BufferedReader in = new BufferedReader(new InputStreamReader(
       
   245                 sslSocket.getInputStream()));
       
   246             BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
       
   247                 sslSocket.getOutputStream()));
       
   248 
       
   249             String outStr = "Hello There!\n";
       
   250             out.write(outStr);
       
   251             out.flush();
       
   252             System.out.print("Sending " + outStr);
       
   253 
       
   254             String inStr = in.readLine();
       
   255             System.out.println("Received " + inStr);
       
   256 
       
   257             String cipherSuiteChosen = sslSocket.getSession().getCipherSuite();
       
   258             System.out.println("Cipher suite in use: " + cipherSuiteChosen);
       
   259             Principal self = sslSocket.getSession().getLocalPrincipal();
       
   260             System.out.println("I am: " + self.toString());
       
   261             Principal peer = sslSocket.getSession().getPeerPrincipal();
       
   262             System.out.println("Server is: " + peer.toString());
       
   263 
       
   264             sslSocket.close();
       
   265             // This line should not be needed. It's the server's duty to
       
   266             // forget the old key
       
   267             //sslSocket.getSession().invalidate();
       
   268             return null;
       
   269         }
       
   270     }
       
   271 
       
   272     private static class JsseServerAction implements Action {
       
   273         public byte[] run(Context s, byte[] input) throws Exception {
       
   274             SSLServerSocketFactory sslssf =
       
   275                 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
       
   276             SSLServerSocket sslServerSocket =
       
   277                 (SSLServerSocket) sslssf.createServerSocket(0); // any port
       
   278             port = sslServerSocket.getLocalPort();
       
   279             System.out.println("Listening on " + port);
       
   280             serverState = 1;
       
   281 
       
   282             // Enable only a KRB5 cipher suite.
       
   283             String enabledSuites[] = {krb5Cipher};
       
   284             sslServerSocket.setEnabledCipherSuites(enabledSuites);
       
   285             // Should check for exception if enabledSuites is not supported
       
   286 
       
   287             if (sniMatcherPattern != null) {
       
   288                 List<SNIMatcher> matchers = new ArrayList<>();
       
   289                 matchers.add(SNIHostName.createSNIMatcher(sniMatcherPattern));
       
   290                 SSLParameters params = sslServerSocket.getSSLParameters();
       
   291                 params.setSNIMatchers(matchers);
       
   292                 sslServerSocket.setSSLParameters(params);
       
   293             }
       
   294 
       
   295             while (loopCount++ < LOOP_LIMIT) {
       
   296                 System.out.println("Waiting for incoming connection...");
       
   297 
       
   298                 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
       
   299 
       
   300                 System.out.println("Got connection from client "
       
   301                     + sslSocket.getInetAddress());
       
   302 
       
   303                 BufferedReader in = new BufferedReader(new InputStreamReader(
       
   304                     sslSocket.getInputStream()));
       
   305                 BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
       
   306                     sslSocket.getOutputStream()));
       
   307 
       
   308                 String inStr = in.readLine();
       
   309                 System.out.println("Received " + inStr);
       
   310 
       
   311                 String outStr = inStr + " " + new Date().toString() + "\n";
       
   312                 out.write(outStr);
       
   313                 System.out.println("Sending " + outStr);
       
   314                 out.flush();
       
   315 
       
   316                 String cipherSuiteChosen =
       
   317                     sslSocket.getSession().getCipherSuite();
       
   318                 System.out.println("Cipher suite in use: " + cipherSuiteChosen);
       
   319                 Principal self = sslSocket.getSession().getLocalPrincipal();
       
   320                 System.out.println("I am: " + self.toString());
       
   321                 Principal peer = sslSocket.getSession().getPeerPrincipal();
       
   322                 System.out.println("Client is: " + peer.toString());
       
   323 
       
   324                 sslSocket.close();
       
   325             }
       
   326             return null;
       
   327         }
       
   328     }
       
   329 }