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  */
  32 
  33 import java.io.*;
  34 import java.util.*;
  35 
  36 import java.security.*;
  37 import java.security.KeyStore.*;
  38 import java.security.cert.*;
  39 
  40 // this test is currently only run for the NSS KeyStore provider, but it
  41 // is really a generic KeyStore test so it should be modified to run for
  42 // all providers.
  43 public class AddPrivateKey extends SecmodTest {
  44 
  45     public static void main(String[] args) throws Exception {
  46         if (initSecmod() == false) {
  47             return;
  48         }
  49 
  50         String configName = BASE + SEP + "nss.cfg";
  51         Provider p = getSunPKCS11(configName);
  52 
  53         boolean supportsEC = (p.getService("KeyFactory", "EC") != null);
  54 
  55         System.out.println(p);
  56         System.out.println();
  57         Security.addProvider(p);
  58 
  59         KeyStore ks = KeyStore.getInstance("PKCS11", p);
  60         ks.load(null, password);
  61         for (String alias : aliases(ks)) {
  62             System.out.println("Deleting: " + alias);
  63             ks.deleteEntry(alias);
  64         }
  65 
  66         KeyStore jks = KeyStore.getInstance("JKS");
  67         InputStream in = new FileInputStream(new File(BASE, "keystore.jks"));
  68         char[] jkspass = "passphrase".toCharArray();
  69         jks.load(in, jkspass);
  70         List<PrivateKeyEntry> entries = new ArrayList<PrivateKeyEntry>();
  71         for (String alias : Collections.list(jks.aliases())) {
  72             if (jks.entryInstanceOf(alias, PrivateKeyEntry.class)) {
  73                 PrivateKeyEntry entry = (PrivateKeyEntry)jks.getEntry(alias, new PasswordProtection(jkspass));
  74                 String algorithm = entry.getPrivateKey().getAlgorithm();
  75                 System.out.println("-Entry " + alias + " (" + algorithm + ")");
  76                 if ((supportsEC == false) && algorithm.equals("EC")) {
  77                     System.out.println("EC not supported by provider, skipping");
  78                     continue;
  79                 }
  80                 if ((supportsEC == false) && algorithm.equals("DSA")) {
  81                     System.out.println("Provider does not appear to have CKA_NETSCAPE_DB fix, skipping");
  82                     continue;
  83                 }
  84                 test(p, entry);
  85             } // else ignore
  86         }
  87         System.out.println("OK");
  88     }
  89 
  90     private static List<String> aliases(KeyStore ks) throws KeyStoreException {
  91         return Collections.list(ks.aliases());
  92     }
  93 
  94     private final static String ALIAS1 = "entry1";
  95     private final static String ALIAS2 = "entry2";
  96     private final static String ALIAS3 = "entry3";
  97 
  98     private static void test(Provider p, PrivateKeyEntry entry) throws Exception {
  99         PrivateKey key = entry.getPrivateKey();
 100         X509Certificate[] chain = (X509Certificate[])entry.getCertificateChain();
 101         PublicKey publicKey = chain[0].getPublicKey();
 102         System.out.println(toString(key));
 103         sign(p, key, publicKey);
 104 
 105         KeyStore ks = KeyStore.getInstance("PKCS11", p);
 106         ks.load(null, null);
 107         if (ks.size() != 0) {
 108             throw new Exception("KeyStore not empty");
 109         }
 110         List<String> aliases;
 111 
 112         // test 1: add entry
 113         ks.setKeyEntry(ALIAS1, key, null, chain);
 114         aliases = aliases(ks);
 115         if (aliases.size() != 1) {
 116             throw new Exception("size not 1: " + aliases);
 117         }
 118         if (aliases.get(0).equals(ALIAS1) == false) {
 119             throw new Exception("alias mismatch: " + aliases);
 120         }
 121 
 122         PrivateKey key2 = (PrivateKey)ks.getKey(ALIAS1, null);
 123         System.out.println(toString(key2));
 124         X509Certificate[] chain2 = (X509Certificate[])ks.getCertificateChain(ALIAS1);
 125         // NSS makes token keys always sensitive, skip this check
 126 //      if (key.equals(key2) == false) {
 127 //          throw new Exception("key mismatch");
 128 //      }
 129         if (Arrays.equals(chain, chain2) == false) {
 130             throw new Exception("chain mismatch");
 131         }
 132         sign(p, key2, publicKey);
 133 
 134         ks.deleteEntry(ALIAS1);
 135         if (ks.size() != 0) {
 136             throw new Exception("KeyStore not empty");
 137         }
 138 
 139         // test 2: translate to session object, then add entry
 140         KeyFactory kf = KeyFactory.getInstance(key.getAlgorithm(), p);
 141         PrivateKey key3 = (PrivateKey)kf.translateKey(key);
 142         System.out.println(toString(key3));
 143         sign(p, key3, publicKey);
 144 
 145         ks.setKeyEntry(ALIAS2, key3, null, chain);
 146         aliases = aliases(ks);
 147         if (aliases.size() != 1) {
 148             throw new Exception("size not 1");
 149         }
 150         if (aliases.get(0).equals(ALIAS2) == false) {
 151             throw new Exception("alias mismatch: " + aliases);
 152         }
 153 
 154         PrivateKey key4 = (PrivateKey)ks.getKey(ALIAS2, null);
 155         System.out.println(toString(key4));
 156         X509Certificate[] chain4 = (X509Certificate[])ks.getCertificateChain(ALIAS2);
 157         if (Arrays.equals(chain, chain4) == false) {
 158             throw new Exception("chain mismatch");
 159         }
 160         sign(p, key4, publicKey);
 161 
 162         // test 3: change alias
 163         ks.setKeyEntry(ALIAS3, key3, null, chain);
 164         aliases = aliases(ks);
 165         if (aliases.size() != 1) {
 166             throw new Exception("size not 1");
 167         }
 168         if (aliases.get(0).equals(ALIAS3) == false) {
 169             throw new Exception("alias mismatch: " + aliases);
 170         }
 171 
 172         PrivateKey key5 = (PrivateKey)ks.getKey(ALIAS3, null);
 173         System.out.println(toString(key5));
 174         X509Certificate[] chain5 = (X509Certificate[])ks.getCertificateChain(ALIAS3);
 175         if (Arrays.equals(chain, chain5) == false) {
 176             throw new Exception("chain mismatch");
 177         }
 178         sign(p, key5, publicKey);
 179 
 180         ks.deleteEntry(ALIAS3);
 181         if (ks.size() != 0) {
 182             throw new Exception("KeyStore not empty");
 183         }
 184 
 185         System.out.println("OK");
 186     }
 187 
 188     private final static byte[] DATA = new byte[4096];
 189 
 190     static {
 191         Random random = new Random();
 192         random.nextBytes(DATA);
 193     }
 194 
 195     private static void sign(Provider p, PrivateKey privateKey, PublicKey publicKey) throws Exception {
 196         String keyAlg = privateKey.getAlgorithm();
 197         String alg;
 198         if (keyAlg.equals("RSA")) {
 199             alg = "SHA1withRSA";
 200         } else if (keyAlg.equals("DSA")) {
 201             alg = "SHA1withDSA";
 202         } else if (keyAlg.equals("EC")) {
 203             alg = "SHA1withECDSA";
 204         } else {
 205             throw new Exception("Unknown algorithm " + keyAlg);
 206         }
 207         Signature s = Signature.getInstance(alg, p);
 208         s.initSign(privateKey);
 209         s.update(DATA);
 210         byte[] sig = s.sign();
 211 
 212         s.initVerify(publicKey);
 213         s.update(DATA);
 214         if (s.verify(sig) == false) {
 215             throw new Exception("Signature did not verify");
 216         }
 217     }
 218 
 219     private final static int MAX_LINE = 85;
 220 
 221     private static String toString(Object o) {
 222         String s = String.valueOf(o).split("\n")[0];
 223         return (s.length() <= MAX_LINE) ? s : s.substring(0, MAX_LINE);
 224     }
 225 
 226 }