Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/pkcs11/Token.java
38919 views
1
/*
2
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
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
*
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.
24
*/
25
26
package sun.security.pkcs11;
27
28
import java.util.*;
29
import java.util.concurrent.ConcurrentHashMap;
30
import java.io.*;
31
import java.lang.ref.*;
32
33
import java.security.*;
34
import javax.security.auth.login.LoginException;
35
36
import sun.security.jca.JCAUtil;
37
38
import sun.security.pkcs11.wrapper.*;
39
import static sun.security.pkcs11.TemplateManager.*;
40
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
41
42
/**
43
* PKCS#11 token.
44
*
45
* @author Andreas Sterbenz
46
* @since 1.5
47
*/
48
class Token implements Serializable {
49
50
// need to be serializable to allow SecureRandom to be serialized
51
private static final long serialVersionUID = 2541527649100571747L;
52
53
// how often to check if the token is still present (in ms)
54
// this is different from checking if a token has been inserted,
55
// that is done in SunPKCS11. Currently 50 ms.
56
private final static long CHECK_INTERVAL = 50;
57
58
final SunPKCS11 provider;
59
60
final PKCS11 p11;
61
62
final Config config;
63
64
final CK_TOKEN_INFO tokenInfo;
65
66
// session manager to pool sessions
67
final SessionManager sessionManager;
68
69
// template manager to customize the attributes used when creating objects
70
private final TemplateManager templateManager;
71
72
// flag indicating whether we need to explicitly cancel operations
73
// we started on the token. If false, we assume operations are
74
// automatically cancelled once we start another one
75
final boolean explicitCancel;
76
77
// translation cache for secret keys
78
final KeyCache secretCache;
79
80
// translation cache for asymmetric keys (public and private)
81
final KeyCache privateCache;
82
83
// cached instances of the various key factories, initialized on demand
84
private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory;
85
86
// table which maps mechanisms to the corresponding cached
87
// MechanismInfo objects
88
private final Map<Long, CK_MECHANISM_INFO> mechInfoMap;
89
90
// single SecureRandomSpi instance we use per token
91
// initialized on demand (if supported)
92
private volatile P11SecureRandom secureRandom;
93
94
// single KeyStoreSpi instance we use per provider
95
// initialized on demand
96
private volatile P11KeyStore keyStore;
97
98
// whether this token is a removable token
99
private final boolean removable;
100
101
// for removable tokens: whether this token is valid or has been removed
102
private volatile boolean valid;
103
104
// for removable tokens: time last checked for token presence
105
private long lastPresentCheck;
106
107
// unique token id, used for serialization only
108
private byte[] tokenId;
109
110
// flag indicating whether the token is write protected
111
private boolean writeProtected;
112
113
// flag indicating whether we are logged in
114
private volatile boolean loggedIn;
115
116
// time we last checked login status
117
private long lastLoginCheck;
118
119
// mutex for token-present-check
120
private final static Object CHECK_LOCK = new Object();
121
122
// object for indicating unsupported mechanism in 'mechInfoMap'
123
private final static CK_MECHANISM_INFO INVALID_MECH =
124
new CK_MECHANISM_INFO(0, 0, 0);
125
126
// flag indicating whether the token supports raw secret key material import
127
private Boolean supportsRawSecretKeyImport;
128
129
Token(SunPKCS11 provider) throws PKCS11Exception {
130
this.provider = provider;
131
this.removable = provider.removable;
132
this.valid = true;
133
p11 = provider.p11;
134
config = provider.config;
135
tokenInfo = p11.C_GetTokenInfo(provider.slotID);
136
writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0;
137
// create session manager and open a test session
138
SessionManager sessionManager;
139
try {
140
sessionManager = new SessionManager(this);
141
Session s = sessionManager.getOpSession();
142
sessionManager.releaseSession(s);
143
} catch (PKCS11Exception e) {
144
if (writeProtected) {
145
throw e;
146
}
147
// token might not permit RW sessions even though
148
// CKF_WRITE_PROTECTED is not set
149
writeProtected = true;
150
sessionManager = new SessionManager(this);
151
Session s = sessionManager.getOpSession();
152
sessionManager.releaseSession(s);
153
}
154
this.sessionManager = sessionManager;
155
secretCache = new KeyCache();
156
privateCache = new KeyCache();
157
templateManager = config.getTemplateManager();
158
explicitCancel = config.getExplicitCancel();
159
mechInfoMap =
160
new ConcurrentHashMap<Long, CK_MECHANISM_INFO>(10);
161
}
162
163
boolean isWriteProtected() {
164
return writeProtected;
165
}
166
167
// return whether the token supports raw secret key material import
168
boolean supportsRawSecretKeyImport() {
169
if (supportsRawSecretKeyImport == null) {
170
SecureRandom random = JCAUtil.getSecureRandom();
171
byte[] encoded = new byte[48];
172
random.nextBytes(encoded);
173
174
CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[3];
175
attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
176
attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET);
177
attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
178
179
Session session = null;
180
try {
181
attributes = getAttributes(O_IMPORT,
182
CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);
183
session = getObjSession();
184
long keyID = p11.C_CreateObject(session.id(), attributes);
185
186
supportsRawSecretKeyImport = Boolean.TRUE;
187
} catch (PKCS11Exception e) {
188
supportsRawSecretKeyImport = Boolean.FALSE;
189
} finally {
190
releaseSession(session);
191
}
192
}
193
194
return supportsRawSecretKeyImport;
195
}
196
197
// return whether we are logged in
198
// uses cached result if current. session is optional and may be null
199
boolean isLoggedIn(Session session) throws PKCS11Exception {
200
// volatile load first
201
boolean loggedIn = this.loggedIn;
202
long time = System.currentTimeMillis();
203
if (time - lastLoginCheck > CHECK_INTERVAL) {
204
loggedIn = isLoggedInNow(session);
205
lastLoginCheck = time;
206
}
207
return loggedIn;
208
}
209
210
// return whether we are logged in now
211
// does not use cache
212
boolean isLoggedInNow(Session session) throws PKCS11Exception {
213
boolean allocSession = (session == null);
214
try {
215
if (allocSession) {
216
session = getOpSession();
217
}
218
CK_SESSION_INFO info = p11.C_GetSessionInfo(session.id());
219
boolean loggedIn = (info.state == CKS_RO_USER_FUNCTIONS) ||
220
(info.state == CKS_RW_USER_FUNCTIONS);
221
this.loggedIn = loggedIn;
222
return loggedIn;
223
} finally {
224
if (allocSession) {
225
releaseSession(session);
226
}
227
}
228
}
229
230
// ensure that we are logged in
231
// call provider.login() if not
232
void ensureLoggedIn(Session session) throws PKCS11Exception, LoginException {
233
if (isLoggedIn(session) == false) {
234
provider.login(null, null);
235
}
236
}
237
238
// return whether this token object is valid (i.e. token not removed)
239
// returns value from last check, does not perform new check
240
boolean isValid() {
241
if (removable == false) {
242
return true;
243
}
244
return valid;
245
}
246
247
void ensureValid() {
248
if (isValid() == false) {
249
throw new ProviderException("Token has been removed");
250
}
251
}
252
253
// return whether a token is present (i.e. token not removed)
254
// returns cached value if current, otherwise performs new check
255
boolean isPresent(long sessionID) {
256
if (removable == false) {
257
return true;
258
}
259
if (valid == false) {
260
return false;
261
}
262
long time = System.currentTimeMillis();
263
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
264
synchronized (CHECK_LOCK) {
265
if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
266
boolean ok = false;
267
try {
268
// check if token still present
269
CK_SLOT_INFO slotInfo =
270
provider.p11.C_GetSlotInfo(provider.slotID);
271
if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
272
// if the token has been removed and re-inserted,
273
// the token should return an error
274
CK_SESSION_INFO sessInfo =
275
provider.p11.C_GetSessionInfo
276
(sessionID);
277
ok = true;
278
}
279
} catch (PKCS11Exception e) {
280
// empty
281
}
282
valid = ok;
283
lastPresentCheck = System.currentTimeMillis();
284
if (ok == false) {
285
destroy();
286
}
287
}
288
}
289
}
290
return valid;
291
}
292
293
void destroy() {
294
valid = false;
295
provider.uninitToken(this);
296
}
297
298
Session getObjSession() throws PKCS11Exception {
299
return sessionManager.getObjSession();
300
}
301
302
Session getOpSession() throws PKCS11Exception {
303
return sessionManager.getOpSession();
304
}
305
306
Session releaseSession(Session session) {
307
return sessionManager.releaseSession(session);
308
}
309
310
Session killSession(Session session) {
311
return sessionManager.killSession(session);
312
}
313
314
CK_ATTRIBUTE[] getAttributes(String op, long type, long alg,
315
CK_ATTRIBUTE[] attrs) throws PKCS11Exception {
316
CK_ATTRIBUTE[] newAttrs =
317
templateManager.getAttributes(op, type, alg, attrs);
318
for (CK_ATTRIBUTE attr : newAttrs) {
319
if (attr.type == CKA_TOKEN) {
320
if (attr.getBoolean()) {
321
try {
322
ensureLoggedIn(null);
323
} catch (LoginException e) {
324
throw new ProviderException("Login failed", e);
325
}
326
}
327
// break once we have found a CKA_TOKEN attribute
328
break;
329
}
330
}
331
return newAttrs;
332
}
333
334
P11KeyFactory getKeyFactory(String algorithm) {
335
P11KeyFactory f;
336
if (algorithm.equals("RSA")) {
337
f = rsaFactory;
338
if (f == null) {
339
f = new P11RSAKeyFactory(this, algorithm);
340
rsaFactory = f;
341
}
342
} else if (algorithm.equals("DSA")) {
343
f = dsaFactory;
344
if (f == null) {
345
f = new P11DSAKeyFactory(this, algorithm);
346
dsaFactory = f;
347
}
348
} else if (algorithm.equals("DH")) {
349
f = dhFactory;
350
if (f == null) {
351
f = new P11DHKeyFactory(this, algorithm);
352
dhFactory = f;
353
}
354
} else if (algorithm.equals("EC")) {
355
f = ecFactory;
356
if (f == null) {
357
f = new P11ECKeyFactory(this, algorithm);
358
ecFactory = f;
359
}
360
} else {
361
throw new ProviderException("Unknown algorithm " + algorithm);
362
}
363
return f;
364
}
365
366
P11SecureRandom getRandom() {
367
if (secureRandom == null) {
368
secureRandom = new P11SecureRandom(this);
369
}
370
return secureRandom;
371
}
372
373
P11KeyStore getKeyStore() {
374
if (keyStore == null) {
375
keyStore = new P11KeyStore(this);
376
}
377
return keyStore;
378
}
379
380
CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception {
381
CK_MECHANISM_INFO result = mechInfoMap.get(mechanism);
382
if (result == null) {
383
try {
384
result = p11.C_GetMechanismInfo(provider.slotID,
385
mechanism);
386
mechInfoMap.put(mechanism, result);
387
} catch (PKCS11Exception e) {
388
if (e.getErrorCode() != PKCS11Constants.CKR_MECHANISM_INVALID) {
389
throw e;
390
} else {
391
mechInfoMap.put(mechanism, INVALID_MECH);
392
}
393
}
394
} else if (result == INVALID_MECH) {
395
result = null;
396
}
397
return result;
398
}
399
400
private synchronized byte[] getTokenId() {
401
if (tokenId == null) {
402
SecureRandom random = JCAUtil.getSecureRandom();
403
tokenId = new byte[20];
404
random.nextBytes(tokenId);
405
serializedTokens.add(new WeakReference<Token>(this));
406
}
407
return tokenId;
408
}
409
410
// list of all tokens that have been serialized within this VM
411
// NOTE that elements are never removed from this list
412
// the assumption is that the number of tokens that are serialized
413
// is relatively small
414
private static final List<Reference<Token>> serializedTokens =
415
new ArrayList<Reference<Token>>();
416
417
private Object writeReplace() throws ObjectStreamException {
418
if (isValid() == false) {
419
throw new NotSerializableException("Token has been removed");
420
}
421
return new TokenRep(this);
422
}
423
424
// serialized representation of a token
425
// tokens can only be de-serialized within the same VM invocation
426
// and if the token has not been removed in the meantime
427
private static class TokenRep implements Serializable {
428
429
private static final long serialVersionUID = 3503721168218219807L;
430
431
private final byte[] tokenId;
432
433
TokenRep(Token token) {
434
tokenId = token.getTokenId();
435
}
436
437
private Object readResolve() throws ObjectStreamException {
438
for (Reference<Token> tokenRef : serializedTokens) {
439
Token token = tokenRef.get();
440
if ((token != null) && token.isValid()) {
441
if (Arrays.equals(token.getTokenId(), tokenId)) {
442
return token;
443
}
444
}
445
}
446
throw new NotSerializableException("Could not find token");
447
}
448
}
449
450
}
451
452