Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECKeyFactory.java
41154 views
/*1* Copyright (c) 2006, 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.IOException;28import java.math.BigInteger;2930import java.security.*;31import java.security.interfaces.*;32import java.security.spec.*;3334import static sun.security.pkcs11.TemplateManager.*;35import sun.security.pkcs11.wrapper.*;36import static sun.security.pkcs11.wrapper.PKCS11Constants.*;3738import sun.security.util.DerValue;39import sun.security.util.ECUtil;4041/**42* EC KeyFactory implementation.43*44* @author Andreas Sterbenz45* @since 1.646*/47final class P11ECKeyFactory extends P11KeyFactory {48private static Provider sunECprovider;4950private static Provider getSunECProvider() {51if (sunECprovider == null) {52sunECprovider = Security.getProvider("SunEC");53if (sunECprovider == null) {54throw new RuntimeException("Cannot load SunEC provider");55}56}5758return sunECprovider;59}6061P11ECKeyFactory(Token token, String algorithm) {62super(token, algorithm);63}6465static ECParameterSpec getECParameterSpec(String name) {66return ECUtil.getECParameterSpec(getSunECProvider(), name);67}6869static ECParameterSpec getECParameterSpec(int keySize) {70return ECUtil.getECParameterSpec(getSunECProvider(), keySize);71}7273// Check that spec is a known supported curve and convert it to our74// ECParameterSpec subclass. If not possible, return null.75static ECParameterSpec getECParameterSpec(ECParameterSpec spec) {76return ECUtil.getECParameterSpec(getSunECProvider(), spec);77}7879static ECParameterSpec decodeParameters(byte[] params) throws IOException {80return ECUtil.getECParameterSpec(getSunECProvider(), params);81}8283static byte[] encodeParameters(ECParameterSpec params) {84return ECUtil.encodeECParameterSpec(getSunECProvider(), params);85}8687static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException {88return ECUtil.decodePoint(encoded, curve);89}9091// Used by ECDH KeyAgreement92static byte[] getEncodedPublicValue(PublicKey key) throws InvalidKeyException {93if (key instanceof ECPublicKey) {94ECPublicKey ecKey = (ECPublicKey)key;95ECPoint w = ecKey.getW();96ECParameterSpec params = ecKey.getParams();97return ECUtil.encodePoint(w, params.getCurve());98} else {99// should never occur100throw new InvalidKeyException101("Key class not yet supported: " + key.getClass().getName());102}103}104105PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException {106try {107if (key instanceof ECPublicKey) {108ECPublicKey ecKey = (ECPublicKey)key;109return generatePublic(110ecKey.getW(),111ecKey.getParams()112);113} else if ("X.509".equals(key.getFormat())) {114// let Sun provider parse for us, then recurse115byte[] encoded = key.getEncoded();116117try {118key = ECUtil.decodeX509ECPublicKey(encoded);119} catch (InvalidKeySpecException ikse) {120throw new InvalidKeyException(ikse);121}122123return implTranslatePublicKey(key);124} else {125throw new InvalidKeyException("PublicKey must be instance "126+ "of ECPublicKey or have X.509 encoding");127}128} catch (PKCS11Exception e) {129throw new InvalidKeyException("Could not create EC public key", e);130}131}132133PrivateKey implTranslatePrivateKey(PrivateKey key)134throws InvalidKeyException {135try {136if (key instanceof ECPrivateKey) {137ECPrivateKey ecKey = (ECPrivateKey)key;138return generatePrivate(139ecKey.getS(),140ecKey.getParams()141);142} else if ("PKCS#8".equals(key.getFormat())) {143// let Sun provider parse for us, then recurse144byte[] encoded = key.getEncoded();145146try {147key = ECUtil.decodePKCS8ECPrivateKey(encoded);148} catch (InvalidKeySpecException ikse) {149throw new InvalidKeyException(ikse);150}151152return implTranslatePrivateKey(key);153} else {154throw new InvalidKeyException("PrivateKey must be instance "155+ "of ECPrivateKey or have PKCS#8 encoding");156}157} catch (PKCS11Exception e) {158throw new InvalidKeyException("Could not create EC private key", e);159}160}161162// see JCA spec163protected PublicKey engineGeneratePublic(KeySpec keySpec)164throws InvalidKeySpecException {165token.ensureValid();166if (keySpec instanceof X509EncodedKeySpec) {167try {168byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded();169PublicKey key = ECUtil.decodeX509ECPublicKey(encoded);170return implTranslatePublicKey(key);171} catch (InvalidKeyException e) {172throw new InvalidKeySpecException173("Could not create EC public key", e);174}175}176if (keySpec instanceof ECPublicKeySpec == false) {177throw new InvalidKeySpecException("Only ECPublicKeySpec and "178+ "X509EncodedKeySpec supported for EC public keys");179}180try {181ECPublicKeySpec ec = (ECPublicKeySpec)keySpec;182return generatePublic(183ec.getW(),184ec.getParams()185);186} catch (PKCS11Exception e) {187throw new InvalidKeySpecException188("Could not create EC public key", e);189}190}191192// see JCA spec193protected PrivateKey engineGeneratePrivate(KeySpec keySpec)194throws InvalidKeySpecException {195token.ensureValid();196if (keySpec instanceof PKCS8EncodedKeySpec) {197try {198byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();199PrivateKey key = ECUtil.decodePKCS8ECPrivateKey(encoded);200return implTranslatePrivateKey(key);201} catch (GeneralSecurityException e) {202throw new InvalidKeySpecException203("Could not create EC private key", e);204}205}206if (keySpec instanceof ECPrivateKeySpec == false) {207throw new InvalidKeySpecException("Only ECPrivateKeySpec and "208+ "PKCS8EncodedKeySpec supported for EC private keys");209}210try {211ECPrivateKeySpec ec = (ECPrivateKeySpec)keySpec;212return generatePrivate(213ec.getS(),214ec.getParams()215);216} catch (PKCS11Exception e) {217throw new InvalidKeySpecException218("Could not create EC private key", e);219}220}221222private PublicKey generatePublic(ECPoint point, ECParameterSpec params)223throws PKCS11Exception {224byte[] encodedParams =225ECUtil.encodeECParameterSpec(getSunECProvider(), params);226byte[] encodedPoint =227ECUtil.encodePoint(point, params.getCurve());228229// Check whether the X9.63 encoding of an EC point shall be wrapped230// in an ASN.1 OCTET STRING231if (!token.config.getUseEcX963Encoding()) {232try {233encodedPoint =234new DerValue(DerValue.tag_OctetString, encodedPoint)235.toByteArray();236} catch (IOException e) {237throw new238IllegalArgumentException("Could not DER encode point", e);239}240}241242CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {243new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),244new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC),245new CK_ATTRIBUTE(CKA_EC_POINT, encodedPoint),246new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),247};248attributes = token.getAttributes249(O_IMPORT, CKO_PUBLIC_KEY, CKK_EC, attributes);250Session session = null;251try {252session = token.getObjSession();253long keyID = token.p11.C_CreateObject(session.id(), attributes);254return P11Key.publicKey255(session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes);256} finally {257token.releaseSession(session);258}259}260261private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params)262throws PKCS11Exception {263byte[] encodedParams =264ECUtil.encodeECParameterSpec(getSunECProvider(), params);265CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {266new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),267new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC),268new CK_ATTRIBUTE(CKA_VALUE, s),269new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),270};271attributes = token.getAttributes272(O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes);273Session session = null;274try {275session = token.getObjSession();276long keyID = token.p11.C_CreateObject(session.id(), attributes);277return P11Key.privateKey278(session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes);279} finally {280token.releaseSession(session);281}282}283284<T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec,285Session[] session) throws PKCS11Exception, InvalidKeySpecException {286if (keySpec.isAssignableFrom(ECPublicKeySpec.class)) {287session[0] = token.getObjSession();288CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {289new CK_ATTRIBUTE(CKA_EC_POINT),290new CK_ATTRIBUTE(CKA_EC_PARAMS),291};292long keyID = key.getKeyID();293try {294token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);295ECParameterSpec params = decodeParameters(attributes[1].getByteArray());296ECPoint point;297298if (!token.config.getUseEcX963Encoding()) {299point = decodePoint(new DerValue(attributes[0].getByteArray()).getOctetString(), params.getCurve());300} else {301point = decodePoint(attributes[0].getByteArray(), params.getCurve());302}303return keySpec.cast(new ECPublicKeySpec(point, params));304} catch (IOException e) {305throw new InvalidKeySpecException("Could not parse key", e);306} finally {307key.releaseKeyID();308}309} else { // X.509 handled in superclass310throw new InvalidKeySpecException("Only ECPublicKeySpec and "311+ "X509EncodedKeySpec supported for EC public keys");312}313}314315<T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec,316Session[] session) throws PKCS11Exception, InvalidKeySpecException {317if (keySpec.isAssignableFrom(ECPrivateKeySpec.class)) {318session[0] = token.getObjSession();319CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {320new CK_ATTRIBUTE(CKA_VALUE),321new CK_ATTRIBUTE(CKA_EC_PARAMS),322};323long keyID = key.getKeyID();324try {325token.p11.C_GetAttributeValue(session[0].id(), keyID, attributes);326ECParameterSpec params = decodeParameters(attributes[1].getByteArray());327return keySpec.cast(328new ECPrivateKeySpec(attributes[0].getBigInteger(), params));329} catch (IOException e) {330throw new InvalidKeySpecException("Could not parse key", e);331} finally {332key.releaseKeyID();333}334} else { // PKCS#8 handled in superclass335throw new InvalidKeySpecException("Only ECPrivateKeySpec "336+ "and PKCS8EncodedKeySpec supported for EC private keys");337}338}339340KeyFactory implGetSoftwareFactory() throws GeneralSecurityException {341return KeyFactory.getInstance("EC", getSunECProvider());342}343344}345346347