/* * 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. Load more
/* * 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);