alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (Token.java)

This example Java source code file (Token.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

check_interval, ck_attribute, ck_mechanism_info, invalid_mech, keycache, object, p11keyfactory, p11securerandom, pkcs11exception, providerexception, security, session, sessionmanager, threading, threads, token, tokenrep, util

The Token.java Java example source code

/*
 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.security.pkcs11;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.io.*;
import java.lang.ref.*;

import java.security.*;
import javax.security.auth.login.LoginException;

import sun.security.jca.JCAUtil;

import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;

/**
 * PKCS#11 token.
 *
 * @author  Andreas Sterbenz
 * @since   1.5
 */
class Token implements Serializable {

    // need to be serializable to allow SecureRandom to be serialized
    private static final long serialVersionUID = 2541527649100571747L;

    // how often to check if the token is still present (in ms)
    // this is different from checking if a token has been inserted,
    // that is done in SunPKCS11. Currently 50 ms.
    private final static long CHECK_INTERVAL = 50;

    final SunPKCS11 provider;

    final PKCS11 p11;

    final Config config;

    final CK_TOKEN_INFO tokenInfo;

    // session manager to pool sessions
    final SessionManager sessionManager;

    // template manager to customize the attributes used when creating objects
    private final TemplateManager templateManager;

    // flag indicating whether we need to explicitly cancel operations
    // we started on the token. If false, we assume operations are
    // automatically cancelled once we start another one
    final boolean explicitCancel;

    // translation cache for secret keys
    final KeyCache secretCache;

    // translation cache for asymmetric keys (public and private)
    final KeyCache privateCache;

    // cached instances of the various key factories, initialized on demand
    private volatile P11KeyFactory rsaFactory, dsaFactory, dhFactory, ecFactory;

    // table which maps mechanisms to the corresponding cached
    // MechanismInfo objects
    private final Map<Long, CK_MECHANISM_INFO> mechInfoMap;

    // single SecureRandomSpi instance we use per token
    // initialized on demand (if supported)
    private volatile P11SecureRandom secureRandom;

    // single KeyStoreSpi instance we use per provider
    // initialized on demand
    private volatile P11KeyStore keyStore;

    // whether this token is a removable token
    private final boolean removable;

    // for removable tokens: whether this token is valid or has been removed
    private volatile boolean valid;

    // for removable tokens: time last checked for token presence
    private long lastPresentCheck;

    // unique token id, used for serialization only
    private byte[] tokenId;

    // flag indicating whether the token is write protected
    private boolean writeProtected;

    // flag indicating whether we are logged in
    private volatile boolean loggedIn;

    // time we last checked login status
    private long lastLoginCheck;

    // mutex for token-present-check
    private final static Object CHECK_LOCK = new Object();

    // object for indicating unsupported mechanism in 'mechInfoMap'
    private final static CK_MECHANISM_INFO INVALID_MECH =
        new CK_MECHANISM_INFO(0, 0, 0);

    Token(SunPKCS11 provider) throws PKCS11Exception {
        this.provider = provider;
        this.removable = provider.removable;
        this.valid = true;
        p11 = provider.p11;
        config = provider.config;
        tokenInfo = p11.C_GetTokenInfo(provider.slotID);
        writeProtected = (tokenInfo.flags & CKF_WRITE_PROTECTED) != 0;
        // create session manager and open a test session
        SessionManager sessionManager;
        try {
            sessionManager = new SessionManager(this);
            Session s = sessionManager.getOpSession();
            sessionManager.releaseSession(s);
        } catch (PKCS11Exception e) {
            if (writeProtected) {
                throw e;
            }
            // token might not permit RW sessions even though
            // CKF_WRITE_PROTECTED is not set
            writeProtected = true;
            sessionManager = new SessionManager(this);
            Session s = sessionManager.getOpSession();
            sessionManager.releaseSession(s);
        }
        this.sessionManager = sessionManager;
        secretCache = new KeyCache();
        privateCache = new KeyCache();
        templateManager = config.getTemplateManager();
        explicitCancel = config.getExplicitCancel();
        mechInfoMap =
            new ConcurrentHashMap<Long, CK_MECHANISM_INFO>(10);
    }

    boolean isWriteProtected() {
        return writeProtected;
    }

    // return whether we are logged in
    // uses cached result if current. session is optional and may be null
    boolean isLoggedIn(Session session) throws PKCS11Exception {
        // volatile load first
        boolean loggedIn = this.loggedIn;
        long time = System.currentTimeMillis();
        if (time - lastLoginCheck > CHECK_INTERVAL) {
            loggedIn = isLoggedInNow(session);
            lastLoginCheck = time;
        }
        return loggedIn;
    }

    // return whether we are logged in now
    // does not use cache
    boolean isLoggedInNow(Session session) throws PKCS11Exception {
        boolean allocSession = (session == null);
        try {
            if (allocSession) {
                session = getOpSession();
            }
            CK_SESSION_INFO info = p11.C_GetSessionInfo(session.id());
            boolean loggedIn = (info.state == CKS_RO_USER_FUNCTIONS) ||
                                (info.state == CKS_RW_USER_FUNCTIONS);
            this.loggedIn = loggedIn;
            return loggedIn;
        } finally {
            if (allocSession) {
                releaseSession(session);
            }
        }
    }

    // ensure that we are logged in
    // call provider.login() if not
    void ensureLoggedIn(Session session) throws PKCS11Exception, LoginException {
        if (isLoggedIn(session) == false) {
            provider.login(null, null);
        }
    }

    // return whether this token object is valid (i.e. token not removed)
    // returns value from last check, does not perform new check
    boolean isValid() {
        if (removable == false) {
            return true;
        }
        return valid;
    }

    void ensureValid() {
        if (isValid() == false) {
            throw new ProviderException("Token has been removed");
        }
    }

    // return whether a token is present (i.e. token not removed)
    // returns cached value if current, otherwise performs new check
    boolean isPresent(long sessionID) {
        if (removable == false) {
            return true;
        }
        if (valid == false) {
            return false;
        }
        long time = System.currentTimeMillis();
        if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
            synchronized (CHECK_LOCK) {
                if ((time - lastPresentCheck) >= CHECK_INTERVAL) {
                    boolean ok = false;
                    try {
                        // check if token still present
                        CK_SLOT_INFO slotInfo =
                                provider.p11.C_GetSlotInfo(provider.slotID);
                        if ((slotInfo.flags & CKF_TOKEN_PRESENT) != 0) {
                            // if the token has been removed and re-inserted,
                            // the token should return an error
                            CK_SESSION_INFO sessInfo =
                                    provider.p11.C_GetSessionInfo
                                    (sessionID);
                            ok = true;
                        }
                    } catch (PKCS11Exception e) {
                        // empty
                    }
                    valid = ok;
                    lastPresentCheck = System.currentTimeMillis();
                    if (ok == false) {
                        destroy();
                    }
                }
            }
        }
        return valid;
    }

    void destroy() {
        valid = false;
        provider.uninitToken(this);
    }

    Session getObjSession() throws PKCS11Exception {
        return sessionManager.getObjSession();
    }

    Session getOpSession() throws PKCS11Exception {
        return sessionManager.getOpSession();
    }

    Session releaseSession(Session session) {
        return sessionManager.releaseSession(session);
    }

    Session killSession(Session session) {
        return sessionManager.killSession(session);
    }

    CK_ATTRIBUTE[] getAttributes(String op, long type, long alg,
            CK_ATTRIBUTE[] attrs) throws PKCS11Exception {
        CK_ATTRIBUTE[] newAttrs =
                    templateManager.getAttributes(op, type, alg, attrs);
        for (CK_ATTRIBUTE attr : newAttrs) {
            if (attr.type == CKA_TOKEN) {
                if (attr.getBoolean()) {
                    try {
                        ensureLoggedIn(null);
                    } catch (LoginException e) {
                        throw new ProviderException("Login failed", e);
                    }
                }
                // break once we have found a CKA_TOKEN attribute
                break;
            }
        }
        return newAttrs;
    }

    P11KeyFactory getKeyFactory(String algorithm) {
        P11KeyFactory f;
        if (algorithm.equals("RSA")) {
            f = rsaFactory;
            if (f == null) {
                f = new P11RSAKeyFactory(this, algorithm);
                rsaFactory = f;
            }
        } else if (algorithm.equals("DSA")) {
            f = dsaFactory;
            if (f == null) {
                f = new P11DSAKeyFactory(this, algorithm);
                dsaFactory = f;
            }
        } else if (algorithm.equals("DH")) {
            f = dhFactory;
            if (f == null) {
                f = new P11DHKeyFactory(this, algorithm);
                dhFactory = f;
            }
        } else if (algorithm.equals("EC")) {
            f = ecFactory;
            if (f == null) {
                f = new P11ECKeyFactory(this, algorithm);
                ecFactory = f;
            }
        } else {
            throw new ProviderException("Unknown algorithm " + algorithm);
        }
        return f;
    }

    P11SecureRandom getRandom() {
        if (secureRandom == null) {
            secureRandom = new P11SecureRandom(this);
        }
        return secureRandom;
    }

    P11KeyStore getKeyStore() {
        if (keyStore == null) {
            keyStore = new P11KeyStore(this);
        }
        return keyStore;
    }

    CK_MECHANISM_INFO getMechanismInfo(long mechanism) throws PKCS11Exception {
        CK_MECHANISM_INFO result = mechInfoMap.get(mechanism);
        if (result == null) {
            try {
                result = p11.C_GetMechanismInfo(provider.slotID,
                                                mechanism);
                mechInfoMap.put(mechanism, result);
            } catch (PKCS11Exception e) {
                if (e.getErrorCode() != PKCS11Constants.CKR_MECHANISM_INVALID) {
                    throw e;
                } else {
                    mechInfoMap.put(mechanism, INVALID_MECH);
                }
            }
        } else if (result == INVALID_MECH) {
            result = null;
        }
        return result;
    }

    private synchronized byte[] getTokenId() {
        if (tokenId == null) {
            SecureRandom random = JCAUtil.getSecureRandom();
            tokenId = new byte[20];
            random.nextBytes(tokenId);
            serializedTokens.add(new WeakReference<Token>(this));
        }
        return tokenId;
    }

    // list of all tokens that have been serialized within this VM
    // NOTE that elements are never removed from this list
    // the assumption is that the number of tokens that are serialized
    // is relatively small
    private static final List<Reference serializedTokens =
        new ArrayList<Reference();

    private Object writeReplace() throws ObjectStreamException {
        if (isValid() == false) {
            throw new NotSerializableException("Token has been removed");
        }
        return new TokenRep(this);
    }

    // serialized representation of a token
    // tokens can only be de-serialized within the same VM invocation
    // and if the token has not been removed in the meantime
    private static class TokenRep implements Serializable {

        private static final long serialVersionUID = 3503721168218219807L;

        private final byte[] tokenId;

        TokenRep(Token token) {
            tokenId = token.getTokenId();
        }

        private Object readResolve() throws ObjectStreamException {
            for (Reference<Token> tokenRef : serializedTokens) {
                Token token = tokenRef.get();
                if ((token != null) && token.isValid()) {
                    if (Arrays.equals(token.getTokenId(), tokenId)) {
                        return token;
                    }
                }
            }
            throw new NotSerializableException("Could not find token");
        }
    }

}

Other Java examples (source code examples)

Here is a short list of links related to this Java Token.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.