1 /* 2 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 6414980 27 * @summary Test that the PKCS#11 KeyStore handles RSA, DSA, and EC keys 28 * @author Andreas Sterbenz 29 * @library .. 30 * @run main/othervm AddPrivateKey 31 * @key randomness 32 */ 33 34 import java.io.*; 35 import java.util.*; 36 37 import java.security.*; 38 import java.security.KeyStore.*; 39 import java.security.cert.*; 40 41 // this test is currently only run for the NSS KeyStore provider, but it 42 // is really a generic KeyStore test so it should be modified to run for 43 // all providers. 44 public class AddPrivateKey extends SecmodTest { 45 46 public static void main(String[] args) throws Exception { 47 if (initSecmod() == false) { 48 return; 49 } 50 51 String configName = BASE + SEP + "nss.cfg"; 52 Provider p = getSunPKCS11(configName); 53 54 boolean supportsEC = (p.getService("KeyFactory", "EC") != null); 55 56 System.out.println(p); 57 System.out.println(); 58 Security.addProvider(p); 59 60 KeyStore ks = KeyStore.getInstance("PKCS11", p); 61 ks.load(null, password); 62 for (String alias : aliases(ks)) { 63 System.out.println("Deleting: " + alias); 64 ks.deleteEntry(alias); 65 } 66 67 KeyStore jks = KeyStore.getInstance("JKS"); 68 InputStream in = new FileInputStream(new File(BASE, "keystore.jks")); 69 char[] jkspass = "passphrase".toCharArray(); 70 jks.load(in, jkspass); 71 List<PrivateKeyEntry> entries = new ArrayList<PrivateKeyEntry>(); 72 for (String alias : Collections.list(jks.aliases())) { 73 if (jks.entryInstanceOf(alias, PrivateKeyEntry.class)) { 74 PrivateKeyEntry entry = (PrivateKeyEntry)jks.getEntry(alias, new PasswordProtection(jkspass)); 75 String algorithm = entry.getPrivateKey().getAlgorithm(); 76 System.out.println("-Entry " + alias + " (" + algorithm + ")"); 77 if ((supportsEC == false) && algorithm.equals("EC")) { 78 System.out.println("EC not supported by provider, skipping"); 79 continue; 80 } 81 if ((supportsEC == false) && algorithm.equals("DSA")) { 82 System.out.println("Provider does not appear to have CKA_NETSCAPE_DB fix, skipping"); 83 continue; 84 } 85 test(p, entry); 86 } // else ignore 87 } 88 System.out.println("OK"); 89 } 90 91 private static List<String> aliases(KeyStore ks) throws KeyStoreException { 92 return Collections.list(ks.aliases()); 93 } 94 95 private final static String ALIAS1 = "entry1"; 96 private final static String ALIAS2 = "entry2"; 97 private final static String ALIAS3 = "entry3"; 98 99 private static void test(Provider p, PrivateKeyEntry entry) throws Exception { 100 PrivateKey key = entry.getPrivateKey(); 101 X509Certificate[] chain = (X509Certificate[])entry.getCertificateChain(); 102 PublicKey publicKey = chain[0].getPublicKey(); 103 System.out.println(toString(key)); 104 sign(p, key, publicKey); 105 106 KeyStore ks = KeyStore.getInstance("PKCS11", p); 107 ks.load(null, null); 108 if (ks.size() != 0) { 109 throw new Exception("KeyStore not empty"); 110 } 111 List<String> aliases; 112 113 // test 1: add entry 114 ks.setKeyEntry(ALIAS1, key, null, chain); 115 aliases = aliases(ks); 116 if (aliases.size() != 1) { 117 throw new Exception("size not 1: " + aliases); 118 } 119 if (aliases.get(0).equals(ALIAS1) == false) { 120 throw new Exception("alias mismatch: " + aliases); 121 } 122 123 PrivateKey key2 = (PrivateKey)ks.getKey(ALIAS1, null); 124 System.out.println(toString(key2)); 125 X509Certificate[] chain2 = (X509Certificate[])ks.getCertificateChain(ALIAS1); 126 // NSS makes token keys always sensitive, skip this check 127 // if (key.equals(key2) == false) { 128 // throw new Exception("key mismatch"); 129 // } 130 if (Arrays.equals(chain, chain2) == false) { 131 throw new Exception("chain mismatch"); 132 } 133 sign(p, key2, publicKey); 134 135 ks.deleteEntry(ALIAS1); 136 if (ks.size() != 0) { 137 throw new Exception("KeyStore not empty"); 138 } 139 140 // test 2: translate to session object, then add entry 141 KeyFactory kf = KeyFactory.getInstance(key.getAlgorithm(), p); 142 PrivateKey key3 = (PrivateKey)kf.translateKey(key); 143 System.out.println(toString(key3)); 144 sign(p, key3, publicKey); 145 146 ks.setKeyEntry(ALIAS2, key3, null, chain); 147 aliases = aliases(ks); 148 if (aliases.size() != 1) { 149 throw new Exception("size not 1"); 150 } 151 if (aliases.get(0).equals(ALIAS2) == false) { 152 throw new Exception("alias mismatch: " + aliases); 153 } 154 155 PrivateKey key4 = (PrivateKey)ks.getKey(ALIAS2, null); 156 System.out.println(toString(key4)); 157 X509Certificate[] chain4 = (X509Certificate[])ks.getCertificateChain(ALIAS2); 158 if (Arrays.equals(chain, chain4) == false) { 159 throw new Exception("chain mismatch"); 160 } 161 sign(p, key4, publicKey); 162 163 // test 3: change alias 164 ks.setKeyEntry(ALIAS3, key3, null, chain); 165 aliases = aliases(ks); 166 if (aliases.size() != 1) { 167 throw new Exception("size not 1"); 168 } 169 if (aliases.get(0).equals(ALIAS3) == false) { 170 throw new Exception("alias mismatch: " + aliases); 171 } 172 173 PrivateKey key5 = (PrivateKey)ks.getKey(ALIAS3, null); 174 System.out.println(toString(key5)); 175 X509Certificate[] chain5 = (X509Certificate[])ks.getCertificateChain(ALIAS3); 176 if (Arrays.equals(chain, chain5) == false) { 177 throw new Exception("chain mismatch"); 178 } 179 sign(p, key5, publicKey); 180 181 ks.deleteEntry(ALIAS3); 182 if (ks.size() != 0) { 183 throw new Exception("KeyStore not empty"); 184 } 185 186 System.out.println("OK"); 187 } 188 189 private final static byte[] DATA = new byte[4096]; 190 191 static { 192 Random random = new Random(); 193 random.nextBytes(DATA); 194 } 195 196 private static void sign(Provider p, PrivateKey privateKey, PublicKey publicKey) throws Exception { 197 String keyAlg = privateKey.getAlgorithm(); 198 String alg; 199 if (keyAlg.equals("RSA")) { 200 alg = "SHA1withRSA"; 201 } else if (keyAlg.equals("DSA")) { 202 alg = "SHA1withDSA"; 203 } else if (keyAlg.equals("EC")) { 204 alg = "SHA1withECDSA"; 205 } else { 206 throw new Exception("Unknown algorithm " + keyAlg); 207 } 208 Signature s = Signature.getInstance(alg, p); 209 s.initSign(privateKey); 210 s.update(DATA); 211 byte[] sig = s.sign(); 212 213 s.initVerify(publicKey); 214 s.update(DATA); 215 if (s.verify(sig) == false) { 216 throw new Exception("Signature did not verify"); 217 } 218 } 219 220 private final static int MAX_LINE = 85; 221 222 private static String toString(Object o) { 223 String s = String.valueOf(o).split("\n")[0]; 224 return (s.length() <= MAX_LINE) ? s : s.substring(0, MAX_LINE); 225 } 226 227 }