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