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