AddPrivateKey.java revision 6073:cea72c2bf071
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
33import java.io.*;
34import java.util.*;
35
36import java.security.*;
37import java.security.KeyStore.*;
38import 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.
43public 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}
227