1 /*
   2  * Copyright (c) 2005, 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  *
  26  *
  27  * @summary Testing keytool
  28  * @author weijun.wang
  29  *
  30  * Run through autotest.sh and manualtest.sh
  31  *
  32  * Testing non-PKCS11 keystores:
  33  *       echo | java -Dfile KeyToolTest
  34  *
  35  * Testing NSS PKCS11 keystores:
  36  *       # testing NSS
  37  *       # make sure the NSS db files are in current directory and writable
  38  *       echo | java -Dnss -Dnss.lib=/path/to/libsoftokn3.so KeyToolTest
  39  *
  40  * Testing Solaris Cryptography Framework PKCS11 keystores:
  41  *       # make sure you've already run pktool and set test12 as pin
  42  *       echo | java -Dsolaris KeyToolTest
  43  *
  44  * ATTENTION:
  45  * Exception in thread "main" java.security.ProviderException:
  46  *   sun.security.pkcs11.wrapper.PKCS11Exception: CKR_KEY_SIZE_RANGE
  47  *       at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:420)
  48  *       ...
  49  * Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_KEY_SIZE_RANGE
  50  *       at sun.security.pkcs11.wrapper.PKCS11.C_SignFinal(Native Method)
  51  *       at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:391)
  52  *       ...
  53  * been observed. Possibly a Solaris bug
  54  *
  55  * ATTENTION:
  56  * NSS PKCS11 config file are changed, DSA not supported now.
  57  */
  58 
  59 import java.nio.file.Files;
  60 import java.nio.file.Paths;
  61 import java.security.KeyStore;
  62 import sun.security.x509.*;
  63 import java.io.*;
  64 import java.security.KeyPairGenerator;
  65 import java.security.NoSuchAlgorithmException;
  66 import java.util.*;
  67 import java.security.cert.X509Certificate;
  68 import sun.security.util.ObjectIdentifier;
  69 
  70 public class KeyToolTest {
  71 
  72     // The stdout and stderr outputs after a keytool run
  73     String out;
  74     String err;
  75 
  76     // the output of println() in KeyTool.run
  77     String ex;
  78 
  79     String lastInput = "", lastCommand = "";
  80     private static final boolean debug =
  81         System.getProperty("debug") != null;
  82 
  83     static final String NSS_P11_ARG =
  84             "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nss " +
  85             "-providerClass sun.security.pkcs11.SunPKCS11 " +
  86             "-providerArg p11-nss.txt ";
  87     static final String NSS_SRC_P11_ARG =
  88             "-srckeystore NONE -srcstoretype PKCS11 " +
  89             "-srcproviderName SunPKCS11-nss " +
  90             "-providerClass sun.security.pkcs11.SunPKCS11 " +
  91             "-providerArg p11-nss.txt ";
  92     static final String NZZ_P11_ARG =
  93             "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nzz " +
  94             "-providerClass sun.security.pkcs11.SunPKCS11 " +
  95             "-providerArg p11-nzz.txt ";
  96     static final String NZZ_SRC_P11_ARG =
  97             "-srckeystore NONE -srcstoretype PKCS11 " +
  98             "-srcproviderName SunPKCS11-nzz " +
  99             "-providerClass sun.security.pkcs11.SunPKCS11 " +
 100             "-providerArg p11-nzz.txt ";
 101     static final String SUN_P11_ARG = "-keystore NONE -storetype PKCS11 ";
 102     static final String SUN_SRC_P11_ARG =
 103             "-srckeystore NONE -srcstoretype PKCS11 ";
 104 
 105     String p11Arg, srcP11Arg;
 106 
 107     /** Creates a new instance of KeyToolTest */
 108     KeyToolTest() {
 109         // so that there is "Warning" and not translated into other language
 110         Locale.setDefault(Locale.US);
 111     }
 112 
 113     /**
 114      * Helper, removes a file
 115      */
 116     void remove(String filename) {
 117         if (debug) {
 118             System.err.println("Removing " + filename);
 119         }
 120         new File(filename).delete();
 121         if (new File(filename).exists()) {
 122             throw new RuntimeException("Error deleting " + filename);
 123         }
 124     }
 125 
 126     /**
 127      * Run a set of keytool command with given terminal input.
 128      * @param input the terminal inputs, the characters typed by human
 129      *        if <code>cmd</code> is running on a terminal
 130      * @param cmd the argument of a keytool command line
 131      * @throws if keytool goes wrong in some place
 132      */
 133     void test(String input, String cmd) throws Exception {
 134         lastInput = input;
 135         lastCommand = cmd;
 136 
 137         // "X" is appended so that we can precisely test how input is consumed
 138         HumanInputStream in = new HumanInputStream(input+"X");
 139         test(in, cmd);
 140         // make sure the input string is no more no less
 141         if(in.read() != 'X' || in.read() != -1)
 142             throw new Exception("Input not consumed exactly");
 143     }
 144 
 145     void test(InputStream in, String cmd) throws Exception {
 146 
 147         // save the original 3 streams
 148         if (debug) {
 149             System.err.println(cmd);
 150         } else {
 151             System.err.print(".");
 152         }
 153         PrintStream p1 = System.out;
 154         PrintStream p2 = System.err;
 155         InputStream i1 = System.in;
 156 
 157         ByteArrayOutputStream b1 = new ByteArrayOutputStream();
 158         ByteArrayOutputStream b2 = new ByteArrayOutputStream();
 159 
 160         try {
 161             System.setIn(in);
 162             System.setOut(new PrintStream(b1));
 163             System.setErr(new PrintStream(b2));
 164 
 165             // since System.in is overrided, the
 166             // sun.security.tools.keytool.Main.main() method will
 167             // never block at user input
 168 
 169             // use -debug so that main() will throw an Exception
 170             // instead of calling System.exit()
 171             sun.security.tools.keytool.Main.main(("-debug "+cmd).split("\\s+"));
 172         } finally {
 173             out = b1.toString();
 174             err = b2.toString();
 175             ex = out;   // now it goes to System.out
 176             System.setIn(i1);
 177             System.setOut(p1);
 178             System.setErr(p2);
 179         }
 180     }
 181 
 182     /**
 183      * Call this method if you expect test(input, cmd) should go OK
 184      */
 185     void testOK(String input, String cmd) throws Exception {
 186         try {
 187             // Workaround for "8057810: Make SHA256withDSA the default
 188             // jarsigner and keytool algorithm for DSA keys". Unfortunately
 189             // SunPKCS11-NSS does not support SHA256withDSA yet.
 190             if (cmd.contains("p11-nss.txt") && cmd.contains("-genkey")
 191                     && !cmd.contains("-keyalg")) {
 192                 cmd += " -sigalg SHA1withDSA -keysize 1024";
 193             }
 194             test(input, cmd);
 195         } catch(Exception e) {
 196             afterFail(input, cmd, "OK");
 197             throw e;
 198         }
 199     }
 200 
 201     /**
 202      * Call this method if you expect test(input, cmd) should fail and throw
 203      * an exception
 204      */
 205     void testFail(String input, String cmd) throws Exception {
 206         boolean ok;
 207         try {
 208             test(input, cmd);
 209             ok = true;
 210         } catch(Exception e) {
 211             if (e instanceof MissingResourceException) {
 212                 ok = true;
 213             } else {
 214                 ok = false;
 215             }
 216         }
 217         if(ok) {
 218             afterFail(input, cmd, "FAIL");
 219             throw new RuntimeException();
 220         }
 221     }
 222 
 223     /**
 224      * Call this method if you expect test(input, cmd) should go OK
 225      */
 226     void testOK(InputStream is, String cmd) throws Exception {
 227         try {
 228             test(is, cmd);
 229         } catch(Exception e) {
 230             afterFail("", cmd, "OK");
 231             throw e;
 232         }
 233     }
 234 
 235     /**
 236      * Call this method if you expect test(input, cmd) should fail and throw
 237      * an exception
 238      */
 239     void testFail(InputStream is, String cmd) throws Exception {
 240         boolean ok;
 241         try {
 242             test(is, cmd);
 243             ok = true;
 244         } catch(Exception e) {
 245             ok = false;
 246         }
 247         if(ok) {
 248             afterFail("", cmd, "FAIL");
 249             throw new RuntimeException();
 250         }
 251     }
 252 
 253     /**
 254      * Call this method if you just want to run the command and does
 255      * not care if it succeeds or fails.
 256      */
 257     void testAnyway(String input, String cmd) {
 258         try {
 259             test(input, cmd);
 260         } catch(Exception e) {
 261             ;
 262         }
 263     }
 264 
 265     /**
 266      * Helper method, print some output after a test does not do as expected
 267      */
 268     void afterFail(String input, String cmd, String should) {
 269         if (cmd.contains("p11-nss.txt")) {
 270             cmd = "-J-Dnss.lib=" + System.getProperty("nss.lib") + " " + cmd;
 271         }
 272         System.err.println("\nTest fails for the command ---\n" +
 273                 "keytool " + cmd + "\nOr its debug version ---\n" +
 274                 "keytool -debug " + cmd);
 275 
 276         System.err.println("The command result should be " + should +
 277                 ", but it's not. Try run the command manually and type" +
 278                 " these input into it: ");
 279         char[] inputChars = input.toCharArray();
 280 
 281         for (int i=0; i<inputChars.length; i++) {
 282             char ch = inputChars[i];
 283             if (ch == '\n') System.err.print("ENTER ");
 284             else if (ch == ' ') System.err.print("SPACE ");
 285             else System.err.print(ch + " ");
 286         }
 287         System.err.println("");
 288 
 289         System.err.println("ERR is:\n"+err);
 290         System.err.println("OUT is:\n"+out);
 291     }
 292 
 293     void assertTrue(boolean bool, String msg) {
 294         if (debug) {
 295             System.err.println("If not " + bool + ", " + msg);
 296         } else {
 297             System.err.print("v");
 298         }
 299         if(!bool) {
 300             afterFail(lastInput, lastCommand, "TRUE");
 301                 System.err.println(msg);
 302             throw new RuntimeException(msg);
 303         }
 304     }
 305 
 306     void assertTrue(boolean bool) {
 307         assertTrue(bool, "well...");
 308     }
 309     /**
 310      * Helper method, load a keystore
 311      * @param file file for keystore, null or "NONE" for PKCS11
 312      * @pass password for the keystore
 313      * @type keystore type
 314      * @returns the KeyStore object
 315      * @exception Exception if anything goes wrong
 316      */
 317     KeyStore loadStore(String file, String pass, String type) throws Exception {
 318         KeyStore ks = KeyStore.getInstance(type);
 319         FileInputStream is = null;
 320         if (file != null && !file.equals("NONE")) {
 321             is = new FileInputStream(file);
 322         }
 323         ks.load(is, pass.toCharArray());
 324         is.close();
 325         return ks;
 326     }
 327 
 328     /**
 329      * The test suite.
 330      * Maybe it's better to put this outside the KeyToolTest class
 331      */
 332     void testAll() throws Exception {
 333         KeyStore ks;
 334 
 335         remove("x.jks");
 336         remove("x.jceks");
 337         remove("x.p12");
 338         remove("x2.jceks");
 339         remove("x2.jks");
 340         remove("x.jks.p1.cert");
 341 
 342         // name changes: genkeypair, importcert, exportcert
 343         remove("x.jks");
 344         remove("x.jks.p1.cert");
 345         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 346                 "-keypass changeit -genkeypair -alias p1 -dname CN=olala");
 347         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 348                 "-exportcert -alias p1 -file x.jks.p1.cert");
 349         ks = loadStore("x.jks", "changeit", "JKS");
 350         assertTrue(ks.getKey("p1", "changeit".toCharArray()) != null,
 351             "key not DSA");
 352         assertTrue(new File("x.jks.p1.cert").exists(), "p1 export err");
 353         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 354                 "-delete -alias p1");
 355         // importcert, prompt for Yes/No
 356         testOK("y\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 357                 "-importcert -alias c1 -file x.jks.p1.cert");
 358         // importcert, -noprompt
 359         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 360                 "-importcert -alias c2 -file x.jks.p1.cert -noprompt");
 361         ks = loadStore("x.jks", "changeit", "JKS");
 362         assertTrue(ks.getCertificate("c1") != null, "import c1 err");
 363 
 364         // v3
 365         byte[] encoded = ks.getCertificate("c1").getEncoded();
 366         X509CertImpl certImpl = new X509CertImpl(encoded);
 367         assertTrue(certImpl.getVersion() == 3, "Version is not 3");
 368 
 369         // changealias and keyclone
 370         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 371                 "-keypass changeit -genkeypair -alias p1 -dname CN=olala");
 372         testOK("changeit\n", "-keystore x.jks -storetype JKS " +
 373                 "-changealias -alias p1 -destalias p11");
 374         testOK("changeit\n", "-keystore x.jks -storetype JKS " +
 375                 "-changealias -alias c1 -destalias c11");
 376         // press ENTER when prompt for p111's keypass
 377         testOK("changeit\n\n", "-keystore x.jks -storetype JKS " +
 378                 "-keyclone -alias p11 -destalias p111");
 379         ks = loadStore("x.jks", "changeit", "JKS");
 380         assertTrue(!ks.containsAlias("p1"), "there is no p1");
 381         assertTrue(!ks.containsAlias("c1"), "there is no c1");
 382         assertTrue(ks.containsAlias("p11"), "there is p11");
 383         assertTrue(ks.containsAlias("c11"), "there is c11");
 384         assertTrue(ks.containsAlias("p111"), "there is p111");
 385 
 386         // genSecKey
 387         remove("x.jceks");
 388         // DES, no need keysize
 389         testOK("changeit\nchangeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 390                 "-genseckey -alias s1");
 391         // DES, keysize cannot be 128
 392         testFail("changeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 393                 "-genseckey -alias s11 -keysize 128");
 394         // DESede. no need keysize
 395         testOK("changeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 396                 "-genseckey -keyalg DESede -alias s2");
 397         // AES, need keysize
 398         testFail("changeit\n\n", "-keystore x.jceks -storetype AES " +
 399                 "-genseckey -keyalg Rijndael -alias s3");
 400         testOK("changeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 401                 "-genseckey -keyalg AES -alias s3 -keysize 128");
 402         // about keypass
 403         // can accept storepass
 404         testOK("\n", "-keystore x.jceks -storetype JCEKS -storepass changeit " +
 405                 "-genseckey -alias s4");
 406         // or a new one
 407         testOK("keypass\nkeypass\n", "-keystore x.jceks -storetype JCEKS " +
 408                 "-storepass changeit -genseckey -alias s5");
 409         // keypass must be valid (prompt 3 times)
 410         testOK("bad\n\bad\nkeypass\nkeypass\n", "-keystore x.jceks " +
 411                 "-storetype JCEKS -storepass changeit -genseckey -alias s6");
 412         // keypass must be valid (prompt 3 times)
 413         testFail("bad\n\bad\nbad\n", "-keystore x.jceks -storetype JCEKS " +
 414                 "-storepass changeit -genseckey -alias s7");
 415         // keypass must be valid (prompt 3 times)
 416         testFail("bad\n\bad\nbad\nkeypass\n", "-keystore x.jceks " +
 417                 "-storetype JCEKS -storepass changeit -genseckey -alias s7");
 418         ks = loadStore("x.jceks", "changeit", "JCEKS");
 419         assertTrue(ks.getKey("s1", "changeit".toCharArray())
 420                 .getAlgorithm().equalsIgnoreCase("DES"), "s1 is DES");
 421         assertTrue(ks.getKey("s1", "changeit".toCharArray())
 422                 .getEncoded().length == 8,  "DES is 56");
 423         assertTrue(ks.getKey("s2", "changeit".toCharArray())
 424                 .getEncoded().length == 24,  "DESede is 168");
 425         assertTrue(ks.getKey("s2", "changeit".toCharArray())
 426                 .getAlgorithm().equalsIgnoreCase("DESede"), "s2 is DESede");
 427         assertTrue(ks.getKey("s3", "changeit".toCharArray())
 428                 .getAlgorithm().equalsIgnoreCase("AES"), "s3 is AES");
 429         assertTrue(ks.getKey("s4", "changeit".toCharArray())
 430                 .getAlgorithm().equalsIgnoreCase("DES"), "s4 is DES");
 431         assertTrue(ks.getKey("s5", "keypass".toCharArray())
 432                 .getAlgorithm().equalsIgnoreCase("DES"), "s5 is DES");
 433         assertTrue(ks.getKey("s6", "keypass".toCharArray())
 434                 .getAlgorithm().equalsIgnoreCase("DES"), "s6 is DES");
 435         assertTrue(!ks.containsAlias("s7"), "s7 not created");
 436 
 437         // maybe we needn't test this, one day JKS will support SecretKey
 438         //testFail("changeit\nchangeit\n", "-keystore x.jks -storetype JKS " +
 439         //        "-genseckey -keyalg AES -alias s3 -keysize 128");
 440 
 441         // importKeyStore
 442         remove("x.jks");
 443         remove("x.jceks");
 444         // create 2 entries...
 445         testOK("changeit\nchangeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 446                 "-genkeypair -alias p1 -dname CN=Olala");
 447         testOK("", "-keystore x.jceks -storetype JCEKS -storepass changeit " +
 448                 "-importcert -alias c1 -file x.jks.p1.cert -noprompt");
 449         ks = loadStore("x.jceks", "changeit", "JCEKS");
 450         assertTrue(ks.size() == 2, "2 entries in JCEKS");
 451         // import, shouldn't mention destalias/srckeypass/destkeypass
 452         // if srcalias is no given
 453         testFail("changeit\nchangeit\n", "-importkeystore " +
 454                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 455                 "-destkeystore x.jks -deststoretype JKS -destalias pp");
 456         testFail("changeit\nchangeit\n", "-importkeystore " +
 457                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 458                 "-destkeystore x.jks -deststoretype JKS -srckeypass changeit");
 459         testFail("changeit\nchangeit\n", "-importkeystore " +
 460                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 461                 "-destkeystore x.jks -deststoretype JKS -destkeypass changeit");
 462         // normal import
 463         testOK("changeit\nchangeit\nchangeit\n", "-importkeystore " +
 464                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 465                 "-destkeystore x.jks -deststoretype JKS");
 466         ks = loadStore("x.jks", "changeit", "JKS");
 467         assertTrue(ks.size() == 2, "2 entries in JKS");
 468         // import again, type yes to overwrite old entries
 469         testOK("changeit\nchangeit\ny\ny\n", "-importkeystore " +
 470                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 471                 "-destkeystore x.jks -deststoretype JKS");
 472         ks = loadStore("x.jks", "changeit", "JKS");
 473         // import again, specify -nopromt
 474         testOK("changeit\nchangeit\n", "-importkeystore " +
 475                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 476                 "-destkeystore x.jks -deststoretype JKS -noprompt");
 477         assertTrue(err.indexOf("Warning") != -1, "noprompt will warn");
 478         ks = loadStore("x.jks", "changeit", "JKS");
 479         assertTrue(ks.size() == 2, "2 entries in JKS");
 480         // import again, type into new aliases when prompted
 481         testOK("changeit\nchangeit\n\ns1\n\ns2\n", "-importkeystore " +
 482                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 483                 "-destkeystore x.jks -deststoretype JKS");
 484         ks = loadStore("x.jks", "changeit", "JKS");
 485         assertTrue(ks.size() == 4, "4 entries in JKS");
 486 
 487         // importkeystore single
 488         // normal
 489         remove("x.jks");
 490         testOK("changeit\nchangeit\nchangeit\n", "-importkeystore " +
 491                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 492                 "-destkeystore x.jks -deststoretype JKS -srcalias p1");
 493         ks = loadStore("x.jks", "changeit", "JKS");
 494         assertTrue(ks.size() == 1, "1 entries in JKS");
 495         // overwrite
 496         testOK("changeit\nchangeit\ny\n", "-importkeystore " +
 497                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 498                 "-destkeystore x.jks -deststoretype JKS -srcalias p1");
 499         ks = loadStore("x.jks", "changeit", "JKS");
 500         assertTrue(ks.size() == 1, "1 entries in JKS");
 501         // noprompt
 502         testOK("changeit\nchangeit\n", "-importkeystore " +
 503                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 504                 "-destkeystore x.jks -deststoretype JKS " +
 505                 "-srcalias p1 -noprompt");
 506         ks = loadStore("x.jks", "changeit", "JKS");
 507         assertTrue(ks.size() == 1, "1 entries in JKS");
 508         // rename
 509         testOK("changeit\nchangeit\n", "-importkeystore " +
 510                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 511                 "-destkeystore x.jks -deststoretype JKS " +
 512                 "-srcalias p1 -destalias p2");
 513         ks = loadStore("x.jks", "changeit", "JKS");
 514         assertTrue(ks.size() == 2, "2 entries in JKS");
 515         // another rename
 516         testOK("changeit\nchangeit\n\nnewalias\n", "-importkeystore " +
 517                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 518                 "-destkeystore x.jks -deststoretype JKS -srcalias p1");
 519         ks = loadStore("x.jks", "changeit", "JKS");
 520         assertTrue(ks.size() == 3, "3 entries in JKS");
 521 
 522         // importkeystore single, different keypass
 523         remove("x.jks");
 524         // generate entry with different keypass
 525         testOK("changeit\nkeypass\nkeypass\n", "-keystore x.jceks " +
 526                 "-storetype JCEKS -genkeypair -alias p2 -dname CN=Olala");
 527         // prompt
 528         testOK("changeit\nchangeit\nchangeit\nkeypass\n", "-importkeystore " +
 529                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 530                 "-destkeystore x.jks -deststoretype JKS -srcalias p2");
 531         ks = loadStore("x.jks", "changeit", "JKS");
 532         assertTrue(ks.size() == 1, "1 entries in JKS");
 533         // diff destkeypass
 534         testOK("changeit\nchangeit\nkeypass\n", "-importkeystore " +
 535                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 536                 "-destkeystore x.jks -deststoretype JKS " +
 537                 "-srcalias p2 -destalias p3 -destkeypass keypass2");
 538         ks = loadStore("x.jks", "changeit", "JKS");
 539         assertTrue(ks.size() == 2, "2 entries in JKS");
 540         assertTrue(ks.getKey("p2", "keypass".toCharArray()) != null,
 541                 "p2 has old password");
 542         assertTrue(ks.getKey("p3", "keypass2".toCharArray()) != null,
 543                 "p3 has new password");
 544 
 545         // importkeystore single, cert
 546         remove("x.jks");
 547         // normal
 548         testOK("changeit\nchangeit\nchangeit\n", "-importkeystore " +
 549                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 550                 "-destkeystore x.jks -deststoretype JKS -srcalias c1");
 551         // in fact srcstorepass can be ignored
 552         testOK("changeit\n\n", "-importkeystore " +
 553                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 554                 "-destkeystore x.jks -deststoretype JKS " +
 555                 "-srcalias c1 -destalias c2");
 556         assertTrue(err.indexOf("WARNING") != -1, "But will warn");
 557         // 2nd import, press y to overwrite ...
 558         testOK("changeit\n\ny\n", "-importkeystore " +
 559                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 560                 "-destkeystore x.jks -deststoretype JKS " +
 561                 "-srcalias c1 -destalias c2");
 562         // ... or rename
 563         testOK("changeit\n\n\nc3\n", "-importkeystore " +
 564                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 565                 "-destkeystore x.jks -deststoretype JKS " +
 566                 "-srcalias c1 -destalias c2");
 567         ks = loadStore("x.jks", "changeit", "JKS");
 568         // c1, c2, c3
 569         assertTrue(ks.size() == 3, "3 entries in JKS");
 570 
 571         // importkeystore, secretkey
 572         remove("x.jks");
 573         // create SecretKeyEntry
 574         testOK("changeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 575                 "-genseckey -alias s1");
 576         // create SecretKeyEntry
 577         testOK("changeit\n\n", "-keystore x.jceks -storetype JCEKS " +
 578                 "-genseckey -alias s2");
 579         // remove the keypass!=storepass one
 580         testOK("changeit\n", "-keystore x.jceks -storetype JCEKS " +
 581                 "-delete -alias p2");
 582         ks = loadStore("x.jceks", "changeit", "JCEKS");
 583         // p1, c1, s1, s2
 584         assertTrue(ks.size() == 4, "4 entries in JCEKS");
 585         // normal
 586         testOK("changeit\nchangeit\nchangeit\n", "-importkeystore " +
 587                 "-srckeystore x.jceks -srcstoretype JCEKS " +
 588                 "-destkeystore x.jks -deststoretype JKS -srcalias s1");
 589         assertTrue(err.indexOf("not imported") != -1, "Not imported");
 590         assertTrue(err.indexOf("Cannot store non-PrivateKeys") != -1,
 591                 "Not imported");
 592 
 593         // Importing a JCEKS keystore to a JKS one. Will warn
 594         // for the 2 SecretKey entries
 595 
 596         remove("x.jks");
 597         // Two "no" answers to bypass warnings
 598         // normal
 599         testOK("\n\n", "-srcstorepass changeit -deststorepass changeit " +
 600                 "-importkeystore -srckeystore x.jceks -srcstoretype JCEKS " +
 601                 "-destkeystore x.jks -deststoretype JKS");
 602         assertTrue(err.indexOf("s1 not") != -1, "s1 not");
 603         assertTrue(err.indexOf("s2 not") != -1, "s2 not");
 604         assertTrue(err.indexOf("c1 success") != -1, "c1 success");
 605         assertTrue(err.indexOf("p1 success") != -1, "p1 success");
 606         remove("x.jks");
 607         // One "yes" to stop
 608         // normal
 609         testOK("yes\n", "-srcstorepass changeit -deststorepass changeit " +
 610                 "-importkeystore -srckeystore x.jceks -srcstoretype JCEKS " +
 611                 "-destkeystore x.jks -deststoretype JKS");
 612         // maybe c1 or p1 has been imported before s1 or s2 is touched,
 613         // anyway we know yesNo is only asked once.
 614 
 615         // pkcs12
 616         remove("x.jks");
 617         // JKS prompt for keypass
 618         testFail("changeit\nchangeit\n", "-keystore x.jks -storetype JKS " +
 619                 "-genkeypair -alias p1 -dname CN=olala");
 620         remove("x.jks");
 621         // just type ENTER means keypass=storepass
 622         testOK("changeit\nchangeit\n\n", "-keystore x.jks -storetype JKS " +
 623                 "-genkeypair -alias p1 -dname CN=olala");
 624         remove("x.p12");
 625         // PKCS12 only need storepass
 626         testOK("", "-keystore x.p12 -storetype PKCS12 -storepass changeit " +
 627                 "-genkeypair -alias p0 -dname CN=olala");
 628         testOK("changeit\n", "-keystore x.p12 -storetype PKCS12 " +
 629                 "-genkeypair -alias p1 -dname CN=olala");
 630         // when specify keypass, make sure keypass==storepass...
 631         testOK("changeit\n", "-keystore x.p12 -keypass changeit " +
 632                 "-storetype PKCS12 -genkeypair -alias p3 -dname CN=olala");
 633         assertTrue(err.indexOf("Warning") == -1,
 634                 "PKCS12 silent when keypass == storepass");
 635         // otherwise, print a warning
 636         testOK("changeit\n", "-keystore x.p12 -keypass another" +
 637                 " -storetype PKCS12 -genkeypair -alias p2 -dname CN=olala");
 638         assertTrue(err.indexOf("Warning") != -1,
 639                 "PKCS12 warning when keypass != storepass");
 640         // no -keypasswd for PKCS12
 641         testFail("", "-keystore x.p12 -storepass changeit -storetype PKCS12" +
 642                 " -keypasswd -new changeit -alias p3");
 643         testOK("", "-keystore x.p12 -storepass changeit -storetype PKCS12 " +
 644                 "-changealias -alias p3 -destalias p33");
 645         testOK("", "-keystore x.p12 -storepass changeit -storetype PKCS12 " +
 646                 "-keyclone -alias p33 -destalias p3");
 647 
 648         // pkcs12
 649         remove("x.p12");
 650         // PKCS12 only need storepass
 651         testOK("", "-keystore x.p12 -storetype PKCS12 -storepass changeit " +
 652                 "-genkeypair -alias p0 -dname CN=olala");
 653         testOK("", "-storepass changeit -keystore x.p12 -storetype PKCS12 " +
 654                 "-genkeypair -alias p1 -dname CN=olala");
 655         // when specify keypass, make sure keypass==storepass...
 656         testOK("", "-storepass changeit -keystore x.p12 -keypass changeit " +
 657                 "-storetype PKCS12 -genkeypair -alias p3 -dname CN=olala");
 658         assertTrue(err.indexOf("Warning") == -1,
 659                 "PKCS12 silent when keypass == storepass");
 660         // otherwise, print a warning
 661         testOK("", "-storepass changeit -keystore x.p12 -keypass another " +
 662                 "-storetype PKCS12 -genkeypair -alias p2 -dname CN=olala");
 663         assertTrue(err.indexOf("Warning") != -1,
 664                 "PKCS12 warning when keypass != storepass");
 665 
 666         remove("x.jks");
 667         remove("x.jceks");
 668         remove("x.p12");
 669         remove("x2.jceks");
 670         remove("x2.jks");
 671         remove("x.jks.p1.cert");
 672     }
 673 
 674     void testPKCS11() throws Exception {
 675         KeyStore ks;
 676         // pkcs11, the password maybe different and maybe PKCS11 not supported
 677 
 678         // in case last test is not executed successfully
 679         testAnyway("", p11Arg + "-storepass test12 -delete -alias p1");
 680         testAnyway("", p11Arg + "-storepass test12 -delete -alias p2");
 681         testAnyway("", p11Arg + "-storepass test12 -delete -alias p3");
 682         testAnyway("", p11Arg + "-storepass test12 -delete -alias nss");
 683 
 684         testOK("", p11Arg + "-storepass test12 -list");
 685         assertTrue(out.indexOf("Your keystore contains 0 entries") != -1,
 686                 "*** MAKE SURE YOU HAVE NO ENTRIES IN YOUR PKCS11 KEYSTORE " +
 687                         "BEFORE THIS TEST ***");
 688 
 689         testOK("", p11Arg +
 690                 "-storepass test12 -genkeypair -alias p1 -dname CN=olala");
 691         testOK("test12\n", p11Arg + "-genkeypair -alias p2 -dname CN=olala2");
 692         // cannot provide keypass for PKCS11
 693         testFail("test12\n", p11Arg +
 694                 "-keypass test12 -genkeypair -alias p3 -dname CN=olala3");
 695         // cannot provide keypass for PKCS11
 696         testFail("test12\n", p11Arg +
 697                 "-keypass nonsense -genkeypair -alias p3 -dname CN=olala3");
 698 
 699         testOK("", p11Arg + "-storepass test12 -list");
 700         assertTrue(out.indexOf("Your keystore contains 2 entries") != -1,
 701                 "2 entries in p11");
 702 
 703         testOK("test12\n", p11Arg + "-alias p1 -changealias -destalias p3");
 704         testOK("", p11Arg + "-storepass test12 -list -alias p3");
 705         testFail("", p11Arg + "-storepass test12 -list -alias p1");
 706 
 707         testOK("test12\n", p11Arg + "-alias p3 -keyclone -destalias p1");
 708         // in PKCS11, keyclone will delete old
 709         testFail("", p11Arg + "-storepass test12 -list -alias p3");
 710         testOK("", p11Arg + "-storepass test12 -list -alias p1");
 711 
 712         // cannot change password for PKCS11
 713         testFail("test12\n", p11Arg + "-alias p1 -keypasswd -new another");
 714 
 715         testOK("", p11Arg + "-storepass test12 -list");
 716         assertTrue(out.indexOf("Your keystore contains 2 entries") != -1,
 717                 "2 entries in p11");
 718 
 719         testOK("", p11Arg + "-storepass test12 -delete -alias p1");
 720         testOK("", p11Arg + "-storepass test12 -delete -alias p2");
 721 
 722         testOK("", p11Arg + "-storepass test12 -list");
 723         assertTrue(out.indexOf("Your keystore contains 0 entries") != -1,
 724                 "*** MAKE SURE YOU HAVE NO ENTRIES IN YOUR PKCS11 KEYSTORE" +
 725                         " BEFORE THIS TEST ***");
 726     }
 727 
 728     void testPKCS11ImportKeyStore() throws Exception {
 729 
 730         KeyStore ks;
 731         testOK("", p11Arg +
 732                 "-storepass test12 -genkeypair -alias p1 -dname CN=olala");
 733         testOK("test12\n", p11Arg + "-genkeypair -alias p2 -dname CN=olala2");
 734         // test importkeystore for pkcs11
 735 
 736         remove("x.jks");
 737         // pkcs11 -> jks
 738         testOK("changeit\nchangeit\ntest12\n", srcP11Arg +
 739                 ("-importkeystore -destkeystore x.jks -deststoretype JKS " +
 740                 "-srcalias p1"));
 741         assertTrue(err.indexOf("not imported") != -1,
 742                 "cannot import key without destkeypass");
 743         ks = loadStore("x.jks", "changeit", "JKS");
 744         assertTrue(!ks.containsAlias("p1"), "p1 is not imported");
 745 
 746         testOK("changeit\ntest12\n", srcP11Arg +
 747                 ("-importkeystore -destkeystore x.jks -deststoretype JKS " +
 748                 "-srcalias p1 -destkeypass changeit"));
 749         testOK("changeit\ntest12\n", srcP11Arg +
 750                 ("-importkeystore -destkeystore x.jks -deststoretype JKS " +
 751                 "-srcalias p2 -destkeypass changeit"));
 752         ks = loadStore("x.jks", "changeit", "JKS");
 753         assertTrue(ks.containsAlias("p1"), "p1 is imported");
 754         assertTrue(ks.containsAlias("p2"), "p2 is imported");
 755         // jks -> pkcs11
 756         testOK("", p11Arg + "-storepass test12 -delete -alias p1");
 757         testOK("", p11Arg + "-storepass test12 -delete -alias p2");
 758         testOK("test12\nchangeit\n", p11Arg +
 759                 "-importkeystore -srckeystore x.jks -srcstoretype JKS");
 760         testOK("", p11Arg + "-storepass test12 -list -alias p1");
 761         testOK("", p11Arg + "-storepass test12 -list -alias p2");
 762         testOK("", p11Arg + "-storepass test12 -list");
 763         assertTrue(out.indexOf("Your keystore contains 2 entries") != -1,
 764                 "2 entries in p11");
 765         // clean up
 766         testOK("", p11Arg + "-storepass test12 -delete -alias p1");
 767         testOK("", p11Arg + "-storepass test12 -delete -alias p2");
 768         testOK("", p11Arg + "-storepass test12 -list");
 769         assertTrue(out.indexOf("Your keystore contains 0 entries") != -1,
 770                 "empty p11");
 771 
 772         remove("x.jks");
 773     }
 774 
 775     // Selected sqeTest
 776     void sqeTest() throws Exception {
 777         FileOutputStream fos = new FileOutputStream("badkeystore");
 778         for (int i=0; i<100; i++) {
 779             fos.write(i);
 780         }
 781         fos.close();
 782 
 783         sqeCsrTest();
 784         sqePrintcertTest();
 785         sqeDeleteTest();
 786         sqeExportTest();
 787         sqeGenkeyTest();
 788         sqeImportTest();
 789         sqeKeyclonetest();
 790         sqeKeypasswdTest();
 791         sqeListTest();
 792         sqeSelfCertTest();
 793         sqeStorepassTest();
 794 
 795         remove("badkeystore");
 796     }
 797 
 798     // Import: cacert, prompt, trusted, non-trusted, bad chain, not match
 799     void sqeImportTest() throws Exception {
 800         KeyStore ks;
 801         remove("x.jks");
 802         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 803                 "-keypass changeit -genkeypair -dname CN=olala");
 804         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 805                 "-exportcert -file x.jks.p1.cert");
 806         /* deleted */ testOK("", "-keystore x.jks -storetype JKS " +
 807                 "-storepass changeit -delete -alias mykey");
 808         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 809                 "-importcert -file x.jks.p1.cert -noprompt");
 810         /* deleted */ testOK("", "-keystore x.jks -storetype JKS " +
 811                 "-storepass changeit -delete -alias mykey");
 812         testOK("yes\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 813                 "-importcert -file x.jks.p1.cert");
 814         ks = loadStore("x.jks", "changeit", "JKS");
 815         assertTrue(ks.containsAlias("mykey"), "imported");
 816         /* deleted */ testOK("", "-keystore x.jks -storetype JKS " +
 817                 "-storepass changeit -delete -alias mykey");
 818         testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 819                 "-importcert -file x.jks.p1.cert");
 820         ks = loadStore("x.jks", "changeit", "JKS");
 821         assertTrue(!ks.containsAlias("mykey"), "imported");
 822         testOK("no\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 823                 "-importcert -file x.jks.p1.cert");
 824         ks = loadStore("x.jks", "changeit", "JKS");
 825         assertTrue(!ks.containsAlias("mykey"), "imported");
 826         testFail("no\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 827                 "-importcert -file nonexist");
 828         testFail("no\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 829                 "-importcert -file x.jks");
 830         remove("x.jks");
 831     }
 832     // keyclone: exist. nonexist err, cert err, dest exist, misc
 833     void sqeKeyclonetest() throws Exception {
 834         remove("x.jks");
 835         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 836                 "-keypass changeit -genkeypair -dname CN=olala");
 837         // new pass
 838         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 839                 "-keypass changeit -new newpass -keyclone -dest p0");
 840         // new pass
 841         testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 842                 "-keypass changeit -keyclone -dest p1");
 843         testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 844                 "-keyclone -dest p2");
 845         testFail("\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 846                 "-keyclone -dest p2");
 847         testFail("\n", "-keystore x.jks -storetype JKS -storepass changeit " +
 848                 "-keyclone -dest p3 -alias noexist");
 849         // no cert
 850         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 851                 "-exportcert -file x.jks.p1.cert");
 852         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 853                 "-delete -alias mykey");
 854         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 855                 "-importcert -file x.jks.p1.cert -noprompt");
 856         // new pass
 857         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 858                 "-keypass changeit -new newpass -keyclone -dest p0");
 859         remove("x.jks");
 860     }
 861     // keypasswd: exist, short, nonexist err, cert err, misc
 862     void sqeKeypasswdTest() throws Exception {
 863         remove("x.jks");
 864         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 865                 "-keypass changeit -genkeypair -dname CN=olala");
 866         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 867                 "-keypass changeit -keypasswd -new newpass");
 868         /*change back*/ testOK("", "-keystore x.jks -storetype JKS " +
 869                 "-storepass changeit -keypass newpass -keypasswd -new changeit");
 870         testOK("newpass\nnewpass\n", "-keystore x.jks -storetype JKS " +
 871                 "-storepass changeit -keypass changeit -keypasswd");
 872         /*change back*/ testOK("", "-keystore x.jks -storetype JKS " +
 873                 "-storepass changeit -keypass newpass -keypasswd -new changeit");
 874         testOK("new\nnew\nnewpass\nnewpass\n", "-keystore x.jks " +
 875                 "-storetype JKS -storepass changeit -keypass changeit -keypasswd");
 876         /*change back*/ testOK("", "-keystore x.jks -storetype JKS " +
 877                 "-storepass changeit -keypass newpass -keypasswd -new changeit");
 878         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 879                 "-keypasswd -new newpass");
 880         /*change back*/ testOK("", "-keystore x.jks -storetype JKS " +
 881                 "-storepass changeit -keypass newpass -keypasswd -new changeit");
 882         testOK("changeit\n", "-keystore x.jks -storetype JKS " +
 883                 "-keypasswd -new newpass");
 884         /*change back*/ testOK("", "-keystore x.jks -storetype JKS " +
 885                 "-storepass changeit -keypass newpass -keypasswd -new changeit");
 886         testFail("", "-keystore x.jks -storetype JKS -storepass badpass " +
 887                 "-keypass changeit -keypasswd -new newpass");
 888         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 889                 "-keypass bad -keypasswd -new newpass");
 890         // no cert
 891         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 892                 "-exportcert -file x.jks.p1.cert");
 893         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 894                 "-delete -alias mykey");
 895         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 896                 "-importcert -file x.jks.p1.cert -noprompt");
 897         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 898                 "-keypass changeit -keypasswd -new newpass");
 899         // diff pass
 900         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 901                 "-delete -alias mykey");
 902         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 903                 "-keypass keypass -genkeypair -dname CN=olala");
 904         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 905                 "-keypasswd -new newpass");
 906         testOK("keypass\n", "-keystore x.jks -storetype JKS " +
 907                 "-storepass changeit -keypasswd -new newpass");
 908         // i hate those misc test
 909         remove("x.jks");
 910     }
 911     // list: -f -alias, exist, nonexist err;
 912     // otherwise, check all shows, -rfc shows more, and misc
 913     void sqeListTest() throws Exception {
 914         remove("x.jks");
 915         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 916                 "-keypass changeit -genkeypair -dname CN=olala");
 917         testOK("", "-keystore x.jks -storetype JKS -storepass changeit -list");
 918         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 919                 "-list -alias mykey");
 920         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 921                 "-list -alias notexist");
 922         testFail("", "-keystore x.jks -storetype JKS -storepass badpass " +
 923                 "-list -alias mykey");
 924         // keypass ignore
 925         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 926                 "-keypass badpass -list -alias mykey");
 927         testOK("\n", "-keystore x.jks -storetype JKS -list");
 928         assertTrue(err.indexOf("WARNING") != -1, "no storepass");
 929         testOK("changeit\n", "-keystore x.jks -storetype JKS -list");
 930         assertTrue(err.indexOf("WARNING") == -1, "has storepass");
 931         testFail("badpass\n", "-keystore x.jks -storetype JKS -list");
 932         // misc
 933         testFail("", "-keystore aa\\bb//cc -storepass changeit -list");
 934         testFail("", "-keystore nonexisting -storepass changeit -list");
 935         testFail("", "-keystore badkeystore -storepass changeit -list");
 936         remove("x.jks");
 937     }
 938     // selfcert: exist, non-exist err, cert err, sig, dname, wrong keypass, misc
 939     void sqeSelfCertTest() throws Exception {
 940         remove("x.jks");
 941         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 942                 "-keypass changeit -genkeypair -dname CN=olala");
 943         testOK("", "-keystore x.jks -storetype JKS -storepass changeit -selfcert");
 944         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 945                 "-keypass changeit -selfcert");
 946         // not exist
 947         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 948                 "-keypass changeit -selfcert -alias nonexisting");
 949         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 950                 "-keypass changeit -selfcert -dname CN=NewName");
 951         // sig not compatible
 952         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 953                 "-keypass changeit -selfcert -sigalg MD5withRSA");
 954         // bad pass
 955         testFail("", "-keystore x.jks -storetype JKS -storepass wrong " +
 956                 "-keypass changeit -selfcert");
 957         // bad pass
 958         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 959                 "-keypass wrong -selfcert");
 960         //misc
 961         testFail("", "-keystore nonexist -storepass changeit " +
 962                 "-keypass changeit -selfcert");
 963         testFail("", "-keystore aa//dd\\gg -storepass changeit " +
 964                 "-keypass changeit -selfcert");
 965         // diff pass
 966         remove("x.jks");
 967         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 968                 "-keypass keypass -genkeypair -dname CN=olala");
 969         testFail("", "-keystore x.jks -storetype JKS " +
 970                 "-storepass changeit -selfcert");
 971         testOK("keypass\n", "-keystore x.jks -storetype JKS " +
 972                 "-storepass changeit -selfcert");
 973 
 974         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 975                 "-exportcert -file x.jks.p1.cert");
 976         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 977                 "-delete -alias mykey");
 978         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 979                 "-importcert -file x.jks.p1.cert -noprompt");
 980         // certentry cannot do selfcert
 981         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
 982                 "-selfcert");
 983         remove("x.jks");
 984     }
 985     // storepass: bad old, short new, misc
 986     void sqeStorepassTest() throws Exception {
 987         remove("x.jks");
 988         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
 989                 "-keypass changeit -genkeypair -dname CN=olala");
 990         // all in arg
 991         testOK("", "-storepasswd -keystore x.jks -storetype JKS " +
 992                 "-storepass changeit -new newstore");
 993         /* Change back */ testOK("", "-storepasswd -keystore x.jks" +
 994                 " -storetype JKS -storepass newstore -new changeit");
 995         // all not in arg, new twice
 996         testOK("changeit\nnewstore\nnewstore\n", "-storepasswd " +
 997                 "-keystore x.jks -storetype JKS");
 998         /* Change back */ testOK("", "-storepasswd -keystore x.jks " +
 999                 "-storetype JKS -storepass newstore -new changeit");
