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.token
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 }