1 /* 2 * Copyright (c) 2008, 2013, 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 import java.io.*; 25 import java.util.*; 26 import java.security.*; 27 import javax.crypto.*; 28 import javax.crypto.spec.*; 29 import javax.xml.bind.DatatypeConverter; 30 31 public class SecretKeysBasic extends PKCS11Test { 32 33 private static final char SEP = File.separatorChar; 34 private static char[] tokenPwd; 35 private static final char[] nssPwd = 36 new char[]{'t', 'e', 's', 't', '1', '2'}; 37 private static final char[] solarisPwd = 38 new char[]{'p', 'i', 'n'}; 39 private static SecretKey sk1; 40 private static SecretKey sk2; 41 private static SecretKey softkey; 42 private static KeyStore ks; 43 private static final String KS_TYPE = "PKCS11"; 44 private static Provider provider; 45 46 public static void main(String[] args) throws Exception { 47 main(new SecretKeysBasic()); 48 } 49 50 public void main(Provider p) throws Exception { 51 this.provider = p; 52 53 // create secret key 54 byte[] keyVal = new byte[16]; 55 (new SecureRandom()).nextBytes(keyVal); 56 // NSS will throw CKR_HOST_MEMORY if calling C_DecryptInit w/ 57 // (keyVal[0] == 0) 58 if (keyVal[0] == 0) { 59 keyVal[0] = 1; 60 } 61 softkey = new SecretKeySpec(keyVal, "AES"); 62 dumpKey("softkey", softkey); 63 64 KeyGenerator kg = KeyGenerator.getInstance("DESede", provider); 65 sk1 = kg.generateKey(); 66 dumpKey("skey1", sk1); 67 sk2 = kg.generateKey(); 68 dumpKey("skey2", sk2); 69 70 String token = System.getProperty("TOKEN"); 71 72 if (token == null || token.length() == 0) { 73 System.out.println("Error: missing TOKEN system property"); 74 throw new Exception("token arg required"); 75 } 76 77 if ("nss".equals(token)) { 78 tokenPwd = nssPwd; 79 } else if ("solaris".equals(token)) { 80 tokenPwd = solarisPwd; 81 } 82 83 int testnum = 1; 84 doTest(); 85 } 86 87 private static boolean checkSecretKeyEntry(String alias, 88 SecretKey expected, 89 boolean saveBeforeCheck) 90 throws Exception { 91 92 // A bug in NSS 3.12 (Mozilla bug 471665) causes AES key lengths 93 // to be read incorrectly. Checking for improper 16 byte length 94 // in key string. 95 if (isNSS(provider) && expected.getAlgorithm().equals("AES") && 96 (getNSSVersion() >= 3.12 && getNSSVersion() <= 3.122)) { 97 System.out.println("NSS 3.12 bug returns incorrect AES key "+ 98 "length breaking key storage. Aborting..."); 99 return true; 100 } 101 102 if (saveBeforeCheck) { 103 ks.setKeyEntry(alias, expected, null, null); 104 } 105 SecretKey result = (SecretKey) (ks.getKey(alias, null)); 106 String keyEncFormat = result.getFormat(); 107 if (keyEncFormat == null) { 108 // sensitive or un-extractable keys - verify by encrypt/decrypt 109 byte[] data = new byte[64]; 110 Cipher c = 111 Cipher.getInstance(result.getAlgorithm() + "/CBC/NoPadding", 112 provider); 113 c.init(Cipher.ENCRYPT_MODE, expected); 114 byte[] encOut = c.doFinal(data); 115 c.init(Cipher.DECRYPT_MODE, result, c.getParameters()); 116 byte[] decOut = c.doFinal(encOut); 117 if (!Arrays.equals(data, decOut)) { 118 return false; 119 } 120 } else if (keyEncFormat.toUpperCase().equals("RAW")) { 121 if (!Arrays.equals(result.getEncoded(), expected.getEncoded())) { 122 dumpKey("\texpected:", expected); 123 dumpKey("\treturns:", result); 124 return false; 125 } 126 } 127 return true; 128 } 129 130 private static void dumpKey(String info, SecretKey key) { 131 System.out.println(info + "> " + key); 132 System.out.println("\tALGO=" + key.getAlgorithm()); 133 if (key.getFormat() != null) { 134 System.out.println("\t[" + key.getFormat() + "] VALUE=" + 135 DatatypeConverter.printHexBinary(key.getEncoded())); 136 } else { 137 System.out.println("\tVALUE=n/a"); 138 } 139 } 140 141 private static void doTest() throws Exception { 142 if (ks == null) { 143 ks = KeyStore.getInstance(KS_TYPE, provider); 144 ks.load(null, tokenPwd); 145 } 146 147 System.out.println("Number of entries: " + ks.size()); 148 if (ks.size() != 0) { 149 System.out.println("Deleting entries under aliases: "); 150 for (Enumeration<String> aliases = ks.aliases(); 151 aliases.hasMoreElements();) { 152 String alias = aliases.nextElement(); 153 System.out.println("\t" + alias); 154 ks.deleteEntry(alias); 155 } 156 } 157 158 String alias = "testSKey"; 159 160 boolean testResult = checkSecretKeyEntry(alias, softkey, true); 161 if (!testResult) { 162 System.out.println("FAILURE: setKey() w/ softSecretKey failed"); 163 } 164 165 if (!checkSecretKeyEntry(alias, sk1, true)) { 166 testResult = false; 167 System.out.println("FAILURE: setKey() w/ skey1 failed"); 168 } 169 if (!checkSecretKeyEntry(alias, sk2, true)) { 170 testResult = false; 171 System.out.println("FAILURE: setKey() w/ skey2 failed"); 172 } 173 174 ks.store(null); 175 System.out.println("Reloading keystore..."); 176 177 ks.load(null, "whatever".toCharArray()); 178 if (ks.size() != 1) { 179 System.out.println("FAILURE: reload#1 ks.size() != 1"); 180 } 181 if (!checkSecretKeyEntry(alias, sk2, false)) { 182 testResult = false; 183 System.out.println("FAILURE: reload#1 ks entry check failed"); 184 } 185 186 ks.deleteEntry(alias); 187 ks.store(null); 188 189 System.out.println("Reloading keystore..."); 190 ks.load(null, "whatever".toCharArray()); 191 if (ks.size() != 0) { 192 testResult = false; 193 System.out.println("FAILURE: reload#2 ks.size() != 0"); 194 } 195 if (!testResult) { 196 throw new Exception("One or more test failed!"); 197 } 198 } 199 }