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 }