Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java
41154 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.pkcs11;2627import java.io.*;28import java.lang.ref.*;29import java.math.BigInteger;30import java.util.*;31import java.security.*;32import java.security.interfaces.*;33import java.security.spec.*;3435import javax.crypto.*;36import javax.crypto.interfaces.*;37import javax.crypto.spec.*;3839import sun.security.rsa.RSAUtil.KeyType;40import sun.security.rsa.RSAPublicKeyImpl;41import sun.security.rsa.RSAPrivateCrtKeyImpl;4243import sun.security.internal.interfaces.TlsMasterSecret;4445import sun.security.pkcs11.wrapper.*;4647import static sun.security.pkcs11.TemplateManager.O_GENERATE;48import static sun.security.pkcs11.wrapper.PKCS11Constants.*;4950import sun.security.util.DerValue;51import sun.security.util.Length;52import sun.security.util.ECUtil;53import sun.security.jca.JCAUtil;5455/**56* Key implementation classes.57*58* In PKCS#11, the components of private and secret keys may or may not59* be accessible. If they are, we use the algorithm specific key classes60* (e.g. DSAPrivateKey) for compatibility with existing applications.61* If the components are not accessible, we use a generic class that62* only implements PrivateKey (or SecretKey). Whether the components of a63* key are extractable is automatically determined when the key object is64* created.65*66* @author Andreas Sterbenz67* @since 1.568*/69abstract class P11Key implements Key, Length {7071private static final long serialVersionUID = -2575874101938349339L;7273private static final String PUBLIC = "public";74private static final String PRIVATE = "private";75private static final String SECRET = "secret";7677// type of key, one of (PUBLIC, PRIVATE, SECRET)78final String type;7980// token instance81final Token token;8283// algorithm name, returned by getAlgorithm(), etc.84final String algorithm;8586// effective key length of the key, e.g. 56 for a DES key87final int keyLength;8889// flags indicating whether the key is a token object, sensitive, extractable90final boolean tokenObject, sensitive, extractable;9192private final NativeKeyHolder keyIDHolder;9394private static final boolean DISABLE_NATIVE_KEYS_EXTRACTION;9596/**97* {@systemProperty sun.security.pkcs11.disableKeyExtraction} property98* indicating whether or not cryptographic keys within tokens are99* extracted to a Java byte array for memory management purposes.100*101* Key extraction affects NSS PKCS11 library only.102*103*/104static {105PrivilegedAction<String> getKeyExtractionProp =106() -> System.getProperty(107"sun.security.pkcs11.disableKeyExtraction", "false");108@SuppressWarnings("removal")109String disableKeyExtraction =110AccessController.doPrivileged(getKeyExtractionProp);111DISABLE_NATIVE_KEYS_EXTRACTION =112"true".equalsIgnoreCase(disableKeyExtraction);113}114115P11Key(String type, Session session, long keyID, String algorithm,116int keyLength, CK_ATTRIBUTE[] attributes) {117this.type = type;118this.token = session.token;119this.algorithm = algorithm;120this.keyLength = keyLength;121boolean tokenObject = false;122boolean sensitive = false;123boolean extractable = true;124int n = (attributes == null) ? 0 : attributes.length;125for (int i = 0; i < n; i++) {126CK_ATTRIBUTE attr = attributes[i];127if (attr.type == CKA_TOKEN) {128tokenObject = attr.getBoolean();129} else if (attr.type == CKA_SENSITIVE) {130sensitive = attr.getBoolean();131} else if (attr.type == CKA_EXTRACTABLE) {132extractable = attr.getBoolean();133}134}135this.tokenObject = tokenObject;136this.sensitive = sensitive;137this.extractable = extractable;138char[] tokenLabel = this.token.tokenInfo.label;139boolean isNSS = (tokenLabel[0] == 'N' && tokenLabel[1] == 'S'140&& tokenLabel[2] == 'S');141boolean extractKeyInfo = (!DISABLE_NATIVE_KEYS_EXTRACTION && isNSS &&142extractable && !tokenObject);143this.keyIDHolder = new NativeKeyHolder(this, keyID, session,144extractKeyInfo, tokenObject);145}146147public long getKeyID() {148return keyIDHolder.getKeyID();149}150151public void releaseKeyID() {152keyIDHolder.releaseKeyID();153}154155// see JCA spec156public final String getAlgorithm() {157token.ensureValid();158return algorithm;159}160161// see JCA spec162public final byte[] getEncoded() {163byte[] b = getEncodedInternal();164return (b == null) ? null : b.clone();165}166167// Called by the NativeResourceCleaner at specified intervals168// See NativeResourceCleaner for more information169static boolean drainRefQueue() {170boolean found = false;171SessionKeyRef next;172while ((next = (SessionKeyRef) SessionKeyRef.refQueue.poll()) != null) {173found = true;174next.dispose();175}176return found;177}178179abstract byte[] getEncodedInternal();180181public boolean equals(Object obj) {182if (this == obj) {183return true;184}185// equals() should never throw exceptions186if (token.isValid() == false) {187return false;188}189if (obj instanceof Key == false) {190return false;191}192String thisFormat = getFormat();193if (thisFormat == null) {194// no encoding, key only equal to itself195// XXX getEncoded() for unextractable keys will change that196return false;197}198Key other = (Key)obj;199if (thisFormat.equals(other.getFormat()) == false) {200return false;201}202byte[] thisEnc = this.getEncodedInternal();203byte[] otherEnc;204if (obj instanceof P11Key) {205otherEnc = ((P11Key)other).getEncodedInternal();206} else {207otherEnc = other.getEncoded();208}209return MessageDigest.isEqual(thisEnc, otherEnc);210}211212public int hashCode() {213// hashCode() should never throw exceptions214if (token.isValid() == false) {215return 0;216}217byte[] b1 = getEncodedInternal();218if (b1 == null) {219return 0;220}221int r = b1.length;222for (int i = 0; i < b1.length; i++) {223r += (b1[i] & 0xff) * 37;224}225return r;226}227228protected Object writeReplace() throws ObjectStreamException {229KeyRep.Type type;230String format = getFormat();231if (isPrivate() && "PKCS#8".equals(format)) {232type = KeyRep.Type.PRIVATE;233} else if (isPublic() && "X.509".equals(format)) {234type = KeyRep.Type.PUBLIC;235} else if (isSecret() && "RAW".equals(format)) {236type = KeyRep.Type.SECRET;237} else {238// XXX short term serialization for unextractable keys239throw new NotSerializableException240("Cannot serialize sensitive and unextractable keys");241}242return new KeyRep(type, getAlgorithm(), format, getEncodedInternal());243}244245public String toString() {246token.ensureValid();247String s1 = token.provider.getName() + " " + algorithm + " " + type248+ " key, " + keyLength + " bits";249s1 += (tokenObject ? "token" : "session") + " object";250if (isPublic()) {251s1 += ")";252} else {253s1 += ", " + (sensitive ? "" : "not ") + "sensitive";254s1 += ", " + (extractable ? "" : "un") + "extractable)";255}256return s1;257}258259/**260* Return bit length of the key.261*/262@Override263public int length() {264return keyLength;265}266267boolean isPublic() {268return type == PUBLIC;269}270271boolean isPrivate() {272return type == PRIVATE;273}274275boolean isSecret() {276return type == SECRET;277}278279void fetchAttributes(CK_ATTRIBUTE[] attributes) {280Session tempSession = null;281long keyID = this.getKeyID();282try {283tempSession = token.getOpSession();284token.p11.C_GetAttributeValue(tempSession.id(), keyID,285attributes);286} catch (PKCS11Exception e) {287throw new ProviderException(e);288} finally {289this.releaseKeyID();290token.releaseSession(tempSession);291}292}293294private static final CK_ATTRIBUTE[] A0 = new CK_ATTRIBUTE[0];295296private static CK_ATTRIBUTE[] getAttributes(Session session, long keyID,297CK_ATTRIBUTE[] knownAttributes, CK_ATTRIBUTE[] desiredAttributes) {298if (knownAttributes == null) {299knownAttributes = A0;300}301for (int i = 0; i < desiredAttributes.length; i++) {302// For each desired attribute, check to see if we have the value303// available already. If everything is here, we save a native call.304CK_ATTRIBUTE attr = desiredAttributes[i];305for (CK_ATTRIBUTE known : knownAttributes) {306if ((attr.type == known.type) && (known.pValue != null)) {307attr.pValue = known.pValue;308break; // break inner for loop309}310}311if (attr.pValue == null) {312// nothing found, need to call C_GetAttributeValue()313for (int j = 0; j < i; j++) {314// clear values copied from knownAttributes315desiredAttributes[j].pValue = null;316}317try {318session.token.p11.C_GetAttributeValue319(session.id(), keyID, desiredAttributes);320} catch (PKCS11Exception e) {321throw new ProviderException(e);322}323break; // break loop, goto return324}325}326return desiredAttributes;327}328329static SecretKey secretKey(Session session, long keyID, String algorithm,330int keyLength, CK_ATTRIBUTE[] attributes) {331attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {332new CK_ATTRIBUTE(CKA_TOKEN),333new CK_ATTRIBUTE(CKA_SENSITIVE),334new CK_ATTRIBUTE(CKA_EXTRACTABLE),335});336return new P11SecretKey(session, keyID, algorithm, keyLength,337attributes);338}339340static SecretKey masterSecretKey(Session session, long keyID, String algorithm,341int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {342attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {343new CK_ATTRIBUTE(CKA_TOKEN),344new CK_ATTRIBUTE(CKA_SENSITIVE),345new CK_ATTRIBUTE(CKA_EXTRACTABLE),346});347return new P11TlsMasterSecretKey(348session, keyID, algorithm, keyLength, attributes, major,349minor);350}351352// we assume that all components of public keys are always accessible353static PublicKey publicKey(Session session, long keyID, String algorithm,354int keyLength, CK_ATTRIBUTE[] attributes) {355switch (algorithm) {356case "RSA":357return new P11RSAPublicKey(session, keyID, algorithm,358keyLength, attributes);359case "DSA":360return new P11DSAPublicKey(session, keyID, algorithm,361keyLength, attributes);362case "DH":363return new P11DHPublicKey(session, keyID, algorithm,364keyLength, attributes);365case "EC":366return new P11ECPublicKey(session, keyID, algorithm,367keyLength, attributes);368default:369throw new ProviderException370("Unknown public key algorithm " + algorithm);371}372}373374static PrivateKey privateKey(Session session, long keyID, String algorithm,375int keyLength, CK_ATTRIBUTE[] attributes) {376attributes = getAttributes(session, keyID, attributes, new CK_ATTRIBUTE[] {377new CK_ATTRIBUTE(CKA_TOKEN),378new CK_ATTRIBUTE(CKA_SENSITIVE),379new CK_ATTRIBUTE(CKA_EXTRACTABLE),380});381if (attributes[1].getBoolean() || (attributes[2].getBoolean() == false)) {382return new P11PrivateKey383(session, keyID, algorithm, keyLength, attributes);384} else {385switch (algorithm) {386case "RSA":387// In order to decide if this is RSA CRT key, we first query388// and see if all extra CRT attributes are available.389CK_ATTRIBUTE[] attrs2 = new CK_ATTRIBUTE[] {390new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),391new CK_ATTRIBUTE(CKA_PRIME_1),392new CK_ATTRIBUTE(CKA_PRIME_2),393new CK_ATTRIBUTE(CKA_EXPONENT_1),394new CK_ATTRIBUTE(CKA_EXPONENT_2),395new CK_ATTRIBUTE(CKA_COEFFICIENT),396};397boolean crtKey;398try {399session.token.p11.C_GetAttributeValue400(session.id(), keyID, attrs2);401crtKey = ((attrs2[0].pValue instanceof byte[]) &&402(attrs2[1].pValue instanceof byte[]) &&403(attrs2[2].pValue instanceof byte[]) &&404(attrs2[3].pValue instanceof byte[]) &&405(attrs2[4].pValue instanceof byte[]) &&406(attrs2[5].pValue instanceof byte[])) ;407} catch (PKCS11Exception e) {408// ignore, assume not available409crtKey = false;410}411if (crtKey) {412return new P11RSAPrivateKey(session, keyID, algorithm,413keyLength, attributes, attrs2);414} else {415return new P11RSAPrivateNonCRTKey(session, keyID,416algorithm, keyLength, attributes);417}418case "DSA":419return new P11DSAPrivateKey(session, keyID, algorithm,420keyLength, attributes);421case "DH":422return new P11DHPrivateKey(session, keyID, algorithm,423keyLength, attributes);424case "EC":425return new P11ECPrivateKey(session, keyID, algorithm,426keyLength, attributes);427default:428throw new ProviderException429("Unknown private key algorithm " + algorithm);430}431}432}433434// class for sensitive and unextractable private keys435private static final class P11PrivateKey extends P11Key436implements PrivateKey {437private static final long serialVersionUID = -2138581185214187615L;438439P11PrivateKey(Session session, long keyID, String algorithm,440int keyLength, CK_ATTRIBUTE[] attributes) {441super(PRIVATE, session, keyID, algorithm, keyLength, attributes);442}443// XXX temporary encoding for serialization purposes444public String getFormat() {445token.ensureValid();446return null;447}448byte[] getEncodedInternal() {449token.ensureValid();450return null;451}452}453454private static class P11SecretKey extends P11Key implements SecretKey {455private static final long serialVersionUID = -7828241727014329084L;456private volatile byte[] encoded;457P11SecretKey(Session session, long keyID, String algorithm,458int keyLength, CK_ATTRIBUTE[] attributes) {459super(SECRET, session, keyID, algorithm, keyLength, attributes);460}461public String getFormat() {462token.ensureValid();463if (sensitive || (extractable == false)) {464return null;465} else {466return "RAW";467}468}469byte[] getEncodedInternal() {470token.ensureValid();471if (getFormat() == null) {472return null;473}474byte[] b = encoded;475if (b == null) {476synchronized (this) {477b = encoded;478if (b == null) {479Session tempSession = null;480long keyID = this.getKeyID();481try {482tempSession = token.getOpSession();483CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {484new CK_ATTRIBUTE(CKA_VALUE),485};486token.p11.C_GetAttributeValue487(tempSession.id(), keyID, attributes);488b = attributes[0].getByteArray();489} catch (PKCS11Exception e) {490throw new ProviderException(e);491} finally {492this.releaseKeyID();493token.releaseSession(tempSession);494}495encoded = b;496}497}498}499return b;500}501}502503@SuppressWarnings("deprecation")504private static class P11TlsMasterSecretKey extends P11SecretKey505implements TlsMasterSecret {506private static final long serialVersionUID = -1318560923770573441L;507508private final int majorVersion, minorVersion;509P11TlsMasterSecretKey(Session session, long keyID, String algorithm,510int keyLength, CK_ATTRIBUTE[] attributes, int major, int minor) {511super(session, keyID, algorithm, keyLength, attributes);512this.majorVersion = major;513this.minorVersion = minor;514}515public int getMajorVersion() {516return majorVersion;517}518519public int getMinorVersion() {520return minorVersion;521}522}523524// RSA CRT private key525private static final class P11RSAPrivateKey extends P11Key526implements RSAPrivateCrtKey {527private static final long serialVersionUID = 9215872438913515220L;528529private BigInteger n, e, d, p, q, pe, qe, coeff;530private byte[] encoded;531P11RSAPrivateKey(Session session, long keyID, String algorithm,532int keyLength, CK_ATTRIBUTE[] attrs, CK_ATTRIBUTE[] crtAttrs) {533super(PRIVATE, session, keyID, algorithm, keyLength, attrs);534535for (CK_ATTRIBUTE a : crtAttrs) {536if (a.type == CKA_PUBLIC_EXPONENT) {537e = a.getBigInteger();538} else if (a.type == CKA_PRIME_1) {539p = a.getBigInteger();540} else if (a.type == CKA_PRIME_2) {541q = a.getBigInteger();542} else if (a.type == CKA_EXPONENT_1) {543pe = a.getBigInteger();544} else if (a.type == CKA_EXPONENT_2) {545qe = a.getBigInteger();546} else if (a.type == CKA_COEFFICIENT) {547coeff = a.getBigInteger();548}549}550}551private synchronized void fetchValues() {552token.ensureValid();553if (n != null) {554return;555}556CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {557new CK_ATTRIBUTE(CKA_MODULUS),558new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),559};560fetchAttributes(attributes);561n = attributes[0].getBigInteger();562d = attributes[1].getBigInteger();563}564565public String getFormat() {566token.ensureValid();567return "PKCS#8";568}569synchronized byte[] getEncodedInternal() {570token.ensureValid();571if (encoded == null) {572fetchValues();573try {574Key newKey = RSAPrivateCrtKeyImpl.newKey575(KeyType.RSA, null, n, e, d, p, q, pe, qe, coeff);576encoded = newKey.getEncoded();577} catch (GeneralSecurityException e) {578throw new ProviderException(e);579}580}581return encoded;582}583public BigInteger getModulus() {584fetchValues();585return n;586}587public BigInteger getPublicExponent() {588return e;589}590public BigInteger getPrivateExponent() {591fetchValues();592return d;593}594public BigInteger getPrimeP() {595return p;596}597public BigInteger getPrimeQ() {598return q;599}600public BigInteger getPrimeExponentP() {601return pe;602}603public BigInteger getPrimeExponentQ() {604return qe;605}606public BigInteger getCrtCoefficient() {607return coeff;608}609}610611// RSA non-CRT private key612private static final class P11RSAPrivateNonCRTKey extends P11Key613implements RSAPrivateKey {614private static final long serialVersionUID = 1137764983777411481L;615616private BigInteger n, d;617private byte[] encoded;618P11RSAPrivateNonCRTKey(Session session, long keyID, String algorithm,619int keyLength, CK_ATTRIBUTE[] attributes) {620super(PRIVATE, session, keyID, algorithm, keyLength, attributes);621}622private synchronized void fetchValues() {623token.ensureValid();624if (n != null) {625return;626}627CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {628new CK_ATTRIBUTE(CKA_MODULUS),629new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),630};631fetchAttributes(attributes);632n = attributes[0].getBigInteger();633d = attributes[1].getBigInteger();634}635public String getFormat() {636token.ensureValid();637return "PKCS#8";638}639synchronized byte[] getEncodedInternal() {640token.ensureValid();641if (encoded == null) {642fetchValues();643try {644// XXX make constructor in SunRsaSign provider public645// and call it directly646KeyFactory factory = KeyFactory.getInstance647("RSA", P11Util.getSunRsaSignProvider());648Key newKey = factory.translateKey(this);649encoded = newKey.getEncoded();650} catch (GeneralSecurityException e) {651throw new ProviderException(e);652}653}654return encoded;655}656public BigInteger getModulus() {657fetchValues();658return n;659}660public BigInteger getPrivateExponent() {661fetchValues();662return d;663}664}665666private static final class P11RSAPublicKey extends P11Key667implements RSAPublicKey {668private static final long serialVersionUID = -826726289023854455L;669private BigInteger n, e;670private byte[] encoded;671P11RSAPublicKey(Session session, long keyID, String algorithm,672int keyLength, CK_ATTRIBUTE[] attributes) {673super(PUBLIC, session, keyID, algorithm, keyLength, attributes);674}675private synchronized void fetchValues() {676token.ensureValid();677if (n != null) {678return;679}680CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {681new CK_ATTRIBUTE(CKA_MODULUS),682new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),683};684fetchAttributes(attributes);685n = attributes[0].getBigInteger();686e = attributes[1].getBigInteger();687}688public String getFormat() {689token.ensureValid();690return "X.509";691}692synchronized byte[] getEncodedInternal() {693token.ensureValid();694if (encoded == null) {695fetchValues();696try {697encoded = RSAPublicKeyImpl.newKey698(KeyType.RSA, null, n, e).getEncoded();699} catch (InvalidKeyException e) {700throw new ProviderException(e);701}702}703return encoded;704}705public BigInteger getModulus() {706fetchValues();707return n;708}709public BigInteger getPublicExponent() {710fetchValues();711return e;712}713public String toString() {714fetchValues();715return super.toString() + "\n modulus: " + n716+ "\n public exponent: " + e;717}718}719720private static final class P11DSAPublicKey extends P11Key721implements DSAPublicKey {722private static final long serialVersionUID = 5989753793316396637L;723724private BigInteger y;725private DSAParams params;726private byte[] encoded;727P11DSAPublicKey(Session session, long keyID, String algorithm,728int keyLength, CK_ATTRIBUTE[] attributes) {729super(PUBLIC, session, keyID, algorithm, keyLength, attributes);730}731private synchronized void fetchValues() {732token.ensureValid();733if (y != null) {734return;735}736CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {737new CK_ATTRIBUTE(CKA_VALUE),738new CK_ATTRIBUTE(CKA_PRIME),739new CK_ATTRIBUTE(CKA_SUBPRIME),740new CK_ATTRIBUTE(CKA_BASE),741};742fetchAttributes(attributes);743y = attributes[0].getBigInteger();744params = new DSAParameterSpec(745attributes[1].getBigInteger(),746attributes[2].getBigInteger(),747attributes[3].getBigInteger()748);749}750public String getFormat() {751token.ensureValid();752return "X.509";753}754synchronized byte[] getEncodedInternal() {755token.ensureValid();756if (encoded == null) {757fetchValues();758try {759Key key = new sun.security.provider.DSAPublicKey760(y, params.getP(), params.getQ(), params.getG());761encoded = key.getEncoded();762} catch (InvalidKeyException e) {763throw new ProviderException(e);764}765}766return encoded;767}768public BigInteger getY() {769fetchValues();770return y;771}772public DSAParams getParams() {773fetchValues();774return params;775}776public String toString() {777fetchValues();778return super.toString() + "\n y: " + y + "\n p: " + params.getP()779+ "\n q: " + params.getQ() + "\n g: " + params.getG();780}781}782783private static final class P11DSAPrivateKey extends P11Key784implements DSAPrivateKey {785private static final long serialVersionUID = 3119629997181999389L;786787private BigInteger x;788private DSAParams params;789private byte[] encoded;790P11DSAPrivateKey(Session session, long keyID, String algorithm,791int keyLength, CK_ATTRIBUTE[] attributes) {792super(PRIVATE, session, keyID, algorithm, keyLength, attributes);793}794private synchronized void fetchValues() {795token.ensureValid();796if (x != null) {797return;798}799CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {800new CK_ATTRIBUTE(CKA_VALUE),801new CK_ATTRIBUTE(CKA_PRIME),802new CK_ATTRIBUTE(CKA_SUBPRIME),803new CK_ATTRIBUTE(CKA_BASE),804};805fetchAttributes(attributes);806x = attributes[0].getBigInteger();807params = new DSAParameterSpec(808attributes[1].getBigInteger(),809attributes[2].getBigInteger(),810attributes[3].getBigInteger()811);812}813public String getFormat() {814token.ensureValid();815return "PKCS#8";816}817synchronized byte[] getEncodedInternal() {818token.ensureValid();819if (encoded == null) {820fetchValues();821Key key = new sun.security.provider.DSAPrivateKey822(x, params.getP(), params.getQ(), params.getG());823encoded = key.getEncoded();824}825return encoded;826}827public BigInteger getX() {828fetchValues();829return x;830}831public DSAParams getParams() {832fetchValues();833return params;834}835}836837private static final class P11DHPrivateKey extends P11Key838implements DHPrivateKey {839private static final long serialVersionUID = -1698576167364928838L;840841private BigInteger x;842private DHParameterSpec params;843private byte[] encoded;844P11DHPrivateKey(Session session, long keyID, String algorithm,845int keyLength, CK_ATTRIBUTE[] attributes) {846super(PRIVATE, session, keyID, algorithm, keyLength, attributes);847}848private synchronized void fetchValues() {849token.ensureValid();850if (x != null) {851return;852}853CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {854new CK_ATTRIBUTE(CKA_VALUE),855new CK_ATTRIBUTE(CKA_PRIME),856new CK_ATTRIBUTE(CKA_BASE),857};858fetchAttributes(attributes);859x = attributes[0].getBigInteger();860params = new DHParameterSpec(861attributes[1].getBigInteger(),862attributes[2].getBigInteger()863);864}865public String getFormat() {866token.ensureValid();867return "PKCS#8";868}869synchronized byte[] getEncodedInternal() {870token.ensureValid();871if (encoded == null) {872fetchValues();873try {874DHPrivateKeySpec spec = new DHPrivateKeySpec875(x, params.getP(), params.getG());876KeyFactory kf = KeyFactory.getInstance877("DH", P11Util.getSunJceProvider());878Key key = kf.generatePrivate(spec);879encoded = key.getEncoded();880} catch (GeneralSecurityException e) {881throw new ProviderException(e);882}883}884return encoded;885}886public BigInteger getX() {887fetchValues();888return x;889}890public DHParameterSpec getParams() {891fetchValues();892return params;893}894public int hashCode() {895if (!token.isValid()) {896return 0;897}898fetchValues();899return Objects.hash(x, params.getP(), params.getG());900}901public boolean equals(Object obj) {902if (this == obj) return true;903// equals() should never throw exceptions904if (!token.isValid()) {905return false;906}907if (!(obj instanceof DHPrivateKey)) {908return false;909}910fetchValues();911DHPrivateKey other = (DHPrivateKey) obj;912DHParameterSpec otherParams = other.getParams();913return ((this.x.compareTo(other.getX()) == 0) &&914(this.params.getP().compareTo(otherParams.getP()) == 0) &&915(this.params.getG().compareTo(otherParams.getG()) == 0));916}917}918919private static final class P11DHPublicKey extends P11Key920implements DHPublicKey {921static final long serialVersionUID = -598383872153843657L;922923private BigInteger y;924private DHParameterSpec params;925private byte[] encoded;926P11DHPublicKey(Session session, long keyID, String algorithm,927int keyLength, CK_ATTRIBUTE[] attributes) {928super(PUBLIC, session, keyID, algorithm, keyLength, attributes);929}930private synchronized void fetchValues() {931token.ensureValid();932if (y != null) {933return;934}935CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {936new CK_ATTRIBUTE(CKA_VALUE),937new CK_ATTRIBUTE(CKA_PRIME),938new CK_ATTRIBUTE(CKA_BASE),939};940fetchAttributes(attributes);941y = attributes[0].getBigInteger();942params = new DHParameterSpec(943attributes[1].getBigInteger(),944attributes[2].getBigInteger()945);946}947public String getFormat() {948token.ensureValid();949return "X.509";950}951synchronized byte[] getEncodedInternal() {952token.ensureValid();953if (encoded == null) {954fetchValues();955try {956DHPublicKeySpec spec = new DHPublicKeySpec957(y, params.getP(), params.getG());958KeyFactory kf = KeyFactory.getInstance959("DH", P11Util.getSunJceProvider());960Key key = kf.generatePublic(spec);961encoded = key.getEncoded();962} catch (GeneralSecurityException e) {963throw new ProviderException(e);964}965}966return encoded;967}968public BigInteger getY() {969fetchValues();970return y;971}972public DHParameterSpec getParams() {973fetchValues();974return params;975}976public String toString() {977fetchValues();978return super.toString() + "\n y: " + y + "\n p: " + params.getP()979+ "\n g: " + params.getG();980}981public int hashCode() {982if (token.isValid() == false) {983return 0;984}985fetchValues();986return Objects.hash(y, params.getP(), params.getG());987}988public boolean equals(Object obj) {989if (this == obj) return true;990// equals() should never throw exceptions991if (token.isValid() == false) {992return false;993}994if (!(obj instanceof DHPublicKey)) {995return false;996}997fetchValues();998DHPublicKey other = (DHPublicKey) obj;999DHParameterSpec otherParams = other.getParams();1000return ((this.y.compareTo(other.getY()) == 0) &&1001(this.params.getP().compareTo(otherParams.getP()) == 0) &&1002(this.params.getG().compareTo(otherParams.getG()) == 0));1003}1004}10051006private static final class P11ECPrivateKey extends P11Key1007implements ECPrivateKey {1008private static final long serialVersionUID = -7786054399510515515L;10091010private BigInteger s;1011private ECParameterSpec params;1012private byte[] encoded;1013P11ECPrivateKey(Session session, long keyID, String algorithm,1014int keyLength, CK_ATTRIBUTE[] attributes) {1015super(PRIVATE, session, keyID, algorithm, keyLength, attributes);1016}1017private synchronized void fetchValues() {1018token.ensureValid();1019if (s != null) {1020return;1021}1022CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {1023new CK_ATTRIBUTE(CKA_VALUE),1024new CK_ATTRIBUTE(CKA_EC_PARAMS, params),1025};1026fetchAttributes(attributes);1027s = attributes[0].getBigInteger();1028try {1029params = P11ECKeyFactory.decodeParameters1030(attributes[1].getByteArray());1031} catch (Exception e) {1032throw new RuntimeException("Could not parse key values", e);1033}1034}1035public String getFormat() {1036token.ensureValid();1037return "PKCS#8";1038}1039synchronized byte[] getEncodedInternal() {1040token.ensureValid();1041if (encoded == null) {1042fetchValues();1043try {1044Key key = ECUtil.generateECPrivateKey(s, params);1045encoded = key.getEncoded();1046} catch (InvalidKeySpecException e) {1047throw new ProviderException(e);1048}1049}1050return encoded;1051}1052public BigInteger getS() {1053fetchValues();1054return s;1055}1056public ECParameterSpec getParams() {1057fetchValues();1058return params;1059}1060}10611062private static final class P11ECPublicKey extends P11Key1063implements ECPublicKey {1064private static final long serialVersionUID = -6371481375154806089L;10651066private ECPoint w;1067private ECParameterSpec params;1068private byte[] encoded;1069P11ECPublicKey(Session session, long keyID, String algorithm,1070int keyLength, CK_ATTRIBUTE[] attributes) {1071super(PUBLIC, session, keyID, algorithm, keyLength, attributes);1072}1073private synchronized void fetchValues() {1074token.ensureValid();1075if (w != null) {1076return;1077}1078CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {1079new CK_ATTRIBUTE(CKA_EC_POINT),1080new CK_ATTRIBUTE(CKA_EC_PARAMS),1081};1082fetchAttributes(attributes);10831084try {1085params = P11ECKeyFactory.decodeParameters1086(attributes[1].getByteArray());1087byte[] ecKey = attributes[0].getByteArray();10881089// Check whether the X9.63 encoding of an EC point is wrapped1090// in an ASN.1 OCTET STRING1091if (!token.config.getUseEcX963Encoding()) {1092DerValue wECPoint = new DerValue(ecKey);10931094if (wECPoint.getTag() != DerValue.tag_OctetString) {1095throw new IOException("Could not DER decode EC point." +1096" Unexpected tag: " + wECPoint.getTag());1097}1098w = P11ECKeyFactory.decodePoint1099(wECPoint.getDataBytes(), params.getCurve());11001101} else {1102w = P11ECKeyFactory.decodePoint(ecKey, params.getCurve());1103}11041105} catch (Exception e) {1106throw new RuntimeException("Could not parse key values", e);1107}1108}1109public String getFormat() {1110token.ensureValid();1111return "X.509";1112}1113synchronized byte[] getEncodedInternal() {1114token.ensureValid();1115if (encoded == null) {1116fetchValues();1117try {1118return ECUtil.x509EncodeECPublicKey(w, params);1119} catch (InvalidKeySpecException e) {1120throw new ProviderException(e);1121}1122}1123return encoded;1124}1125public ECPoint getW() {1126fetchValues();1127return w;1128}1129public ECParameterSpec getParams() {1130fetchValues();1131return params;1132}1133public String toString() {1134fetchValues();1135return super.toString()1136+ "\n public x coord: " + w.getAffineX()1137+ "\n public y coord: " + w.getAffineY()1138+ "\n parameters: " + params;1139}1140}1141}1142final class NativeKeyHolder {11431144private static long nativeKeyWrapperKeyID = 0;1145private static CK_MECHANISM nativeKeyWrapperMechanism = null;1146private static long nativeKeyWrapperRefCount = 0;1147private static Session nativeKeyWrapperSession = null;11481149private final P11Key p11Key;1150private final byte[] nativeKeyInfo;1151private boolean wrapperKeyUsed;11521153// destroyed and recreated when refCount toggles to 11154private long keyID;11551156// phantom reference notification clean up for session keys1157private SessionKeyRef ref;11581159private int refCount;11601161private static void createNativeKeyWrapper(Token token)1162throws PKCS11Exception {1163assert(nativeKeyWrapperKeyID == 0);1164assert(nativeKeyWrapperRefCount == 0);1165assert(nativeKeyWrapperSession == null);1166// Create a global wrapping/unwrapping key1167CK_ATTRIBUTE[] wrappingAttributes = token.getAttributes(O_GENERATE,1168CKO_SECRET_KEY, CKK_AES, new CK_ATTRIBUTE[] {1169new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),1170new CK_ATTRIBUTE(CKA_VALUE_LEN, 256 >> 3)});1171Session s = null;1172try {1173s = token.getObjSession();1174nativeKeyWrapperKeyID = token.p11.C_GenerateKey(1175s.id(), new CK_MECHANISM(CKM_AES_KEY_GEN),1176wrappingAttributes);1177nativeKeyWrapperSession = s;1178nativeKeyWrapperSession.addObject();1179byte[] iv = new byte[16];1180JCAUtil.getSecureRandom().nextBytes(iv);1181nativeKeyWrapperMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv);1182} catch (PKCS11Exception e) {1183// best effort1184} finally {1185token.releaseSession(s);1186}1187}11881189private static void deleteNativeKeyWrapper() {1190Token token = nativeKeyWrapperSession.token;1191if (token.isValid()) {1192Session s = null;1193try {1194s = token.getOpSession();1195token.p11.C_DestroyObject(s.id(), nativeKeyWrapperKeyID);1196nativeKeyWrapperSession.removeObject();1197} catch (PKCS11Exception e) {1198// best effort1199} finally {1200token.releaseSession(s);1201}1202}1203nativeKeyWrapperKeyID = 0;1204nativeKeyWrapperMechanism = null;1205nativeKeyWrapperSession = null;1206}12071208static void decWrapperKeyRef() {1209synchronized(NativeKeyHolder.class) {1210assert(nativeKeyWrapperKeyID != 0);1211assert(nativeKeyWrapperRefCount > 0);1212nativeKeyWrapperRefCount--;1213if (nativeKeyWrapperRefCount == 0) {1214deleteNativeKeyWrapper();1215}1216}1217}12181219NativeKeyHolder(P11Key p11Key, long keyID, Session keySession,1220boolean extractKeyInfo, boolean isTokenObject) {1221this.p11Key = p11Key;1222this.keyID = keyID;1223this.refCount = -1;1224byte[] ki = null;1225if (isTokenObject) {1226this.ref = null;1227} else {1228// Try extracting key info, if any error, disable it1229Token token = p11Key.token;1230if (extractKeyInfo) {1231try {1232if (p11Key.sensitive) {1233// p11Key native key information has to be wrapped1234synchronized(NativeKeyHolder.class) {1235if (nativeKeyWrapperKeyID == 0) {1236createNativeKeyWrapper(token);1237}1238// If a wrapper-key was successfully created or1239// already exists, increment its reference1240// counter to keep it alive while native key1241// information is being held.1242if (nativeKeyWrapperKeyID != 0) {1243nativeKeyWrapperRefCount++;1244wrapperKeyUsed = true;1245}1246}1247}1248Session opSession = null;1249try {1250opSession = token.getOpSession();1251ki = p11Key.token.p11.getNativeKeyInfo(opSession.id(),1252keyID, nativeKeyWrapperKeyID,1253nativeKeyWrapperMechanism);1254} catch (PKCS11Exception e) {1255// best effort1256} finally {1257token.releaseSession(opSession);1258}1259} catch (PKCS11Exception e) {1260// best effort1261}1262}1263this.ref = new SessionKeyRef(p11Key, keyID, wrapperKeyUsed,1264keySession);1265}12661267this.nativeKeyInfo = ((ki == null || ki.length == 0)? null : ki);1268}12691270long getKeyID() throws ProviderException {1271if (this.nativeKeyInfo != null) {1272synchronized(this.nativeKeyInfo) {1273if (this.refCount == -1) {1274this.refCount = 0;1275}1276int cnt = (this.refCount)++;1277if (keyID == 0) {1278if (cnt != 0) {1279throw new RuntimeException(1280"Error: null keyID with non-zero refCount " + cnt);1281}1282Token token = p11Key.token;1283// Create keyID using nativeKeyInfo1284Session session = null;1285try {1286session = token.getObjSession();1287this.keyID = token.p11.createNativeKey(session.id(),1288nativeKeyInfo, nativeKeyWrapperKeyID,1289nativeKeyWrapperMechanism);1290this.ref.registerNativeKey(this.keyID, session);1291} catch (PKCS11Exception e) {1292this.refCount--;1293throw new ProviderException("Error recreating native key", e);1294} finally {1295token.releaseSession(session);1296}1297} else {1298if (cnt < 0) {1299throw new RuntimeException("ERROR: negative refCount");1300}1301}1302}1303}1304return keyID;1305}13061307void releaseKeyID() {1308if (this.nativeKeyInfo != null) {1309synchronized(this.nativeKeyInfo) {1310if (this.refCount == -1) {1311throw new RuntimeException("Error: miss match getKeyID call");1312}1313int cnt = --(this.refCount);1314if (cnt == 0) {1315// destroy1316if (this.keyID == 0) {1317throw new RuntimeException("ERROR: null keyID can't be destroyed");1318}13191320// destroy1321this.keyID = 0;1322this.ref.removeNativeKey();1323} else {1324if (cnt < 0) {1325// should never happen as we start count at 1 and pair get/release calls1326throw new RuntimeException("wrong refCount value: " + cnt);1327}1328}1329}1330}1331}1332}13331334/*1335* NOTE: Must use PhantomReference here and not WeakReference1336* otherwise the key maybe cleared before other objects which1337* still use these keys during finalization such as SSLSocket.1338*/1339final class SessionKeyRef extends PhantomReference<P11Key> {1340static ReferenceQueue<P11Key> refQueue = new ReferenceQueue<>();1341private static Set<SessionKeyRef> refSet =1342Collections.synchronizedSet(new HashSet<>());13431344// handle to the native key and the session it is generated under1345private long keyID;1346private Session session;1347private boolean wrapperKeyUsed;13481349SessionKeyRef(P11Key p11Key, long keyID, boolean wrapperKeyUsed,1350Session session) {1351super(p11Key, refQueue);1352if (session == null) {1353throw new ProviderException1354("key must be associated with a session");1355}1356registerNativeKey(keyID, session);1357this.wrapperKeyUsed = wrapperKeyUsed;13581359refSet.add(this);1360}13611362void registerNativeKey(long newKeyID, Session newSession) {1363assert(newKeyID != 0);1364assert(newSession != null);1365updateNativeKey(newKeyID, newSession);1366}13671368void removeNativeKey() {1369assert(session != null);1370updateNativeKey(0, null);1371}13721373private void updateNativeKey(long newKeyID, Session newSession) {1374if (newKeyID == 0) {1375assert(newSession == null);1376Token token = session.token;1377// If the token is still valid, try to remove the key object1378if (token.isValid()) {1379Session s = null;1380try {1381s = token.getOpSession();1382token.p11.C_DestroyObject(s.id(), this.keyID);1383} catch (PKCS11Exception e) {1384// best effort1385} finally {1386token.releaseSession(s);1387}1388}1389session.removeObject();1390} else {1391newSession.addObject();1392}1393keyID = newKeyID;1394session = newSession;1395}13961397// Called when the GC disposes a p11Key1398void dispose() {1399if (wrapperKeyUsed) {1400// Wrapper-key no longer needed for1401// p11Key native key information1402NativeKeyHolder.decWrapperKeyRef();1403}1404if (keyID != 0) {1405removeNativeKey();1406}1407refSet.remove(this);1408this.clear();1409}1410}141114121413