1000         // new in arg
1001         testOK("changeit\n", "-storepasswd -keystore x.jks " +
1002                 "-storetype JKS -new newstore");
1003         /* Change back */ testOK("", "-storepasswd -keystore x.jks " +
1004                 "-storetype JKS -storepass newstore -new changeit");
1005         // old in arg
1006         testOK("newstore\nnewstore\n", "-storepasswd -keystore x.jks " +
1007                 "-storetype JKS -storepass changeit");
1008         /* Change back */ testOK("", "-storepasswd -keystore x.jks " +
1009                 "-storetype JKS -storepass newstore -new changeit");
1010         // old in arg
1011         testOK("new\nnew\nnewstore\nnewstore\n", "-storepasswd " +
1012                 "-keystore x.jks -storetype JKS -storepass changeit");
1013         /* Change back */ testOK("", "-storepasswd -keystore x.jks " +
1014                 "-storetype JKS -storepass newstore -new changeit");
1015         // bad old
1016         testFail("", "-storepasswd -keystore x.jks -storetype JKS " +
1017                 "-storepass badold -new newstore");
1018         // short new
1019         testFail("", "-storepasswd -keystore x.jks -storetype JKS " +
1020                 "-storepass changeit -new new");
1021         // misc
1022         // non exist
1023         testFail("", "-storepasswd -keystore nonexist " +
1024                 "-storepass changeit -new newstore");
1025         // bad file
1026         testFail("", "-storepasswd -keystore badkeystore " +
1027                 "-storepass changeit -new newstore");
1028         // bad file
1029         testFail("", "-storepasswd -keystore aa\\bb//cc//dd " +
1030                 "-storepass changeit -new newstore");
1031         remove("x.jks");
1032     }
1033 
1034     void sqeGenkeyTest() throws Exception {
1035 
1036         remove("x.jks");
1037         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1038                 "-keypass changeit -genkeypair -dname CN=olala");
1039         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1040                 "-keypass changeit -genkeypair -dname CN=olala");
1041         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1042                 "-keypass changeit -genkeypair -dname CN=olala -alias newentry");
1043         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1044                 "-keypass changeit -genkeypair -dname CN=olala -alias newentry");
1045         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1046                 "-keypass changeit -genkeypair -dname CN=olala -keyalg DSA " +
1047                 "-alias n1");
1048         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1049                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " +
1050                 "-alias n2");
1051         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1052                 "-keypass changeit -genkeypair -dname CN=olala " +
1053                 "-keyalg NoSuchAlg -alias n3");
1054         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1055                 "-keypass changeit -genkeypair -dname CN=olala -keysize 56 " +
1056                 "-alias n4");
1057         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1058                 "-keypass changeit -genkeypair -dname CN=olala -keysize 999 " +
1059                 "-alias n5");
1060         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1061                 "-keypass changeit -genkeypair -dname CN=olala -keysize 512 " +
1062                 "-alias n6");
1063         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1064                 "-keypass changeit -genkeypair -dname CN=olala -keysize 1024 " +
1065                 "-alias n7");
1066         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1067                 "-keypass changeit -genkeypair -dname CN=olala " +
1068                 "-sigalg NoSuchAlg -alias n8");
1069         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1070                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " +
1071                 "-sigalg MD2withRSA -alias n9");
1072         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1073                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " +
1074                 "-sigalg MD5withRSA -alias n10");
1075         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1076                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " +
1077                 "-sigalg SHA1withRSA -alias n11");
1078         testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " +
1079                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " +
1080                 "-sigalg NoSuchAlg -alias n12");
1081         testFail("", "-keystore badkeystore -storepass changeit " +
1082                 "-keypass changeit -genkeypair -dname CN=olala " +
1083                 "-alias n14");
1084         testFail("", "-keystore x.jks -storetype JKS -storepass badpass " +
1085                 "-keypass changeit -genkeypair -dname CN=olala -alias n16");
1086         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1087                 "-keypass changeit -genkeypair -dname CNN=olala -alias n17");
1088         remove("x.jks");
1089     }
1090 
1091     void sqeExportTest() throws Exception {
1092         remove("x.jks");
1093         // nonexist
1094         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1095                 "-export -file mykey.cert -alias mykey");
1096         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1097                 "-keypass changeit -genkeypair -dname CN=olala");
1098         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1099                 "-export -file mykey.cert -alias mykey");
1100         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1101                 "-delete -alias mykey");
1102         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1103                 "-import -file mykey.cert -noprompt -alias c1");
1104         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1105                 "-export -file mykey.cert2 -alias c1");
1106         testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " +
1107                 "-export -file mykey.cert2 -alias c1");
1108         testFail("", "-keystore nonexistkeystore -storepass changeit " +
1109                 "-export -file mykey.cert2 -alias c1");
1110         testFail("", "-keystore badkeystore -storepass changeit " +
1111                 "-export -file mykey.cert2 -alias c1");
1112         testFail("", "-keystore x.jks -storetype JKS -storepass badpass " +
1113                 "-export -file mykey.cert2 -alias c1");
1114         remove("mykey.cert");
1115         remove("mykey.cert2");
1116         remove("x.jks");
1117     }
1118 
1119     void sqeDeleteTest() throws Exception {
1120         remove("x.jks");
1121         // nonexist
1122         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1123                 "-delete -alias mykey");
1124         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1125                 "-keypass changeit -genkeypair -dname CN=olala");
1126         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1127                 "-delete -alias mykey");
1128         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1129                 "-keypass changeit -genkeypair -dname CN=olala");
1130         // keystore name illegal
1131         testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " +
1132                 "-delete -alias mykey");
1133         // keystore not exist
1134         testFail("", "-keystore nonexistkeystore -storepass changeit " +
1135                 "-delete -alias mykey");
1136         // keystore invalid
1137         testFail("", "-keystore badkeystore -storepass changeit " +
1138                 "-delete -alias mykey");
1139         // wrong pass
1140         testFail("", "-keystore x.jks -storetype JKS -storepass xxxxxxxx " +
1141                 "-delete -alias mykey");
1142         remove("x.jks");
1143     }
1144 
1145     void sqeCsrTest() throws Exception {
1146         remove("x.jks");
1147         remove("x.jks.p1.cert");
1148         remove("csr1");
1149         // PrivateKeyEntry can do certreq
1150         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1151                 "-keypass changeit -genkeypair -dname CN=olala -keysize 1024");
1152         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1153                 "-certreq -file csr1 -alias mykey");
1154         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1155                 "-certreq -file csr1");
1156         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1157                 "-certreq -file csr1 -sigalg SHA1withDSA");
1158         // unmatched sigalg
1159         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1160                 "-certreq -file csr1 -sigalg MD5withRSA");
1161         // misc test
1162         // bad storepass
1163         testFail("", "-keystore x.jks -storetype JKS -storepass badstorepass " +
1164                 "-certreq -file csr1");
1165         // storepass from terminal
1166         testOK("changeit\n", "-keystore x.jks -storetype JKS " +
1167                 "-certreq -file csr1");
1168         // must provide storepass
1169         testFail("\n", "-keystore x.jks -storetype JKS " +
1170                 "-certreq -file csr1");
1171         // bad keypass
1172         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1173                 "-keypass badkeypass -certreq -file csr1");
1174         // bad filepath
1175         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1176                 "-certreq -file aa\\bb//cc\\dd");
1177         // non-existing keystore
1178         testFail("", "-keystore noexistks -storepass changeit " +
1179                 "-certreq -file csr1");
1180         // Try the RSA private key
1181         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1182                 "-delete -alias mykey");
1183         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1184                 "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA");
1185         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1186                 "-certreq -file csr1 -alias mykey");
1187         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1188                 "-certreq -file csr1");
1189         // unmatched sigalg
1190         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1191                 "-certreq -file csr1 -sigalg SHA1withDSA");
1192         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1193                 "-certreq -file csr1 -sigalg MD5withRSA");
1194         // TrustedCertificateEntry cannot do certreq
1195         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1196                 "-exportcert -file x.jks.p1.cert");
1197         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1198                 "-delete -alias mykey");
1199         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1200                 "-importcert -file x.jks.p1.cert -noprompt");
1201         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1202                 "-certreq -file csr1 -alias mykey");
1203         testFail("", "-keystore x.jks -storetype JKS -storepass changeit " +
1204                 "-certreq -file csr1");
1205         remove("x.jks");
1206         remove("x.jks.p1.cert");
1207         remove("csr1");
1208     }
1209 
1210     void sqePrintcertTest() throws Exception {
1211         remove("x.jks");
1212         remove("mykey.cert");
1213         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1214                 "-keypass changeit -genkeypair -dname CN=olala");
1215         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
1216                 "-export -file mykey.cert -alias mykey");
1217         testFail("", "-printcert -file badkeystore");
1218         testFail("", "-printcert -file a/b/c/d");
1219         testOK("", "-printcert -file mykey.cert");
1220         FileInputStream fin = new FileInputStream("mykey.cert");
1221         testOK(fin, "-printcert");
1222         fin.close();
1223         remove("x.jks");
1224         remove("mykey.cert");
1225     }
1226 
1227     // 8074935: jdk8 keytool doesn't validate pem files for RFC 1421 correctness
1228     static void checkPem(String file) throws Exception {
1229         boolean maybeLast = false;
1230         for (String s: Files.readAllLines(Paths.get(file))) {
1231             if (s.isEmpty()) continue;
1232             if (s.startsWith("---")) continue;
1233             if (maybeLast) {
1234                 throw new Exception("Last line already seen");
1235             }
1236             if (s.length() > 64) {
1237                 throw new Exception(s);
1238             }
1239             if (s.length() < 64) {
1240                 maybeLast = true;
1241             }
1242         }
1243     }
1244 
1245     void v3extTest(String keyAlg) throws Exception {
1246         KeyStore ks;
1247         remove("x.jks");
1248         String simple = "-keystore x.jks -storetype JKS -storepass changeit " +
1249                 "-keypass changeit -noprompt -keyalg " + keyAlg + " ";
1250         String pre = simple + "-genkeypair -dname CN=Olala -alias ";
1251 
1252         // Version and SKID
1253         testOK("", pre + "o1");
1254 
1255         ks = loadStore("x.jks", "changeit", "JKS");
1256         assertTrue(((X509Certificate)ks.getCertificate("o1")).getVersion() == 3);
1257         assertTrue(((X509CertImpl)ks.getCertificate("o1"))
1258                 .getSubjectKeyIdentifierExtension() != null);
1259 
1260         // BC
1261         testOK("", pre + "b1 -ext BC:critical");
1262         testOK("", pre + "b2 -ext BC");
1263         testOK("", pre + "b3 -ext bc");
1264         testOK("", pre + "b4 -ext BasicConstraints");
1265         testOK("", pre + "b5 -ext basicconstraints");
1266         testOK("", pre + "b6 -ext BC=ca:true,pathlen:12");
1267         testOK("", pre + "b7 -ext BC=ca:false");
1268         testOK("", pre + "b8 -ext BC:critical=ca:false");
1269         testOK("", pre + "b9 -ext BC=12");
1270 
1271         ks = loadStore("x.jks", "changeit", "JKS");
1272         assertTrue(((X509CertImpl)ks.getCertificate("b1"))
1273                 .getBasicConstraintsExtension().isCritical());
1274         assertTrue(!((X509CertImpl)ks.getCertificate("b2"))
1275                 .getBasicConstraintsExtension().isCritical());
1276         assertTrue(((X509CertImpl)ks.getCertificate("b8"))
1277                 .getBasicConstraintsExtension().isCritical());
1278         assertTrue(((X509Certificate)ks.getCertificate("b1"))
1279                 .getBasicConstraints() == Integer.MAX_VALUE);
1280         assertTrue(((X509Certificate)ks.getCertificate("b2"))
1281                 .getBasicConstraints() == Integer.MAX_VALUE);
1282         assertTrue(((X509Certificate)ks.getCertificate("b3"))
1283                 .getBasicConstraints() == Integer.MAX_VALUE);
1284         assertTrue(((X509Certificate)ks.getCertificate("b4"))
1285                 .getBasicConstraints() == Integer.MAX_VALUE);
1286         assertTrue(((X509Certificate)ks.getCertificate("b5"))
1287                 .getBasicConstraints() == Integer.MAX_VALUE);
1288         assertTrue(((X509Certificate)ks.getCertificate("b6"))
1289                 .getBasicConstraints() == 12);
1290         assertTrue(((X509Certificate)ks.getCertificate("b7"))
1291                 .getBasicConstraints() == -1);
1292         assertTrue(((X509Certificate)ks.getCertificate("b9"))
1293                 .getBasicConstraints() == 12);
1294 
1295         // KU
1296         testOK("", pre + "ku1 -ext KeyUsage:critical=digitalsignature");
1297         testOK("", pre + "ku2 -ext KU=digitalSignature");
1298         testOK("", pre + "ku3 -ext KU=ds");
1299         testOK("", pre + "ku4 -ext KU=dig");
1300         // ambigous value
1301         testFail("", pre + "ku5 -ext KU=d");
1302         // cRLSign cannot be cs
1303         testFail("", pre + "ku6 -ext KU=cs");
1304         testOK("", pre + "ku11 -ext KU=nr");
1305         // ke also means keyAgreement
1306         testFail("", pre + "ku12 -ext KU=ke");
1307         testOK("", pre + "ku12 -ext KU=keyE");
1308         // de also means decipherOnly
1309         testFail("", pre + "ku13 -ext KU=de");
1310         testOK("", pre + "ku13 -ext KU=dataE");
1311         testOK("", pre + "ku14 -ext KU=ka");
1312         testOK("", pre + "ku15 -ext KU=kcs");
1313         testOK("", pre + "ku16 -ext KU=crls");
1314         testOK("", pre + "ku17 -ext KU=eo");
1315         testOK("", pre + "ku18 -ext KU=do");
1316         testOK("", pre + "ku19 -ext KU=cc");
1317 
1318         testOK("", pre + "ku017 -ext KU=ds,cc,eo");
1319         testOK("", pre + "ku135 -ext KU=nr,dataEncipherment,keyCertSign");
1320         testOK("", pre + "ku246 -ext KU=keyEnc,cRL,keyA");
1321         testOK("", pre + "ku1234 -ext KU=ka,da,keyE,nonR");
1322 
1323         ks = loadStore("x.jks", "changeit", "JKS");
1324         class CheckKU {
1325             void check(KeyStore ks, String alias, int... pos) throws Exception {
1326                 System.err.print("x");
1327                 boolean[] bs = ((X509Certificate)ks.getCertificate(alias))
1328                         .getKeyUsage();
1329                 bs = Arrays.copyOf(bs, 9);
1330                 for (int i=0; i<bs.length; i++) {
1331                     boolean found = false;
1332                     for (int p: pos) {
1333                         if (p == i) found = true;
1334                     }
1335                     if (!found ^ bs[i]) {
1336                         // OK
1337                     } else {
1338                         throw new RuntimeException("KU not match at " + i +
1339                                 ": " + found + " vs " + bs[i]);
1340                     }
1341                 }
1342             }
1343         }
1344         CheckKU c = new CheckKU();
1345         assertTrue(((X509CertImpl)ks.getCertificate("ku1"))
1346                 .getExtension(PKIXExtensions.KeyUsage_Id).isCritical());
1347         assertTrue(!((X509CertImpl)ks.getCertificate("ku2"))
1348                 .getExtension(PKIXExtensions.KeyUsage_Id).isCritical());
1349         c.check(ks, "ku1", 0);
1350         c.check(ks, "ku2", 0);
1351         c.check(ks, "ku3", 0);
1352         c.check(ks, "ku4", 0);
1353         c.check(ks, "ku11", 1);
1354         c.check(ks, "ku12", 2);
1355         c.check(ks, "ku13", 3);
1356         c.check(ks, "ku14", 4);
1357         c.check(ks, "ku15", 5);
1358         c.check(ks, "ku16", 6);
1359         c.check(ks, "ku17", 7);
1360         c.check(ks, "ku18", 8);
1361         c.check(ks, "ku19", 1);
1362         c.check(ks, "ku11", 1);
1363         c.check(ks, "ku11", 1);
1364         c.check(ks, "ku11", 1);
1365         c.check(ks, "ku017", 0, 1, 7);
1366         c.check(ks, "ku135", 1, 3, 5);
1367         c.check(ks, "ku246", 6, 2, 4);
1368         c.check(ks, "ku1234", 1, 2, 3, 4);
1369 
1370         // EKU
1371         testOK("", pre + "eku1 -ext EKU:critical=sa");
1372         testOK("", pre + "eku2 -ext ExtendedKeyUsage=ca");
1373         testOK("", pre + "eku3 -ext EKU=cs");
1374         testOK("", pre + "eku4 -ext EKU=ep");
1375         testOK("", pre + "eku8 -ext EKU=ts");
1376         testFail("", pre + "eku9 -ext EKU=os");
1377         testOK("", pre + "eku9 -ext EKU=ocsps");
1378         testOK("", pre + "eku10 -ext EKU=any");
1379         testOK("", pre + "eku11 -ext EKU=1.2.3.4,1.3.5.7,ep");
1380         testFail("", pre + "eku12 -ext EKU=c");
1381         testFail("", pre + "eku12 -ext EKU=nothing");
1382 
1383         ks = loadStore("x.jks", "changeit", "JKS");
1384         class CheckEKU {
1385             void check(KeyStore ks, String alias, String... pos) throws Exception {
1386                 System.err.print("x");
1387                 List<String> bs = ((X509Certificate)ks.getCertificate(alias))
1388                         .getExtendedKeyUsage();
1389                 int found = 0;
1390                 for (String p: pos) {
1391                     if (bs.contains(p)) {
1392                         found++;
1393                     } else {
1394                         throw new RuntimeException("EKU: not included " + p);
1395                     }
1396                 }
1397                 if (found != bs.size()) {
1398                     throw new RuntimeException("EKU: more items than expected");
1399                 }
1400             }
1401         }
1402         CheckEKU cx = new CheckEKU();
1403         assertTrue(((X509CertImpl)ks.getCertificate("eku1"))
1404                 .getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical());
1405         assertTrue(!((X509CertImpl)ks.getCertificate("eku2"))
1406                 .getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical());
1407         cx.check(ks, "eku1", "1.3.6.1.5.5.7.3.1");
1408         cx.check(ks, "eku2", "1.3.6.1.5.5.7.3.2");
1409         cx.check(ks, "eku3", "1.3.6.1.5.5.7.3.3");
1410         cx.check(ks, "eku4", "1.3.6.1.5.5.7.3.4");
1411         cx.check(ks, "eku8", "1.3.6.1.5.5.7.3.8");
1412         cx.check(ks, "eku9", "1.3.6.1.5.5.7.3.9");
1413         cx.check(ks, "eku10", "2.5.29.37.0");
1414         cx.check(ks, "eku11", "1.3.6.1.5.5.7.3.4", "1.2.3.4", "1.3.5.7");
1415 
1416         // SAN
1417         testOK("", pre+"san1 -ext san:critical=email:me@me.org");
1418         testOK("", pre+"san2 -ext san=uri:http://me.org");
1419         testOK("", pre+"san3 -ext san=dns:me.org");
1420         testOK("", pre+"san4 -ext san=ip:192.168.0.1");
1421         testOK("", pre+"san5 -ext san=oid:1.2.3.4");
1422         testOK("", pre+"san235 -ext san=uri:http://me.org,dns:me.org,oid:1.2.3.4");
1423 
1424         ks = loadStore("x.jks", "changeit", "JKS");
1425         class CheckSAN {
1426             // Please sort items with name type
1427             void check(KeyStore ks, String alias, int type, Object... items)
1428                     throws Exception {
1429                 int pos = 0;
1430                 System.err.print("x");
1431                 Object[] names = null;
1432                 if (type == 0) names = ((X509Certificate)ks.getCertificate(alias))
1433                         .getSubjectAlternativeNames().toArray();
1434                 else names = ((X509Certificate)ks.getCertificate(alias))
1435                         .getIssuerAlternativeNames().toArray();
1436                 Arrays.sort(names, new Comparator() {
1437                     public int compare(Object o1, Object o2) {
1438                         int i1 = (Integer)((List)o1).get(0);
1439                         int i2 = (Integer)((List)o2).get(0);
1440                         return i1 - i2;
1441                     }
1442                 });
1443                 for (Object o: names) {
1444                     List l = (List)o;
1445                     for (Object o2: l) {
1446                         if (!items[pos++].equals(o2)) {
1447                             throw new RuntimeException("Not equals at " + pos
1448                                     + ": " + items[pos-1] + " vs " + o2);
1449                         }
1450                     }
1451                 }
1452                 if (pos != items.length) {
1453                     throw new RuntimeException("Extra items, pos is " + pos);
1454                 }
1455             }
1456         }
1457         CheckSAN csan = new CheckSAN();
1458         assertTrue(((X509CertImpl)ks.getCertificate("san1"))
1459                 .getSubjectAlternativeNameExtension().isCritical());
1460         assertTrue(!((X509CertImpl)ks.getCertificate("san2"))
1461                 .getSubjectAlternativeNameExtension().isCritical());
1462         csan.check(ks, "san1", 0, 1, "me@me.org");
1463         csan.check(ks, "san2", 0, 6, "http://me.org");
1464         csan.check(ks, "san3", 0, 2, "me.org");
1465         csan.check(ks, "san4", 0, 7, "192.168.0.1");
1466         csan.check(ks, "san5", 0, 8, "1.2.3.4");
1467         csan.check(ks, "san235", 0, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4");
1468 
1469         // IAN
1470         testOK("", pre+"ian1 -ext ian:critical=email:me@me.org");
1471         testOK("", pre+"ian2 -ext ian=uri:http://me.org");
1472         testOK("", pre+"ian3 -ext ian=dns:me.org");
1473         testOK("", pre+"ian4 -ext ian=ip:192.168.0.1");
1474         testOK("", pre+"ian5 -ext ian=oid:1.2.3.4");
1475         testOK("", pre+"ian235 -ext ian=uri:http://me.org,dns:me.org,oid:1.2.3.4");
1476 
1477         ks = loadStore("x.jks", "changeit", "JKS");
1478         assertTrue(((X509CertImpl)ks.getCertificate("ian1"))
1479                 .getIssuerAlternativeNameExtension().isCritical());
1480         assertTrue(!((X509CertImpl)ks.getCertificate("ian2"))
1481                 .getIssuerAlternativeNameExtension().isCritical());
1482         csan.check(ks, "ian1", 1, 1, "me@me.org");
1483         csan.check(ks, "ian2", 1, 6, "http://me.org");
1484         csan.check(ks, "ian3", 1, 2, "me.org");
1485         csan.check(ks, "ian4", 1, 7, "192.168.0.1");
1486         csan.check(ks, "ian5", 1, 8, "1.2.3.4");
1487         csan.check(ks, "ian235", 1, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4");
1488 
1489         // SIA
1490         testOK("", pre+"sia1 -ext sia=care:uri:ldap://ca.com/cn=CA");
1491         testOK("", pre+"sia2 -ext sia=ts:email:ts@ca.com");
1492         testFail("SIA never critical", pre +
1493                 "sia3 -ext sia:critical=ts:email:ts@ca.com");
1494 
1495         ks = loadStore("x.jks", "changeit", "JKS");
1496         class CheckSia {
1497             void check(KeyStore ks, String alias, int type, Object... items)
1498                     throws Exception {
1499                 int pos = 0;
1500                 System.err.print("x");
1501                 AccessDescription[] ads = null;
1502                 if (type == 0) {
1503                     SubjectInfoAccessExtension siae = (SubjectInfoAccessExtension)
1504                             ((X509CertImpl)ks.getCertificate(alias))
1505                             .getExtension(PKIXExtensions.SubjectInfoAccess_Id);
1506                     ads = siae.getAccessDescriptions()
1507                             .toArray(new AccessDescription[0]);
1508                 } else {
1509                     AuthorityInfoAccessExtension aiae =
1510                             (AuthorityInfoAccessExtension)
1511                             ((X509CertImpl)ks.getCertificate(alias))
1512                             .getExtension(PKIXExtensions.AuthInfoAccess_Id);
1513                     ads = aiae.getAccessDescriptions()
1514                             .toArray(new AccessDescription[0]);
1515                 }
1516                 Arrays.sort(ads, new Comparator<AccessDescription>() {
1517                     @Override
1518                     public int compare(AccessDescription o1,
1519                                        AccessDescription o2) {
1520                         return o1.getAccessMethod().toString()
1521                                 .compareTo(o2.getAccessMethod().toString());
1522                     }
1523                 });
1524                 for (AccessDescription ad: ads) {
1525                     if (!ad.getAccessMethod().equals(items[pos++]) ||
1526                             !new Integer(ad.getAccessLocation().getType())
1527                                     .equals(items[pos++])) {
1528                         throw new RuntimeException("Not same type at " + pos);
1529                     }
1530                     String name = null;
1531                     switch (ad.getAccessLocation().getType()) {
1532                         case 1:
1533                             name = ((RFC822Name)ad.getAccessLocation()
1534                                     .getName()).getName();
1535                             break;
1536                         case 6:
1537                             name = ((URIName)ad.getAccessLocation()
1538                                     .getName()).getURI().toString();
1539                             break;
1540                         default:
1541                             throw new RuntimeException("Not implemented: " + ad);
1542                     }
1543                     if (!name.equals(items[pos++])) {
1544                         throw new Exception("Name not same for " + ad +
1545                                 " at pos " + pos);
1546                     }
1547                 }
1548             }
1549         }
1550         CheckSia csia = new CheckSia();
1551         assertTrue(!((X509CertImpl)ks.getCertificate("sia1"))
1552                 .getExtension(PKIXExtensions.SubjectInfoAccess_Id).isCritical());
1553         csia.check(ks, "sia1", 0,
1554                 AccessDescription.Ad_CAREPOSITORY_Id, 6, "ldap://ca.com/cn=CA");
1555         csia.check(ks, "sia2",
1556                 0, AccessDescription.Ad_TIMESTAMPING_Id, 1, "ts@ca.com");
1557 
1558         // AIA
1559         testOK("", pre+"aia1 -ext aia=cai:uri:ldap://ca.com/cn=CA");
1560         testOK("", pre+"aia2 -ext aia=ocsp:email:ocsp@ca.com");
1561         testFail("AIA never critical", pre +
1562                 "aia3 -ext aia:critical=ts:email:ts@ca.com");
1563 
1564         ks = loadStore("x.jks", "changeit", "JKS");
1565         assertTrue(!((X509CertImpl)ks.getCertificate("aia1"))
1566                 .getExtension(PKIXExtensions.AuthInfoAccess_Id).isCritical());
1567         csia.check(ks, "aia1", 1,
1568                 AccessDescription.Ad_CAISSUERS_Id, 6, "ldap://ca.com/cn=CA");
1569         csia.check(ks, "aia2", 1,
1570                 AccessDescription.Ad_OCSP_Id, 1, "ocsp@ca.com");
1571 
1572         // OID
1573         testOK("", pre+"oid1 -ext 1.2.3:critical=0102");
1574         testOK("", pre+"oid2 -ext 1.2.3");
1575         testOK("", pre+"oid12 -ext 1.2.3 -ext 1.2.4=01:02:03");
1576 
1577         ks = loadStore("x.jks", "changeit", "JKS");
1578         class CheckOid {
1579             void check(KeyStore ks, String alias, String oid, byte[] value)
1580                     throws Exception {
1581                 int pos = 0;
1582                 System.err.print("x");
1583                 Extension ex = ((X509CertImpl)ks.getCertificate(alias))
1584                         .getExtension(new ObjectIdentifier(oid));
1585                 if (!Arrays.equals(value, ex.getValue())) {
1586                     throw new RuntimeException("Not same content in " +
1587                             alias + " for " + oid);
1588                 }
1589             }
1590         }
1591         CheckOid coid = new CheckOid();
1592         assertTrue(((X509CertImpl)ks.getCertificate("oid1"))
1593                 .getExtension(new ObjectIdentifier("1.2.3")).isCritical());
1594         assertTrue(!((X509CertImpl)ks.getCertificate("oid2"))
1595                 .getExtension(new ObjectIdentifier("1.2.3")).isCritical());
1596         coid.check(ks, "oid1", "1.2.3", new byte[]{1,2});
1597         coid.check(ks, "oid2", "1.2.3", new byte[]{});
1598         coid.check(ks, "oid12", "1.2.3", new byte[]{});
1599         coid.check(ks, "oid12", "1.2.4", new byte[]{1,2,3});
1600 
1601         // honored
1602         testOK("", pre+"ca");
1603         testOK("", pre+"a");
1604         // request: BC,KU,1.2.3,1.2.4,1.2.5
1605         testOK("", simple+"-alias a -certreq " +
1606                 "-ext BC=1 -ext KU=crl " +
1607                 "-ext 1.2.3=01 -ext 1.2.4:critical=0102 -ext 1.2.5=010203 " +
1608                 "-rfc -file test.req");
1609         // printcertreq
1610         testOK("", "-printcertreq -file test.req");
1611         checkPem("test.req");
1612         // issue: deny KU, change criticality of 1.2.3 and 1.2.4,
1613         // change content of BC, add 2.3.4
1614         testOK("", simple+"-gencert -alias ca -infile test.req -ext " +
1615                 "honored=all,-KU,1.2.3:critical,1.2.4:non-critical " +
1616                 "-ext BC=2 -ext 2.3.4=01020304 " +
1617                 "-debug -rfc -outfile test.cert");
1618         checkPem("test.cert");
1619         testOK("", simple+"-importcert -file test.cert -alias a");
1620         ks = loadStore("x.jks", "changeit", "JKS");
1621         X509CertImpl a = (X509CertImpl)ks.getCertificate("a");
1622         assertTrue(a.getAuthorityKeyIdentifierExtension() != null);
1623         assertTrue(a.getSubjectKeyIdentifierExtension() != null);
1624         assertTrue(a.getKeyUsage() == null);
1625         assertTrue(a.getExtension(new ObjectIdentifier("1.2.3")).isCritical());
1626         assertTrue(!a.getExtension(new ObjectIdentifier("1.2.4")).isCritical());
1627         assertTrue(!a.getExtension(new ObjectIdentifier("1.2.5")).isCritical());
1628         assertTrue(a.getExtensionValue("1.2.3").length == 3);
1629         assertTrue(a.getExtensionValue("1.2.4").length == 4);
1630         assertTrue(a.getExtensionValue("1.2.5").length == 5);
1631         assertTrue(a.getBasicConstraints() == 2);
1632         assertTrue(!a.getExtension(new ObjectIdentifier("2.3.4")).isCritical());
1633         assertTrue(a.getExtensionValue("2.3.4").length == 6);
1634 
1635         // 8073181: keytool -ext honored not working correctly
1636         testOK("", simple+"-gencert -alias ca -infile test.req -ext " +
1637                 "honored=1.2.3,KU,1.2.4:critical " +
1638                 "-debug -rfc -outfile test2.cert");
1639         testOK("", simple+"-importcert -file test2.cert -alias b");
1640         ks = loadStore("x.jks", "changeit", "JKS");
1641         X509CertImpl b = (X509CertImpl)ks.getCertificate("b");
1642         assertTrue(!b.getExtension(new ObjectIdentifier("1.2.3")).isCritical());
1643         assertTrue(b.getExtension(new ObjectIdentifier("1.2.4")).isCritical());
1644 
1645         // 8073182: keytool may generate duplicate extensions
1646         testOK("", pre+"dup -ext bc=2 -ext 2.5.29.19=30030101FF -ext bc=3");
1647         ks = loadStore("x.jks", "changeit", "JKS");
1648         X509CertImpl dup = (X509CertImpl)ks.getCertificate("dup");
1649         assertTrue(dup.getBasicConstraints() == 3);
1650 
1651         remove("x.jks");
1652         remove("test.req");
1653         remove("test.cert");
1654     }
1655 
1656     void i18nTest() throws Exception {
1657         //   1.  keytool -help
1658         remove("x.jks");
1659         testOK("", "-help");
1660 
1661         //   2. keytool -genkey -v -keysize 512 Enter "a" for the keystore
1662         // password. Check error (password too short). Enter "password" for
1663         // the keystore password. Hit 'return' for "first and last name",
1664         // "organizational unit", "City", "State", and "Country Code".
1665         // Type "yes" when they ask you if everything is correct.
1666         // Type 'return' for new key password.
1667         testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n",
1668                 "-genkey -v -keysize 512 -keystore x.jks -storetype JKS");
1669         //   3. keytool -list -v -storepass password
1670         testOK("", "-list -v -storepass password -keystore x.jks -storetype JKS");
1671         //   4. keytool -list -v Type "a" for the keystore password.
1672         // Check error (wrong keystore password).
1673         testFail("a\n", "-list -v -keystore x.jks -storetype JKS");
1674         assertTrue(ex.indexOf("password was incorrect") != -1);
1675         //   5. keytool -genkey -v -keysize 512 Enter "password" as the password.
1676         // Check error (alias 'mykey' already exists).
1677         testFail("password\n", "-genkey -v -keysize 512" +
1678                 " -keystore x.jks -storetype JKS");
1679         assertTrue(ex.indexOf("alias <mykey> already exists") != -1);
1680         //   6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password
1681         // Hit 'return' for "first and last name", "organizational unit", "City",
1682         // "State", and "Country Code". Type "yes" when they ask you if
1683         // everything is correct. Type 'return' for new key password.
1684         testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2" +
1685                 " -storepass password -keystore x.jks -storetype JKS");
1686         //   7. keytool -list -v Type 'password' for the store password.
1687         testOK("password\n", "-list -v -keystore x.jks -storetype JKS");
1688         //   8. keytool -keypasswd -v -alias mykey2 -storepass password
1689         // Type "a" for the new key password. Type "aaaaaa" for the new key
1690         // password. Type "bbbbbb" when re-entering the new key password.
1691         // Type "a" for the new key password. Check Error (too many failures).
1692         testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2" +
1693                 " -storepass password -keystore x.jks -storetype JKS");
1694         assertTrue(ex.indexOf("Too many failures - try later") != -1);
1695         //   9. keytool -keypasswd -v -alias mykey2 -storepass password
1696         // Type "aaaaaa" for the new key password. Type "aaaaaa"
1697         // when re-entering the new key password.
1698         testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 " +
1699                 "-storepass password -keystore x.jks -storetype JKS");
1700         //  10. keytool -selfcert -v -alias mykey -storepass password
1701         testOK("", "-selfcert -v -alias mykey -storepass password " +
1702                 "-keystore x.jks -storetype JKS");
1703         //  11. keytool -list -v -storepass password
1704         testOK("", "-list -v -storepass password -keystore x.jks -storetype JKS");
1705         //  12. keytool -export -v -alias mykey -file cert -storepass password
1706         remove("cert");
1707         testOK("", "-export -v -alias mykey -file cert -storepass password " +
1708                 "-keystore x.jks -storetype JKS");
1709         //  13. keytool -import -v -file cert -storepass password
1710         // Check error (Certificate reply and cert are the same)
1711         testFail("", "-import -v -file cert -storepass password" +
1712                 " -keystore x.jks -storetype JKS");
1713         assertTrue(ex.indexOf("Certificate reply and certificate" +
1714                 " in keystore are identical") != -1);
1715         //  14. keytool -printcert -file cert
1716         testOK("", "-printcert -file cert -keystore x.jks -storetype JKS");
1717         remove("cert");
1718         //  15. keytool -list -storepass password -providerClass sun.security.provider.Sun
1719         testOK("", "-list -storepass password" +
1720                 " -providerClass sun.security.provider.Sun" +
1721                 " -keystore x.jks -storetype JKS");
1722 
1723         //Error tests
1724 
1725         //   1. keytool -storepasswd -storepass password -new abc
1726         // Check error (password too short)
1727         testFail("", "-storepasswd -storepass password -new abc");
1728         assertTrue(ex.indexOf("New password must be at least 6 characters") != -1);
1729         // Changed, no NONE needed now
1730         //   2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE)
1731         //testFail("", "-list -storetype PKCS11");
1732         //assertTrue(err.indexOf("keystore must be NONE") != -1);
1733         //   3. keytool -storepasswd -storetype PKCS11 -keystore NONE
1734         // Check error (unsupported operation)
1735         testFail("", "-storepasswd -storetype PKCS11 -keystore NONE");
1736         assertTrue(ex.indexOf("UnsupportedOperationException") != -1);
1737         //   4. keytool -keypasswd -storetype PKCS11 -keystore NONE
1738         // Check error (unsupported operation)
1739         testFail("", "-keypasswd -storetype PKCS11 -keystore NONE");
1740         assertTrue(ex.indexOf("UnsupportedOperationException") != -1);
1741         //   5. keytool -list -protected -storepass password
1742         // Check error (password can not be specified with -protected)
1743         testFail("", "-list -protected -storepass password " +
1744                 "-keystore x.jks -storetype JKS");
1745         assertTrue(ex.indexOf("if -protected is specified, then") != -1);
1746         //   6. keytool -keypasswd -protected -keypass password
1747         // Check error (password can not be specified with -protected)
1748         testFail("", "-keypasswd -protected -keypass password " +
1749                 "-keystore x.jks -storetype JKS");
1750         assertTrue(ex.indexOf("if -protected is specified, then") != -1);
1751         //   7. keytool -keypasswd -protected -new password
1752         // Check error (password can not be specified with -protected)
1753         testFail("", "-keypasswd -protected -new password " +
1754                 "-keystore x.jks -storetype JKS");
1755         assertTrue(ex.indexOf("if -protected is specified, then") != -1);
1756         remove("x.jks");
1757     }
1758 
1759     void i18nPKCS11Test() throws Exception {
1760         //PKCS#11 tests
1761 
1762         //   1. sccs edit cert8.db key3.db
1763         //Runtime.getRuntime().exec("/usr/ccs/bin/sccs edit cert8.db key3.db");
1764         testOK("", p11Arg + ("-storepass test12 -genkey -alias genkey" +
1765                 " -dname cn=genkey -keysize 512 -keyalg rsa"));
1766         testOK("", p11Arg + "-storepass test12 -list");
1767         testOK("", p11Arg + "-storepass test12 -list -alias genkey");
1768         testOK("", p11Arg +
1769                 "-storepass test12 -certreq -alias genkey -file genkey.certreq");
1770         testOK("", p11Arg +
1771                 "-storepass test12 -export -alias genkey -file genkey.cert");
1772         testOK("", "-printcert -file genkey.cert");
1773         testOK("", p11Arg +
1774                 "-storepass test12 -selfcert -alias genkey -dname cn=selfCert");
1775         testOK("", p11Arg +
1776                 "-storepass test12 -list -alias genkey -v");
1777         assertTrue(out.indexOf("Owner: CN=selfCert") != -1);
1778         //(check that cert subject DN is [cn=selfCert])
1779         testOK("", p11Arg + "-storepass test12 -delete -alias genkey");
1780         testOK("", p11Arg + "-storepass test12 -list");
1781         assertTrue(out.indexOf("Your keystore contains 0 entries") != -1);
1782         //(check for empty database listing)
1783         //Runtime.getRuntime().exec("/usr/ccs/bin/sccs unedit cert8.db key3.db");
1784         remove("genkey.cert");
1785         remove("genkey.certreq");
1786         //  12. sccs unedit cert8.db key3.db
1787     }
1788 
1789     // tesing new option -srcProviderName
1790     void sszzTest() throws Exception {
1791         testAnyway("", NSS_P11_ARG+"-delete -alias nss -storepass test12");
1792         testAnyway("", NZZ_P11_ARG+"-delete -alias nss -storepass test12");
1793         testOK("", NSS_P11_ARG+"-genkeypair -dname CN=NSS " +
1794                 "-alias nss -storepass test12");
1795         testOK("", NSS_SRC_P11_ARG + NZZ_P11_ARG +
1796                 "-importkeystore -srcstorepass test12 -deststorepass test12");
1797         testAnyway("", NSS_P11_ARG+"-delete -alias nss -storepass test12");
1798         testAnyway("", NZZ_P11_ARG+"-delete -alias nss -storepass test12");
1799     }
1800 
1801     public static void main(String[] args) throws Exception {
1802         Locale reservedLocale = Locale.getDefault();
1803         try {
1804             // first test if HumanInputStream really acts like a human being
1805             HumanInputStream.test();
1806             KeyToolTest t = new KeyToolTest();
1807 
1808             if (System.getProperty("file") != null) {
1809                 t.sqeTest();
1810                 t.testAll();
1811                 t.i18nTest();
1812                 t.v3extTest("RSA");
1813                 t.v3extTest("DSA");
1814                 boolean testEC = true;
1815                 try {
1816                     KeyPairGenerator.getInstance("EC");
1817                 } catch (NoSuchAlgorithmException nae) {
1818                     testEC = false;
1819                 }
1820                 if (testEC) t.v3extTest("EC");
1821             }
1822 
1823             if (System.getProperty("nss") != null) {
1824                 t.srcP11Arg = NSS_SRC_P11_ARG;
1825                 t.p11Arg = NSS_P11_ARG;
1826 
1827                 t.testPKCS11();
1828 
1829                 // FAIL:
1830                 // 1. we still don't have srcprovidername yet
1831                 // 2. cannot store privatekey into NSS keystore
1832                 //    java.security.KeyStoreException: sun.security.pkcs11
1833                 //      .wrapper.PKCS11Exception: CKR_TEMPLATE_INCOMPLETE.
1834                 //t.testPKCS11ImportKeyStore();
1835 
1836                 t.i18nPKCS11Test();
1837                 //FAIL: currently PKCS11-NSS does not support
1838                 // 2 NSS KeyStores to be loaded at the same time
1839                 //t.sszzTest();
1840             }
1841 
1842             if (System.getProperty("solaris") != null) {
1843                 // For Solaris Cryptography Framework
1844                 t.srcP11Arg = SUN_SRC_P11_ARG;
1845                 t.p11Arg = SUN_P11_ARG;
1846                 t.testPKCS11();
1847                 t.testPKCS11ImportKeyStore();
1848                 t.i18nPKCS11Test();
1849             }
1850 
1851             System.out.println("Test pass!!!");
1852         } finally {
1853             // restore the reserved locale
1854             Locale.setDefault(reservedLocale);
1855         }
1856     }
1857 }
1858 
1859 class TestException extends Exception {
1860     public TestException(String e) {
1861         super(e);
1862     }
1863 }
1864 
1865 /**
1866  * HumanInputStream tries to act like a human sitting in front of a computer
1867  * terminal typing on the keyboard while the keytool program is running.
1868  *
1869  * keytool has called InputStream.read() and BufferedReader.readLine() in
1870  * various places. a call to B.readLine() will try to buffer as much input as
1871  * possible. Thus, a trivial InputStream will find it impossible to feed
1872  * anything to I.read() after a B.readLine() call.
1873  *
1874  * This is why i create HumanInputStream, which will only send a single line
1875  * to B.readLine(), no more, no less, and the next I.read() can have a chance
1876  * to read the exact character right after "\n".
1877  *
1878  * I don't know why HumanInputStream works.
1879  */
1880 class HumanInputStream extends InputStream {
1881     byte[] src;
1882     int pos;
1883     int length;
1884     boolean inLine;
1885     int stopIt;
1886 
1887     public HumanInputStream(String input) {
1888         src = input.getBytes();
1889         pos = 0;
1890         length = src.length;
1891         stopIt = 0;
1892         inLine = false;
1893     }
1894 
1895     // the trick: when called through read(byte[], int, int),
1896     // return -1 twice after "\n"
1897 
1898     @Override public int read() throws IOException {
1899         int re;
1900         if(pos < length) {
1901             re = src[pos];
1902             if(inLine) {
1903                 if(stopIt > 0) {
1904                     stopIt--;
1905                     re = -1;
1906                 } else {
1907                     if(re == '\n') {
1908                         stopIt = 2;
1909                     }
1910                     pos++;
1911                 }
1912             } else {
1913                 pos++;
1914             }
1915         } else {
1916             re = -1;//throw new IOException("NO MORE TO READ");
1917         }
1918         //if (re < 32) System.err.printf("[%02d]", re);
1919         //else System.err.printf("[%c]", (char)re);
1920         return re;
1921     }
1922     @Override public int read(byte[] buffer, int offset, int len) {
1923         inLine = true;
1924         try {
1925             int re = super.read(buffer, offset, len);
1926             return re;
1927         } catch(Exception e) {
1928             throw new RuntimeException("HumanInputStream error");
1929         } finally {
1930             inLine = false;
1931         }
1932     }
1933     @Override public int available() {
1934         if(pos < length) return 1;
1935         return 0;
1936     }
1937 
1938     // test part
1939     static void assertTrue(boolean bool) {
1940         if(!bool)
1941             throw new RuntimeException();
1942     }
1943 
1944     public static void test() throws Exception {
1945 
1946         class Tester {
1947             HumanInputStream is;
1948             BufferedReader reader;
1949             Tester(String s) {
1950                 is = new HumanInputStream(s);
1951                 reader = new BufferedReader(new InputStreamReader(is));
1952             }
1953 
1954             // three kinds of test method
1955             // 1. read byte by byte from InputStream
1956             void testStreamReadOnce(int expection) throws Exception {
1957                 assertTrue(is.read() == expection);
1958             }
1959             void testStreamReadMany(String expection) throws Exception {
1960                 char[] keys = expection.toCharArray();
1961                 for(int i=0; i<keys.length; i++) {
1962                     assertTrue(is.read() == keys[i]);
1963                 }
1964             }
1965             // 2. read a line with a newly created Reader
1966             void testReaderReadline(String expection) throws Exception {
1967                 String s = new BufferedReader(new InputStreamReader(is)).readLine();
1968                 if(s == null) assertTrue(expection == null);
1969                 else assertTrue(s.equals(expection));
1970             }
1971             // 3. read a line with the old Reader
1972             void testReaderReadline2(String expection) throws Exception  {
1973                 String s = reader.readLine();
1974                 if(s == null) assertTrue(expection == null);
1975                 else assertTrue(s.equals(expection));
1976             }
1977         }
1978 
1979         Tester test;
1980 
1981         test = new Tester("111\n222\n\n444\n\n");
1982         test.testReaderReadline("111");
1983         test.testReaderReadline("222");
1984         test.testReaderReadline("");
1985         test.testReaderReadline("444");
1986         test.testReaderReadline("");
1987         test.testReaderReadline(null);
1988 
1989         test = new Tester("111\n222\n\n444\n\n");
1990         test.testReaderReadline2("111");
1991         test.testReaderReadline2("222");
1992         test.testReaderReadline2("");
1993         test.testReaderReadline2("444");
1994         test.testReaderReadline2("");
1995         test.testReaderReadline2(null);
1996 
1997         test = new Tester("111\n222\n\n444\n\n");
1998         test.testReaderReadline2("111");
1999         test.testReaderReadline("222");
2000         test.testReaderReadline2("");
2001         test.testReaderReadline2("444");
2002         test.testReaderReadline("");
2003         test.testReaderReadline2(null);
2004 
2005         test = new Tester("1\n2");
2006         test.testStreamReadMany("1\n2");
2007         test.testStreamReadOnce(-1);
2008 
2009         test = new Tester("12\n234");
2010         test.testStreamReadOnce('1');
2011         test.testReaderReadline("2");
2012         test.testStreamReadOnce('2');
2013         test.testReaderReadline2("34");
2014         test.testReaderReadline2(null);
2015 
2016         test = new Tester("changeit\n");
2017         test.testStreamReadMany("changeit\n");
2018         test.testReaderReadline(null);
2019 
2020         test = new Tester("changeit\nName\nCountry\nYes\n");
2021         test.testStreamReadMany("changeit\n");
2022         test.testReaderReadline("Name");
2023         test.testReaderReadline("Country");
2024         test.testReaderReadline("Yes");
2025         test.testReaderReadline(null);
2026 
2027         test = new Tester("Me\nHere\n");
2028         test.testReaderReadline2("Me");
2029         test.testReaderReadline2("Here");
2030     }
2031 }