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