1132 lines · 40.0 KB · Java
RawDownload
/* * Copyright (c) 2003, 2011, 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.DerValue; /** * 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 {     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 : (byte[])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 Arrays.equals(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;    }     int keyLength() {        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) {        if (algorithm.equals("RSA")) {            return new P11RSAPublicKey                (session, keyID, algorithm, keyLength, attributes);        } else if (algorithm.equals("DSA")) {            return new P11DSAPublicKey                (session, keyID, algorithm, keyLength, attributes);        } else if (algorithm.equals("DH")) {            return new P11DHPublicKey                (session, keyID, algorithm, keyLength, attributes);        } else if (algorithm.equals("EC")) {            return new P11ECPublicKey                (session, keyID, algorithm, keyLength, attributes);        } else {            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 {            if (algorithm.equals("RSA")) {                // XXX better test for RSA CRT keys (single getAttributes() call)                // we need to determine whether this is a CRT key                // see if we can obtain the public exponent                // this should also be readable for sensitive/extractable keys                CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {                    new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),                };                boolean crtKey;                try {                    session.token.p11.C_GetAttributeValue                        (session.id(), keyID, attrs2);                    crtKey = (attrs2[0].pValue instanceof byte[]);                } catch (PKCS11Exception e) {                    // ignore, assume not available                    crtKey = false;                }                if (crtKey) {                    return new P11RSAPrivateKey                            (session, keyID, algorithm, keyLength, attributes);                } else {                    return new P11RSAPrivateNonCRTKey                            (session, keyID, algorithm, keyLength, attributes);                }            } else if (algorithm.equals("DSA")) {                return new P11DSAPrivateKey                        (session, keyID, algorithm, keyLength, attributes);            } else if (algorithm.equals("DH")) {                return new P11DHPrivateKey                        (session, keyID, algorithm, keyLength, attributes);            } else if (algorithm.equals("EC")) {                return new P11ECPrivateKey                        (session, keyID, algorithm, keyLength, attributes);            } else {                throw new ProviderException                        ("Unknown private key algorithm " + algorithm);            }        }    }     // class for sensitive and unextractable private keys    private static final class P11PrivateKey extends P11Key                                                implements PrivateKey {        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 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;        }    }     private static class P11TlsMasterSecretKey extends P11SecretKey            implements TlsMasterSecret {        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 BigInteger n, e, d, p, q, pe, qe, coeff;        private byte[] encoded;        P11RSAPrivateKey(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_PUBLIC_EXPONENT),                new CK_ATTRIBUTE(CKA_PRIVATE_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),            };            fetchAttributes(attributes);            n = attributes[0].getBigInteger();            e = attributes[1].getBigInteger();            d = attributes[2].getBigInteger();            p = attributes[3].getBigInteger();            q = attributes[4].getBigInteger();            pe = attributes[5].getBigInteger();            qe = attributes[6].getBigInteger();            coeff = attributes[7].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);

Lines 1–500 of 1132.