jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Key.java
changeset 42939 e5d5f0f2d40d
parent 42938 c0b3077af726
parent 42767 8ea2f3d10b8c
child 42940 0d1409532a41
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Key.java	Tue Dec 06 14:54:11 2016 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1188 +0,0 @@
-/*
- * Copyright (c) 2003, 2016, 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.io.*;
-import java.lang.ref.*;
-import java.math.BigInteger;
-import java.util.*;
-
-import java.security.*;
-import java.security.interfaces.*;
-import java.security.spec.*;
-
-import javax.crypto.*;
-import javax.crypto.interfaces.*;
-import javax.crypto.spec.*;
-
-import sun.security.rsa.RSAPublicKeyImpl;
-
-import sun.security.internal.interfaces.TlsMasterSecret;
-
-import sun.security.pkcs11.wrapper.*;
-import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
-
-import sun.security.util.Debug;
-import sun.security.util.DerValue;
-import sun.security.util.Length;
-import sun.security.util.ECUtil;
-
-/**
- * Key implementation classes.
- *
- * In PKCS#11, the components of private and secret keys may or may not
- * be accessible. If they are, we use the algorithm specific key classes
- * (e.g. DSAPrivateKey) for compatibility with existing applications.
- * If the components are not accessible, we use a generic class that
- * only implements PrivateKey (or SecretKey). Whether the components of a
- * key are extractable is automatically determined when the key object is
- * created.
- *
- * @author  Andreas Sterbenz
- * @since   1.5
- */
-abstract class P11Key implements Key, Length {
-
-    private static final long serialVersionUID = -2575874101938349339L;
-
-    private final static String PUBLIC = "public";
-    private final static String PRIVATE = "private";
-    private final static String SECRET = "secret";
-
-    // type of key, one of (PUBLIC, PRIVATE, SECRET)
-    final String type;
-
-    // token instance
-    final Token token;
-
-    // algorithm name, returned by getAlgorithm(), etc.
-    final String algorithm;
-
-    // key id
-    final long keyID;
-
-    // effective key length of the key, e.g. 56 for a DES key
-    final int keyLength;
-
-    // flags indicating whether the key is a token object, sensitive, extractable
-    final boolean tokenObject, sensitive, extractable;
-
-    // phantom reference notification clean up for session keys
-    private final SessionKeyRef sessionKeyRef;
-
-    P11Key(String type, Session session, long keyID, String algorithm,
-            int keyLength, CK_ATTRIBUTE[] attributes) {
-        this.type = type;
-        this.token = session.token;
-        this.keyID = keyID;
-        this.algorithm = algorithm;
-        this.keyLength = keyLength;
-        boolean tokenObject = false;
-        boolean sensitive = false;
-        boolean extractable = true;
-        int n = (attributes == null) ? 0 : attributes.length;
-        for (int i = 0; i < n; i++) {
-            CK_ATTRIBUTE attr = attributes[i];
-            if (attr.type == CKA_TOKEN) {
-                tokenObject = attr.getBoolean();
-            } else if (attr.type == CKA_SENSITIVE) {
-                sensitive = attr.getBoolean();
-            } else if (attr.type == CKA_EXTRACTABLE) {
-                extractable = attr.getBoolean();
-            }
-        }
-        this.tokenObject = tokenObject;
-        this.sensitive = sensitive;
-        this.extractable = extractable;
-        if (tokenObject == false) {
-            sessionKeyRef = new SessionKeyRef(this, keyID, session);
-        } else {
-            sessionKeyRef = null;
-        }
-    }
-
-    // see JCA spec
-    public final String getAlgorithm() {
-        token.ensureValid();
-        return algorithm;
-    }
-
-    // see JCA spec
-    public final byte[] getEncoded() {
-        byte[] b = getEncodedInternal();
-        return (b == null) ? null : b.clone();
-    }
-
-    abstract byte[] getEncodedInternal();
-
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        // equals() should never throw exceptions
-        if (token.isValid() == false) {
-            return false;
-        }
-        if (obj instanceof Key == false) {
-            return false;
-        }
-        String thisFormat = getFormat();
-        if (thisFormat == null) {
-            // no encoding, key only equal to itself
-            // XXX getEncoded() for unextractable keys will change that
-            return false;
-        }
-        Key other = (Key)obj;
-        if (thisFormat.equals(other.getFormat()) == false) {
-            return false;
-        }
-        byte[] thisEnc = this.getEncodedInternal();
-        byte[] otherEnc;
-        if (obj instanceof P11Key) {
-            otherEnc = ((P11Key)other).getEncodedInternal();
-        } else {
-            otherEnc = other.getEncoded();
-        }
-        return MessageDigest.isEqual(thisEnc, otherEnc);
-    }
-
-    public int hashCode() {
-        // hashCode() should never throw exceptions
-        if (token.isValid() == false) {
-            return 0;
-        }
-        byte[] b1 = getEncodedInternal();
-        if (b1 == null) {
-            return 0;
-        }
-        int r = b1.length;
-        for (int i = 0; i < b1.length; i++) {
-            r += (b1[i] & 0xff) * 37;
-        }
-        return r;
-    }
-
-    protected Object writeReplace() throws ObjectStreamException {
-        KeyRep.Type type;
-        String format = getFormat();
-        if (isPrivate() && "PKCS#8".equals(format)) {
-            type = KeyRep.Type.PRIVATE;
-        } else if (isPublic() && "X.509".equals(format)) {
-            type = KeyRep.Type.PUBLIC;
-        } else if (isSecret() && "RAW".equals(format)) {
-            type = KeyRep.Type.SECRET;
-        } else {
-            // XXX short term serialization for unextractable keys
-            throw new NotSerializableException
-                ("Cannot serialize sensitive and unextractable keys");
-        }
-        return new KeyRep(type, getAlgorithm(), format, getEncoded());
-    }
-
-    public String toString() {
-        token.ensureValid();
-        String s1 = token.provider.getName() + " " + algorithm + " " + type
-                + " key, " + keyLength + " bits";
-        s1 += " (id " + keyID + ", "
-                + (tokenObject ? "token" : "session") + " object";
-        if (isPublic()) {
-            s1 += ")";
-        } else {
-            s1 += ", " + (sensitive ? "" : "not ") + "sensitive";
-            s1 += ", " + (extractable ? "" : "un") + "extractable)";
-        }
-        return s1;
-    }
-
-    /**
-     * Return bit length of the key.
-     */
-    @Override
-    public int length() {
-        return keyLength;
-    }
-
-    boolean isPublic() {
-        return type == PUBLIC;
-    }
-
-    boolean isPrivate() {
-        return type == PRIVATE;
-    }
-
-    boolean isSecret() {
-        return type == SECRET;
-    }
-
-    void fetchAttributes(CK_ATTRIBUTE[] attributes) {
-        Session tempSession = null;
-        try {
-            tempSession = token.getOpSession();
-            token.p11.C_GetAttributeValue(tempSession.id(), keyID, attributes);
-        } catch (PKCS11Exception e) {
-            throw new ProviderException(e);
-        } finally {
-            token.releaseSession(tempSession);
-        }
-    }
-
-    private final static CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];
-
-    private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,
-            CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {
-        if (knownAttributes == null) {
-            knownAttributes = A0;
-        }
-        for (int i = 0; i < desiredAttributes.length; i++) {
-            // For each desired attribute, check to see if we have the value
-            // available already. If everything is here, we save a native call.
-            CK_ATTRIBUTE attr = desiredAttributes[i];
-            for (CK_ATTRIBUTE known : knownAttributes) {
-                if ((attr.type == known.type) && (known.pValue != null)) {
-                    attr.pValue = known.pValue;
-                    break; // break inner for loop
-                }
-            }
-            if (attr.pValue == null) {
-                // nothing found, need to call C_GetAttributeValue()
-                for (int j = 0; j < i; j++) {
-                    // clear values copied from knownAttributes
-                    desiredAttributes[j].pValue = null;
-                }
-                try {
-                    session.token.p11.C_GetAttributeValue
-                            (session.id(), keyID, desiredAttributes);
-                } catch (PKCS11Exception e) {
-                    throw new ProviderException(e);
-                }
-                break; // break loop, goto return
-            }
-        }
-        return desiredAttributes;
-    }
-
-    static SecretKey secretKey(Session session, long keyID, String algorithm,
-            int keyLength, CK_ATTRIBUTE[] attributes) {
-        attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
-            new CK_ATTRIBUTE(CKA_TOKEN),
-            new CK_ATTRIBUTE(CKA_SENSITIVE),
-            new CK_ATTRIBUTE(CKA_EXTRACTABLE),
-        });
-        return new P11SecretKey(session, keyID, algorithm, keyLength, attributes);
-    }
-
-    static SecretKey masterSecretKey(Session session, long keyID, String algorithm,
-            int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
-        attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
-            new CK_ATTRIBUTE(CKA_TOKEN),
-            new CK_ATTRIBUTE(CKA_SENSITIVE),
-            new CK_ATTRIBUTE(CKA_EXTRACTABLE),
-        });
-        return new P11TlsMasterSecretKey
-                (session, keyID, algorithm, keyLength, attributes, major, minor);
-    }
-
-    // we assume that all components of public keys are always accessible
-    static PublicKey publicKey(Session session, long keyID, String algorithm,
-            int keyLength, CK_ATTRIBUTE[] attributes) {
-        switch (algorithm) {
-            case "RSA":
-                return new P11RSAPublicKey
-                    (session, keyID, algorithm, keyLength, attributes);
-            case "DSA":
-                return new P11DSAPublicKey
-                    (session, keyID, algorithm, keyLength, attributes);
-            case "DH":
-                return new P11DHPublicKey
-                    (session, keyID, algorithm, keyLength, attributes);
-            case "EC":
-                return new P11ECPublicKey
-                    (session, keyID, algorithm, keyLength, attributes);
-            default:
-                throw new ProviderException
-                    ("Unknown public key algorithm " + algorithm);
-        }
-    }
-
-    static PrivateKey privateKey(Session session, long keyID, String algorithm,
-            int keyLength, CK_ATTRIBUTE[] attributes) {
-        attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {
-            new CK_ATTRIBUTE(CKA_TOKEN),
-            new CK_ATTRIBUTE(CKA_SENSITIVE),
-            new CK_ATTRIBUTE(CKA_EXTRACTABLE),
-        });
-        if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {
-            return new P11PrivateKey
-                (session, keyID, algorithm, keyLength, attributes);
-        } else {
-            switch (algorithm) {
-                case "RSA":
-                    // In order to decide if this is RSA CRT key, we first query
-                    // and see if all extra CRT attributes are available.
-                    CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {
-                        new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
-                        new CK_ATTRIBUTE(CKA_PRIME_1),
-                        new CK_ATTRIBUTE(CKA_PRIME_2),
-                        new CK_ATTRIBUTE(CKA_EXPONENT_1),
-                        new CK_ATTRIBUTE(CKA_EXPONENT_2),
-                        new CK_ATTRIBUTE(CKA_COEFFICIENT),
-                    };
-                    boolean crtKey;
-                    try {
-                        session.token.p11.C_GetAttributeValue
-                            (session.id(), keyID, attrs2);
-                        crtKey = ((attrs2[0].pValue instanceof byte[]) &&
-                                  (attrs2[1].pValue instanceof byte[]) &&
-                                  (attrs2[2].pValue instanceof byte[]) &&
-                                  (attrs2[3].pValue instanceof byte[]) &&
-                                  (attrs2[4].pValue instanceof byte[]) &&
-                                  (attrs2[5].pValue instanceof byte[])) ;
-                    } catch (PKCS11Exception e) {
-                        // ignore, assume not available
-                        crtKey = false;
-                    }
-                    if (crtKey) {
-                        return new P11RSAPrivateKey
-                                (session, keyID, algorithm, keyLength, attributes, attrs2);
-                    } else {
-                        return new P11RSAPrivateNonCRTKey
-                                (session, keyID, algorithm, keyLength, attributes);
-                    }
-                case "DSA":
-                    return new P11DSAPrivateKey
-                            (session, keyID, algorithm, keyLength, attributes);
-                case "DH":
-                    return new P11DHPrivateKey
-                            (session, keyID, algorithm, keyLength, attributes);
-                case "EC":
-                    return new P11ECPrivateKey
-                            (session, keyID, algorithm, keyLength, attributes);
-                default:
-                    throw new ProviderException
-                            ("Unknown private key algorithm " + algorithm);
-            }
-        }
-    }
-
-    // class for sensitive and unextractable private keys
-    private static final class P11PrivateKey extends P11Key
-                                                implements PrivateKey {
-        private static final long serialVersionUID = -2138581185214187615L;
-
-        P11PrivateKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
-        }
-        // XXX temporary encoding for serialization purposes
-        public String getFormat() {
-            token.ensureValid();
-            return null;
-        }
-        byte[] getEncodedInternal() {
-            token.ensureValid();
-            return null;
-        }
-    }
-
-    private static class P11SecretKey extends P11Key implements SecretKey {
-        private static final long serialVersionUID = -7828241727014329084L;
-        private volatile byte[] encoded;
-        P11SecretKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(SECRET, session, keyID, algorithm, keyLength, attributes);
-        }
-        public String getFormat() {
-            token.ensureValid();
-            if (sensitive || (extractable == false)) {
-                return null;
-            } else {
-                return "RAW";
-            }
-        }
-        byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (getFormat() == null) {
-                return null;
-            }
-            byte[] b = encoded;
-            if (b == null) {
-                synchronized (this) {
-                    b = encoded;
-                    if (b == null) {
-                        Session tempSession = null;
-                        try {
-                            tempSession = token.getOpSession();
-                            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                                new CK_ATTRIBUTE(CKA_VALUE),
-                            };
-                            token.p11.C_GetAttributeValue
-                                (tempSession.id(), keyID, attributes);
-                            b = attributes[0].getByteArray();
-                        } catch (PKCS11Exception e) {
-                            throw new ProviderException(e);
-                        } finally {
-                            token.releaseSession(tempSession);
-                        }
-                        encoded = b;
-                    }
-                }
-            }
-            return b;
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private static class P11TlsMasterSecretKey extends P11SecretKey
-            implements TlsMasterSecret {
-        private static final long serialVersionUID = -1318560923770573441L;
-
-        private final int majorVersion, minorVersion;
-        P11TlsMasterSecretKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {
-            super(session, keyID, algorithm, keyLength, attributes);
-            this.majorVersion = major;
-            this.minorVersion = minor;
-        }
-        public int getMajorVersion() {
-            return majorVersion;
-        }
-
-        public int getMinorVersion() {
-            return minorVersion;
-        }
-    }
-
-    // RSA CRT private key
-    private static final class P11RSAPrivateKey extends P11Key
-                implements RSAPrivateCrtKey {
-        private static final long serialVersionUID = 9215872438913515220L;
-
-        private BigInteger n, e, d, p, q, pe, qe, coeff;
-        private byte[] encoded;
-        P11RSAPrivateKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attrs);
-
-            for (CK_ATTRIBUTE a : crtAttrs) {
-                if (a.type == CKA_PUBLIC_EXPONENT) {
-                    e = a.getBigInteger();
-                } else if (a.type == CKA_PRIME_1) {
-                    p = a.getBigInteger();
-                } else if (a.type == CKA_PRIME_2) {
-                    q = a.getBigInteger();
-                } else if (a.type == CKA_EXPONENT_1) {
-                    pe = a.getBigInteger();
-                } else if (a.type == CKA_EXPONENT_2) {
-                    qe = a.getBigInteger();
-                } else if (a.type == CKA_COEFFICIENT) {
-                    coeff = a.getBigInteger();
-                }
-            }
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (n != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_MODULUS),
-                new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
-            };
-            fetchAttributes(attributes);
-            n = attributes[0].getBigInteger();
-            d = attributes[1].getBigInteger();
-        }
-
-        public String getFormat() {
-            token.ensureValid();
-            return "PKCS#8";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    // XXX make constructor in SunRsaSign provider public
-                    // and call it directly
-                    KeyFactory factory = KeyFactory.getInstance
-                        ("RSA", P11Util.getSunRsaSignProvider());
-                    Key newKey = factory.translateKey(this);
-                    encoded = newKey.getEncoded();
-                } catch (GeneralSecurityException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getModulus() {
-            fetchValues();
-            return n;
-        }
-        public BigInteger getPublicExponent() {
-            return e;
-        }
-        public BigInteger getPrivateExponent() {
-            fetchValues();
-            return d;
-        }
-        public BigInteger getPrimeP() {
-            return p;
-        }
-        public BigInteger getPrimeQ() {
-            return q;
-        }
-        public BigInteger getPrimeExponentP() {
-            return pe;
-        }
-        public BigInteger getPrimeExponentQ() {
-            return qe;
-        }
-        public BigInteger getCrtCoefficient() {
-            return coeff;
-        }
-    }
-
-    // RSA non-CRT private key
-    private static final class P11RSAPrivateNonCRTKey extends P11Key
-                implements RSAPrivateKey {
-        private static final long serialVersionUID = 1137764983777411481L;
-
-        private BigInteger n, d;
-        private byte[] encoded;
-        P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (n != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_MODULUS),
-                new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
-            };
-            fetchAttributes(attributes);
-            n = attributes[0].getBigInteger();
-            d = attributes[1].getBigInteger();
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "PKCS#8";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    // XXX make constructor in SunRsaSign provider public
-                    // and call it directly
-                    KeyFactory factory = KeyFactory.getInstance
-                        ("RSA", P11Util.getSunRsaSignProvider());
-                    Key newKey = factory.translateKey(this);
-                    encoded = newKey.getEncoded();
-                } catch (GeneralSecurityException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getModulus() {
-            fetchValues();
-            return n;
-        }
-        public BigInteger getPrivateExponent() {
-            fetchValues();
-            return d;
-        }
-    }
-
-    private static final class P11RSAPublicKey extends P11Key
-                                                implements RSAPublicKey {
-        private static final long serialVersionUID = -826726289023854455L;
-
-        private BigInteger n, e;
-        private byte[] encoded;
-        P11RSAPublicKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (n != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_MODULUS),
-                new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
-            };
-            fetchAttributes(attributes);
-            n = attributes[0].getBigInteger();
-            e = attributes[1].getBigInteger();
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "X.509";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    encoded = new RSAPublicKeyImpl(n, e).getEncoded();
-                } catch (InvalidKeyException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getModulus() {
-            fetchValues();
-            return n;
-        }
-        public BigInteger getPublicExponent() {
-            fetchValues();
-            return e;
-        }
-        public String toString() {
-            fetchValues();
-            return super.toString() +  "\n  modulus: " + n
-                + "\n  public exponent: " + e;
-        }
-    }
-
-    private static final class P11DSAPublicKey extends P11Key
-                                                implements DSAPublicKey {
-        private static final long serialVersionUID = 5989753793316396637L;
-
-        private BigInteger y;
-        private DSAParams params;
-        private byte[] encoded;
-        P11DSAPublicKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (y != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_VALUE),
-                new CK_ATTRIBUTE(CKA_PRIME),
-                new CK_ATTRIBUTE(CKA_SUBPRIME),
-                new CK_ATTRIBUTE(CKA_BASE),
-            };
-            fetchAttributes(attributes);
-            y = attributes[0].getBigInteger();
-            params = new DSAParameterSpec(
-                attributes[1].getBigInteger(),
-                attributes[2].getBigInteger(),
-                attributes[3].getBigInteger()
-            );
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "X.509";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    Key key = new sun.security.provider.DSAPublicKey
-                            (y, params.getP(), params.getQ(), params.getG());
-                    encoded = key.getEncoded();
-                } catch (InvalidKeyException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getY() {
-            fetchValues();
-            return y;
-        }
-        public DSAParams getParams() {
-            fetchValues();
-            return params;
-        }
-        public String toString() {
-            fetchValues();
-            return super.toString() +  "\n  y: " + y + "\n  p: " + params.getP()
-                + "\n  q: " + params.getQ() + "\n  g: " + params.getG();
-        }
-    }
-
-    private static final class P11DSAPrivateKey extends P11Key
-                                                implements DSAPrivateKey {
-        private static final long serialVersionUID = 3119629997181999389L;
-
-        private BigInteger x;
-        private DSAParams params;
-        private byte[] encoded;
-        P11DSAPrivateKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (x != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_VALUE),
-                new CK_ATTRIBUTE(CKA_PRIME),
-                new CK_ATTRIBUTE(CKA_SUBPRIME),
-                new CK_ATTRIBUTE(CKA_BASE),
-            };
-            fetchAttributes(attributes);
-            x = attributes[0].getBigInteger();
-            params = new DSAParameterSpec(
-                attributes[1].getBigInteger(),
-                attributes[2].getBigInteger(),
-                attributes[3].getBigInteger()
-            );
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "PKCS#8";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    Key key = new sun.security.provider.DSAPrivateKey
-                            (x, params.getP(), params.getQ(), params.getG());
-                    encoded = key.getEncoded();
-                } catch (InvalidKeyException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getX() {
-            fetchValues();
-            return x;
-        }
-        public DSAParams getParams() {
-            fetchValues();
-            return params;
-        }
-    }
-
-    private static final class P11DHPrivateKey extends P11Key
-                                                implements DHPrivateKey {
-        private static final long serialVersionUID = -1698576167364928838L;
-
-        private BigInteger x;
-        private DHParameterSpec params;
-        private byte[] encoded;
-        P11DHPrivateKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (x != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_VALUE),
-                new CK_ATTRIBUTE(CKA_PRIME),
-                new CK_ATTRIBUTE(CKA_BASE),
-            };
-            fetchAttributes(attributes);
-            x = attributes[0].getBigInteger();
-            params = new DHParameterSpec(
-                attributes[1].getBigInteger(),
-                attributes[2].getBigInteger()
-            );
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "PKCS#8";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    DHPrivateKeySpec spec = new DHPrivateKeySpec
-                        (x, params.getP(), params.getG());
-                    KeyFactory kf = KeyFactory.getInstance
-                        ("DH", P11Util.getSunJceProvider());
-                    Key key = kf.generatePrivate(spec);
-                    encoded = key.getEncoded();
-                } catch (GeneralSecurityException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getX() {
-            fetchValues();
-            return x;
-        }
-        public DHParameterSpec getParams() {
-            fetchValues();
-            return params;
-        }
-        public int hashCode() {
-            if (token.isValid() == false) {
-                return 0;
-            }
-            fetchValues();
-            return Objects.hash(x, params.getP(), params.getG());
-        }
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            // equals() should never throw exceptions
-            if (token.isValid() == false) {
-                return false;
-            }
-            if (!(obj instanceof DHPrivateKey)) {
-                return false;
-            }
-            fetchValues();
-            DHPrivateKey other = (DHPrivateKey) obj;
-            DHParameterSpec otherParams = other.getParams();
-            return ((this.x.compareTo(other.getX()) == 0) &&
-                    (this.params.getP().compareTo(otherParams.getP()) == 0) &&
-                    (this.params.getG().compareTo(otherParams.getG()) == 0));
-        }
-    }
-
-    private static final class P11DHPublicKey extends P11Key
-                                                implements DHPublicKey {
-        static final long serialVersionUID = -598383872153843657L;
-
-        private BigInteger y;
-        private DHParameterSpec params;
-        private byte[] encoded;
-        P11DHPublicKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (y != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_VALUE),
-                new CK_ATTRIBUTE(CKA_PRIME),
-                new CK_ATTRIBUTE(CKA_BASE),
-            };
-            fetchAttributes(attributes);
-            y = attributes[0].getBigInteger();
-            params = new DHParameterSpec(
-                attributes[1].getBigInteger(),
-                attributes[2].getBigInteger()
-            );
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "X.509";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    DHPublicKeySpec spec = new DHPublicKeySpec
-                        (y, params.getP(), params.getG());
-                    KeyFactory kf = KeyFactory.getInstance
-                        ("DH", P11Util.getSunJceProvider());
-                    Key key = kf.generatePublic(spec);
-                    encoded = key.getEncoded();
-                } catch (GeneralSecurityException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getY() {
-            fetchValues();
-            return y;
-        }
-        public DHParameterSpec getParams() {
-            fetchValues();
-            return params;
-        }
-        public String toString() {
-            fetchValues();
-            return super.toString() +  "\n  y: " + y + "\n  p: " + params.getP()
-                + "\n  g: " + params.getG();
-        }
-        public int hashCode() {
-            if (token.isValid() == false) {
-                return 0;
-            }
-            fetchValues();
-            return Objects.hash(y, params.getP(), params.getG());
-        }
-        public boolean equals(Object obj) {
-            if (this == obj) return true;
-            // equals() should never throw exceptions
-            if (token.isValid() == false) {
-                return false;
-            }
-            if (!(obj instanceof DHPublicKey)) {
-                return false;
-            }
-            fetchValues();
-            DHPublicKey other = (DHPublicKey) obj;
-            DHParameterSpec otherParams = other.getParams();
-            return ((this.y.compareTo(other.getY()) == 0) &&
-                    (this.params.getP().compareTo(otherParams.getP()) == 0) &&
-                    (this.params.getG().compareTo(otherParams.getG()) == 0));
-        }
-    }
-
-    private static final class P11ECPrivateKey extends P11Key
-                                                implements ECPrivateKey {
-        private static final long serialVersionUID = -7786054399510515515L;
-
-        private BigInteger s;
-        private ECParameterSpec params;
-        private byte[] encoded;
-        P11ECPrivateKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PRIVATE, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (s != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_VALUE),
-                new CK_ATTRIBUTE(CKA_EC_PARAMS, params),
-            };
-            fetchAttributes(attributes);
-            s = attributes[0].getBigInteger();
-            try {
-                params = P11ECKeyFactory.decodeParameters
-                            (attributes[1].getByteArray());
-            } catch (Exception e) {
-                throw new RuntimeException("Could not parse key values", e);
-            }
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "PKCS#8";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    Key key = ECUtil.generateECPrivateKey(s, params);
-                    encoded = key.getEncoded();
-                } catch (InvalidKeySpecException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public BigInteger getS() {
-            fetchValues();
-            return s;
-        }
-        public ECParameterSpec getParams() {
-            fetchValues();
-            return params;
-        }
-    }
-
-    private static final class P11ECPublicKey extends P11Key
-                                                implements ECPublicKey {
-        private static final long serialVersionUID = -6371481375154806089L;
-
-        private ECPoint w;
-        private ECParameterSpec params;
-        private byte[] encoded;
-        P11ECPublicKey(Session session, long keyID, String algorithm,
-                int keyLength, CK_ATTRIBUTE[] attributes) {
-            super(PUBLIC, session, keyID, algorithm, keyLength, attributes);
-        }
-        private synchronized void fetchValues() {
-            token.ensureValid();
-            if (w != null) {
-                return;
-            }
-            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
-                new CK_ATTRIBUTE(CKA_EC_POINT),
-                new CK_ATTRIBUTE(CKA_EC_PARAMS),
-            };
-            fetchAttributes(attributes);
-
-            try {
-                params = P11ECKeyFactory.decodeParameters
-                            (attributes[1].getByteArray());
-                byte[] ecKey = attributes[0].getByteArray();
-
-                // Check whether the X9.63 encoding of an EC point is wrapped
-                // in an ASN.1 OCTET STRING
-                if (!token.config.getUseEcX963Encoding()) {
-                    DerValue wECPoint = new DerValue(ecKey);
-
-                    if (wECPoint.getTag() != DerValue.tag_OctetString) {
-                        throw new IOException("Could not DER decode EC point." +
-                            " Unexpected tag: " + wECPoint.getTag());
-                    }
-                    w = P11ECKeyFactory.decodePoint
-                        (wECPoint.getDataBytes(), params.getCurve());
-
-                } else {
-                    w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve());
-                }
-
-            } catch (Exception e) {
-                throw new RuntimeException("Could not parse key values", e);
-            }
-        }
-        public String getFormat() {
-            token.ensureValid();
-            return "X.509";
-        }
-        synchronized byte[] getEncodedInternal() {
-            token.ensureValid();
-            if (encoded == null) {
-                fetchValues();
-                try {
-                    return ECUtil.x509EncodeECPublicKey(w, params);
-                } catch (InvalidKeySpecException e) {
-                    throw new ProviderException(e);
-                }
-            }
-            return encoded;
-        }
-        public ECPoint getW() {
-            fetchValues();
-            return w;
-        }
-        public ECParameterSpec getParams() {
-            fetchValues();
-            return params;
-        }
-        public String toString() {
-            fetchValues();
-            return super.toString()
-                + "\n  public x coord: " + w.getAffineX()
-                + "\n  public y coord: " + w.getAffineY()
-                + "\n  parameters: " + params;
-        }
-    }
-}
-
-/*
- * NOTE: Must use PhantomReference here and not WeakReference
- * otherwise the key maybe cleared before other objects which
- * still use these keys during finalization such as SSLSocket.
- */
-final class SessionKeyRef extends PhantomReference<P11Key>
-    implements Comparable<SessionKeyRef> {
-    private static ReferenceQueue<P11Key> refQueue =
-        new ReferenceQueue<P11Key>();
-    private static Set<SessionKeyRef> refList =
-        Collections.synchronizedSortedSet(new TreeSet<SessionKeyRef>());
-
-    static ReferenceQueue<P11Key> referenceQueue() {
-        return refQueue;
-    }
-
-    private static void drainRefQueueBounded() {
-        Session sess = null;
-        Token tkn = null;
-        while (true) {
-            SessionKeyRef next = (SessionKeyRef) refQueue.poll();
-            if (next == null) {
-                break;
-            }
-
-            // If the token is still valid, try to remove the object
-            if (next.session.token.isValid()) {
-                // If this key's token is the same as the previous key, the
-                // same session can be used for C_DestroyObject.
-                try {
-                    if (next.session.token != tkn || sess == null) {
-                        // Release session if not using previous token
-                        if (tkn != null && sess != null) {
-                            tkn.releaseSession(sess);
-                            sess = null;
-                        }
-
-                        tkn = next.session.token;
-                        sess = tkn.getOpSession();
-                    }
-                    next.disposeNative(sess);
-                } catch (PKCS11Exception e) {
-                    // ignore
-                }
-            }
-            // Regardless of native results, dispose of java references
-            next.dispose();
-        }
-
-        if (tkn != null && sess != null) {
-            tkn.releaseSession(sess);
-        }
-    }
-
-    // handle to the native key
-    private long keyID;
-    private Session session;
-
-    SessionKeyRef(P11Key key , long keyID, Session session) {
-        super(key, refQueue);
-        this.keyID = keyID;
-        this.session = session;
-        this.session.addObject();
-        refList.add(this);
-        drainRefQueueBounded();
-    }
-
-    private void disposeNative(Session s) throws PKCS11Exception {
-        session.token.p11.C_DestroyObject(s.id(), keyID);
-    }
-
-    private void dispose() {
-        refList.remove(this);
-        this.clear();
-        session.removeObject();
-    }
-
-    public int compareTo(SessionKeyRef other) {
-        if (this.keyID == other.keyID) {
-            return 0;
-        } else {
-            return (this.keyID < other.keyID) ? -1 : 1;
-        }
-    }
-}