diff -r 4ebc2e2fb97c -r 71c04702a3d5 test/jdk/sun/security/tools/keytool/KeyToolTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/sun/security/tools/keytool/KeyToolTest.java Tue Sep 12 19:03:39 2017 +0200 @@ -0,0 +1,2040 @@ +/* + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * + * + * @summary Testing keytool + * @author weijun.wang + * + * Run through autotest.sh and manualtest.sh + * + * Testing non-PKCS11 keystores: + * echo | java -Dfile KeyToolTest + * + * Testing NSS PKCS11 keystores: + * # testing NSS + * # make sure the NSS db files are in current directory and writable + * echo | java -Dnss -Dnss.lib=/path/to/libsoftokn3.so KeyToolTest + * + * Testing Solaris Cryptography Framework PKCS11 keystores: + * # make sure you've already run pktool and set test12 as pin + * echo | java -Dsolaris KeyToolTest + * + * ATTENTION: + * Exception in thread "main" java.security.ProviderException: + * sun.security.pkcs11.wrapper.PKCS11Exception: CKR_KEY_SIZE_RANGE + * at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:420) + * ... + * Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_KEY_SIZE_RANGE + * at sun.security.pkcs11.wrapper.PKCS11.C_SignFinal(Native Method) + * at sun.security.pkcs11.P11Signature.engineSign(P11Signature.java:391) + * ... + * been observed. Possibly a Solaris bug + * + * ATTENTION: + * NSS PKCS11 config file are changed, DSA not supported now. + */ + +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyStore; +import sun.security.x509.*; +import java.io.*; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.security.cert.X509Certificate; +import sun.security.util.ObjectIdentifier; + +public class KeyToolTest { + + // The stdout and stderr outputs after a keytool run + String out; + String err; + + // the output of println() in KeyTool.run + String ex; + + String lastInput = "", lastCommand = ""; + private static final boolean debug = + System.getProperty("debug") != null; + + static final String NSS_P11_ARG = + "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nss " + + "-addprovider SunPKCS11 " + + "-providerArg p11-nss.txt "; + // Use -providerClass here, to confirm it still works for SunPKCS11. + static final String NSS_SRC_P11_ARG = + "-srckeystore NONE -srcstoretype PKCS11 " + + "-srcproviderName SunPKCS11-nss " + + "-providerClass sun.security.pkcs11.SunPKCS11 " + + "-providerArg p11-nss.txt "; + static final String NZZ_P11_ARG = + "-keystore NONE -storetype PKCS11 -providerName SunPKCS11-nzz " + + "-addprovider SunPKCS11 " + + "-providerArg p11-nzz.txt "; + static final String NZZ_SRC_P11_ARG = + "-srckeystore NONE -srcstoretype PKCS11 " + + "-srcproviderName SunPKCS11-nzz " + + "-addprovider SunPKCS11 " + + "-providerArg p11-nzz.txt "; + static final String SUN_P11_ARG = "-keystore NONE -storetype PKCS11 "; + static final String SUN_SRC_P11_ARG = + "-srckeystore NONE -srcstoretype PKCS11 "; + + String p11Arg, srcP11Arg; + + /** Creates a new instance of KeyToolTest */ + KeyToolTest() { + // so that there is "Warning" and not translated into other language + Locale.setDefault(Locale.US); + } + + /** + * Helper, removes a file + */ + void remove(String filename) { + if (debug) { + System.err.println("Removing " + filename); + } + new File(filename).delete(); + if (new File(filename).exists()) { + throw new RuntimeException("Error deleting " + filename); + } + } + + /** + * Run a set of keytool command with given terminal input. + * @param input the terminal inputs, the characters typed by human + * if cmd is running on a terminal + * @param cmd the argument of a keytool command line + * @throws if keytool goes wrong in some place + */ + void test(String input, String cmd) throws Exception { + lastInput = input; + lastCommand = cmd; + + // "X" is appended so that we can precisely test how input is consumed + HumanInputStream in = new HumanInputStream(input+"X"); + test(in, cmd); + // make sure the input string is no more no less + if(in.read() != 'X' || in.read() != -1) + throw new Exception("Input not consumed exactly"); + } + + void test(InputStream in, String cmd) throws Exception { + + // save the original 3 streams + if (debug) { + System.err.println(cmd); + } else { + System.err.print("."); + } + PrintStream p1 = System.out; + PrintStream p2 = System.err; + InputStream i1 = System.in; + + ByteArrayOutputStream b1 = new ByteArrayOutputStream(); + ByteArrayOutputStream b2 = new ByteArrayOutputStream(); + + try { + System.setIn(in); + System.setOut(new PrintStream(b1)); + System.setErr(new PrintStream(b2)); + + // since System.in is overrided, the + // sun.security.tools.keytool.Main.main() method will + // never block at user input + + // use -debug so that main() will throw an Exception + // instead of calling System.exit() + sun.security.tools.keytool.Main.main(("-debug "+cmd).split("\\s+")); + } finally { + out = b1.toString(); + err = b2.toString(); + ex = out; // now it goes to System.out + System.setIn(i1); + System.setOut(p1); + System.setErr(p2); + } + } + + /** + * Call this method if you expect test(input, cmd) should go OK + */ + void testOK(String input, String cmd) throws Exception { + try { + // Workaround for "8057810: Make SHA256withDSA the default + // jarsigner and keytool algorithm for DSA keys". Unfortunately + // SunPKCS11-NSS does not support SHA256withDSA yet. + if (cmd.contains("p11-nss.txt") && cmd.contains("-genkey") + && !cmd.contains("-keyalg")) { + cmd += " -sigalg SHA1withDSA -keysize 1024"; + } + test(input, cmd); + } catch(Exception e) { + afterFail(input, cmd, "OK"); + throw e; + } + } + + /** + * Call this method if you expect test(input, cmd) should fail and throw + * an exception + */ + void testFail(String input, String cmd) throws Exception { + boolean ok; + try { + test(input, cmd); + ok = true; + } catch(Exception e) { + if (e instanceof MissingResourceException) { + ok = true; + } else { + ok = false; + } + } + if(ok) { + afterFail(input, cmd, "FAIL"); + throw new RuntimeException(); + } + } + + /** + * Call this method if you expect test(input, cmd) should go OK + */ + void testOK(InputStream is, String cmd) throws Exception { + try { + test(is, cmd); + } catch(Exception e) { + afterFail("", cmd, "OK"); + throw e; + } + } + + /** + * Call this method if you expect test(input, cmd) should fail and throw + * an exception + */ + void testFail(InputStream is, String cmd) throws Exception { + boolean ok; + try { + test(is, cmd); + ok = true; + } catch(Exception e) { + ok = false; + } + if(ok) { + afterFail("", cmd, "FAIL"); + throw new RuntimeException(); + } + } + + /** + * Call this method if you just want to run the command and does + * not care if it succeeds or fails. + */ + void testAnyway(String input, String cmd) { + try { + test(input, cmd); + } catch(Exception e) { + ; + } + } + + /** + * Helper method, print some output after a test does not do as expected + */ + void afterFail(String input, String cmd, String should) { + if (cmd.contains("p11-nss.txt")) { + cmd = "-J-Dnss.lib=" + System.getProperty("nss.lib") + " " + cmd; + } + System.err.println("\nTest fails for the command ---\n" + + "keytool " + cmd + "\nOr its debug version ---\n" + + "keytool -debug " + cmd); + + System.err.println("The command result should be " + should + + ", but it's not. Try run the command manually and type" + + " these input into it: "); + char[] inputChars = input.toCharArray(); + + for (int i=0; i jks + testOK("changeit\nchangeit\ntest12\n", srcP11Arg + + ("-importkeystore -destkeystore x.jks -deststoretype JKS " + + "-srcalias p1")); + assertTrue(err.indexOf("not imported") != -1, + "cannot import key without destkeypass"); + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!ks.containsAlias("p1"), "p1 is not imported"); + + testOK("changeit\ntest12\n", srcP11Arg + + ("-importkeystore -destkeystore x.jks -deststoretype JKS " + + "-srcalias p1 -destkeypass changeit")); + testOK("changeit\ntest12\n", srcP11Arg + + ("-importkeystore -destkeystore x.jks -deststoretype JKS " + + "-srcalias p2 -destkeypass changeit")); + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(ks.containsAlias("p1"), "p1 is imported"); + assertTrue(ks.containsAlias("p2"), "p2 is imported"); + // jks -> pkcs11 + testOK("", p11Arg + "-storepass test12 -delete -alias p1"); + testOK("", p11Arg + "-storepass test12 -delete -alias p2"); + testOK("test12\nchangeit\n", p11Arg + + "-importkeystore -srckeystore x.jks -srcstoretype JKS"); + testOK("", p11Arg + "-storepass test12 -list -alias p1"); + testOK("", p11Arg + "-storepass test12 -list -alias p2"); + testOK("", p11Arg + "-storepass test12 -list"); + assertTrue(out.indexOf("Your keystore contains 2 entries") != -1, + "2 entries in p11"); + // clean up + testOK("", p11Arg + "-storepass test12 -delete -alias p1"); + testOK("", p11Arg + "-storepass test12 -delete -alias p2"); + testOK("", p11Arg + "-storepass test12 -list"); + assertTrue(out.indexOf("Your keystore contains 0 entries") != -1, + "empty p11"); + + remove("x.jks"); + } + + // Selected sqeTest + void sqeTest() throws Exception { + FileOutputStream fos = new FileOutputStream("badkeystore"); + for (int i=0; i<100; i++) { + fos.write(i); + } + fos.close(); + + sqeCsrTest(); + sqePrintcertTest(); + sqeDeleteTest(); + sqeExportTest(); + sqeGenkeyTest(); + sqeImportTest(); + sqeKeyclonetest(); + sqeKeypasswdTest(); + sqeListTest(); + sqeSelfCertTest(); + sqeStorepassTest(); + + remove("badkeystore"); + } + + // Import: cacert, prompt, trusted, non-trusted, bad chain, not match + void sqeImportTest() throws Exception { + KeyStore ks; + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-exportcert -file x.jks.p1.cert"); + /* deleted */ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert -noprompt"); + /* deleted */ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -delete -alias mykey"); + testOK("yes\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert"); + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(ks.containsAlias("mykey"), "imported"); + /* deleted */ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -delete -alias mykey"); + testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert"); + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!ks.containsAlias("mykey"), "imported"); + testOK("no\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert"); + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!ks.containsAlias("mykey"), "imported"); + testFail("no\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file nonexist"); + testFail("no\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks"); + remove("x.jks"); + } + // keyclone: exist. nonexist err, cert err, dest exist, misc + void sqeKeyclonetest() throws Exception { + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + // new pass + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -new newpass -keyclone -dest p0"); + // new pass + testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -keyclone -dest p1"); + testOK("\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keyclone -dest p2"); + testFail("\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keyclone -dest p2"); + testFail("\n", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keyclone -dest p3 -alias noexist"); + // no cert + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-exportcert -file x.jks.p1.cert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert -noprompt"); + // new pass + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -new newpass -keyclone -dest p0"); + remove("x.jks"); + } + // keypasswd: exist, short, nonexist err, cert err, misc + void sqeKeypasswdTest() throws Exception { + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -keypasswd -new newpass"); + /*change back*/ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass newpass -keypasswd -new changeit"); + testOK("newpass\nnewpass\n", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass changeit -keypasswd"); + /*change back*/ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass newpass -keypasswd -new changeit"); + testOK("new\nnew\nnewpass\nnewpass\n", "-keystore x.jks " + + "-storetype JKS -storepass changeit -keypass changeit -keypasswd"); + /*change back*/ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass newpass -keypasswd -new changeit"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypasswd -new newpass"); + /*change back*/ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass newpass -keypasswd -new changeit"); + testOK("changeit\n", "-keystore x.jks -storetype JKS " + + "-keypasswd -new newpass"); + /*change back*/ testOK("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypass newpass -keypasswd -new changeit"); + testFail("", "-keystore x.jks -storetype JKS -storepass badpass " + + "-keypass changeit -keypasswd -new newpass"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass bad -keypasswd -new newpass"); + // no cert + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-exportcert -file x.jks.p1.cert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert -noprompt"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -keypasswd -new newpass"); + // diff pass + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass keypass -genkeypair -dname CN=olala"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypasswd -new newpass"); + testOK("keypass\n", "-keystore x.jks -storetype JKS " + + "-storepass changeit -keypasswd -new newpass"); + // i hate those misc test + remove("x.jks"); + } + // list: -f -alias, exist, nonexist err; + // otherwise, check all shows, -rfc shows more, and misc + void sqeListTest() throws Exception { + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit -list"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-list -alias mykey"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-list -alias notexist"); + testFail("", "-keystore x.jks -storetype JKS -storepass badpass " + + "-list -alias mykey"); + // keypass ignore + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass badpass -list -alias mykey"); + testOK("\n", "-keystore x.jks -storetype JKS -list"); + assertTrue(err.indexOf("WARNING") != -1, "no storepass"); + testOK("changeit\n", "-keystore x.jks -storetype JKS -list"); + assertTrue(err.indexOf("WARNING") == -1, "has storepass"); + testFail("badpass\n", "-keystore x.jks -storetype JKS -list"); + // misc + testFail("", "-keystore aa\\bb//cc -storepass changeit -list"); + testFail("", "-keystore nonexisting -storepass changeit -list"); + testFail("", "-keystore badkeystore -storepass changeit -list"); + remove("x.jks"); + } + // selfcert: exist, non-exist err, cert err, sig, dname, wrong keypass, misc + void sqeSelfCertTest() throws Exception { + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit -selfcert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -selfcert"); + // not exist + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -selfcert -alias nonexisting"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -selfcert -dname CN=NewName"); + // sig not compatible + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -selfcert -sigalg MD5withRSA"); + // bad pass + testFail("", "-keystore x.jks -storetype JKS -storepass wrong " + + "-keypass changeit -selfcert"); + // bad pass + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass wrong -selfcert"); + //misc + testFail("", "-keystore nonexist -storepass changeit " + + "-keypass changeit -selfcert"); + testFail("", "-keystore aa//dd\\gg -storepass changeit " + + "-keypass changeit -selfcert"); + // diff pass + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass keypass -genkeypair -dname CN=olala"); + testFail("", "-keystore x.jks -storetype JKS " + + "-storepass changeit -selfcert"); + testOK("keypass\n", "-keystore x.jks -storetype JKS " + + "-storepass changeit -selfcert"); + + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-exportcert -file x.jks.p1.cert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert -noprompt"); + // certentry cannot do selfcert + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-selfcert"); + remove("x.jks"); + } + // storepass: bad old, short new, misc + void sqeStorepassTest() throws Exception { + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + // all in arg + testOK("", "-storepasswd -keystore x.jks -storetype JKS " + + "-storepass changeit -new newstore"); + /* Change back */ testOK("", "-storepasswd -keystore x.jks" + + " -storetype JKS -storepass newstore -new changeit"); + // all not in arg, new twice + testOK("changeit\nnewstore\nnewstore\n", "-storepasswd " + + "-keystore x.jks -storetype JKS"); + /* Change back */ testOK("", "-storepasswd -keystore x.jks " + + "-storetype JKS -storepass newstore -new changeit"); + // new in arg + testOK("changeit\n", "-storepasswd -keystore x.jks " + + "-storetype JKS -new newstore"); + /* Change back */ testOK("", "-storepasswd -keystore x.jks " + + "-storetype JKS -storepass newstore -new changeit"); + // old in arg + testOK("newstore\nnewstore\n", "-storepasswd -keystore x.jks " + + "-storetype JKS -storepass changeit"); + /* Change back */ testOK("", "-storepasswd -keystore x.jks " + + "-storetype JKS -storepass newstore -new changeit"); + // old in arg + testOK("new\nnew\nnewstore\nnewstore\n", "-storepasswd " + + "-keystore x.jks -storetype JKS -storepass changeit"); + /* Change back */ testOK("", "-storepasswd -keystore x.jks " + + "-storetype JKS -storepass newstore -new changeit"); + // bad old + testFail("", "-storepasswd -keystore x.jks -storetype JKS " + + "-storepass badold -new newstore"); + // short new + testFail("", "-storepasswd -keystore x.jks -storetype JKS " + + "-storepass changeit -new new"); + // misc + // non exist + testFail("", "-storepasswd -keystore nonexist " + + "-storepass changeit -new newstore"); + // bad file + testFail("", "-storepasswd -keystore badkeystore " + + "-storepass changeit -new newstore"); + // bad file + testFail("", "-storepasswd -keystore aa\\bb//cc//dd " + + "-storepass changeit -new newstore"); + remove("x.jks"); + } + + void sqeGenkeyTest() throws Exception { + + remove("x.jks"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -alias newentry"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -alias newentry"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg DSA " + + "-alias n1"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-alias n2"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala " + + "-keyalg NoSuchAlg -alias n3"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keysize 56 " + + "-alias n4"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keysize 999 " + + "-alias n5"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keysize 512 " + + "-alias n6"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keysize 1024 " + + "-alias n7"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala " + + "-sigalg NoSuchAlg -alias n8"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-sigalg MD2withRSA -alias n9"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-sigalg MD5withRSA -alias n10"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-sigalg SHA1withRSA -alias n11"); + testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA " + + "-sigalg NoSuchAlg -alias n12"); + testFail("", "-keystore badkeystore -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala " + + "-alias n14"); + testFail("", "-keystore x.jks -storetype JKS -storepass badpass " + + "-keypass changeit -genkeypair -dname CN=olala -alias n16"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CNN=olala -alias n17"); + remove("x.jks"); + } + + void sqeExportTest() throws Exception { + remove("x.jks"); + // nonexist + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-export -file mykey.cert -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-export -file mykey.cert -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-import -file mykey.cert -noprompt -alias c1"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-export -file mykey.cert2 -alias c1"); + testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " + + "-export -file mykey.cert2 -alias c1"); + testFail("", "-keystore nonexistkeystore -storepass changeit " + + "-export -file mykey.cert2 -alias c1"); + testFail("", "-keystore badkeystore -storepass changeit " + + "-export -file mykey.cert2 -alias c1"); + testFail("", "-keystore x.jks -storetype JKS -storepass badpass " + + "-export -file mykey.cert2 -alias c1"); + remove("mykey.cert"); + remove("mykey.cert2"); + remove("x.jks"); + } + + void sqeDeleteTest() throws Exception { + remove("x.jks"); + // nonexist + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + // keystore name illegal + testFail("", "-keystore aa\\bb//cc\\dd -storepass changeit " + + "-delete -alias mykey"); + // keystore not exist + testFail("", "-keystore nonexistkeystore -storepass changeit " + + "-delete -alias mykey"); + // keystore invalid + testFail("", "-keystore badkeystore -storepass changeit " + + "-delete -alias mykey"); + // wrong pass + testFail("", "-keystore x.jks -storetype JKS -storepass xxxxxxxx " + + "-delete -alias mykey"); + remove("x.jks"); + } + + void sqeCsrTest() throws Exception { + remove("x.jks"); + remove("x.jks.p1.cert"); + remove("csr1"); + // PrivateKeyEntry can do certreq + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keysize 1024"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -sigalg SHA1withDSA"); + // unmatched sigalg + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -sigalg MD5withRSA"); + // misc test + // bad storepass + testFail("", "-keystore x.jks -storetype JKS -storepass badstorepass " + + "-certreq -file csr1"); + // storepass from terminal + testOK("changeit\n", "-keystore x.jks -storetype JKS " + + "-certreq -file csr1"); + // must provide storepass + testFail("\n", "-keystore x.jks -storetype JKS " + + "-certreq -file csr1"); + // bad keypass + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass badkeypass -certreq -file csr1"); + // bad filepath + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file aa\\bb//cc\\dd"); + // non-existing keystore + testFail("", "-keystore noexistks -storepass changeit " + + "-certreq -file csr1"); + // Try the RSA private key + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala -keyalg RSA"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1"); + // unmatched sigalg + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -sigalg SHA1withDSA"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -sigalg MD5withRSA"); + // TrustedCertificateEntry cannot do certreq + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-exportcert -file x.jks.p1.cert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-delete -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-importcert -file x.jks.p1.cert -noprompt"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1 -alias mykey"); + testFail("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-certreq -file csr1"); + remove("x.jks"); + remove("x.jks.p1.cert"); + remove("csr1"); + } + + void sqePrintcertTest() throws Exception { + remove("x.jks"); + remove("mykey.cert"); + remove("myweakkey.cert"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=olala"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-export -file mykey.cert -alias mykey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -genkeypair -dname CN=weak -keyalg rsa " + + "-keysize 512 -sigalg MD5withRSA -alias myweakkey"); + testOK("", "-keystore x.jks -storetype JKS -storepass changeit " + + "-export -file myweakkey.cert -alias myweakkey"); + testFail("", "-printcert -file badkeystore"); + testFail("", "-printcert -file a/b/c/d"); + testOK("", "-printcert -file mykey.cert"); + testOK("", "-printcert -file myweakkey.cert"); + FileInputStream fin = new FileInputStream("mykey.cert"); + testOK(fin, "-printcert"); + fin.close(); + remove("x.jks"); + remove("mykey.cert"); + remove("myweakkey.cert"); + } + + // 8074935: jdk8 keytool doesn't validate pem files for RFC 1421 correctness + static void checkPem(String file) throws Exception { + boolean maybeLast = false; + for (String s: Files.readAllLines(Paths.get(file))) { + if (s.isEmpty()) continue; + if (s.startsWith("---")) continue; + if (maybeLast) { + throw new Exception("Last line already seen"); + } + if (s.length() > 64) { + throw new Exception(s); + } + if (s.length() < 64) { + maybeLast = true; + } + } + } + + void v3extTest(String keyAlg) throws Exception { + KeyStore ks; + remove("x.jks"); + String simple = "-keystore x.jks -storetype JKS -storepass changeit " + + "-keypass changeit -noprompt -keyalg " + keyAlg + " "; + String pre = simple + "-genkeypair -dname CN=Olala -alias "; + + // Version and SKID + testOK("", pre + "o1"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509Certificate)ks.getCertificate("o1")).getVersion() == 3); + assertTrue(((X509CertImpl)ks.getCertificate("o1")) + .getSubjectKeyIdentifierExtension() != null); + + // BC + testOK("", pre + "b1 -ext BC:critical"); + testOK("", pre + "b2 -ext BC"); + testOK("", pre + "b3 -ext bc"); + testOK("", pre + "b4 -ext BasicConstraints"); + testOK("", pre + "b5 -ext basicconstraints"); + testOK("", pre + "b6 -ext BC=ca:true,pathlen:12"); + testOK("", pre + "b7 -ext BC=ca:false"); + testOK("", pre + "b8 -ext BC:critical=ca:false"); + testOK("", pre + "b9 -ext BC=12"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509CertImpl)ks.getCertificate("b1")) + .getBasicConstraintsExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("b2")) + .getBasicConstraintsExtension().isCritical()); + assertTrue(((X509CertImpl)ks.getCertificate("b8")) + .getBasicConstraintsExtension().isCritical()); + assertTrue(((X509Certificate)ks.getCertificate("b1")) + .getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b2")) + .getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b3")) + .getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b4")) + .getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b5")) + .getBasicConstraints() == Integer.MAX_VALUE); + assertTrue(((X509Certificate)ks.getCertificate("b6")) + .getBasicConstraints() == 12); + assertTrue(((X509Certificate)ks.getCertificate("b7")) + .getBasicConstraints() == -1); + assertTrue(((X509Certificate)ks.getCertificate("b9")) + .getBasicConstraints() == 12); + + // KU + testOK("", pre + "ku1 -ext KeyUsage:critical=digitalsignature"); + testOK("", pre + "ku2 -ext KU=digitalSignature"); + testOK("", pre + "ku3 -ext KU=ds"); + testOK("", pre + "ku4 -ext KU=dig"); + // ambigous value + testFail("", pre + "ku5 -ext KU=d"); + // cRLSign cannot be cs + testFail("", pre + "ku6 -ext KU=cs"); + testOK("", pre + "ku11 -ext KU=nr"); + // ke also means keyAgreement + testFail("", pre + "ku12 -ext KU=ke"); + testOK("", pre + "ku12 -ext KU=keyE"); + // de also means decipherOnly + testFail("", pre + "ku13 -ext KU=de"); + testOK("", pre + "ku13 -ext KU=dataE"); + testOK("", pre + "ku14 -ext KU=ka"); + testOK("", pre + "ku15 -ext KU=kcs"); + testOK("", pre + "ku16 -ext KU=crls"); + testOK("", pre + "ku17 -ext KU=eo"); + testOK("", pre + "ku18 -ext KU=do"); + testOK("", pre + "ku19 -ext KU=cc"); + + testOK("", pre + "ku017 -ext KU=ds,cc,eo"); + testOK("", pre + "ku135 -ext KU=nr,dataEncipherment,keyCertSign"); + testOK("", pre + "ku246 -ext KU=keyEnc,cRL,keyA"); + testOK("", pre + "ku1234 -ext KU=ka,da,keyE,nonR"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckKU { + void check(KeyStore ks, String alias, int... pos) throws Exception { + System.err.print("x"); + boolean[] bs = ((X509Certificate)ks.getCertificate(alias)) + .getKeyUsage(); + bs = Arrays.copyOf(bs, 9); + for (int i=0; i bs = ((X509Certificate)ks.getCertificate(alias)) + .getExtendedKeyUsage(); + int found = 0; + for (String p: pos) { + if (bs.contains(p)) { + found++; + } else { + throw new RuntimeException("EKU: not included " + p); + } + } + if (found != bs.size()) { + throw new RuntimeException("EKU: more items than expected"); + } + } + } + CheckEKU cx = new CheckEKU(); + assertTrue(((X509CertImpl)ks.getCertificate("eku1")) + .getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("eku2")) + .getExtension(PKIXExtensions.ExtendedKeyUsage_Id).isCritical()); + cx.check(ks, "eku1", "1.3.6.1.5.5.7.3.1"); + cx.check(ks, "eku2", "1.3.6.1.5.5.7.3.2"); + cx.check(ks, "eku3", "1.3.6.1.5.5.7.3.3"); + cx.check(ks, "eku4", "1.3.6.1.5.5.7.3.4"); + cx.check(ks, "eku8", "1.3.6.1.5.5.7.3.8"); + cx.check(ks, "eku9", "1.3.6.1.5.5.7.3.9"); + cx.check(ks, "eku10", "2.5.29.37.0"); + cx.check(ks, "eku11", "1.3.6.1.5.5.7.3.4", "1.2.3.4", "1.3.5.7"); + + // SAN + testOK("", pre+"san1 -ext san:critical=email:me@me.org"); + testOK("", pre+"san2 -ext san=uri:http://me.org"); + testOK("", pre+"san3 -ext san=dns:me.org"); + testOK("", pre+"san4 -ext san=ip:192.168.0.1"); + testOK("", pre+"san5 -ext san=oid:1.2.3.4"); + testOK("", pre+"san235 -ext san=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSAN { + // Please sort items with name type + void check(KeyStore ks, String alias, int type, Object... items) + throws Exception { + int pos = 0; + System.err.print("x"); + Object[] names = null; + if (type == 0) names = ((X509Certificate)ks.getCertificate(alias)) + .getSubjectAlternativeNames().toArray(); + else names = ((X509Certificate)ks.getCertificate(alias)) + .getIssuerAlternativeNames().toArray(); + Arrays.sort(names, new Comparator() { + public int compare(Object o1, Object o2) { + int i1 = (Integer)((List)o1).get(0); + int i2 = (Integer)((List)o2).get(0); + return i1 - i2; + } + }); + for (Object o: names) { + List l = (List)o; + for (Object o2: l) { + if (!items[pos++].equals(o2)) { + throw new RuntimeException("Not equals at " + pos + + ": " + items[pos-1] + " vs " + o2); + } + } + } + if (pos != items.length) { + throw new RuntimeException("Extra items, pos is " + pos); + } + } + } + CheckSAN csan = new CheckSAN(); + assertTrue(((X509CertImpl)ks.getCertificate("san1")) + .getSubjectAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("san2")) + .getSubjectAlternativeNameExtension().isCritical()); + csan.check(ks, "san1", 0, 1, "me@me.org"); + csan.check(ks, "san2", 0, 6, "http://me.org"); + csan.check(ks, "san3", 0, 2, "me.org"); + csan.check(ks, "san4", 0, 7, "192.168.0.1"); + csan.check(ks, "san5", 0, 8, "1.2.3.4"); + csan.check(ks, "san235", 0, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // IAN + testOK("", pre+"ian1 -ext ian:critical=email:me@me.org"); + testOK("", pre+"ian2 -ext ian=uri:http://me.org"); + testOK("", pre+"ian3 -ext ian=dns:me.org"); + testOK("", pre+"ian4 -ext ian=ip:192.168.0.1"); + testOK("", pre+"ian5 -ext ian=oid:1.2.3.4"); + testOK("", pre+"ian235 -ext ian=uri:http://me.org,dns:me.org,oid:1.2.3.4"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(((X509CertImpl)ks.getCertificate("ian1")) + .getIssuerAlternativeNameExtension().isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("ian2")) + .getIssuerAlternativeNameExtension().isCritical()); + csan.check(ks, "ian1", 1, 1, "me@me.org"); + csan.check(ks, "ian2", 1, 6, "http://me.org"); + csan.check(ks, "ian3", 1, 2, "me.org"); + csan.check(ks, "ian4", 1, 7, "192.168.0.1"); + csan.check(ks, "ian5", 1, 8, "1.2.3.4"); + csan.check(ks, "ian235", 1, 2, "me.org", 6, "http://me.org", 8, "1.2.3.4"); + + // SIA + testOK("", pre+"sia1 -ext sia=care:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"sia2 -ext sia=ts:email:ts@ca.com"); + testFail("SIA never critical", pre + + "sia3 -ext sia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckSia { + void check(KeyStore ks, String alias, int type, Object... items) + throws Exception { + int pos = 0; + System.err.print("x"); + AccessDescription[] ads = null; + if (type == 0) { + SubjectInfoAccessExtension siae = (SubjectInfoAccessExtension) + ((X509CertImpl)ks.getCertificate(alias)) + .getExtension(PKIXExtensions.SubjectInfoAccess_Id); + ads = siae.getAccessDescriptions() + .toArray(new AccessDescription[0]); + } else { + AuthorityInfoAccessExtension aiae = + (AuthorityInfoAccessExtension) + ((X509CertImpl)ks.getCertificate(alias)) + .getExtension(PKIXExtensions.AuthInfoAccess_Id); + ads = aiae.getAccessDescriptions() + .toArray(new AccessDescription[0]); + } + Arrays.sort(ads, new Comparator() { + @Override + public int compare(AccessDescription o1, + AccessDescription o2) { + return o1.getAccessMethod().toString() + .compareTo(o2.getAccessMethod().toString()); + } + }); + for (AccessDescription ad: ads) { + if (!ad.getAccessMethod().equals(items[pos++]) || + !new Integer(ad.getAccessLocation().getType()) + .equals(items[pos++])) { + throw new RuntimeException("Not same type at " + pos); + } + String name = null; + switch (ad.getAccessLocation().getType()) { + case 1: + name = ((RFC822Name)ad.getAccessLocation() + .getName()).getName(); + break; + case 6: + name = ((URIName)ad.getAccessLocation() + .getName()).getURI().toString(); + break; + default: + throw new RuntimeException("Not implemented: " + ad); + } + if (!name.equals(items[pos++])) { + throw new Exception("Name not same for " + ad + + " at pos " + pos); + } + } + } + } + CheckSia csia = new CheckSia(); + assertTrue(!((X509CertImpl)ks.getCertificate("sia1")) + .getExtension(PKIXExtensions.SubjectInfoAccess_Id).isCritical()); + csia.check(ks, "sia1", 0, + AccessDescription.Ad_CAREPOSITORY_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "sia2", + 0, AccessDescription.Ad_TIMESTAMPING_Id, 1, "ts@ca.com"); + + // AIA + testOK("", pre+"aia1 -ext aia=cai:uri:ldap://ca.com/cn=CA"); + testOK("", pre+"aia2 -ext aia=ocsp:email:ocsp@ca.com"); + testFail("AIA never critical", pre + + "aia3 -ext aia:critical=ts:email:ts@ca.com"); + + ks = loadStore("x.jks", "changeit", "JKS"); + assertTrue(!((X509CertImpl)ks.getCertificate("aia1")) + .getExtension(PKIXExtensions.AuthInfoAccess_Id).isCritical()); + csia.check(ks, "aia1", 1, + AccessDescription.Ad_CAISSUERS_Id, 6, "ldap://ca.com/cn=CA"); + csia.check(ks, "aia2", 1, + AccessDescription.Ad_OCSP_Id, 1, "ocsp@ca.com"); + + // OID + testOK("", pre+"oid1 -ext 1.2.3:critical=0102"); + testOK("", pre+"oid2 -ext 1.2.3"); + testOK("", pre+"oid12 -ext 1.2.3 -ext 1.2.4=01:02:03"); + + ks = loadStore("x.jks", "changeit", "JKS"); + class CheckOid { + void check(KeyStore ks, String alias, String oid, byte[] value) + throws Exception { + int pos = 0; + System.err.print("x"); + Extension ex = ((X509CertImpl)ks.getCertificate(alias)) + .getExtension(new ObjectIdentifier(oid)); + if (!Arrays.equals(value, ex.getValue())) { + throw new RuntimeException("Not same content in " + + alias + " for " + oid); + } + } + } + CheckOid coid = new CheckOid(); + assertTrue(((X509CertImpl)ks.getCertificate("oid1")) + .getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!((X509CertImpl)ks.getCertificate("oid2")) + .getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + coid.check(ks, "oid1", "1.2.3", new byte[]{1,2}); + coid.check(ks, "oid2", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.3", new byte[]{}); + coid.check(ks, "oid12", "1.2.4", new byte[]{1,2,3}); + + // honored + testOK("", pre+"ca"); + testOK("", pre+"a"); + // request: BC,KU,1.2.3,1.2.4,1.2.5 + testOK("", simple+"-alias a -certreq " + + "-ext BC=1 -ext KU=crl " + + "-ext 1.2.3=01 -ext 1.2.4:critical=0102 -ext 1.2.5=010203 " + + "-rfc -file test.req"); + // printcertreq + testOK("", "-printcertreq -file test.req"); + checkPem("test.req"); + // issue: deny KU, change criticality of 1.2.3 and 1.2.4, + // change content of BC, add 2.3.4 + testOK("", simple+"-gencert -alias ca -infile test.req -ext " + + "honored=all,-KU,1.2.3:critical,1.2.4:non-critical " + + "-ext BC=2 -ext 2.3.4=01020304 " + + "-debug -rfc -outfile test.cert"); + checkPem("test.cert"); + testOK("", simple+"-importcert -file test.cert -alias a"); + ks = loadStore("x.jks", "changeit", "JKS"); + X509CertImpl a = (X509CertImpl)ks.getCertificate("a"); + assertTrue(a.getAuthorityKeyIdentifierExtension() != null); + assertTrue(a.getSubjectKeyIdentifierExtension() != null); + assertTrue(a.getKeyUsage() == null); + assertTrue(a.getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.4")).isCritical()); + assertTrue(!a.getExtension(new ObjectIdentifier("1.2.5")).isCritical()); + assertTrue(a.getExtensionValue("1.2.3").length == 3); + assertTrue(a.getExtensionValue("1.2.4").length == 4); + assertTrue(a.getExtensionValue("1.2.5").length == 5); + assertTrue(a.getBasicConstraints() == 2); + assertTrue(!a.getExtension(new ObjectIdentifier("2.3.4")).isCritical()); + assertTrue(a.getExtensionValue("2.3.4").length == 6); + + // 8073181: keytool -ext honored not working correctly + testOK("", simple+"-gencert -alias ca -infile test.req -ext " + + "honored=1.2.3,KU,1.2.4:critical " + + "-debug -rfc -outfile test2.cert"); + testOK("", simple+"-importcert -file test2.cert -alias b"); + ks = loadStore("x.jks", "changeit", "JKS"); + X509CertImpl b = (X509CertImpl)ks.getCertificate("b"); + assertTrue(!b.getExtension(new ObjectIdentifier("1.2.3")).isCritical()); + assertTrue(b.getExtension(new ObjectIdentifier("1.2.4")).isCritical()); + + // 8073182: keytool may generate duplicate extensions + testOK("", pre+"dup -ext bc=2 -ext 2.5.29.19=30030101FF -ext bc=3"); + ks = loadStore("x.jks", "changeit", "JKS"); + X509CertImpl dup = (X509CertImpl)ks.getCertificate("dup"); + assertTrue(dup.getBasicConstraints() == 3); + + remove("x.jks"); + remove("test.req"); + remove("test.cert"); + } + + void i18nTest() throws Exception { + // 1. keytool -help + remove("x.jks"); + testOK("", "-help"); + + // 2. keytool -genkey -v -keysize 512 Enter "a" for the keystore + // password. Check error (password too short). Enter "password" for + // the keystore password. Hit 'return' for "first and last name", + // "organizational unit", "City", "State", and "Country Code". + // Type "yes" when they ask you if everything is correct. + // Type 'return' for new key password. + testOK("a\npassword\npassword\nMe\nHere\nNow\nPlace\nPlace\nUS\nyes\n\n", + "-genkey -v -keysize 512 -keystore x.jks -storetype JKS"); + // 3. keytool -list -v -storepass password + testOK("", "-list -v -storepass password -keystore x.jks -storetype JKS"); + // 4. keytool -list -v Type "a" for the keystore password. + // Check error (wrong keystore password). + testFail("a\n", "-list -v -keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("password was incorrect") != -1); + // 5. keytool -genkey -v -keysize 512 Enter "password" as the password. + // Check error (alias 'mykey' already exists). + testFail("password\n", "-genkey -v -keysize 512" + + " -keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("alias already exists") != -1); + // 6. keytool -genkey -v -keysize 512 -alias mykey2 -storepass password + // Hit 'return' for "first and last name", "organizational unit", "City", + // "State", and "Country Code". Type "yes" when they ask you if + // everything is correct. Type 'return' for new key password. + testOK("\n\n\n\n\n\nyes\n\n", "-genkey -v -keysize 512 -alias mykey2" + + " -storepass password -keystore x.jks -storetype JKS"); + // 7. keytool -list -v Type 'password' for the store password. + testOK("password\n", "-list -v -keystore x.jks -storetype JKS"); + // 8. keytool -keypasswd -v -alias mykey2 -storepass password + // Type "a" for the new key password. Type "aaaaaa" for the new key + // password. Type "bbbbbb" when re-entering the new key password. + // Type "a" for the new key password. Check Error (too many failures). + testFail("a\naaaaaa\nbbbbbb\na\n", "-keypasswd -v -alias mykey2" + + " -storepass password -keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("Too many failures - try later") != -1); + // 9. keytool -keypasswd -v -alias mykey2 -storepass password + // Type "aaaaaa" for the new key password. Type "aaaaaa" + // when re-entering the new key password. + testOK("aaaaaa\naaaaaa\n", "-keypasswd -v -alias mykey2 " + + "-storepass password -keystore x.jks -storetype JKS"); + // 10. keytool -selfcert -v -alias mykey -storepass password + testOK("", "-selfcert -v -alias mykey -storepass password " + + "-keystore x.jks -storetype JKS"); + // 11. keytool -list -v -storepass password + testOK("", "-list -v -storepass password -keystore x.jks -storetype JKS"); + // 12. keytool -export -v -alias mykey -file cert -storepass password + remove("cert"); + testOK("", "-export -v -alias mykey -file cert -storepass password " + + "-keystore x.jks -storetype JKS"); + // 13. keytool -import -v -file cert -storepass password + // Check error (Certificate reply and cert are the same) + testFail("", "-import -v -file cert -storepass password" + + " -keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("Certificate reply and certificate" + + " in keystore are identical") != -1); + // 14. keytool -printcert -file cert + testOK("", "-printcert -file cert -keystore x.jks -storetype JKS"); + remove("cert"); + // 15. keytool -list -storepass password -addprovider SUN + testOK("", "-list -storepass password" + + " -addprovider SUN" + + " -keystore x.jks -storetype JKS"); + + //Error tests + + // 1. keytool -storepasswd -storepass password -new abc + // Check error (password too short) + testFail("", "-storepasswd -storepass password -new abc"); + assertTrue(ex.indexOf("New password must be at least 6 characters") != -1); + // Changed, no NONE needed now + // 2. keytool -list -storetype PKCS11 Check error (-keystore must be NONE) + //testFail("", "-list -storetype PKCS11"); + //assertTrue(err.indexOf("keystore must be NONE") != -1); + // 3. keytool -storepasswd -storetype PKCS11 -keystore NONE + // Check error (unsupported operation) + testFail("", "-storepasswd -storetype PKCS11 -keystore NONE"); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); + // 4. keytool -keypasswd -storetype PKCS11 -keystore NONE + // Check error (unsupported operation) + testFail("", "-keypasswd -storetype PKCS11 -keystore NONE"); + assertTrue(ex.indexOf("UnsupportedOperationException") != -1); + // 5. keytool -list -protected -storepass password + // Check error (password can not be specified with -protected) + testFail("", "-list -protected -storepass password " + + "-keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); + // 6. keytool -keypasswd -protected -keypass password + // Check error (password can not be specified with -protected) + testFail("", "-keypasswd -protected -keypass password " + + "-keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); + // 7. keytool -keypasswd -protected -new password + // Check error (password can not be specified with -protected) + testFail("", "-keypasswd -protected -new password " + + "-keystore x.jks -storetype JKS"); + assertTrue(ex.indexOf("if -protected is specified, then") != -1); + remove("x.jks"); + } + + void i18nPKCS11Test() throws Exception { + //PKCS#11 tests + + // 1. sccs edit cert8.db key3.db + //Runtime.getRuntime().exec("/usr/bin/sccs edit cert8.db key3.db"); + testOK("", p11Arg + ("-storepass test12 -genkey -alias genkey" + + " -dname cn=genkey -keysize 512 -keyalg rsa")); + testOK("", p11Arg + "-storepass test12 -list"); + testOK("", p11Arg + "-storepass test12 -list -alias genkey"); + testOK("", p11Arg + + "-storepass test12 -certreq -alias genkey -file genkey.certreq"); + testOK("", p11Arg + + "-storepass test12 -export -alias genkey -file genkey.cert"); + testOK("", "-printcert -file genkey.cert"); + testOK("", p11Arg + + "-storepass test12 -selfcert -alias genkey -dname cn=selfCert"); + testOK("", p11Arg + + "-storepass test12 -list -alias genkey -v"); + assertTrue(out.indexOf("Owner: CN=selfCert") != -1); + //(check that cert subject DN is [cn=selfCert]) + testOK("", p11Arg + "-storepass test12 -delete -alias genkey"); + testOK("", p11Arg + "-storepass test12 -list"); + assertTrue(out.indexOf("Your keystore contains 0 entries") != -1); + //(check for empty database listing) + //Runtime.getRuntime().exec("/usr/bin/sccs unedit cert8.db key3.db"); + remove("genkey.cert"); + remove("genkey.certreq"); + // 12. sccs unedit cert8.db key3.db + } + + // tesing new option -srcProviderName + void sszzTest() throws Exception { + testAnyway("", NSS_P11_ARG+"-delete -alias nss -storepass test12"); + testAnyway("", NZZ_P11_ARG+"-delete -alias nss -storepass test12"); + testOK("", NSS_P11_ARG+"-genkeypair -dname CN=NSS " + + "-alias nss -storepass test12"); + testOK("", NSS_SRC_P11_ARG + NZZ_P11_ARG + + "-importkeystore -srcstorepass test12 -deststorepass test12"); + testAnyway("", NSS_P11_ARG+"-delete -alias nss -storepass test12"); + testAnyway("", NZZ_P11_ARG+"-delete -alias nss -storepass test12"); + } + + public static void main(String[] args) throws Exception { + Locale reservedLocale = Locale.getDefault(); + try { + // first test if HumanInputStream really acts like a human being + HumanInputStream.test(); + KeyToolTest t = new KeyToolTest(); + + if (System.getProperty("file") != null) { + t.sqeTest(); + t.testAll(); + t.i18nTest(); + t.v3extTest("RSA"); + t.v3extTest("DSA"); + boolean testEC = true; + try { + KeyPairGenerator.getInstance("EC"); + } catch (NoSuchAlgorithmException nae) { + testEC = false; + } + if (testEC) t.v3extTest("EC"); + } + + if (System.getProperty("nss") != null) { + t.srcP11Arg = NSS_SRC_P11_ARG; + t.p11Arg = NSS_P11_ARG; + + t.testPKCS11(); + + // FAIL: + // 1. we still don't have srcprovidername yet + // 2. cannot store privatekey into NSS keystore + // java.security.KeyStoreException: sun.security.pkcs11 + // .wrapper.PKCS11Exception: CKR_TEMPLATE_INCOMPLETE. + //t.testPKCS11ImportKeyStore(); + + t.i18nPKCS11Test(); + //FAIL: currently PKCS11-NSS does not support + // 2 NSS KeyStores to be loaded at the same time + //t.sszzTest(); + } + + if (System.getProperty("solaris") != null) { + // For Solaris Cryptography Framework + t.srcP11Arg = SUN_SRC_P11_ARG; + t.p11Arg = SUN_P11_ARG; + t.testPKCS11(); + t.testPKCS11ImportKeyStore(); + t.i18nPKCS11Test(); + } + + System.out.println("Test pass!!!"); + } finally { + // restore the reserved locale + Locale.setDefault(reservedLocale); + } + } +} + +class TestException extends Exception { + public TestException(String e) { + super(e); + } +} + +/** + * HumanInputStream tries to act like a human sitting in front of a computer + * terminal typing on the keyboard while the keytool program is running. + * + * keytool has called InputStream.read() and BufferedReader.readLine() in + * various places. a call to B.readLine() will try to buffer as much input as + * possible. Thus, a trivial InputStream will find it impossible to feed + * anything to I.read() after a B.readLine() call. + * + * This is why i create HumanInputStream, which will only send a single line + * to B.readLine(), no more, no less, and the next I.read() can have a chance + * to read the exact character right after "\n". + * + * I don't know why HumanInputStream works. + */ +class HumanInputStream extends InputStream { + byte[] src; + int pos; + int length; + boolean inLine; + int stopIt; + + public HumanInputStream(String input) { + src = input.getBytes(); + pos = 0; + length = src.length; + stopIt = 0; + inLine = false; + } + + // the trick: when called through read(byte[], int, int), + // return -1 twice after "\n" + + @Override public int read() throws IOException { + int re; + if(pos < length) { + re = src[pos]; + if(inLine) { + if(stopIt > 0) { + stopIt--; + re = -1; + } else { + if(re == '\n') { + stopIt = 2; + } + pos++; + } + } else { + pos++; + } + } else { + re = -1;//throw new IOException("NO MORE TO READ"); + } + //if (re < 32) System.err.printf("[%02d]", re); + //else System.err.printf("[%c]", (char)re); + return re; + } + @Override public int read(byte[] buffer, int offset, int len) { + inLine = true; + try { + int re = super.read(buffer, offset, len); + return re; + } catch(Exception e) { + throw new RuntimeException("HumanInputStream error"); + } finally { + inLine = false; + } + } + @Override public int available() { + if(pos < length) return 1; + return 0; + } + + // test part + static void assertTrue(boolean bool) { + if(!bool) + throw new RuntimeException(); + } + + public static void test() throws Exception { + + class Tester { + HumanInputStream is; + BufferedReader reader; + Tester(String s) { + is = new HumanInputStream(s); + reader = new BufferedReader(new InputStreamReader(is)); + } + + // three kinds of test method + // 1. read byte by byte from InputStream + void testStreamReadOnce(int expection) throws Exception { + assertTrue(is.read() == expection); + } + void testStreamReadMany(String expection) throws Exception { + char[] keys = expection.toCharArray(); + for(int i=0; i