author | alanb |
Fri, 07 Apr 2017 08:05:54 +0000 | |
changeset 44545 | 83b611b88ac8 |
parent 43248 | 5e15de85a1a0 |
child 44546 | 10bdbc025c7f |
permissions | -rw-r--r-- |
2 | 1 |
/* |
32634
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
2 |
* Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package sun.security.pkcs11; |
|
27 |
||
28 |
import java.math.BigInteger; |
|
29 |
||
30 |
import java.io.InputStream; |
|
31 |
import java.io.OutputStream; |
|
32 |
import java.io.IOException; |
|
33 |
import java.io.ByteArrayInputStream; |
|
34 |
import java.io.UnsupportedEncodingException; |
|
35 |
||
36 |
import java.util.Arrays; |
|
37 |
import java.util.Collections; |
|
38 |
import java.util.Date; |
|
39 |
import java.util.Enumeration; |
|
40 |
import java.util.ArrayList; |
|
41 |
import java.util.HashSet; |
|
42 |
import java.util.HashMap; |
|
43 |
import java.util.Set; |
|
44 |
||
45 |
import java.security.*; |
|
46 |
import java.security.KeyStore.*; |
|
47 |
||
48 |
import java.security.cert.Certificate; |
|
49 |
import java.security.cert.X509Certificate; |
|
50 |
import java.security.cert.CertificateFactory; |
|
51 |
import java.security.cert.CertificateException; |
|
52 |
||
53 |
import java.security.interfaces.*; |
|
54 |
import java.security.spec.*; |
|
55 |
||
56 |
import javax.crypto.SecretKey; |
|
57 |
import javax.crypto.interfaces.*; |
|
58 |
||
59 |
import javax.security.auth.x500.X500Principal; |
|
60 |
import javax.security.auth.login.LoginException; |
|
61 |
import javax.security.auth.callback.Callback; |
|
62 |
import javax.security.auth.callback.PasswordCallback; |
|
63 |
import javax.security.auth.callback.CallbackHandler; |
|
64 |
import javax.security.auth.callback.UnsupportedCallbackException; |
|
65 |
||
66 |
import sun.security.util.Debug; |
|
67 |
import sun.security.util.DerValue; |
|
17491
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
68 |
import sun.security.util.ECUtil; |
2 | 69 |
|
70 |
import sun.security.pkcs11.Secmod.*; |
|
71 |
import static sun.security.pkcs11.P11Util.*; |
|
72 |
||
73 |
import sun.security.pkcs11.wrapper.*; |
|
74 |
import static sun.security.pkcs11.wrapper.PKCS11Constants.*; |
|
75 |
||
2596 | 76 |
import sun.security.rsa.RSAKeyFactory; |
77 |
||
2 | 78 |
final class P11KeyStore extends KeyStoreSpi { |
79 |
||
80 |
private static final CK_ATTRIBUTE ATTR_CLASS_CERT = |
|
81 |
new CK_ATTRIBUTE(CKA_CLASS, CKO_CERTIFICATE); |
|
82 |
private static final CK_ATTRIBUTE ATTR_CLASS_PKEY = |
|
83 |
new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY); |
|
84 |
private static final CK_ATTRIBUTE ATTR_CLASS_SKEY = |
|
85 |
new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); |
|
86 |
||
87 |
private static final CK_ATTRIBUTE ATTR_X509_CERT_TYPE = |
|
88 |
new CK_ATTRIBUTE(CKA_CERTIFICATE_TYPE, CKC_X_509); |
|
89 |
||
90 |
private static final CK_ATTRIBUTE ATTR_TOKEN_TRUE = |
|
91 |
new CK_ATTRIBUTE(CKA_TOKEN, true); |
|
92 |
||
93 |
// XXX for testing purposes only |
|
94 |
// - NSS doesn't support persistent secret keys |
|
95 |
// (key type gets mangled if secret key is a token key) |
|
96 |
// - if debug is turned on, then this is set to false |
|
97 |
private static CK_ATTRIBUTE ATTR_SKEY_TOKEN_TRUE = ATTR_TOKEN_TRUE; |
|
98 |
||
99 |
private static final CK_ATTRIBUTE ATTR_TRUSTED_TRUE = |
|
100 |
new CK_ATTRIBUTE(CKA_TRUSTED, true); |
|
101 |
private static final CK_ATTRIBUTE ATTR_PRIVATE_TRUE = |
|
102 |
new CK_ATTRIBUTE(CKA_PRIVATE, true); |
|
103 |
||
104 |
private static final long NO_HANDLE = -1; |
|
105 |
private static final long FINDOBJECTS_MAX = 100; |
|
106 |
private static final String ALIAS_SEP = "/"; |
|
107 |
||
108 |
private static final boolean NSS_TEST = false; |
|
109 |
private static final Debug debug = |
|
110 |
Debug.getInstance("pkcs11keystore"); |
|
111 |
private static boolean CKA_TRUSTED_SUPPORTED = true; |
|
112 |
||
113 |
private final Token token; |
|
114 |
||
115 |
// If multiple certs are found to share the same CKA_LABEL |
|
116 |
// at load time (NSS-style keystore), then the keystore is read |
|
117 |
// and the unique keystore aliases are mapped to the entries. |
|
118 |
// However, write capabilities are disabled. |
|
119 |
private boolean writeDisabled = false; |
|
120 |
||
121 |
// Map of unique keystore aliases to entries in the token |
|
122 |
private HashMap<String, AliasInfo> aliasMap; |
|
123 |
||
124 |
// whether to use NSS Secmod info for trust attributes |
|
125 |
private final boolean useSecmodTrust; |
|
126 |
||
127 |
// if useSecmodTrust == true, which type of trust we are interested in |
|
128 |
private Secmod.TrustType nssTrustType; |
|
129 |
||
130 |
/** |
|
131 |
* The underlying token may contain multiple certs belonging to the |
|
132 |
* same "personality" (for example, a signing cert and encryption cert), |
|
133 |
* all sharing the same CKA_LABEL. These must be resolved |
|
134 |
* into unique keystore aliases. |
|
135 |
* |
|
136 |
* In addition, private keys and certs may not have a CKA_LABEL. |
|
137 |
* It is assumed that a private key and corresponding certificate |
|
138 |
* share the same CKA_ID, and that the CKA_ID is unique across the token. |
|
139 |
* The CKA_ID may not be human-readable. |
|
140 |
* These pairs must be resolved into unique keystore aliases. |
|
141 |
* |
|
142 |
* Furthermore, secret keys are assumed to have a CKA_LABEL |
|
143 |
* unique across the entire token. |
|
144 |
* |
|
145 |
* When the KeyStore is loaded, instances of this class are |
|
146 |
* created to represent the private keys/secret keys/certs |
|
147 |
* that reside on the token. |
|
148 |
*/ |
|
149 |
private static class AliasInfo { |
|
150 |
||
151 |
// CKA_CLASS - entry type |
|
152 |
private CK_ATTRIBUTE type = null; |
|
153 |
||
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
154 |
// CKA_LABEL of cert and secret key |
2 | 155 |
private String label = null; |
156 |
||
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
157 |
// CKA_ID of the private key/cert pair |
2 | 158 |
private byte[] id = null; |
159 |
||
160 |
// CKA_TRUSTED - true if cert is trusted |
|
161 |
private boolean trusted = false; |
|
162 |
||
163 |
// either end-entity cert or trusted cert depending on 'type' |
|
164 |
private X509Certificate cert = null; |
|
165 |
||
166 |
// chain |
|
31538
0981099a3e54
8130022: Use Java-style array declarations consistently
igerasim
parents:
28059
diff
changeset
|
167 |
private X509Certificate[] chain = null; |
2 | 168 |
|
169 |
// true if CKA_ID for private key and cert match up |
|
170 |
private boolean matched = false; |
|
171 |
||
172 |
// SecretKeyEntry |
|
173 |
public AliasInfo(String label) { |
|
174 |
this.type = ATTR_CLASS_SKEY; |
|
175 |
this.label = label; |
|
176 |
} |
|
177 |
||
178 |
// PrivateKeyEntry |
|
179 |
public AliasInfo(String label, |
|
180 |
byte[] id, |
|
181 |
boolean trusted, |
|
182 |
X509Certificate cert) { |
|
183 |
this.type = ATTR_CLASS_PKEY; |
|
184 |
this.label = label; |
|
185 |
this.id = id; |
|
186 |
this.trusted = trusted; |
|
187 |
this.cert = cert; |
|
188 |
} |
|
189 |
||
190 |
public String toString() { |
|
191 |
StringBuilder sb = new StringBuilder(); |
|
192 |
if (type == ATTR_CLASS_PKEY) { |
|
193 |
sb.append("\ttype=[private key]\n"); |
|
194 |
} else if (type == ATTR_CLASS_SKEY) { |
|
195 |
sb.append("\ttype=[secret key]\n"); |
|
196 |
} else if (type == ATTR_CLASS_CERT) { |
|
197 |
sb.append("\ttype=[trusted cert]\n"); |
|
198 |
} |
|
199 |
sb.append("\tlabel=[" + label + "]\n"); |
|
200 |
if (id == null) { |
|
201 |
sb.append("\tid=[null]\n"); |
|
202 |
} else { |
|
203 |
sb.append("\tid=" + P11KeyStore.getID(id) + "\n"); |
|
204 |
} |
|
205 |
sb.append("\ttrusted=[" + trusted + "]\n"); |
|
206 |
sb.append("\tmatched=[" + matched + "]\n"); |
|
207 |
if (cert == null) { |
|
208 |
sb.append("\tcert=[null]\n"); |
|
209 |
} else { |
|
210 |
sb.append("\tcert=[\tsubject: " + |
|
211 |
cert.getSubjectX500Principal() + |
|
212 |
"\n\t\tissuer: " + |
|
213 |
cert.getIssuerX500Principal() + |
|
214 |
"\n\t\tserialNum: " + |
|
215 |
cert.getSerialNumber().toString() + |
|
216 |
"]"); |
|
217 |
} |
|
218 |
return sb.toString(); |
|
219 |
} |
|
220 |
} |
|
221 |
||
222 |
/** |
|
223 |
* callback handler for passing password to Provider.login method |
|
224 |
*/ |
|
225 |
private static class PasswordCallbackHandler implements CallbackHandler { |
|
226 |
||
227 |
private char[] password; |
|
228 |
||
229 |
private PasswordCallbackHandler(char[] password) { |
|
230 |
if (password != null) { |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
231 |
this.password = password.clone(); |
2 | 232 |
} |
233 |
} |
|
234 |
||
235 |
public void handle(Callback[] callbacks) |
|
236 |
throws IOException, UnsupportedCallbackException { |
|
237 |
if (!(callbacks[0] instanceof PasswordCallback)) { |
|
238 |
throw new UnsupportedCallbackException(callbacks[0]); |
|
239 |
} |
|
240 |
PasswordCallback pc = (PasswordCallback)callbacks[0]; |
|
241 |
pc.setPassword(password); // this clones the password if not null |
|
242 |
} |
|
243 |
||
244 |
protected void finalize() throws Throwable { |
|
245 |
if (password != null) { |
|
246 |
Arrays.fill(password, ' '); |
|
247 |
} |
|
248 |
super.finalize(); |
|
249 |
} |
|
250 |
} |
|
251 |
||
252 |
/** |
|
253 |
* getTokenObject return value. |
|
254 |
* |
|
255 |
* if object is not found, type is set to null. |
|
256 |
* otherwise, type is set to the requested type. |
|
257 |
*/ |
|
258 |
private static class THandle { |
|
259 |
private final long handle; // token object handle |
|
260 |
private final CK_ATTRIBUTE type; // CKA_CLASS |
|
261 |
||
262 |
private THandle(long handle, CK_ATTRIBUTE type) { |
|
263 |
this.handle = handle; |
|
264 |
this.type = type; |
|
265 |
} |
|
266 |
} |
|
267 |
||
268 |
P11KeyStore(Token token) { |
|
269 |
this.token = token; |
|
270 |
this.useSecmodTrust = token.provider.nssUseSecmodTrust; |
|
271 |
} |
|
272 |
||
273 |
/** |
|
274 |
* Returns the key associated with the given alias. |
|
275 |
* The key must have been associated with |
|
276 |
* the alias by a call to <code>setKeyEntry</code>, |
|
277 |
* or by a call to <code>setEntry</code> with a |
|
278 |
* <code>PrivateKeyEntry</code> or <code>SecretKeyEntry</code>. |
|
279 |
* |
|
280 |
* @param alias the alias name |
|
281 |
* @param password the password, which must be <code>null</code> |
|
282 |
* |
|
283 |
* @return the requested key, or null if the given alias does not exist |
|
284 |
* or does not identify a key-related entry. |
|
285 |
* |
|
286 |
* @exception NoSuchAlgorithmException if the algorithm for recovering the |
|
287 |
* key cannot be found |
|
288 |
* @exception UnrecoverableKeyException if the key cannot be recovered |
|
289 |
*/ |
|
290 |
public synchronized Key engineGetKey(String alias, char[] password) |
|
291 |
throws NoSuchAlgorithmException, UnrecoverableKeyException { |
|
292 |
||
293 |
token.ensureValid(); |
|
294 |
if (password != null && !token.config.getKeyStoreCompatibilityMode()) { |
|
295 |
throw new NoSuchAlgorithmException("password must be null"); |
|
296 |
} |
|
297 |
||
298 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
299 |
if (aliasInfo == null || aliasInfo.type == ATTR_CLASS_CERT) { |
|
300 |
return null; |
|
301 |
} |
|
302 |
||
303 |
Session session = null; |
|
304 |
try { |
|
305 |
session = token.getOpSession(); |
|
306 |
||
307 |
if (aliasInfo.type == ATTR_CLASS_PKEY) { |
|
308 |
THandle h = getTokenObject(session, |
|
309 |
aliasInfo.type, |
|
310 |
aliasInfo.id, |
|
311 |
null); |
|
312 |
if (h.type == ATTR_CLASS_PKEY) { |
|
313 |
return loadPkey(session, h.handle); |
|
314 |
} |
|
315 |
} else { |
|
316 |
THandle h = getTokenObject(session, |
|
317 |
ATTR_CLASS_SKEY, |
|
318 |
null, |
|
319 |
alias); |
|
320 |
if (h.type == ATTR_CLASS_SKEY) { |
|
321 |
return loadSkey(session, h.handle); |
|
322 |
} |
|
323 |
} |
|
324 |
||
325 |
// did not find anything |
|
326 |
return null; |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
327 |
} catch (PKCS11Exception | KeyStoreException e) { |
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
328 |
throw new ProviderException(e); |
2 | 329 |
} finally { |
330 |
token.releaseSession(session); |
|
331 |
} |
|
332 |
} |
|
333 |
||
334 |
/** |
|
335 |
* Returns the certificate chain associated with the given alias. |
|
336 |
* The certificate chain must have been associated with the alias |
|
337 |
* by a call to <code>setKeyEntry</code>, |
|
338 |
* or by a call to <code>setEntry</code> with a |
|
339 |
* <code>PrivateKeyEntry</code>. |
|
340 |
* |
|
341 |
* @param alias the alias name |
|
342 |
* |
|
343 |
* @return the certificate chain (ordered with the user's certificate first |
|
344 |
* and the root certificate authority last), or null if the given alias |
|
345 |
* does not exist or does not contain a certificate chain |
|
346 |
*/ |
|
347 |
public synchronized Certificate[] engineGetCertificateChain(String alias) { |
|
348 |
||
349 |
token.ensureValid(); |
|
350 |
||
351 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
352 |
if (aliasInfo == null || aliasInfo.type != ATTR_CLASS_PKEY) { |
|
353 |
return null; |
|
354 |
} |
|
355 |
return aliasInfo.chain; |
|
356 |
} |
|
357 |
||
358 |
/** |
|
359 |
* Returns the certificate associated with the given alias. |
|
360 |
* |
|
361 |
* <p> If the given alias name identifies an entry |
|
362 |
* created by a call to <code>setCertificateEntry</code>, |
|
363 |
* or created by a call to <code>setEntry</code> with a |
|
364 |
* <code>TrustedCertificateEntry</code>, |
|
365 |
* then the trusted certificate contained in that entry is returned. |
|
366 |
* |
|
367 |
* <p> If the given alias name identifies an entry |
|
368 |
* created by a call to <code>setKeyEntry</code>, |
|
369 |
* or created by a call to <code>setEntry</code> with a |
|
370 |
* <code>PrivateKeyEntry</code>, |
|
371 |
* then the first element of the certificate chain in that entry |
|
372 |
* (if a chain exists) is returned. |
|
373 |
* |
|
374 |
* @param alias the alias name |
|
375 |
* |
|
376 |
* @return the certificate, or null if the given alias does not exist or |
|
377 |
* does not contain a certificate. |
|
378 |
*/ |
|
379 |
public synchronized Certificate engineGetCertificate(String alias) { |
|
380 |
token.ensureValid(); |
|
381 |
||
382 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
383 |
if (aliasInfo == null) { |
|
384 |
return null; |
|
385 |
} |
|
386 |
return aliasInfo.cert; |
|
387 |
} |
|
388 |
||
389 |
/** |
|
390 |
* Returns the creation date of the entry identified by the given alias. |
|
391 |
* |
|
392 |
* @param alias the alias name |
|
393 |
* |
|
394 |
* @return the creation date of this entry, or null if the given alias does |
|
395 |
* not exist |
|
396 |
*/ |
|
397 |
public Date engineGetCreationDate(String alias) { |
|
398 |
token.ensureValid(); |
|
399 |
throw new ProviderException(new UnsupportedOperationException()); |
|
400 |
} |
|
401 |
||
402 |
/** |
|
403 |
* Assigns the given key to the given alias, protecting it with the given |
|
404 |
* password. |
|
405 |
* |
|
406 |
* <p>If the given key is of type <code>java.security.PrivateKey</code>, |
|
407 |
* it must be accompanied by a certificate chain certifying the |
|
408 |
* corresponding public key. |
|
409 |
* |
|
410 |
* <p>If the given alias already exists, the keystore information |
|
411 |
* associated with it is overridden by the given key (and possibly |
|
412 |
* certificate chain). |
|
413 |
* |
|
414 |
* @param alias the alias name |
|
415 |
* @param key the key to be associated with the alias |
|
416 |
* @param password the password to protect the key |
|
417 |
* @param chain the certificate chain for the corresponding public |
|
418 |
* key (only required if the given key is of type |
|
419 |
* <code>java.security.PrivateKey</code>). |
|
420 |
* |
|
421 |
* @exception KeyStoreException if the given key cannot be protected, or |
|
422 |
* this operation fails for some other reason |
|
423 |
*/ |
|
424 |
public synchronized void engineSetKeyEntry(String alias, Key key, |
|
425 |
char[] password, |
|
426 |
Certificate[] chain) |
|
427 |
throws KeyStoreException { |
|
428 |
||
429 |
token.ensureValid(); |
|
430 |
checkWrite(); |
|
431 |
||
432 |
if (!(key instanceof PrivateKey) && !(key instanceof SecretKey)) { |
|
433 |
throw new KeyStoreException("key must be PrivateKey or SecretKey"); |
|
434 |
} else if (key instanceof PrivateKey && chain == null) { |
|
435 |
throw new KeyStoreException |
|
436 |
("PrivateKey must be accompanied by non-null chain"); |
|
437 |
} else if (key instanceof SecretKey && chain != null) { |
|
438 |
throw new KeyStoreException |
|
439 |
("SecretKey must be accompanied by null chain"); |
|
440 |
} else if (password != null && |
|
441 |
!token.config.getKeyStoreCompatibilityMode()) { |
|
442 |
throw new KeyStoreException("Password must be null"); |
|
443 |
} |
|
444 |
||
445 |
KeyStore.Entry entry = null; |
|
446 |
try { |
|
447 |
if (key instanceof PrivateKey) { |
|
448 |
entry = new KeyStore.PrivateKeyEntry((PrivateKey)key, chain); |
|
449 |
} else if (key instanceof SecretKey) { |
|
450 |
entry = new KeyStore.SecretKeyEntry((SecretKey)key); |
|
451 |
} |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
452 |
} catch (NullPointerException | IllegalArgumentException e) { |
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
453 |
throw new KeyStoreException(e); |
2 | 454 |
} |
455 |
engineSetEntry(alias, entry, new KeyStore.PasswordProtection(password)); |
|
456 |
} |
|
457 |
||
458 |
/** |
|
459 |
* Assigns the given key (that has already been protected) to the given |
|
460 |
* alias. |
|
461 |
* |
|
462 |
* <p>If the protected key is of type |
|
463 |
* <code>java.security.PrivateKey</code>, |
|
464 |
* it must be accompanied by a certificate chain certifying the |
|
465 |
* corresponding public key. |
|
466 |
* |
|
467 |
* <p>If the given alias already exists, the keystore information |
|
468 |
* associated with it is overridden by the given key (and possibly |
|
469 |
* certificate chain). |
|
470 |
* |
|
471 |
* @param alias the alias name |
|
472 |
* @param key the key (in protected format) to be associated with the alias |
|
473 |
* @param chain the certificate chain for the corresponding public |
|
474 |
* key (only useful if the protected key is of type |
|
475 |
* <code>java.security.PrivateKey</code>). |
|
476 |
* |
|
477 |
* @exception KeyStoreException if this operation fails. |
|
478 |
*/ |
|
479 |
public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) |
|
480 |
throws KeyStoreException { |
|
481 |
token.ensureValid(); |
|
482 |
throw new ProviderException(new UnsupportedOperationException()); |
|
483 |
} |
|
484 |
||
485 |
/** |
|
486 |
* Assigns the given certificate to the given alias. |
|
487 |
* |
|
488 |
* <p> If the given alias identifies an existing entry |
|
489 |
* created by a call to <code>setCertificateEntry</code>, |
|
490 |
* or created by a call to <code>setEntry</code> with a |
|
491 |
* <code>TrustedCertificateEntry</code>, |
|
492 |
* the trusted certificate in the existing entry |
|
493 |
* is overridden by the given certificate. |
|
494 |
* |
|
495 |
* @param alias the alias name |
|
496 |
* @param cert the certificate |
|
497 |
* |
|
498 |
* @exception KeyStoreException if the given alias already exists and does |
|
499 |
* not identify an entry containing a trusted certificate, |
|
500 |
* or this operation fails for some other reason. |
|
501 |
*/ |
|
502 |
public synchronized void engineSetCertificateEntry |
|
503 |
(String alias, Certificate cert) throws KeyStoreException { |
|
504 |
||
505 |
token.ensureValid(); |
|
506 |
checkWrite(); |
|
507 |
||
508 |
if (cert == null) { |
|
509 |
throw new KeyStoreException("invalid null certificate"); |
|
510 |
} |
|
511 |
||
512 |
KeyStore.Entry entry = null; |
|
513 |
entry = new KeyStore.TrustedCertificateEntry(cert); |
|
514 |
engineSetEntry(alias, entry, null); |
|
515 |
} |
|
516 |
||
517 |
/** |
|
518 |
* Deletes the entry identified by the given alias from this keystore. |
|
519 |
* |
|
520 |
* @param alias the alias name |
|
521 |
* |
|
522 |
* @exception KeyStoreException if the entry cannot be removed. |
|
523 |
*/ |
|
524 |
public synchronized void engineDeleteEntry(String alias) |
|
525 |
throws KeyStoreException { |
|
526 |
token.ensureValid(); |
|
527 |
||
528 |
if (token.isWriteProtected()) { |
|
529 |
throw new KeyStoreException("token write-protected"); |
|
530 |
} |
|
531 |
checkWrite(); |
|
532 |
deleteEntry(alias); |
|
533 |
} |
|
534 |
||
535 |
/** |
|
536 |
* XXX - not sure whether to keep this |
|
537 |
*/ |
|
538 |
private boolean deleteEntry(String alias) throws KeyStoreException { |
|
539 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
540 |
if (aliasInfo != null) { |
|
541 |
||
542 |
aliasMap.remove(alias); |
|
543 |
||
544 |
try { |
|
545 |
if (aliasInfo.type == ATTR_CLASS_CERT) { |
|
546 |
// trusted certificate entry |
|
547 |
return destroyCert(aliasInfo.id); |
|
548 |
} else if (aliasInfo.type == ATTR_CLASS_PKEY) { |
|
549 |
// private key entry |
|
550 |
return destroyPkey(aliasInfo.id) && |
|
551 |
destroyChain(aliasInfo.id); |
|
552 |
} else if (aliasInfo.type == ATTR_CLASS_SKEY) { |
|
553 |
// secret key entry |
|
554 |
return destroySkey(alias); |
|
555 |
} else { |
|
556 |
throw new KeyStoreException("unexpected entry type"); |
|
557 |
} |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
558 |
} catch (PKCS11Exception | CertificateException e) { |
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
559 |
throw new KeyStoreException(e); |
2 | 560 |
} |
561 |
} |
|
562 |
return false; |
|
563 |
} |
|
564 |
||
565 |
/** |
|
566 |
* Lists all the alias names of this keystore. |
|
567 |
* |
|
568 |
* @return enumeration of the alias names |
|
569 |
*/ |
|
570 |
public synchronized Enumeration<String> engineAliases() { |
|
571 |
token.ensureValid(); |
|
572 |
||
573 |
// don't want returned enumeration to iterate off actual keySet - |
|
574 |
// otherwise applications that iterate and modify the keystore |
|
575 |
// may run into concurrent modification problems |
|
576 |
return Collections.enumeration(new HashSet<String>(aliasMap.keySet())); |
|
577 |
} |
|
578 |
||
579 |
/** |
|
580 |
* Checks if the given alias exists in this keystore. |
|
581 |
* |
|
582 |
* @param alias the alias name |
|
583 |
* |
|
584 |
* @return true if the alias exists, false otherwise |
|
585 |
*/ |
|
586 |
public synchronized boolean engineContainsAlias(String alias) { |
|
587 |
token.ensureValid(); |
|
588 |
return aliasMap.containsKey(alias); |
|
589 |
} |
|
590 |
||
591 |
/** |
|
592 |
* Retrieves the number of entries in this keystore. |
|
593 |
* |
|
594 |
* @return the number of entries in this keystore |
|
595 |
*/ |
|
596 |
public synchronized int engineSize() { |
|
597 |
token.ensureValid(); |
|
598 |
return aliasMap.size(); |
|
599 |
} |
|
600 |
||
601 |
/** |
|
602 |
* Returns true if the entry identified by the given alias |
|
603 |
* was created by a call to <code>setKeyEntry</code>, |
|
604 |
* or created by a call to <code>setEntry</code> with a |
|
605 |
* <code>PrivateKeyEntry</code> or a <code>SecretKeyEntry</code>. |
|
606 |
* |
|
607 |
* @param alias the alias for the keystore entry to be checked |
|
608 |
* |
|
609 |
* @return true if the entry identified by the given alias is a |
|
610 |
* key-related, false otherwise. |
|
611 |
*/ |
|
612 |
public synchronized boolean engineIsKeyEntry(String alias) { |
|
613 |
token.ensureValid(); |
|
614 |
||
615 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
616 |
if (aliasInfo == null || aliasInfo.type == ATTR_CLASS_CERT) { |
|
617 |
return false; |
|
618 |
} |
|
619 |
return true; |
|
620 |
} |
|
621 |
||
622 |
/** |
|
623 |
* Returns true if the entry identified by the given alias |
|
624 |
* was created by a call to <code>setCertificateEntry</code>, |
|
625 |
* or created by a call to <code>setEntry</code> with a |
|
626 |
* <code>TrustedCertificateEntry</code>. |
|
627 |
* |
|
628 |
* @param alias the alias for the keystore entry to be checked |
|
629 |
* |
|
630 |
* @return true if the entry identified by the given alias contains a |
|
631 |
* trusted certificate, false otherwise. |
|
632 |
*/ |
|
633 |
public synchronized boolean engineIsCertificateEntry(String alias) { |
|
634 |
token.ensureValid(); |
|
635 |
||
636 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
637 |
if (aliasInfo == null || aliasInfo.type != ATTR_CLASS_CERT) { |
|
638 |
return false; |
|
639 |
} |
|
640 |
return true; |
|
641 |
} |
|
642 |
||
643 |
/** |
|
644 |
* Returns the (alias) name of the first keystore entry whose certificate |
|
645 |
* matches the given certificate. |
|
646 |
* |
|
647 |
* <p>This method attempts to match the given certificate with each |
|
648 |
* keystore entry. If the entry being considered was |
|
649 |
* created by a call to <code>setCertificateEntry</code>, |
|
650 |
* or created by a call to <code>setEntry</code> with a |
|
651 |
* <code>TrustedCertificateEntry</code>, |
|
652 |
* then the given certificate is compared to that entry's certificate. |
|
653 |
* |
|
654 |
* <p> If the entry being considered was |
|
655 |
* created by a call to <code>setKeyEntry</code>, |
|
656 |
* or created by a call to <code>setEntry</code> with a |
|
657 |
* <code>PrivateKeyEntry</code>, |
|
658 |
* then the given certificate is compared to the first |
|
659 |
* element of that entry's certificate chain. |
|
660 |
* |
|
661 |
* @param cert the certificate to match with. |
|
662 |
* |
|
663 |
* @return the alias name of the first entry with matching certificate, |
|
664 |
* or null if no such entry exists in this keystore. |
|
665 |
*/ |
|
666 |
public synchronized String engineGetCertificateAlias(Certificate cert) { |
|
667 |
token.ensureValid(); |
|
668 |
Enumeration<String> e = engineAliases(); |
|
669 |
while (e.hasMoreElements()) { |
|
670 |
String alias = e.nextElement(); |
|
671 |
Certificate tokenCert = engineGetCertificate(alias); |
|
672 |
if (tokenCert != null && tokenCert.equals(cert)) { |
|
673 |
return alias; |
|
674 |
} |
|
675 |
} |
|
676 |
return null; |
|
677 |
} |
|
678 |
||
679 |
/** |
|
680 |
* engineStore currently is a No-op. |
|
681 |
* Entries are stored to the token during engineSetEntry |
|
682 |
* |
|
683 |
* @param stream this must be <code>null</code> |
|
684 |
* @param password this must be <code>null</code> |
|
685 |
*/ |
|
686 |
public synchronized void engineStore(OutputStream stream, char[] password) |
|
687 |
throws IOException, NoSuchAlgorithmException, CertificateException { |
|
688 |
token.ensureValid(); |
|
689 |
if (stream != null && !token.config.getKeyStoreCompatibilityMode()) { |
|
690 |
throw new IOException("output stream must be null"); |
|
691 |
} |
|
692 |
||
693 |
if (password != null && !token.config.getKeyStoreCompatibilityMode()) { |
|
694 |
throw new IOException("password must be null"); |
|
695 |
} |
|
696 |
} |
|
697 |
||
698 |
/** |
|
699 |
* engineStore currently is a No-op. |
|
700 |
* Entries are stored to the token during engineSetEntry |
|
701 |
* |
|
702 |
* @param param this must be <code>null</code> |
|
703 |
* |
|
704 |
* @exception IllegalArgumentException if the given |
|
705 |
* <code>KeyStore.LoadStoreParameter</code> |
|
706 |
* input is not <code>null</code> |
|
707 |
*/ |
|
708 |
public synchronized void engineStore(KeyStore.LoadStoreParameter param) |
|
709 |
throws IOException, NoSuchAlgorithmException, CertificateException { |
|
710 |
token.ensureValid(); |
|
711 |
if (param != null) { |
|
712 |
throw new IllegalArgumentException |
|
713 |
("LoadStoreParameter must be null"); |
|
714 |
} |
|
715 |
} |
|
716 |
||
717 |
/** |
|
718 |
* Loads the keystore. |
|
719 |
* |
|
720 |
* @param stream the input stream, which must be <code>null</code> |
|
721 |
* @param password the password used to unlock the keystore, |
|
722 |
* or <code>null</code> if the token supports a |
|
723 |
* CKF_PROTECTED_AUTHENTICATION_PATH |
|
724 |
* |
|
725 |
* @exception IOException if the given <code>stream</code> is not |
|
726 |
* <code>null</code>, if the token supports a |
|
727 |
* CKF_PROTECTED_AUTHENTICATION_PATH and a non-null |
|
728 |
* password is given, of if the token login operation failed |
|
729 |
*/ |
|
730 |
public synchronized void engineLoad(InputStream stream, char[] password) |
|
731 |
throws IOException, NoSuchAlgorithmException, CertificateException { |
|
732 |
||
733 |
token.ensureValid(); |
|
734 |
||
735 |
if (NSS_TEST) { |
|
736 |
ATTR_SKEY_TOKEN_TRUE = new CK_ATTRIBUTE(CKA_TOKEN, false); |
|
737 |
} |
|
738 |
||
739 |
if (stream != null && !token.config.getKeyStoreCompatibilityMode()) { |
|
740 |
throw new IOException("input stream must be null"); |
|
741 |
} |
|
742 |
||
743 |
if (useSecmodTrust) { |
|
744 |
nssTrustType = Secmod.TrustType.ALL; |
|
745 |
} |
|
746 |
||
747 |
try { |
|
748 |
if (password == null) { |
|
749 |
login(null); |
|
750 |
} else { |
|
751 |
login(new PasswordCallbackHandler(password)); |
|
752 |
} |
|
32634
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
753 |
} catch(LoginException e) { |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
754 |
Throwable cause = e.getCause(); |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
755 |
if (cause instanceof PKCS11Exception) { |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
756 |
PKCS11Exception pe = (PKCS11Exception) cause; |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
757 |
if (pe.getErrorCode() == CKR_PIN_INCORRECT) { |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
758 |
// if password is wrong, the cause of the IOException |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
759 |
// should be an UnrecoverableKeyException |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
760 |
throw new IOException("load failed", |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
761 |
new UnrecoverableKeyException().initCause(e)); |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
762 |
} |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
763 |
} |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
764 |
throw new IOException("load failed", e); |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
765 |
} |
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
766 |
|
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
767 |
try { |
2 | 768 |
if (mapLabels() == true) { |
769 |
// CKA_LABELs are shared by multiple certs |
|
770 |
writeDisabled = true; |
|
771 |
} |
|
772 |
if (debug != null) { |
|
773 |
dumpTokenMap(); |
|
774 |
} |
|
32634
614f8e5859aa
8134232: KeyStore.load() throws an IOException with a wrong cause in case of wrong password
asmotrak
parents:
31538
diff
changeset
|
775 |
} catch (KeyStoreException | PKCS11Exception e) { |
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
776 |
throw new IOException("load failed", e); |
2 | 777 |
} |
778 |
} |
|
779 |
||
780 |
/** |
|
781 |
* Loads the keystore using the given |
|
782 |
* <code>KeyStore.LoadStoreParameter</code>. |
|
783 |
* |
|
784 |
* <p> The <code>LoadStoreParameter.getProtectionParameter()</code> |
|
785 |
* method is expected to return a <code>KeyStore.PasswordProtection</code> |
|
786 |
* object. The password is retrieved from that object and used |
|
787 |
* to unlock the PKCS#11 token. |
|
788 |
* |
|
789 |
* <p> If the token supports a CKF_PROTECTED_AUTHENTICATION_PATH |
|
790 |
* then the provided password must be <code>null</code>. |
|
791 |
* |
|
792 |
* @param param the <code>KeyStore.LoadStoreParameter</code> |
|
793 |
* |
|
794 |
* @exception IllegalArgumentException if the given |
|
795 |
* <code>KeyStore.LoadStoreParameter</code> is <code>null</code>, |
|
796 |
* or if that parameter returns a <code>null</code> |
|
797 |
* <code>ProtectionParameter</code> object. |
|
798 |
* input is not recognized |
|
799 |
* @exception IOException if the token supports a |
|
800 |
* CKF_PROTECTED_AUTHENTICATION_PATH and the provided password |
|
801 |
* is non-null, or if the token login operation fails |
|
802 |
*/ |
|
803 |
public synchronized void engineLoad(KeyStore.LoadStoreParameter param) |
|
804 |
throws IOException, NoSuchAlgorithmException, |
|
805 |
CertificateException { |
|
806 |
||
807 |
token.ensureValid(); |
|
808 |
||
809 |
if (NSS_TEST) { |
|
810 |
ATTR_SKEY_TOKEN_TRUE = new CK_ATTRIBUTE(CKA_TOKEN, false); |
|
811 |
} |
|
812 |
||
813 |
// if caller wants to pass a NULL password, |
|
814 |
// force it to pass a non-NULL PasswordProtection that returns |
|
815 |
// a NULL password |
|
816 |
||
817 |
if (param == null) { |
|
818 |
throw new IllegalArgumentException |
|
819 |
("invalid null LoadStoreParameter"); |
|
820 |
} |
|
821 |
if (useSecmodTrust) { |
|
822 |
if (param instanceof Secmod.KeyStoreLoadParameter) { |
|
823 |
nssTrustType = ((Secmod.KeyStoreLoadParameter)param).getTrustType(); |
|
824 |
} else { |
|
825 |
nssTrustType = Secmod.TrustType.ALL; |
|
826 |
} |
|
827 |
} |
|
828 |
||
829 |
CallbackHandler handler; |
|
830 |
KeyStore.ProtectionParameter pp = param.getProtectionParameter(); |
|
831 |
if (pp instanceof PasswordProtection) { |
|
832 |
char[] password = ((PasswordProtection)pp).getPassword(); |
|
833 |
if (password == null) { |
|
834 |
handler = null; |
|
835 |
} else { |
|
836 |
handler = new PasswordCallbackHandler(password); |
|
837 |
} |
|
838 |
} else if (pp instanceof CallbackHandlerProtection) { |
|
839 |
handler = ((CallbackHandlerProtection)pp).getCallbackHandler(); |
|
840 |
} else { |
|
841 |
throw new IllegalArgumentException |
|
842 |
("ProtectionParameter must be either " + |
|
843 |
"PasswordProtection or CallbackHandlerProtection"); |
|
844 |
} |
|
845 |
||
846 |
try { |
|
847 |
login(handler); |
|
848 |
if (mapLabels() == true) { |
|
849 |
// CKA_LABELs are shared by multiple certs |
|
850 |
writeDisabled = true; |
|
851 |
} |
|
852 |
if (debug != null) { |
|
853 |
dumpTokenMap(); |
|
854 |
} |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
855 |
} catch (LoginException | KeyStoreException | PKCS11Exception e) { |
2 | 856 |
throw new IOException("load failed", e); |
857 |
} |
|
858 |
} |
|
859 |
||
860 |
private void login(CallbackHandler handler) throws LoginException { |
|
861 |
if ((token.tokenInfo.flags & CKF_PROTECTED_AUTHENTICATION_PATH) == 0) { |
|
862 |
token.provider.login(null, handler); |
|
863 |
} else { |
|
864 |
// token supports protected authentication path |
|
865 |
// (external pin-pad, for example) |
|
866 |
if (handler != null && |
|
867 |
!token.config.getKeyStoreCompatibilityMode()) { |
|
868 |
throw new LoginException("can not specify password if token " + |
|
869 |
"supports protected authentication path"); |
|
870 |
} |
|
871 |
||
872 |
// must rely on application-set or default handler |
|
873 |
// if one is necessary |
|
874 |
token.provider.login(null, null); |
|
875 |
} |
|
876 |
} |
|
877 |
||
878 |
/** |
|
879 |
* Get a <code>KeyStore.Entry</code> for the specified alias |
|
880 |
* |
|
881 |
* @param alias get the <code>KeyStore.Entry</code> for this alias |
|
882 |
* @param protParam this must be <code>null</code> |
|
883 |
* |
|
884 |
* @return the <code>KeyStore.Entry</code> for the specified alias, |
|
885 |
* or <code>null</code> if there is no such entry |
|
886 |
* |
|
887 |
* @exception KeyStoreException if the operation failed |
|
888 |
* @exception NoSuchAlgorithmException if the algorithm for recovering the |
|
889 |
* entry cannot be found |
|
890 |
* @exception UnrecoverableEntryException if the specified |
|
891 |
* <code>protParam</code> were insufficient or invalid |
|
892 |
* |
|
893 |
* @since 1.5 |
|
894 |
*/ |
|
895 |
public synchronized KeyStore.Entry engineGetEntry(String alias, |
|
896 |
KeyStore.ProtectionParameter protParam) |
|
897 |
throws KeyStoreException, NoSuchAlgorithmException, |
|
898 |
UnrecoverableEntryException { |
|
899 |
||
900 |
token.ensureValid(); |
|
901 |
||
902 |
if (protParam != null && |
|
903 |
protParam instanceof KeyStore.PasswordProtection && |
|
904 |
((KeyStore.PasswordProtection)protParam).getPassword() != null && |
|
905 |
!token.config.getKeyStoreCompatibilityMode()) { |
|
906 |
throw new KeyStoreException("ProtectionParameter must be null"); |
|
907 |
} |
|
908 |
||
909 |
AliasInfo aliasInfo = aliasMap.get(alias); |
|
910 |
if (aliasInfo == null) { |
|
911 |
if (debug != null) { |
|
912 |
debug.println("engineGetEntry did not find alias [" + |
|
913 |
alias + |
|
914 |
"] in map"); |
|
915 |
} |
|
916 |
return null; |
|
917 |
} |
|
918 |
||
919 |
Session session = null; |
|
920 |
try { |
|
921 |
session = token.getOpSession(); |
|
922 |
||
923 |
if (aliasInfo.type == ATTR_CLASS_CERT) { |
|
924 |
// trusted certificate entry |
|
925 |
if (debug != null) { |
|
926 |
debug.println("engineGetEntry found trusted cert entry"); |
|
927 |
} |
|
928 |
return new KeyStore.TrustedCertificateEntry(aliasInfo.cert); |
|
929 |
} else if (aliasInfo.type == ATTR_CLASS_SKEY) { |
|
930 |
// secret key entry |
|
931 |
if (debug != null) { |
|
932 |
debug.println("engineGetEntry found secret key entry"); |
|
933 |
} |
|
934 |
||
935 |
THandle h = getTokenObject |
|
936 |
(session, ATTR_CLASS_SKEY, null, aliasInfo.label); |
|
937 |
if (h.type != ATTR_CLASS_SKEY) { |
|
938 |
throw new KeyStoreException |
|
939 |
("expected but could not find secret key"); |
|
940 |
} else { |
|
941 |
SecretKey skey = loadSkey(session, h.handle); |
|
942 |
return new KeyStore.SecretKeyEntry(skey); |
|
943 |
} |
|
944 |
} else { |
|
945 |
// private key entry |
|
946 |
if (debug != null) { |
|
947 |
debug.println("engineGetEntry found private key entry"); |
|
948 |
} |
|
949 |
||
950 |
THandle h = getTokenObject |
|
951 |
(session, ATTR_CLASS_PKEY, aliasInfo.id, null); |
|
952 |
if (h.type != ATTR_CLASS_PKEY) { |
|
953 |
throw new KeyStoreException |
|
954 |
("expected but could not find private key"); |
|
955 |
} else { |
|
956 |
PrivateKey pkey = loadPkey(session, h.handle); |
|
957 |
Certificate[] chain = aliasInfo.chain; |
|
958 |
if ((pkey != null) && (chain != null)) { |
|
959 |
return new KeyStore.PrivateKeyEntry(pkey, chain); |
|
960 |
} else { |
|
961 |
if (debug != null) { |
|
962 |
debug.println |
|
963 |
("engineGetEntry got null cert chain or private key"); |
|
964 |
} |
|
965 |
} |
|
966 |
} |
|
967 |
} |
|
968 |
return null; |
|
969 |
} catch (PKCS11Exception pe) { |
|
970 |
throw new KeyStoreException(pe); |
|
971 |
} finally { |
|
972 |
token.releaseSession(session); |
|
973 |
} |
|
974 |
} |
|
975 |
||
976 |
/** |
|
977 |
* Save a <code>KeyStore.Entry</code> under the specified alias. |
|
978 |
* |
|
979 |
* <p> If an entry already exists for the specified alias, |
|
980 |
* it is overridden. |
|
981 |
* |
|
982 |
* <p> This KeyStore implementation only supports the standard |
|
983 |
* entry types, and only supports X509Certificates in |
|
984 |
* TrustedCertificateEntries. Also, this implementation does not support |
|
985 |
* protecting entries using a different password |
|
986 |
* from the one used for token login. |
|
987 |
* |
|
988 |
* <p> Entries are immediately stored on the token. |
|
989 |
* |
|
990 |
* @param alias save the <code>KeyStore.Entry</code> under this alias |
|
991 |
* @param entry the <code>Entry</code> to save |
|
992 |
* @param protParam this must be <code>null</code> |
|
993 |
* |
|
994 |
* @exception KeyStoreException if this operation fails |
|
995 |
* |
|
996 |
* @since 1.5 |
|
997 |
*/ |
|
998 |
public synchronized void engineSetEntry(String alias, KeyStore.Entry entry, |
|
999 |
KeyStore.ProtectionParameter protParam) |
|
1000 |
throws KeyStoreException { |
|
1001 |
||
1002 |
token.ensureValid(); |
|
1003 |
checkWrite(); |
|
1004 |
||
1005 |
if (protParam != null && |
|
1006 |
protParam instanceof KeyStore.PasswordProtection && |
|
1007 |
((KeyStore.PasswordProtection)protParam).getPassword() != null && |
|
1008 |
!token.config.getKeyStoreCompatibilityMode()) { |
|
1009 |
throw new KeyStoreException(new UnsupportedOperationException |
|
1010 |
("ProtectionParameter must be null")); |
|
1011 |
} |
|
1012 |
||
1013 |
if (token.isWriteProtected()) { |
|
1014 |
throw new KeyStoreException("token write-protected"); |
|
1015 |
} |
|
1016 |
||
1017 |
if (entry instanceof KeyStore.TrustedCertificateEntry) { |
|
1018 |
||
1019 |
if (useSecmodTrust == false) { |
|
1020 |
// PKCS #11 does not allow app to modify trusted certs - |
|
1021 |
throw new KeyStoreException(new UnsupportedOperationException |
|
1022 |
("trusted certificates may only be set by " + |
|
1023 |
"token initialization application")); |
|
1024 |
} |
|
44545
83b611b88ac8
8177530: Module system implementation refresh (4/2017)
alanb
parents:
43248
diff
changeset
|
1025 |
Secmod.Module module = token.provider.nssModule; |
2 | 1026 |
if ((module.type != ModuleType.KEYSTORE) && (module.type != ModuleType.FIPS)) { |
1027 |
// XXX allow TRUSTANCHOR module |
|
1028 |
throw new KeyStoreException("Trusted certificates can only be " |
|
1029 |
+ "added to the NSS KeyStore module"); |
|
1030 |
} |
|
1031 |
Certificate cert = ((TrustedCertificateEntry)entry).getTrustedCertificate(); |
|
1032 |
if (cert instanceof X509Certificate == false) { |
|
1033 |
throw new KeyStoreException("Certificate must be an X509Certificate"); |
|
1034 |
} |
|
1035 |
X509Certificate xcert = (X509Certificate)cert; |
|
1036 |
AliasInfo info = aliasMap.get(alias); |
|
1037 |
if (info != null) { |
|
1038 |
// XXX try to update |
|
1039 |
deleteEntry(alias); |
|
1040 |
} |
|
1041 |
try { |
|
1042 |
storeCert(alias, xcert); |
|
1043 |
module.setTrust(token, xcert); |
|
1044 |
mapLabels(); |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
1045 |
} catch (PKCS11Exception | CertificateException e) { |
2 | 1046 |
throw new KeyStoreException(e); |
1047 |
} |
|
1048 |
||
1049 |
} else { |
|
1050 |
||
1051 |
if (entry instanceof KeyStore.PrivateKeyEntry) { |
|
1052 |
||
1053 |
PrivateKey key = |
|
1054 |
((KeyStore.PrivateKeyEntry)entry).getPrivateKey(); |
|
1055 |
if (!(key instanceof P11Key) && |
|
1056 |
!(key instanceof RSAPrivateKey) && |
|
1057 |
!(key instanceof DSAPrivateKey) && |
|
1058 |
!(key instanceof DHPrivateKey) && |
|
1059 |
!(key instanceof ECPrivateKey)) { |
|
1060 |
throw new KeyStoreException("unsupported key type: " + |
|
1061 |
key.getClass().getName()); |
|
1062 |
} |
|
1063 |
||
1064 |
// only support X509Certificate chains |
|
1065 |
Certificate[] chain = |
|
1066 |
((KeyStore.PrivateKeyEntry)entry).getCertificateChain(); |
|
1067 |
if (!(chain instanceof X509Certificate[])) { |
|
1068 |
throw new KeyStoreException |
|
1069 |
(new UnsupportedOperationException |
|
1070 |
("unsupported certificate array type: " + |
|
1071 |
chain.getClass().getName())); |
|
1072 |
} |
|
1073 |
||
1074 |
try { |
|
1075 |
boolean updatedAlias = false; |
|
1076 |
Set<String> aliases = aliasMap.keySet(); |
|
1077 |
for (String oldAlias : aliases) { |
|
1078 |
||
1079 |
// see if there's an existing entry with the same info |
|
1080 |
||
1081 |
AliasInfo aliasInfo = aliasMap.get(oldAlias); |
|
1082 |
if (aliasInfo.type == ATTR_CLASS_PKEY && |
|
1083 |
aliasInfo.cert.getPublicKey().equals |
|
1084 |
(chain[0].getPublicKey())) { |
|
1085 |
||
1086 |
// found existing entry - |
|
1087 |
// caller is renaming entry or updating cert chain |
|
1088 |
// |
|
1089 |
// set new CKA_LABEL/CKA_ID |
|
1090 |
// and update certs if necessary |
|
1091 |
||
1092 |
updatePkey(alias, |
|
1093 |
aliasInfo.id, |
|
1094 |
(X509Certificate[])chain, |
|
1095 |
!aliasInfo.cert.equals(chain[0])); |
|
1096 |
updatedAlias = true; |
|
1097 |
break; |
|
1098 |
} |
|
1099 |
} |
|
1100 |
||
1101 |
if (!updatedAlias) { |
|
1102 |
// caller adding new entry |
|
1103 |
engineDeleteEntry(alias); |
|
1104 |
storePkey(alias, (KeyStore.PrivateKeyEntry)entry); |
|
1105 |
} |
|
1106 |
||
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
1107 |
} catch (PKCS11Exception | CertificateException pe) { |
2 | 1108 |
throw new KeyStoreException(pe); |
1109 |
} |
|
1110 |
||
1111 |
} else if (entry instanceof KeyStore.SecretKeyEntry) { |
|
1112 |
||
1113 |
KeyStore.SecretKeyEntry ske = (KeyStore.SecretKeyEntry)entry; |
|
1114 |
SecretKey skey = ske.getSecretKey(); |
|
1115 |
||
1116 |
try { |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1117 |
// first check if the key already exists |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1118 |
AliasInfo aliasInfo = aliasMap.get(alias); |
2 | 1119 |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1120 |
if (aliasInfo != null) { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1121 |
engineDeleteEntry(alias); |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1122 |
} |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1123 |
storeSkey(alias, ske); |
2 | 1124 |
|
1125 |
} catch (PKCS11Exception pe) { |
|
1126 |
throw new KeyStoreException(pe); |
|
1127 |
} |
|
1128 |
||
1129 |
} else { |
|
1130 |
throw new KeyStoreException(new UnsupportedOperationException |
|
1131 |
("unsupported entry type: " + entry.getClass().getName())); |
|
1132 |
} |
|
1133 |
||
1134 |
try { |
|
1135 |
||
1136 |
// XXX NSS does not write out the CKA_ID we pass to them |
|
1137 |
// |
|
1138 |
// therefore we must re-map labels |
|
1139 |
// (can not simply update aliasMap) |
|
1140 |
||
1141 |
mapLabels(); |
|
1142 |
if (debug != null) { |
|
1143 |
dumpTokenMap(); |
|
1144 |
} |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
1145 |
} catch (PKCS11Exception | CertificateException pe) { |
2 | 1146 |
throw new KeyStoreException(pe); |
1147 |
} |
|
1148 |
} |
|
1149 |
||
1150 |
if (debug != null) { |
|
1151 |
debug.println |
|
1152 |
("engineSetEntry added new entry for [" + |
|
1153 |
alias + |
|
1154 |
"] to token"); |
|
1155 |
} |
|
1156 |
} |
|
1157 |
||
1158 |
/** |
|
1159 |
* Determines if the keystore <code>Entry</code> for the specified |
|
1160 |
* <code>alias</code> is an instance or subclass of the specified |
|
1161 |
* <code>entryClass</code>. |
|
1162 |
* |
|
1163 |
* @param alias the alias name |
|
1164 |
* @param entryClass the entry class |
|
1165 |
* |
|
1166 |
* @return true if the keystore <code>Entry</code> for the specified |
|
1167 |
* <code>alias</code> is an instance or subclass of the |
|
1168 |
* specified <code>entryClass</code>, false otherwise |
|
1169 |
*/ |
|
1170 |
public synchronized boolean engineEntryInstanceOf |
|
1171 |
(String alias, Class<? extends KeyStore.Entry> entryClass) { |
|
1172 |
token.ensureValid(); |
|
1173 |
return super.engineEntryInstanceOf(alias, entryClass); |
|
1174 |
} |
|
1175 |
||
1176 |
private X509Certificate loadCert(Session session, long oHandle) |
|
1177 |
throws PKCS11Exception, CertificateException { |
|
1178 |
||
1179 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] |
|
1180 |
{ new CK_ATTRIBUTE(CKA_VALUE) }; |
|
1181 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1182 |
||
1183 |
byte[] bytes = attrs[0].getByteArray(); |
|
1184 |
if (bytes == null) { |
|
1185 |
throw new CertificateException |
|
1186 |
("unexpectedly retrieved null byte array"); |
|
1187 |
} |
|
1188 |
CertificateFactory cf = CertificateFactory.getInstance("X.509"); |
|
1189 |
return (X509Certificate)cf.generateCertificate |
|
1190 |
(new ByteArrayInputStream(bytes)); |
|
1191 |
} |
|
1192 |
||
1193 |
private X509Certificate[] loadChain(Session session, |
|
1194 |
X509Certificate endCert) |
|
1195 |
throws PKCS11Exception, CertificateException { |
|
1196 |
||
1197 |
ArrayList<X509Certificate> lChain = null; |
|
1198 |
||
1199 |
if (endCert.getSubjectX500Principal().equals |
|
1200 |
(endCert.getIssuerX500Principal())) { |
|
1201 |
// self signed |
|
1202 |
return new X509Certificate[] { endCert }; |
|
1203 |
} else { |
|
1204 |
lChain = new ArrayList<X509Certificate>(); |
|
1205 |
lChain.add(endCert); |
|
1206 |
} |
|
1207 |
||
1208 |
// try loading remaining certs in chain by following |
|
1209 |
// issuer->subject links |
|
1210 |
||
1211 |
X509Certificate next = endCert; |
|
1212 |
while (true) { |
|
1213 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1214 |
ATTR_TOKEN_TRUE, |
|
1215 |
ATTR_CLASS_CERT, |
|
1216 |
new CK_ATTRIBUTE(CKA_SUBJECT, |
|
1217 |
next.getIssuerX500Principal().getEncoded()) }; |
|
1218 |
long[] ch = findObjects(session, attrs); |
|
1219 |
||
1220 |
if (ch == null || ch.length == 0) { |
|
1221 |
// done |
|
1222 |
break; |
|
1223 |
} else { |
|
1224 |
// if more than one found, use first |
|
1225 |
if (debug != null && ch.length > 1) { |
|
1226 |
debug.println("engineGetEntry found " + |
|
1227 |
ch.length + |
|
1228 |
" certificate entries for subject [" + |
|
1229 |
next.getIssuerX500Principal().toString() + |
|
1230 |
"] in token - using first entry"); |
|
1231 |
} |
|
1232 |
||
1233 |
next = loadCert(session, ch[0]); |
|
1234 |
lChain.add(next); |
|
1235 |
if (next.getSubjectX500Principal().equals |
|
1236 |
(next.getIssuerX500Principal())) { |
|
1237 |
// self signed |
|
1238 |
break; |
|
1239 |
} |
|
1240 |
} |
|
1241 |
} |
|
1242 |
||
1243 |
return lChain.toArray(new X509Certificate[lChain.size()]); |
|
1244 |
} |
|
1245 |
||
1246 |
private SecretKey loadSkey(Session session, long oHandle) |
|
1247 |
throws PKCS11Exception { |
|
1248 |
||
1249 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1250 |
new CK_ATTRIBUTE(CKA_KEY_TYPE) }; |
|
1251 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1252 |
long kType = attrs[0].getLong(); |
|
1253 |
||
1254 |
String keyType = null; |
|
1255 |
int keyLength = -1; |
|
1256 |
||
1257 |
// XXX NSS mangles the stored key type for secret key token objects |
|
1258 |
||
1259 |
if (kType == CKK_DES || kType == CKK_DES3) { |
|
1260 |
if (kType == CKK_DES) { |
|
1261 |
keyType = "DES"; |
|
1262 |
keyLength = 64; |
|
1263 |
} else if (kType == CKK_DES3) { |
|
1264 |
keyType = "DESede"; |
|
1265 |
keyLength = 192; |
|
1266 |
} |
|
1267 |
} else { |
|
1268 |
if (kType == CKK_AES) { |
|
1269 |
keyType = "AES"; |
|
1270 |
} else if (kType == CKK_BLOWFISH) { |
|
1271 |
keyType = "Blowfish"; |
|
1272 |
} else if (kType == CKK_RC4) { |
|
1273 |
keyType = "ARCFOUR"; |
|
1274 |
} else { |
|
1275 |
if (debug != null) { |
|
1276 |
debug.println("unknown key type [" + |
|
1277 |
kType + |
|
1278 |
"] - using 'Generic Secret'"); |
|
1279 |
} |
|
1280 |
keyType = "Generic Secret"; |
|
1281 |
} |
|
1282 |
||
1283 |
// XXX NSS problem CKR_ATTRIBUTE_TYPE_INVALID? |
|
1284 |
if (NSS_TEST) { |
|
1285 |
keyLength = 128; |
|
1286 |
} else { |
|
1287 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_VALUE_LEN) }; |
|
1288 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1289 |
keyLength = (int)attrs[0].getLong(); |
|
1290 |
} |
|
1291 |
} |
|
1292 |
||
1293 |
return P11Key.secretKey(session, oHandle, keyType, keyLength, null); |
|
1294 |
} |
|
1295 |
||
1296 |
private PrivateKey loadPkey(Session session, long oHandle) |
|
1297 |
throws PKCS11Exception, KeyStoreException { |
|
1298 |
||
1299 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1300 |
new CK_ATTRIBUTE(CKA_KEY_TYPE) }; |
|
1301 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1302 |
long kType = attrs[0].getLong(); |
|
1303 |
String keyType = null; |
|
1304 |
int keyLength = 0; |
|
1305 |
||
1306 |
if (kType == CKK_RSA) { |
|
1307 |
||
1308 |
keyType = "RSA"; |
|
1309 |
||
1310 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_MODULUS) }; |
|
1311 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1312 |
BigInteger modulus = attrs[0].getBigInteger(); |
|
1313 |
keyLength = modulus.bitLength(); |
|
1314 |
||
2596 | 1315 |
// This check will combine our "don't care" values here |
1316 |
// with the system-wide min/max values. |
|
1317 |
try { |
|
1318 |
RSAKeyFactory.checkKeyLengths(keyLength, null, |
|
1319 |
-1, Integer.MAX_VALUE); |
|
1320 |
} catch (InvalidKeyException e) { |
|
1321 |
throw new KeyStoreException(e.getMessage()); |
|
1322 |
} |
|
1323 |
||
2 | 1324 |
return P11Key.privateKey(session, |
1325 |
oHandle, |
|
1326 |
keyType, |
|
1327 |
keyLength, |
|
1328 |
null); |
|
1329 |
||
1330 |
} else if (kType == CKK_DSA) { |
|
1331 |
||
1332 |
keyType = "DSA"; |
|
1333 |
||
1334 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_PRIME) }; |
|
1335 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1336 |
BigInteger prime = attrs[0].getBigInteger(); |
|
1337 |
keyLength = prime.bitLength(); |
|
1338 |
||
1339 |
return P11Key.privateKey(session, |
|
1340 |
oHandle, |
|
1341 |
keyType, |
|
1342 |
keyLength, |
|
1343 |
null); |
|
1344 |
||
1345 |
} else if (kType == CKK_DH) { |
|
1346 |
||
1347 |
keyType = "DH"; |
|
1348 |
||
1349 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_PRIME) }; |
|
1350 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1351 |
BigInteger prime = attrs[0].getBigInteger(); |
|
1352 |
keyLength = prime.bitLength(); |
|
1353 |
||
1354 |
return P11Key.privateKey(session, |
|
1355 |
oHandle, |
|
1356 |
keyType, |
|
1357 |
keyLength, |
|
1358 |
null); |
|
1359 |
||
1360 |
} else if (kType == CKK_EC) { |
|
1361 |
||
1362 |
attrs = new CK_ATTRIBUTE[] { |
|
1363 |
new CK_ATTRIBUTE(CKA_EC_PARAMS), |
|
1364 |
}; |
|
1365 |
token.p11.C_GetAttributeValue(session.id(), oHandle, attrs); |
|
1366 |
byte[] encodedParams = attrs[0].getByteArray(); |
|
1367 |
try { |
|
17491
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
1368 |
ECParameterSpec params = |
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
1369 |
ECUtil.getECParameterSpec(null, encodedParams); |
2 | 1370 |
keyLength = params.getCurve().getField().getFieldSize(); |
1371 |
} catch (IOException e) { |
|
1372 |
// we do not want to accept key with unsupported parameters |
|
1373 |
throw new KeyStoreException("Unsupported parameters", e); |
|
1374 |
} |
|
1375 |
||
1376 |
return P11Key.privateKey(session, oHandle, "EC", keyLength, null); |
|
1377 |
||
1378 |
} else { |
|
1379 |
if (debug != null) { |
|
1380 |
debug.println("unknown key type [" + kType + "]"); |
|
1381 |
} |
|
1382 |
throw new KeyStoreException("unknown key type"); |
|
1383 |
} |
|
1384 |
} |
|
1385 |
||
1386 |
||
1387 |
/** |
|
1388 |
* XXX On ibutton, when you C_SetAttribute(CKA_ID) for a private key |
|
1389 |
* it not only changes the CKA_ID of the private key, |
|
1390 |
* it changes the CKA_ID of the corresponding cert too. |
|
1391 |
* And vice versa. |
|
1392 |
* |
|
1393 |
* XXX On ibutton, CKR_DEVICE_ERROR if you C_SetAttribute(CKA_ID) |
|
1394 |
* for a private key, and then try to delete the corresponding cert. |
|
1395 |
* So this code reverses the order. |
|
1396 |
* After the cert is first destroyed (if necessary), |
|
1397 |
* then the CKA_ID of the private key can be changed successfully. |
|
1398 |
* |
|
1399 |
* @param replaceCert if true, then caller is updating alias info for |
|
1400 |
* existing cert (only update CKA_ID/CKA_LABEL). |
|
1401 |
* if false, then caller is updating cert chain |
|
1402 |
* (delete old end cert and add new chain). |
|
1403 |
*/ |
|
1404 |
private void updatePkey(String alias, |
|
1405 |
byte[] cka_id, |
|
1406 |
X509Certificate[] chain, |
|
1407 |
boolean replaceCert) throws |
|
1408 |
KeyStoreException, CertificateException, PKCS11Exception { |
|
1409 |
||
1410 |
// XXX |
|
1411 |
// |
|
1412 |
// always set replaceCert to true |
|
1413 |
// |
|
1414 |
// NSS does not allow resetting of CKA_LABEL on an existing cert |
|
1415 |
// (C_SetAttribute call succeeds, but is ignored) |
|
1416 |
||
1417 |
replaceCert = true; |
|
1418 |
||
1419 |
Session session = null; |
|
1420 |
try { |
|
1421 |
session = token.getOpSession(); |
|
1422 |
||
1423 |
// first get private key object handle and hang onto it |
|
1424 |
||
1425 |
THandle h = getTokenObject(session, ATTR_CLASS_PKEY, cka_id, null); |
|
1426 |
long pKeyHandle; |
|
1427 |
if (h.type == ATTR_CLASS_PKEY) { |
|
1428 |
pKeyHandle = h.handle; |
|
1429 |
} else { |
|
1430 |
throw new KeyStoreException |
|
1431 |
("expected but could not find private key " + |
|
1432 |
"with CKA_ID " + |
|
1433 |
getID(cka_id)); |
|
1434 |
} |
|
1435 |
||
1436 |
// next find existing end entity cert |
|
1437 |
||
1438 |
h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); |
|
1439 |
if (h.type != ATTR_CLASS_CERT) { |
|
1440 |
throw new KeyStoreException |
|
1441 |
("expected but could not find certificate " + |
|
1442 |
"with CKA_ID " + |
|
1443 |
getID(cka_id)); |
|
1444 |
} else { |
|
1445 |
if (replaceCert) { |
|
1446 |
// replacing existing cert and chain |
|
1447 |
destroyChain(cka_id); |
|
1448 |
} else { |
|
1449 |
// renaming alias for existing cert |
|
1450 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1451 |
new CK_ATTRIBUTE(CKA_LABEL, alias), |
|
1452 |
new CK_ATTRIBUTE(CKA_ID, alias) }; |
|
1453 |
token.p11.C_SetAttributeValue |
|
1454 |
(session.id(), h.handle, attrs); |
|
1455 |
} |
|
1456 |
} |
|
1457 |
||
1458 |
// add new chain |
|
1459 |
||
1460 |
if (replaceCert) { |
|
1461 |
// add all certs in chain |
|
1462 |
storeChain(alias, chain); |
|
1463 |
} else { |
|
1464 |
// already updated alias info for existing end cert - |
|
1465 |
// just update CA certs |
|
1466 |
storeCaCerts(chain, 1); |
|
1467 |
} |
|
1468 |
||
1469 |
// finally update CKA_ID for private key |
|
1470 |
// |
|
1471 |
// ibutton may have already done this (that is ok) |
|
1472 |
||
1473 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1474 |
new CK_ATTRIBUTE(CKA_ID, alias) }; |
|
1475 |
token.p11.C_SetAttributeValue(session.id(), pKeyHandle, attrs); |
|
1476 |
||
1477 |
if (debug != null) { |
|
1478 |
debug.println("updatePkey set new alias [" + |
|
1479 |
alias + |
|
1480 |
"] for private key entry"); |
|
1481 |
} |
|
1482 |
} finally { |
|
1483 |
token.releaseSession(session); |
|
1484 |
} |
|
1485 |
} |
|
1486 |
||
1487 |
private void updateP11Pkey(String alias, CK_ATTRIBUTE attribute, P11Key key) |
|
1488 |
throws PKCS11Exception { |
|
1489 |
||
1490 |
// if token key, update alias. |
|
1491 |
// if session key, convert to token key. |
|
1492 |
||
1493 |
Session session = null; |
|
1494 |
try { |
|
1495 |
session = token.getOpSession(); |
|
1496 |
if (key.tokenObject == true) { |
|
1497 |
||
1498 |
// token key - set new CKA_ID |
|
1499 |
||
1500 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1501 |
new CK_ATTRIBUTE(CKA_ID, alias) }; |
|
1502 |
token.p11.C_SetAttributeValue |
|
1503 |
(session.id(), key.keyID, attrs); |
|
1504 |
if (debug != null) { |
|
1505 |
debug.println("updateP11Pkey set new alias [" + |
|
1506 |
alias + |
|
1507 |
"] for key entry"); |
|
1508 |
} |
|
1509 |
} else { |
|
1510 |
||
1511 |
// session key - convert to token key and set CKA_ID |
|
1512 |
||
1513 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1514 |
ATTR_TOKEN_TRUE, |
|
1515 |
new CK_ATTRIBUTE(CKA_ID, alias), |
|
1516 |
}; |
|
1517 |
if (attribute != null) { |
|
1518 |
attrs = addAttribute(attrs, attribute); |
|
1519 |
} |
|
1520 |
token.p11.C_CopyObject(session.id(), key.keyID, attrs); |
|
1521 |
if (debug != null) { |
|
1522 |
debug.println("updateP11Pkey copied private session key " + |
|
1523 |
"for [" + |
|
1524 |
alias + |
|
1525 |
"] to token entry"); |
|
1526 |
} |
|
1527 |
} |
|
1528 |
} finally { |
|
1529 |
token.releaseSession(session); |
|
1530 |
} |
|
1531 |
} |
|
1532 |
||
1533 |
private void storeCert(String alias, X509Certificate cert) |
|
1534 |
throws PKCS11Exception, CertificateException { |
|
1535 |
||
1536 |
ArrayList<CK_ATTRIBUTE> attrList = new ArrayList<CK_ATTRIBUTE>(); |
|
1537 |
attrList.add(ATTR_TOKEN_TRUE); |
|
1538 |
attrList.add(ATTR_CLASS_CERT); |
|
1539 |
attrList.add(ATTR_X509_CERT_TYPE); |
|
1540 |
attrList.add(new CK_ATTRIBUTE(CKA_SUBJECT, |
|
1541 |
cert.getSubjectX500Principal().getEncoded())); |
|
1542 |
attrList.add(new CK_ATTRIBUTE(CKA_ISSUER, |
|
1543 |
cert.getIssuerX500Principal().getEncoded())); |
|
1544 |
attrList.add(new CK_ATTRIBUTE(CKA_SERIAL_NUMBER, |
|
1545 |
cert.getSerialNumber().toByteArray())); |
|
1546 |
attrList.add(new CK_ATTRIBUTE(CKA_VALUE, cert.getEncoded())); |
|
1547 |
||
1548 |
if (alias != null) { |
|
1549 |
attrList.add(new CK_ATTRIBUTE(CKA_LABEL, alias)); |
|
1550 |
attrList.add(new CK_ATTRIBUTE(CKA_ID, alias)); |
|
1551 |
} else { |
|
1552 |
// ibutton requires something to be set |
|
1553 |
// - alias must be unique |
|
1554 |
attrList.add(new CK_ATTRIBUTE(CKA_ID, |
|
1555 |
getID(cert.getSubjectX500Principal().getName |
|
1556 |
(X500Principal.CANONICAL), cert))); |
|
1557 |
} |
|
1558 |
||
1559 |
Session session = null; |
|
1560 |
try { |
|
1561 |
session = token.getOpSession(); |
|
1562 |
token.p11.C_CreateObject(session.id(), |
|
1563 |
attrList.toArray(new CK_ATTRIBUTE[attrList.size()])); |
|
1564 |
} finally { |
|
1565 |
token.releaseSession(session); |
|
1566 |
} |
|
1567 |
} |
|
1568 |
||
1569 |
private void storeChain(String alias, X509Certificate[] chain) |
|
1570 |
throws PKCS11Exception, CertificateException { |
|
1571 |
||
1572 |
// add new chain |
|
1573 |
// |
|
1574 |
// end cert has CKA_LABEL and CKA_ID set to alias. |
|
1575 |
// other certs in chain have neither set. |
|
1576 |
||
1577 |
storeCert(alias, chain[0]); |
|
1578 |
storeCaCerts(chain, 1); |
|
1579 |
} |
|
1580 |
||
1581 |
private void storeCaCerts(X509Certificate[] chain, int start) |
|
1582 |
throws PKCS11Exception, CertificateException { |
|
1583 |
||
1584 |
// do not add duplicate CA cert if already in token |
|
1585 |
// |
|
1586 |
// XXX ibutton stores duplicate CA certs, NSS does not |
|
1587 |
||
1588 |
Session session = null; |
|
1589 |
HashSet<X509Certificate> cacerts = new HashSet<X509Certificate>(); |
|
1590 |
try { |
|
1591 |
session = token.getOpSession(); |
|
1592 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
1593 |
ATTR_TOKEN_TRUE, |
|
1594 |
ATTR_CLASS_CERT }; |
|
1595 |
long[] handles = findObjects(session, attrs); |
|
1596 |
||
1597 |
// load certs currently on the token |
|
1598 |
for (long handle : handles) { |
|
1599 |
cacerts.add(loadCert(session, handle)); |
|
1600 |
} |
|
1601 |
} finally { |
|
1602 |
token.releaseSession(session); |
|
1603 |
} |
|
1604 |
||
1605 |
for (int i = start; i < chain.length; i++) { |
|
1606 |
if (!cacerts.contains(chain[i])) { |
|
1607 |
storeCert(null, chain[i]); |
|
1608 |
} else if (debug != null) { |
|
1609 |
debug.println("ignoring duplicate CA cert for [" + |
|
1610 |
chain[i].getSubjectX500Principal() + |
|
1611 |
"]"); |
|
1612 |
} |
|
1613 |
} |
|
1614 |
} |
|
1615 |
||
1616 |
private void storeSkey(String alias, KeyStore.SecretKeyEntry ske) |
|
1617 |
throws PKCS11Exception, KeyStoreException { |
|
1618 |
||
1619 |
SecretKey skey = ske.getSecretKey(); |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1620 |
// No need to specify CKA_CLASS, CKA_KEY_TYPE, CKA_VALUE since |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1621 |
// they are handled in P11SecretKeyFactory.createKey() method. |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1622 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1623 |
ATTR_SKEY_TOKEN_TRUE, |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1624 |
ATTR_PRIVATE_TRUE, |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1625 |
new CK_ATTRIBUTE(CKA_LABEL, alias), |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1626 |
}; |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1627 |
try { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1628 |
P11SecretKeyFactory.convertKey(token, skey, null, attrs); |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1629 |
} catch (InvalidKeyException ike) { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1630 |
// re-throw KeyStoreException to match javadoc |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1631 |
throw new KeyStoreException("Cannot convert to PKCS11 keys", ike); |
2 | 1632 |
} |
1633 |
||
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1634 |
// update global alias map |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1635 |
aliasMap.put(alias, new AliasInfo(alias)); |
2 | 1636 |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1637 |
if (debug != null) { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1638 |
debug.println("storeSkey created token secret key for [" + |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
1639 |
alias + "]"); |
2 | 1640 |
} |
1641 |
} |
|
1642 |
||
1643 |
private static CK_ATTRIBUTE[] addAttribute(CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE attr) { |
|
1644 |
int n = attrs.length; |
|
1645 |
CK_ATTRIBUTE[] newAttrs = new CK_ATTRIBUTE[n + 1]; |
|
1646 |
System.arraycopy(attrs, 0, newAttrs, 0, n); |
|
1647 |
newAttrs[n] = attr; |
|
1648 |
return newAttrs; |
|
1649 |
} |
|
1650 |
||
1651 |
private void storePkey(String alias, KeyStore.PrivateKeyEntry pke) |
|
1652 |
throws PKCS11Exception, CertificateException, KeyStoreException { |
|
1653 |
||
1654 |
PrivateKey key = pke.getPrivateKey(); |
|
1655 |
CK_ATTRIBUTE[] attrs = null; |
|
1656 |
||
1657 |
// If the key is a token object on this token, update it instead |
|
1658 |
// of creating a duplicate key object. |
|
28059
e576535359cc
8067377: My hobby: caning, then then canning, the the can-can
martin
parents:
25859
diff
changeset
|
1659 |
// Otherwise, treat a P11Key like any other key, if it is extractable. |
2 | 1660 |
if (key instanceof P11Key) { |
1661 |
P11Key p11Key = (P11Key)key; |
|
1662 |
if (p11Key.tokenObject && (p11Key.token == this.token)) { |
|
1663 |
updateP11Pkey(alias, null, p11Key); |
|
1664 |
storeChain(alias, (X509Certificate[])pke.getCertificateChain()); |
|
1665 |
return; |
|
1666 |
} |
|
1667 |
} |
|
1668 |
||
1669 |
boolean useNDB = token.config.getNssNetscapeDbWorkaround(); |
|
1670 |
PublicKey publicKey = pke.getCertificate().getPublicKey(); |
|
1671 |
||
1672 |
if (key instanceof RSAPrivateKey) { |
|
1673 |
||
1674 |
X509Certificate cert = (X509Certificate)pke.getCertificate(); |
|
1675 |
attrs = getRsaPrivKeyAttrs |
|
1676 |
(alias, (RSAPrivateKey)key, cert.getSubjectX500Principal()); |
|
1677 |
||
1678 |
} else if (key instanceof DSAPrivateKey) { |
|
1679 |
||
1680 |
DSAPrivateKey dsaKey = (DSAPrivateKey)key; |
|
1681 |
||
1682 |
CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); |
|
1683 |
if (idAttrs[0] == null) { |
|
1684 |
idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); |
|
1685 |
} |
|
1686 |
||
1687 |
attrs = new CK_ATTRIBUTE[] { |
|
1688 |
ATTR_TOKEN_TRUE, |
|
1689 |
ATTR_CLASS_PKEY, |
|
1690 |
ATTR_PRIVATE_TRUE, |
|
1691 |
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DSA), |
|
1692 |
idAttrs[0], |
|
1693 |
new CK_ATTRIBUTE(CKA_PRIME, dsaKey.getParams().getP()), |
|
1694 |
new CK_ATTRIBUTE(CKA_SUBPRIME, dsaKey.getParams().getQ()), |
|
1695 |
new CK_ATTRIBUTE(CKA_BASE, dsaKey.getParams().getG()), |
|
1696 |
new CK_ATTRIBUTE(CKA_VALUE, dsaKey.getX()), |
|
1697 |
}; |
|
1698 |
if (idAttrs[1] != null) { |
|
1699 |
attrs = addAttribute(attrs, idAttrs[1]); |
|
1700 |
} |
|
1701 |
||
1702 |
attrs = token.getAttributes |
|
1703 |
(TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_DSA, attrs); |
|
1704 |
||
1705 |
if (debug != null) { |
|
1706 |
debug.println("storePkey created DSA template"); |
|
1707 |
} |
|
1708 |
||
1709 |
} else if (key instanceof DHPrivateKey) { |
|
1710 |
||
1711 |
DHPrivateKey dhKey = (DHPrivateKey)key; |
|
1712 |
||
1713 |
CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); |
|
1714 |
if (idAttrs[0] == null) { |
|
1715 |
idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); |
|
1716 |
} |
|
1717 |
||
1718 |
attrs = new CK_ATTRIBUTE[] { |
|
1719 |
ATTR_TOKEN_TRUE, |
|
1720 |
ATTR_CLASS_PKEY, |
|
1721 |
ATTR_PRIVATE_TRUE, |
|
1722 |
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_DH), |
|
1723 |
idAttrs[0], |
|
1724 |
new CK_ATTRIBUTE(CKA_PRIME, dhKey.getParams().getP()), |
|
1725 |
new CK_ATTRIBUTE(CKA_BASE, dhKey.getParams().getG()), |
|
1726 |
new CK_ATTRIBUTE(CKA_VALUE, dhKey.getX()), |
|
1727 |
}; |
|
1728 |
if (idAttrs[1] != null) { |
|
1729 |
attrs = addAttribute(attrs, idAttrs[1]); |
|
1730 |
} |
|
1731 |
||
1732 |
attrs = token.getAttributes |
|
1733 |
(TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_DH, attrs); |
|
1734 |
||
1735 |
} else if (key instanceof ECPrivateKey) { |
|
1736 |
||
1737 |
ECPrivateKey ecKey = (ECPrivateKey)key; |
|
1738 |
||
1739 |
CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, useNDB); |
|
1740 |
if (idAttrs[0] == null) { |
|
1741 |
idAttrs[0] = new CK_ATTRIBUTE(CKA_ID, alias); |
|
1742 |
} |
|
1743 |
||
17491
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
1744 |
byte[] encodedParams = |
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
1745 |
ECUtil.encodeECParameterSpec(null, ecKey.getParams()); |
2 | 1746 |
attrs = new CK_ATTRIBUTE[] { |
1747 |
ATTR_TOKEN_TRUE, |
|
1748 |
ATTR_CLASS_PKEY, |
|
1749 |
ATTR_PRIVATE_TRUE, |
|
1750 |
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC), |
|
1751 |
idAttrs[0], |
|
1752 |
new CK_ATTRIBUTE(CKA_VALUE, ecKey.getS()), |
|
1753 |
new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams), |
|
1754 |
}; |
|
1755 |
if (idAttrs[1] != null) { |
|
1756 |
attrs = addAttribute(attrs, idAttrs[1]); |
|
1757 |
} |
|
1758 |
||
1759 |
attrs = token.getAttributes |
|
1760 |
(TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attrs); |
|
1761 |
||
1762 |
if (debug != null) { |
|
1763 |
debug.println("storePkey created EC template"); |
|
1764 |
} |
|
1765 |
||
1766 |
} else if (key instanceof P11Key) { |
|
1767 |
// sensitive/non-extractable P11Key |
|
1768 |
P11Key p11Key = (P11Key)key; |
|
1769 |
if (p11Key.token != this.token) { |
|
1770 |
throw new KeyStoreException |
|
1771 |
("Cannot move sensitive keys across tokens"); |
|
1772 |
} |
|
1773 |
CK_ATTRIBUTE netscapeDB = null; |
|
1774 |
if (useNDB) { |
|
1775 |
// Note that this currently fails due to an NSS bug. |
|
1776 |
// They do not allow the CKA_NETSCAPE_DB attribute to be |
|
1777 |
// specified during C_CopyObject() and fail with |
|
1778 |
// CKR_ATTRIBUTE_READ_ONLY. |
|
1779 |
// But if we did not specify it, they would fail with |
|
1780 |
// CKA_TEMPLATE_INCOMPLETE, so leave this code in here. |
|
1781 |
CK_ATTRIBUTE[] idAttrs = getIdAttributes(key, publicKey, false, true); |
|
1782 |
netscapeDB = idAttrs[1]; |
|
1783 |
} |
|
1784 |
// Update the key object. |
|
1785 |
updateP11Pkey(alias, netscapeDB, p11Key); |
|
1786 |
storeChain(alias, (X509Certificate[])pke.getCertificateChain()); |
|
1787 |
return; |
|
1788 |
||
1789 |
} else { |
|
1790 |
throw new KeyStoreException("unsupported key type: " + key); |
|
1791 |
} |
|
1792 |
||
1793 |
Session session = null; |
|
1794 |
try { |
|
1795 |
session = token.getOpSession(); |
|
1796 |
||
1797 |
// create private key entry |
|
1798 |
token.p11.C_CreateObject(session.id(), attrs); |
|
1799 |
if (debug != null) { |
|
1800 |
debug.println("storePkey created token key for [" + |
|
1801 |
alias + |
|
1802 |
"]"); |
|
1803 |
} |
|
1804 |
} finally { |
|
1805 |
token.releaseSession(session); |
|
1806 |
} |
|
1807 |
||
1808 |
storeChain(alias, (X509Certificate[])pke.getCertificateChain()); |
|
1809 |
} |
|
1810 |
||
1811 |
private CK_ATTRIBUTE[] getRsaPrivKeyAttrs(String alias, |
|
1812 |
RSAPrivateKey key, |
|
1813 |
X500Principal subject) throws PKCS11Exception { |
|
1814 |
||
1815 |
// subject is currently ignored - could be used to set CKA_SUBJECT |
|
1816 |
||
1817 |
CK_ATTRIBUTE[] attrs = null; |
|
1818 |
if (key instanceof RSAPrivateCrtKey) { |
|
1819 |
||
1820 |
if (debug != null) { |
|
1821 |
debug.println("creating RSAPrivateCrtKey attrs"); |
|
1822 |
} |
|
1823 |
||
1824 |
RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key; |
|
1825 |
||
1826 |
attrs = new CK_ATTRIBUTE[] { |
|
1827 |
ATTR_TOKEN_TRUE, |
|
1828 |
ATTR_CLASS_PKEY, |
|
1829 |
ATTR_PRIVATE_TRUE, |
|
1830 |
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), |
|
1831 |
new CK_ATTRIBUTE(CKA_ID, alias), |
|
1832 |
new CK_ATTRIBUTE(CKA_MODULUS, |
|
1833 |
rsaKey.getModulus()), |
|
1834 |
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, |
|
1835 |
rsaKey.getPrivateExponent()), |
|
1836 |
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, |
|
1837 |
rsaKey.getPublicExponent()), |
|
1838 |
new CK_ATTRIBUTE(CKA_PRIME_1, |
|
1839 |
rsaKey.getPrimeP()), |
|
1840 |
new CK_ATTRIBUTE(CKA_PRIME_2, |
|
1841 |
rsaKey.getPrimeQ()), |
|
1842 |
new CK_ATTRIBUTE(CKA_EXPONENT_1, |
|
1843 |
rsaKey.getPrimeExponentP()), |
|
1844 |
new CK_ATTRIBUTE(CKA_EXPONENT_2, |
|
1845 |
rsaKey.getPrimeExponentQ()), |
|
1846 |
new CK_ATTRIBUTE(CKA_COEFFICIENT, |
|
1847 |
rsaKey.getCrtCoefficient()) }; |
|
1848 |
attrs = token.getAttributes |
|
1849 |
(TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attrs); |
|
1850 |
||
1851 |
} else { |
|
1852 |
||
1853 |
if (debug != null) { |
|
1854 |
debug.println("creating RSAPrivateKey attrs"); |
|
1855 |
} |
|
1856 |
||
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
1857 |
RSAPrivateKey rsaKey = key; |
2 | 1858 |
|
1859 |
attrs = new CK_ATTRIBUTE[] { |
|
1860 |
ATTR_TOKEN_TRUE, |
|
1861 |
ATTR_CLASS_PKEY, |
|
1862 |
ATTR_PRIVATE_TRUE, |
|
1863 |
new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA), |
|
1864 |
new CK_ATTRIBUTE(CKA_ID, alias), |
|
1865 |
new CK_ATTRIBUTE(CKA_MODULUS, |
|
1866 |
rsaKey.getModulus()), |
|
1867 |
new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, |
|
1868 |
rsaKey.getPrivateExponent()) }; |
|
1869 |
attrs = token.getAttributes |
|
1870 |
(TemplateManager.O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attrs); |
|
1871 |
} |
|
1872 |
||
1873 |
return attrs; |
|
1874 |
} |
|
1875 |
||
1876 |
/** |
|
1877 |
* Compute the CKA_ID and/or CKA_NETSCAPE_DB attributes that should be |
|
1878 |
* used for this private key. It uses the same algorithm to calculate the |
|
1879 |
* values as NSS. The public and private keys MUST match for the result to |
|
1880 |
* be correct. |
|
1881 |
* |
|
1882 |
* It returns a 2 element array with CKA_ID at index 0 and CKA_NETSCAPE_DB |
|
1883 |
* at index 1. The boolean flags determine what is to be calculated. |
|
1884 |
* If false or if we could not calculate the value, that element is null. |
|
1885 |
* |
|
1886 |
* NOTE that we currently do not use the CKA_ID value calculated by this |
|
1887 |
* method. |
|
1888 |
*/ |
|
1889 |
private CK_ATTRIBUTE[] getIdAttributes(PrivateKey privateKey, |
|
1890 |
PublicKey publicKey, boolean id, boolean netscapeDb) { |
|
1891 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[2]; |
|
1892 |
if ((id || netscapeDb) == false) { |
|
1893 |
return attrs; |
|
1894 |
} |
|
1895 |
String alg = privateKey.getAlgorithm(); |
|
1896 |
if (id && alg.equals("RSA") && (publicKey instanceof RSAPublicKey)) { |
|
1897 |
// CKA_NETSCAPE_DB not needed for RSA public keys |
|
1898 |
BigInteger n = ((RSAPublicKey)publicKey).getModulus(); |
|
1899 |
attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(n))); |
|
1900 |
} else if (alg.equals("DSA") && (publicKey instanceof DSAPublicKey)) { |
|
1901 |
BigInteger y = ((DSAPublicKey)publicKey).getY(); |
|
1902 |
if (id) { |
|
1903 |
attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(y))); |
|
1904 |
} |
|
1905 |
if (netscapeDb) { |
|
1906 |
attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, y); |
|
1907 |
} |
|
1908 |
} else if (alg.equals("DH") && (publicKey instanceof DHPublicKey)) { |
|
1909 |
BigInteger y = ((DHPublicKey)publicKey).getY(); |
|
1910 |
if (id) { |
|
1911 |
attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(getMagnitude(y))); |
|
1912 |
} |
|
1913 |
if (netscapeDb) { |
|
1914 |
attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, y); |
|
1915 |
} |
|
1916 |
} else if (alg.equals("EC") && (publicKey instanceof ECPublicKey)) { |
|
1917 |
ECPublicKey ecPub = (ECPublicKey)publicKey; |
|
1918 |
ECPoint point = ecPub.getW(); |
|
1919 |
ECParameterSpec params = ecPub.getParams(); |
|
17491
7a33824ec8c5
7194075: Various classes of sunec.jar are duplicated in rt.jar
vinnie
parents:
10336
diff
changeset
|
1920 |
byte[] encodedPoint = ECUtil.encodePoint(point, params.getCurve()); |
2 | 1921 |
if (id) { |
1922 |
attrs[0] = new CK_ATTRIBUTE(CKA_ID, sha1(encodedPoint)); |
|
1923 |
} |
|
1924 |
if (netscapeDb) { |
|
1925 |
attrs[1] = new CK_ATTRIBUTE(CKA_NETSCAPE_DB, encodedPoint); |
|
1926 |
} |
|
1927 |
} else { |
|
1928 |
throw new RuntimeException("Unknown key algorithm " + alg); |
|
1929 |
} |
|
1930 |
return attrs; |
|
1931 |
} |
|
1932 |
||
1933 |
/** |
|
1934 |
* return true if cert destroyed |
|
1935 |
*/ |
|
1936 |
private boolean destroyCert(byte[] cka_id) |
|
1937 |
throws PKCS11Exception, KeyStoreException { |
|
1938 |
Session session = null; |
|
1939 |
try { |
|
1940 |
session = token.getOpSession(); |
|
1941 |
THandle h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); |
|
1942 |
if (h.type != ATTR_CLASS_CERT) { |
|
1943 |
return false; |
|
1944 |
} |
|
1945 |
||
1946 |
token.p11.C_DestroyObject(session.id(), h.handle); |
|
1947 |
if (debug != null) { |
|
1948 |
debug.println("destroyCert destroyed cert with CKA_ID [" + |
|
1949 |
getID(cka_id) + |
|
1950 |
"]"); |
|
1951 |
} |
|
1952 |
return true; |
|
1953 |
} finally { |
|
1954 |
token.releaseSession(session); |
|
1955 |
} |
|
1956 |
} |
|
1957 |
||
1958 |
/** |
|
1959 |
* return true if chain destroyed |
|
1960 |
*/ |
|
1961 |
private boolean destroyChain(byte[] cka_id) |
|
1962 |
throws PKCS11Exception, CertificateException, KeyStoreException { |
|
1963 |
||
1964 |
Session session = null; |
|
1965 |
try { |
|
1966 |
session = token.getOpSession(); |
|
1967 |
||
1968 |
THandle h = getTokenObject(session, ATTR_CLASS_CERT, cka_id, null); |
|
1969 |
if (h.type != ATTR_CLASS_CERT) { |
|
1970 |
if (debug != null) { |
|
1971 |
debug.println("destroyChain could not find " + |
|
1972 |
"end entity cert with CKA_ID [0x" + |
|
1973 |
Functions.toHexString(cka_id) + |
|
1974 |
"]"); |
|
1975 |
} |
|
1976 |
return false; |
|
1977 |
} |
|
1978 |
||
1979 |
X509Certificate endCert = loadCert(session, h.handle); |
|
1980 |
token.p11.C_DestroyObject(session.id(), h.handle); |
|
1981 |
if (debug != null) { |
|
1982 |
debug.println("destroyChain destroyed end entity cert " + |
|
1983 |
"with CKA_ID [" + |
|
1984 |
getID(cka_id) + |
|
1985 |
"]"); |
|
1986 |
} |
|
1987 |
||
1988 |
// build chain following issuer->subject links |
|
1989 |
||
1990 |
X509Certificate next = endCert; |
|
1991 |
while (true) { |
|
1992 |
||
1993 |
if (next.getSubjectX500Principal().equals |
|
1994 |
(next.getIssuerX500Principal())) { |
|
1995 |
// self signed - done |
|
1996 |
break; |
|
1997 |
} |
|
1998 |
||
1999 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
2000 |
ATTR_TOKEN_TRUE, |
|
2001 |
ATTR_CLASS_CERT, |
|
2002 |
new CK_ATTRIBUTE(CKA_SUBJECT, |
|
2003 |
next.getIssuerX500Principal().getEncoded()) }; |
|
2004 |
long[] ch = findObjects(session, attrs); |
|
2005 |
||
2006 |
if (ch == null || ch.length == 0) { |
|
2007 |
// done |
|
2008 |
break; |
|
2009 |
} else { |
|
2010 |
// if more than one found, use first |
|
2011 |
if (debug != null && ch.length > 1) { |
|
2012 |
debug.println("destroyChain found " + |
|
2013 |
ch.length + |
|
2014 |
" certificate entries for subject [" + |
|
2015 |
next.getIssuerX500Principal() + |
|
2016 |
"] in token - using first entry"); |
|
2017 |
} |
|
2018 |
||
2019 |
next = loadCert(session, ch[0]); |
|
2020 |
||
2021 |
// only delete if not part of any other chain |
|
2022 |
||
2023 |
attrs = new CK_ATTRIBUTE[] { |
|
2024 |
ATTR_TOKEN_TRUE, |
|
2025 |
ATTR_CLASS_CERT, |
|
2026 |
new CK_ATTRIBUTE(CKA_ISSUER, |
|
2027 |
next.getSubjectX500Principal().getEncoded()) }; |
|
2028 |
long[] issuers = findObjects(session, attrs); |
|
2029 |
||
2030 |
boolean destroyIt = false; |
|
2031 |
if (issuers == null || issuers.length == 0) { |
|
2032 |
// no other certs with this issuer - |
|
2033 |
// destroy it |
|
2034 |
destroyIt = true; |
|
2035 |
} else if (issuers.length == 1) { |
|
2036 |
X509Certificate iCert = loadCert(session, issuers[0]); |
|
2037 |
if (next.equals(iCert)) { |
|
2038 |
// only cert with issuer is itself (self-signed) - |
|
2039 |
// destroy it |
|
2040 |
destroyIt = true; |
|
2041 |
} |
|
2042 |
} |
|
2043 |
||
2044 |
if (destroyIt) { |
|
2045 |
token.p11.C_DestroyObject(session.id(), ch[0]); |
|
2046 |
if (debug != null) { |
|
2047 |
debug.println |
|
2048 |
("destroyChain destroyed cert in chain " + |
|
2049 |
"with subject [" + |
|
2050 |
next.getSubjectX500Principal() + "]"); |
|
2051 |
} |
|
2052 |
} else { |
|
2053 |
if (debug != null) { |
|
2054 |
debug.println("destroyChain did not destroy " + |
|
2055 |
"shared cert in chain with subject [" + |
|
2056 |
next.getSubjectX500Principal() + "]"); |
|
2057 |
} |
|
2058 |
} |
|
2059 |
} |
|
2060 |
} |
|
2061 |
||
2062 |
return true; |
|
2063 |
||
2064 |
} finally { |
|
2065 |
token.releaseSession(session); |
|
2066 |
} |
|
2067 |
} |
|
2068 |
||
2069 |
/** |
|
2070 |
* return true if secret key destroyed |
|
2071 |
*/ |
|
2072 |
private boolean destroySkey(String alias) |
|
2073 |
throws PKCS11Exception, KeyStoreException { |
|
2074 |
Session session = null; |
|
2075 |
try { |
|
2076 |
session = token.getOpSession(); |
|
2077 |
||
2078 |
THandle h = getTokenObject(session, ATTR_CLASS_SKEY, null, alias); |
|
2079 |
if (h.type != ATTR_CLASS_SKEY) { |
|
2080 |
if (debug != null) { |
|
2081 |
debug.println("destroySkey did not find secret key " + |
|
2082 |
"with CKA_LABEL [" + |
|
2083 |
alias + |
|
2084 |
"]"); |
|
2085 |
} |
|
2086 |
return false; |
|
2087 |
} |
|
2088 |
token.p11.C_DestroyObject(session.id(), h.handle); |
|
2089 |
return true; |
|
2090 |
} finally { |
|
2091 |
token.releaseSession(session); |
|
2092 |
} |
|
2093 |
} |
|
2094 |
||
2095 |
/** |
|
2096 |
* return true if private key destroyed |
|
2097 |
*/ |
|
2098 |
private boolean destroyPkey(byte[] cka_id) |
|
2099 |
throws PKCS11Exception, KeyStoreException { |
|
2100 |
Session session = null; |
|
2101 |
try { |
|
2102 |
session = token.getOpSession(); |
|
2103 |
||
2104 |
THandle h = getTokenObject(session, ATTR_CLASS_PKEY, cka_id, null); |
|
2105 |
if (h.type != ATTR_CLASS_PKEY) { |
|
2106 |
if (debug != null) { |
|
2107 |
debug.println |
|
2108 |
("destroyPkey did not find private key with CKA_ID [" + |
|
2109 |
getID(cka_id) + |
|
2110 |
"]"); |
|
2111 |
} |
|
2112 |
return false; |
|
2113 |
} |
|
2114 |
token.p11.C_DestroyObject(session.id(), h.handle); |
|
2115 |
return true; |
|
2116 |
} finally { |
|
2117 |
token.releaseSession(session); |
|
2118 |
} |
|
2119 |
} |
|
2120 |
||
2121 |
/** |
|
2122 |
* build [alias + issuer + serialNumber] string from a cert |
|
2123 |
*/ |
|
2124 |
private String getID(String alias, X509Certificate cert) { |
|
2125 |
X500Principal issuer = cert.getIssuerX500Principal(); |
|
2126 |
BigInteger serialNum = cert.getSerialNumber(); |
|
2127 |
||
2128 |
return alias + |
|
2129 |
ALIAS_SEP + |
|
2130 |
issuer.getName(X500Principal.CANONICAL) + |
|
2131 |
ALIAS_SEP + |
|
2132 |
serialNum.toString(); |
|
2133 |
} |
|
2134 |
||
2135 |
/** |
|
2136 |
* build CKA_ID string from bytes |
|
2137 |
*/ |
|
2138 |
private static String getID(byte[] bytes) { |
|
2139 |
boolean printable = true; |
|
2140 |
for (int i = 0; i < bytes.length; i++) { |
|
2141 |
if (!DerValue.isPrintableStringChar((char)bytes[i])) { |
|
2142 |
printable = false; |
|
2143 |
break; |
|
2144 |
} |
|
2145 |
} |
|
2146 |
||
2147 |
if (!printable) { |
|
2148 |
return "0x" + Functions.toHexString(bytes); |
|
2149 |
} else { |
|
2150 |
try { |
|
2151 |
return new String(bytes, "UTF-8"); |
|
2152 |
} catch (UnsupportedEncodingException uee) { |
|
2153 |
return "0x" + Functions.toHexString(bytes); |
|
2154 |
} |
|
2155 |
} |
|
2156 |
} |
|
2157 |
||
2158 |
/** |
|
2159 |
* find an object on the token |
|
2160 |
* |
|
2161 |
* @param type either ATTR_CLASS_CERT, ATTR_CLASS_PKEY, or ATTR_CLASS_SKEY |
|
2162 |
* @param cka_id the CKA_ID if type is ATTR_CLASS_CERT or ATTR_CLASS_PKEY |
|
2163 |
* @param cka_label the CKA_LABEL if type is ATTR_CLASS_SKEY |
|
2164 |
*/ |
|
2165 |
private THandle getTokenObject(Session session, |
|
2166 |
CK_ATTRIBUTE type, |
|
2167 |
byte[] cka_id, |
|
2168 |
String cka_label) |
|
2169 |
throws PKCS11Exception, KeyStoreException { |
|
2170 |
||
2171 |
CK_ATTRIBUTE[] attrs; |
|
2172 |
if (type == ATTR_CLASS_SKEY) { |
|
2173 |
attrs = new CK_ATTRIBUTE[] { |
|
2174 |
ATTR_SKEY_TOKEN_TRUE, |
|
2175 |
new CK_ATTRIBUTE(CKA_LABEL, cka_label), |
|
2176 |
type }; |
|
2177 |
} else { |
|
2178 |
attrs = new CK_ATTRIBUTE[] { |
|
2179 |
ATTR_TOKEN_TRUE, |
|
2180 |
new CK_ATTRIBUTE(CKA_ID, cka_id), |
|
2181 |
type }; |
|
2182 |
} |
|
2183 |
long[] h = findObjects(session, attrs); |
|
2184 |
if (h.length == 0) { |
|
2185 |
if (debug != null) { |
|
2186 |
if (type == ATTR_CLASS_SKEY) { |
|
2187 |
debug.println("getTokenObject did not find secret key " + |
|
2188 |
"with CKA_LABEL [" + |
|
2189 |
cka_label + |
|
2190 |
"]"); |
|
2191 |
} else if (type == ATTR_CLASS_CERT) { |
|
2192 |
debug.println |
|
2193 |
("getTokenObject did not find cert with CKA_ID [" + |
|
2194 |
getID(cka_id) + |
|
2195 |
"]"); |
|
2196 |
} else { |
|
2197 |
debug.println("getTokenObject did not find private key " + |
|
2198 |
"with CKA_ID [" + |
|
2199 |
getID(cka_id) + |
|
2200 |
"]"); |
|
2201 |
} |
|
2202 |
} |
|
2203 |
} else if (h.length == 1) { |
|
2204 |
||
2205 |
// found object handle - return it |
|
2206 |
return new THandle(h[0], type); |
|
2207 |
||
2208 |
} else { |
|
2209 |
||
2210 |
// found multiple object handles - |
|
2211 |
// see if token ignored CKA_LABEL during search (e.g. NSS) |
|
2212 |
||
2213 |
if (type == ATTR_CLASS_SKEY) { |
|
2214 |
||
2215 |
ArrayList<THandle> list = new ArrayList<THandle>(h.length); |
|
2216 |
for (int i = 0; i < h.length; i++) { |
|
2217 |
||
2218 |
CK_ATTRIBUTE[] label = new CK_ATTRIBUTE[] |
|
2219 |
{ new CK_ATTRIBUTE(CKA_LABEL) }; |
|
2220 |
token.p11.C_GetAttributeValue(session.id(), h[i], label); |
|
2221 |
if (label[0].pValue != null && |
|
2222 |
cka_label.equals(new String(label[0].getCharArray()))) { |
|
2223 |
list.add(new THandle(h[i], ATTR_CLASS_SKEY)); |
|
2224 |
} |
|
2225 |
} |
|
2226 |
if (list.size() == 1) { |
|
2227 |
// yes, there was only one CKA_LABEL that matched |
|
2228 |
return list.get(0); |
|
2229 |
} else { |
|
2230 |
throw new KeyStoreException("invalid KeyStore state: " + |
|
2231 |
"found " + |
|
2232 |
list.size() + |
|
2233 |
" secret keys sharing CKA_LABEL [" + |
|
2234 |
cka_label + |
|
2235 |
"]"); |
|
2236 |
} |
|
2237 |
} else if (type == ATTR_CLASS_CERT) { |
|
2238 |
throw new KeyStoreException("invalid KeyStore state: " + |
|
2239 |
"found " + |
|
2240 |
h.length + |
|
2241 |
" certificates sharing CKA_ID " + |
|
2242 |
getID(cka_id)); |
|
2243 |
} else { |
|
2244 |
throw new KeyStoreException("invalid KeyStore state: " + |
|
2245 |
"found " + |
|
2246 |
h.length + |
|
2247 |
" private keys sharing CKA_ID " + |
|
2248 |
getID(cka_id)); |
|
2249 |
} |
|
2250 |
} |
|
2251 |
return new THandle(NO_HANDLE, null); |
|
2252 |
} |
|
2253 |
||
2254 |
/** |
|
2255 |
* Create a mapping of all key pairs, trusted certs, and secret keys |
|
2256 |
* on the token into logical KeyStore entries unambiguously |
|
2257 |
* accessible via an alias. |
|
2258 |
* |
|
2259 |
* If the token is removed, the map may contain stale values. |
|
2260 |
* KeyStore.load should be called to re-create the map. |
|
2261 |
* |
|
2262 |
* Assume all private keys and matching certs share a unique CKA_ID. |
|
2263 |
* |
|
2264 |
* Assume all secret keys have a unique CKA_LABEL. |
|
2265 |
* |
|
2266 |
* @return true if multiple certs found sharing the same CKA_LABEL |
|
2267 |
* (if so, write capabilities are disabled) |
|
2268 |
*/ |
|
2269 |
private boolean mapLabels() throws |
|
2270 |
PKCS11Exception, CertificateException, KeyStoreException { |
|
2271 |
||
2272 |
CK_ATTRIBUTE[] trustedAttr = new CK_ATTRIBUTE[] { |
|
2273 |
new CK_ATTRIBUTE(CKA_TRUSTED) }; |
|
2274 |
||
2275 |
Session session = null; |
|
2276 |
try { |
|
2277 |
session = token.getOpSession(); |
|
2278 |
||
2279 |
// get all private key CKA_IDs |
|
2280 |
||
2281 |
ArrayList<byte[]> pkeyIDs = new ArrayList<byte[]>(); |
|
2282 |
CK_ATTRIBUTE[] attrs = new CK_ATTRIBUTE[] { |
|
2283 |
ATTR_TOKEN_TRUE, |
|
2284 |
ATTR_CLASS_PKEY, |
|
2285 |
}; |
|
2286 |
long[] handles = findObjects(session, attrs); |
|
2287 |
||
2288 |
for (long handle : handles) { |
|
2289 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID) }; |
|
2290 |
token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
|
2291 |
||
2292 |
if (attrs[0].pValue != null) { |
|
2293 |
pkeyIDs.add(attrs[0].getByteArray()); |
|
2294 |
} |
|
2295 |
} |
|
2296 |
||
2297 |
// Get all certificates |
|
2298 |
// |
|
2299 |
// If cert does not have a CKA_LABEL nor CKA_ID, it is ignored. |
|
2300 |
// |
|
2301 |
// Get the CKA_LABEL for each cert |
|
2302 |
// (if the cert does not have a CKA_LABEL, use the CKA_ID). |
|
2303 |
// |
|
2304 |
// Map each cert to the its CKA_LABEL |
|
2305 |
// (multiple certs may be mapped to a single CKA_LABEL) |
|
2306 |
||
2307 |
HashMap<String, HashSet<AliasInfo>> certMap = |
|
2308 |
new HashMap<String, HashSet<AliasInfo>>(); |
|
2309 |
||
2310 |
attrs = new CK_ATTRIBUTE[] { |
|
2311 |
ATTR_TOKEN_TRUE, |
|
2312 |
ATTR_CLASS_CERT, |
|
2313 |
}; |
|
2314 |
handles = findObjects(session, attrs); |
|
2315 |
||
2316 |
for (long handle : handles) { |
|
2317 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_LABEL) }; |
|
2318 |
||
2319 |
String cka_label = null; |
|
2320 |
byte[] cka_id = null; |
|
2321 |
try { |
|
2322 |
token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
|
2323 |
if (attrs[0].pValue != null) { |
|
2324 |
// there is a CKA_LABEL |
|
2325 |
cka_label = new String(attrs[0].getCharArray()); |
|
2326 |
} |
|
2327 |
} catch (PKCS11Exception pe) { |
|
2328 |
if (pe.getErrorCode() != CKR_ATTRIBUTE_TYPE_INVALID) { |
|
2329 |
throw pe; |
|
2330 |
} |
|
2331 |
||
2332 |
// GetAttributeValue for CKA_LABEL not supported |
|
2333 |
// |
|
2334 |
// XXX SCA1000 |
|
2335 |
} |
|
2336 |
||
2337 |
// get CKA_ID |
|
2338 |
||
2339 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_ID) }; |
|
2340 |
token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
|
2341 |
if (attrs[0].pValue == null) { |
|
2342 |
if (cka_label == null) { |
|
2343 |
// no cka_label nor cka_id - ignore |
|
2344 |
continue; |
|
2345 |
} |
|
2346 |
} else { |
|
2347 |
if (cka_label == null) { |
|
2348 |
// use CKA_ID as CKA_LABEL |
|
2349 |
cka_label = getID(attrs[0].getByteArray()); |
|
2350 |
} |
|
2351 |
cka_id = attrs[0].getByteArray(); |
|
2352 |
} |
|
2353 |
||
2354 |
X509Certificate cert = loadCert(session, handle); |
|
2355 |
||
2356 |
// get CKA_TRUSTED |
|
2357 |
||
2358 |
boolean cka_trusted = false; |
|
2359 |
||
2360 |
if (useSecmodTrust) { |
|
2361 |
cka_trusted = Secmod.getInstance().isTrusted(cert, nssTrustType); |
|
2362 |
} else { |
|
2363 |
if (CKA_TRUSTED_SUPPORTED) { |
|
2364 |
try { |
|
2365 |
token.p11.C_GetAttributeValue |
|
2366 |
(session.id(), handle, trustedAttr); |
|
2367 |
cka_trusted = trustedAttr[0].getBoolean(); |
|
2368 |
} catch (PKCS11Exception pe) { |
|
2369 |
if (pe.getErrorCode() == CKR_ATTRIBUTE_TYPE_INVALID) { |
|
2370 |
// XXX NSS, ibutton, sca1000 |
|
2371 |
CKA_TRUSTED_SUPPORTED = false; |
|
2372 |
if (debug != null) { |
|
2373 |
debug.println |
|
2374 |
("CKA_TRUSTED attribute not supported"); |
|
2375 |
} |
|
2376 |
} |
|
2377 |
} |
|
2378 |
} |
|
2379 |
} |
|
2380 |
||
2381 |
HashSet<AliasInfo> infoSet = certMap.get(cka_label); |
|
2382 |
if (infoSet == null) { |
|
2383 |
infoSet = new HashSet<AliasInfo>(2); |
|
2384 |
certMap.put(cka_label, infoSet); |
|
2385 |
} |
|
2386 |
||
2387 |
// initially create private key entry AliasInfo entries - |
|
2388 |
// these entries will get resolved into their true |
|
2389 |
// entry types later |
|
2390 |
||
2391 |
infoSet.add(new AliasInfo |
|
2392 |
(cka_label, |
|
2393 |
cka_id, |
|
2394 |
cka_trusted, |
|
2395 |
cert)); |
|
2396 |
} |
|
2397 |
||
2398 |
// create list secret key CKA_LABELS - |
|
2399 |
// if there are duplicates (either between secret keys, |
|
2400 |
// or between a secret key and another object), |
|
2401 |
// throw an exception |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2402 |
HashMap<String, AliasInfo> sKeyMap = |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2403 |
new HashMap<String, AliasInfo>(); |
2 | 2404 |
|
2405 |
attrs = new CK_ATTRIBUTE[] { |
|
2406 |
ATTR_SKEY_TOKEN_TRUE, |
|
2407 |
ATTR_CLASS_SKEY, |
|
2408 |
}; |
|
2409 |
handles = findObjects(session, attrs); |
|
2410 |
||
2411 |
for (long handle : handles) { |
|
2412 |
attrs = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_LABEL) }; |
|
2413 |
token.p11.C_GetAttributeValue(session.id(), handle, attrs); |
|
2414 |
if (attrs[0].pValue != null) { |
|
2415 |
||
2416 |
// there is a CKA_LABEL |
|
2417 |
String cka_label = new String(attrs[0].getCharArray()); |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2418 |
if (sKeyMap.get(cka_label) == null) { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2419 |
sKeyMap.put(cka_label, new AliasInfo(cka_label)); |
2 | 2420 |
} else { |
2421 |
throw new KeyStoreException("invalid KeyStore state: " + |
|
2422 |
"found multiple secret keys sharing same " + |
|
2423 |
"CKA_LABEL [" + |
|
2424 |
cka_label + |
|
2425 |
"]"); |
|
2426 |
} |
|
2427 |
} |
|
2428 |
} |
|
2429 |
||
2430 |
// update global aliasMap with alias mappings |
|
2431 |
ArrayList<AliasInfo> matchedCerts = |
|
2432 |
mapPrivateKeys(pkeyIDs, certMap); |
|
2433 |
boolean sharedLabel = mapCerts(matchedCerts, certMap); |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2434 |
mapSecretKeys(sKeyMap); |
2 | 2435 |
|
2436 |
return sharedLabel; |
|
2437 |
||
2438 |
} finally { |
|
2439 |
token.releaseSession(session); |
|
2440 |
} |
|
2441 |
} |
|
2442 |
||
2443 |
/** |
|
2444 |
* for each private key CKA_ID, find corresponding cert with same CKA_ID. |
|
2445 |
* if found cert, see if cert CKA_LABEL is unique. |
|
2446 |
* if CKA_LABEL unique, map private key/cert alias to that CKA_LABEL. |
|
2447 |
* if CKA_LABEL not unique, map private key/cert alias to: |
|
2448 |
* CKA_LABEL + ALIAS_SEP + ISSUER + ALIAS_SEP + SERIAL |
|
2449 |
* if cert not found, ignore private key |
|
2450 |
* (don't support private key entries without a cert chain yet) |
|
2451 |
* |
|
2452 |
* @return a list of AliasInfo entries that represents all matches |
|
2453 |
*/ |
|
2454 |
private ArrayList<AliasInfo> mapPrivateKeys(ArrayList<byte[]> pkeyIDs, |
|
2455 |
HashMap<String, HashSet<AliasInfo>> certMap) |
|
2456 |
throws PKCS11Exception, CertificateException { |
|
2457 |
||
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2458 |
// reset global alias map |
2 | 2459 |
aliasMap = new HashMap<String, AliasInfo>(); |
2460 |
||
2461 |
// list of matched certs that we will return |
|
2462 |
ArrayList<AliasInfo> matchedCerts = new ArrayList<AliasInfo>(); |
|
2463 |
||
2464 |
for (byte[] pkeyID : pkeyIDs) { |
|
2465 |
||
2466 |
// try to find a matching CKA_ID in a certificate |
|
2467 |
||
2468 |
boolean foundMatch = false; |
|
2469 |
Set<String> certLabels = certMap.keySet(); |
|
2470 |
for (String certLabel : certLabels) { |
|
2471 |
||
2472 |
// get cert CKA_IDs (if present) for each cert |
|
2473 |
||
2474 |
HashSet<AliasInfo> infoSet = certMap.get(certLabel); |
|
2475 |
for (AliasInfo aliasInfo : infoSet) { |
|
2476 |
if (Arrays.equals(pkeyID, aliasInfo.id)) { |
|
2477 |
||
2478 |
// found private key with matching cert |
|
2479 |
||
2480 |
if (infoSet.size() == 1) { |
|
2481 |
// unique CKA_LABEL - use certLabel as alias |
|
2482 |
aliasInfo.matched = true; |
|
2483 |
aliasMap.put(certLabel, aliasInfo); |
|
2484 |
} else { |
|
2485 |
// create new alias |
|
2486 |
aliasInfo.matched = true; |
|
2487 |
aliasMap.put(getID(certLabel, aliasInfo.cert), |
|
2488 |
aliasInfo); |
|
2489 |
} |
|
2490 |
matchedCerts.add(aliasInfo); |
|
2491 |
foundMatch = true; |
|
2492 |
break; |
|
2493 |
} |
|
2494 |
} |
|
2495 |
if (foundMatch) { |
|
2496 |
break; |
|
2497 |
} |
|
2498 |
} |
|
2499 |
||
2500 |
if (!foundMatch) { |
|
2501 |
if (debug != null) { |
|
2502 |
debug.println |
|
2503 |
("did not find match for private key with CKA_ID [" + |
|
2504 |
getID(pkeyID) + |
|
2505 |
"] (ignoring entry)"); |
|
2506 |
} |
|
2507 |
} |
|
2508 |
} |
|
2509 |
||
2510 |
return matchedCerts; |
|
2511 |
} |
|
2512 |
||
2513 |
/** |
|
2514 |
* for each cert not matched with a private key but is CKA_TRUSTED: |
|
2515 |
* if CKA_LABEL unique, map cert to CKA_LABEL. |
|
2516 |
* if CKA_LABEL not unique, map cert to [label+issuer+serialNum] |
|
2517 |
* |
|
2518 |
* if CKA_TRUSTED not supported, treat all certs not part of a chain |
|
2519 |
* as trusted |
|
2520 |
* |
|
2521 |
* @return true if multiple certs found sharing the same CKA_LABEL |
|
2522 |
*/ |
|
2523 |
private boolean mapCerts(ArrayList<AliasInfo> matchedCerts, |
|
2524 |
HashMap<String, HashSet<AliasInfo>> certMap) |
|
2525 |
throws PKCS11Exception, CertificateException { |
|
2526 |
||
2527 |
// load all cert chains |
|
2528 |
for (AliasInfo aliasInfo : matchedCerts) { |
|
2529 |
Session session = null; |
|
2530 |
try { |
|
2531 |
session = token.getOpSession(); |
|
2532 |
aliasInfo.chain = loadChain(session, aliasInfo.cert); |
|
2533 |
} finally { |
|
2534 |
token.releaseSession(session); |
|
2535 |
} |
|
2536 |
} |
|
2537 |
||
2538 |
// find all certs in certMap not part of a cert chain |
|
2539 |
// - these are trusted |
|
2540 |
||
2541 |
boolean sharedLabel = false; |
|
2542 |
||
2543 |
Set<String> certLabels = certMap.keySet(); |
|
2544 |
for (String certLabel : certLabels) { |
|
2545 |
HashSet<AliasInfo> infoSet = certMap.get(certLabel); |
|
2546 |
for (AliasInfo aliasInfo : infoSet) { |
|
2547 |
||
2548 |
if (aliasInfo.matched == true) { |
|
2549 |
// already found a private key match for this cert - |
|
2550 |
// just continue |
|
2551 |
aliasInfo.trusted = false; |
|
2552 |
continue; |
|
2553 |
} |
|
2554 |
||
2555 |
// cert in this aliasInfo is not matched yet |
|
2556 |
// |
|
2557 |
// if CKA_TRUSTED_SUPPORTED == true, |
|
2558 |
// then check if cert is trusted |
|
2559 |
||
2560 |
if (CKA_TRUSTED_SUPPORTED) { |
|
2561 |
if (aliasInfo.trusted) { |
|
2562 |
// trusted certificate |
|
2563 |
if (mapTrustedCert |
|
2564 |
(certLabel, aliasInfo, infoSet) == true) { |
|
2565 |
sharedLabel = true; |
|
2566 |
} |
|
2567 |
} |
|
2568 |
continue; |
|
2569 |
} |
|
2570 |
||
2571 |
// CKA_TRUSTED_SUPPORTED == false |
|
2572 |
// |
|
2573 |
// XXX treat all certs not part of a chain as trusted |
|
2574 |
// XXX |
|
2575 |
// XXX Unsupported |
|
2576 |
// |
|
2577 |
// boolean partOfChain = false; |
|
2578 |
// for (AliasInfo matchedInfo : matchedCerts) { |
|
2579 |
// for (int i = 0; i < matchedInfo.chain.length; i++) { |
|
2580 |
// if (matchedInfo.chain[i].equals(aliasInfo.cert)) { |
|
2581 |
// partOfChain = true; |
|
2582 |
// break; |
|
2583 |
// } |
|
2584 |
// } |
|
2585 |
// if (partOfChain) { |
|
2586 |
// break; |
|
2587 |
// } |
|
2588 |
// } |
|
2589 |
// |
|
2590 |
// if (!partOfChain) { |
|
2591 |
// if (mapTrustedCert(certLabel,aliasInfo,infoSet) == true){ |
|
2592 |
// sharedLabel = true; |
|
2593 |
// } |
|
2594 |
// } else { |
|
2595 |
// if (debug != null) { |
|
2596 |
// debug.println("ignoring unmatched/untrusted cert " + |
|
2597 |
// "that is part of cert chain - cert subject is [" + |
|
2598 |
// aliasInfo.cert.getSubjectX500Principal().getName |
|
2599 |
// (X500Principal.CANONICAL) + |
|
2600 |
// "]"); |
|
2601 |
// } |
|
2602 |
// } |
|
2603 |
} |
|
2604 |
} |
|
2605 |
||
2606 |
return sharedLabel; |
|
2607 |
} |
|
2608 |
||
2609 |
private boolean mapTrustedCert(String certLabel, |
|
2610 |
AliasInfo aliasInfo, |
|
2611 |
HashSet<AliasInfo> infoSet) { |
|
2612 |
||
2613 |
boolean sharedLabel = false; |
|
2614 |
||
2615 |
aliasInfo.type = ATTR_CLASS_CERT; |
|
2616 |
aliasInfo.trusted = true; |
|
2617 |
if (infoSet.size() == 1) { |
|
2618 |
// unique CKA_LABEL - use certLabel as alias |
|
2619 |
aliasMap.put(certLabel, aliasInfo); |
|
2620 |
} else { |
|
2621 |
// create new alias |
|
2622 |
sharedLabel = true; |
|
2623 |
aliasMap.put(getID(certLabel, aliasInfo.cert), aliasInfo); |
|
2624 |
} |
|
2625 |
||
2626 |
return sharedLabel; |
|
2627 |
} |
|
2628 |
||
2629 |
/** |
|
2630 |
* If the secret key shares a CKA_LABEL with another entry, |
|
2631 |
* throw an exception |
|
2632 |
*/ |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2633 |
private void mapSecretKeys(HashMap<String, AliasInfo> sKeyMap) |
2 | 2634 |
throws KeyStoreException { |
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2635 |
for (String label : sKeyMap.keySet()) { |
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2636 |
if (aliasMap.containsKey(label)) { |
2 | 2637 |
throw new KeyStoreException("invalid KeyStore state: " + |
2638 |
"found secret key sharing CKA_LABEL [" + |
|
2639 |
label + |
|
2640 |
"] with another token object"); |
|
2641 |
} |
|
2642 |
} |
|
291
be2e0a87d658
6599979: KeyStore.setEntry/setKeyEntry() do not override existing entry for secret key objects
valeriep
parents:
2
diff
changeset
|
2643 |
aliasMap.putAll(sKeyMap); |
2 | 2644 |
} |
2645 |
||
2646 |
private void dumpTokenMap() { |
|
2647 |
Set<String> aliases = aliasMap.keySet(); |
|
2648 |
System.out.println("Token Alias Map:"); |
|
10336
0bb1999251f8
7064075: Security libraries don't build with javac -Xlint:all,-deprecation -Werror
jjg
parents:
5506
diff
changeset
|
2649 |
if (aliases.isEmpty()) { |
2 | 2650 |
System.out.println(" [empty]"); |
2651 |
} else { |
|
2652 |
for (String s : aliases) { |
|
2653 |
System.out.println(" " + s + aliasMap.get(s)); |
|
2654 |
} |
|
2655 |
} |
|
2656 |
} |
|
2657 |
||
2658 |
private void checkWrite() throws KeyStoreException { |
|
2659 |
if (writeDisabled) { |
|
2660 |
throw new KeyStoreException |
|
2661 |
("This PKCS11KeyStore does not support write capabilities"); |
|
2662 |
} |
|
2663 |
} |
|
2664 |
||
2665 |
private final static long[] LONG0 = new long[0]; |
|
2666 |
||
2667 |
private static long[] findObjects(Session session, CK_ATTRIBUTE[] attrs) |
|
2668 |
throws PKCS11Exception { |
|
2669 |
Token token = session.token; |
|
2670 |
long[] handles = LONG0; |
|
2671 |
token.p11.C_FindObjectsInit(session.id(), attrs); |
|
2672 |
while (true) { |
|
2673 |
long[] h = token.p11.C_FindObjects(session.id(), FINDOBJECTS_MAX); |
|
2674 |
if (h.length == 0) { |
|
2675 |
break; |
|
2676 |
} |
|
2677 |
handles = P11Util.concat(handles, h); |
|
2678 |
} |
|
2679 |
token.p11.C_FindObjectsFinal(session.id()); |
|
2680 |
return handles; |
|
2681 |
} |
|
2682 |
||
2683 |
} |