1 /*
   2  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.pkcs11;
  27 
  28 import java.io.IOException;
  29 import java.math.BigInteger;
  30 
  31 import java.security.*;
  32 import java.security.interfaces.*;
  33 import java.security.spec.*;
  34 
  35 import sun.security.ec.ECPublicKeyImpl;
  36 import sun.security.ec.ECParameters;
  37 import sun.security.ec.NamedCurve;
  38 
  39 import static sun.security.pkcs11.TemplateManager.*;
  40 import sun.security.pkcs11.wrapper.*;
  41 import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
  42 
  43 import sun.security.util.DerValue;
  44 
  45 /**
  46  * EC KeyFactory implemenation.
  47  *
  48  * @author  Andreas Sterbenz
  49  * @since   1.6
  50  */
  51 final class P11ECKeyFactory extends P11KeyFactory {
  52 
  53     P11ECKeyFactory(Token token, String algorithm) {
  54         super(token, algorithm);
  55     }
  56 
  57     static ECParameterSpec getECParameterSpec(String name) {
  58         return NamedCurve.getECParameterSpec(name);
  59     }
  60 
  61     static ECParameterSpec getECParameterSpec(int keySize) {
  62         return NamedCurve.getECParameterSpec(keySize);
  63     }
  64 
  65     // Check that spec is a known supported curve and convert it to our
  66     // ECParameterSpec subclass. If not possible, return null.
  67     static ECParameterSpec getECParameterSpec(ECParameterSpec spec) {
  68         return ECParameters.getNamedCurve(spec);
  69     }
  70 
  71     static ECParameterSpec decodeParameters(byte[] params) throws IOException {
  72         return ECParameters.decodeParameters(params);
  73     }
  74 
  75     static byte[] encodeParameters(ECParameterSpec params) {
  76         return ECParameters.encodeParameters(params);
  77     }
  78 
  79     static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) throws IOException {
  80         return ECParameters.decodePoint(encoded, curve);
  81     }
  82 
  83     // Used by ECDH KeyAgreement
  84     static byte[] getEncodedPublicValue(PublicKey key) throws InvalidKeyException {
  85         if (key instanceof ECPublicKeyImpl) {
  86             return ((ECPublicKeyImpl)key).getEncodedPublicValue();
  87         } else if (key instanceof ECPublicKey) {
  88             ECPublicKey ecKey = (ECPublicKey)key;
  89             ECPoint w = ecKey.getW();
  90             ECParameterSpec params = ecKey.getParams();
  91             return ECParameters.encodePoint(w, params.getCurve());
  92         } else {
  93             // should never occur
  94             throw new InvalidKeyException
  95                 ("Key class not yet supported: " + key.getClass().getName());
  96         }
  97     }
  98 
  99     PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException {
 100         try {
 101             if (key instanceof ECPublicKey) {
 102                 ECPublicKey ecKey = (ECPublicKey)key;
 103                 return generatePublic(
 104                     ecKey.getW(),
 105                     ecKey.getParams()
 106                 );
 107             } else if ("X.509".equals(key.getFormat())) {
 108                 // let Sun provider parse for us, then recurse
 109                 byte[] encoded = key.getEncoded();
 110                 key = new sun.security.ec.ECPublicKeyImpl(encoded);
 111                 return implTranslatePublicKey(key);
 112             } else {
 113                 throw new InvalidKeyException("PublicKey must be instance "
 114                         + "of ECPublicKey or have X.509 encoding");
 115             }
 116         } catch (PKCS11Exception e) {
 117             throw new InvalidKeyException("Could not create EC public key", e);
 118         }
 119     }
 120 
 121     PrivateKey implTranslatePrivateKey(PrivateKey key)
 122             throws InvalidKeyException {
 123         try {
 124             if (key instanceof ECPrivateKey) {
 125                 ECPrivateKey ecKey = (ECPrivateKey)key;
 126                 return generatePrivate(
 127                     ecKey.getS(),
 128                     ecKey.getParams()
 129                 );
 130             } else if ("PKCS#8".equals(key.getFormat())) {
 131                 // let Sun provider parse for us, then recurse
 132                 byte[] encoded = key.getEncoded();
 133                 key = new sun.security.ec.ECPrivateKeyImpl(encoded);
 134                 return implTranslatePrivateKey(key);
 135             } else {
 136                 throw new InvalidKeyException("PrivateKey must be instance "
 137                         + "of ECPrivateKey or have PKCS#8 encoding");
 138             }
 139         } catch (PKCS11Exception e) {
 140             throw new InvalidKeyException("Could not create EC private key", e);
 141         }
 142     }
 143 
 144     // see JCA spec
 145     protected PublicKey engineGeneratePublic(KeySpec keySpec)
 146             throws InvalidKeySpecException {
 147         token.ensureValid();
 148         if (keySpec instanceof X509EncodedKeySpec) {
 149             try {
 150                 byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded();
 151                 PublicKey key = new sun.security.ec.ECPublicKeyImpl(encoded);
 152                 return implTranslatePublicKey(key);
 153             } catch (InvalidKeyException e) {
 154                 throw new InvalidKeySpecException
 155                         ("Could not create EC public key", e);
 156             }
 157         }
 158         if (keySpec instanceof ECPublicKeySpec == false) {
 159             throw new InvalidKeySpecException("Only ECPublicKeySpec and "
 160                 + "X509EncodedKeySpec supported for EC public keys");
 161         }
 162         try {
 163             ECPublicKeySpec ec = (ECPublicKeySpec)keySpec;
 164             return generatePublic(
 165                 ec.getW(),
 166                 ec.getParams()
 167             );
 168         } catch (PKCS11Exception e) {
 169             throw new InvalidKeySpecException
 170                 ("Could not create EC public key", e);
 171         }
 172     }
 173 
 174     // see JCA spec
 175     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
 176             throws InvalidKeySpecException {
 177         token.ensureValid();
 178         if (keySpec instanceof PKCS8EncodedKeySpec) {
 179             try {
 180                 byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
 181                 PrivateKey key = new sun.security.ec.ECPrivateKeyImpl(encoded);
 182                 return implTranslatePrivateKey(key);
 183             } catch (GeneralSecurityException e) {
 184                 throw new InvalidKeySpecException
 185                         ("Could not create EC private key", e);
 186             }
 187         }
 188         if (keySpec instanceof ECPrivateKeySpec == false) {
 189             throw new InvalidKeySpecException("Only ECPrivateKeySpec and "
 190                 + "PKCS8EncodedKeySpec supported for EC private keys");
 191         }
 192         try {
 193             ECPrivateKeySpec ec = (ECPrivateKeySpec)keySpec;
 194             return generatePrivate(
 195                 ec.getS(),
 196                 ec.getParams()
 197             );
 198         } catch (PKCS11Exception e) {
 199             throw new InvalidKeySpecException
 200                 ("Could not create EC private key", e);
 201         }
 202     }
 203 
 204     private PublicKey generatePublic(ECPoint point, ECParameterSpec params) throws PKCS11Exception {
 205         byte[] encodedParams = ECParameters.encodeParameters(params);
 206         byte[] encodedPoint = null;
 207         DerValue pkECPoint = new DerValue(DerValue.tag_OctetString,
 208             ECParameters.encodePoint(point, params.getCurve()));
 209 
 210         try {
 211             encodedPoint = pkECPoint.toByteArray();
 212         } catch (IOException e) {
 213             throw new IllegalArgumentException("Could not DER encode point", e);
 214         }
 215 
 216         CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 217             new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),
 218             new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC),
 219             new CK_ATTRIBUTE(CKA_EC_POINT, encodedPoint),
 220             new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),
 221         };
 222         attributes = token.getAttributes
 223                 (O_IMPORT, CKO_PUBLIC_KEY, CKK_EC, attributes);
 224         Session session = null;
 225         try {
 226             session = token.getObjSession();
 227             long keyID = token.p11.C_CreateObject(session.id(), attributes);
 228             return P11Key.publicKey
 229                 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes);
 230         } finally {
 231             token.releaseSession(session);
 232         }
 233     }
 234 
 235     private PrivateKey generatePrivate(BigInteger s, ECParameterSpec params) throws PKCS11Exception {
 236         byte[] encodedParams = ECParameters.encodeParameters(params);
 237         CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 238             new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
 239             new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_EC),
 240             new CK_ATTRIBUTE(CKA_VALUE, s),
 241             new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),
 242         };
 243         attributes = token.getAttributes
 244                 (O_IMPORT, CKO_PRIVATE_KEY, CKK_EC, attributes);
 245         Session session = null;
 246         try {
 247             session = token.getObjSession();
 248             long keyID = token.p11.C_CreateObject(session.id(), attributes);
 249             return P11Key.privateKey
 250                 (session, keyID, "EC", params.getCurve().getField().getFieldSize(), attributes);
 251         } finally {
 252             token.releaseSession(session);
 253         }
 254     }
 255 
 256     KeySpec implGetPublicKeySpec(P11Key key, Class keySpec, Session[] session)
 257             throws PKCS11Exception, InvalidKeySpecException {
 258         if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
 259             session[0] = token.getObjSession();
 260             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 261                 new CK_ATTRIBUTE(CKA_EC_POINT),
 262                 new CK_ATTRIBUTE(CKA_EC_PARAMS),
 263             };
 264             token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes);
 265             try {
 266                 ECParameterSpec params = decodeParameters(attributes[1].getByteArray());
 267                 ECPoint point = decodePoint(attributes[0].getByteArray(), params.getCurve());
 268                 return new ECPublicKeySpec(point, params);
 269             } catch (IOException e) {
 270                 throw new InvalidKeySpecException("Could not parse key", e);
 271             }
 272         } else { // X.509 handled in superclass
 273             throw new InvalidKeySpecException("Only ECPublicKeySpec and "
 274                 + "X509EncodedKeySpec supported for EC public keys");
 275         }
 276     }
 277 
 278     KeySpec implGetPrivateKeySpec(P11Key key, Class keySpec, Session[] session)
 279             throws PKCS11Exception, InvalidKeySpecException {
 280         if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
 281             session[0] = token.getObjSession();
 282             CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
 283                 new CK_ATTRIBUTE(CKA_VALUE),
 284                 new CK_ATTRIBUTE(CKA_EC_PARAMS),
 285             };
 286             token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes);
 287             try {
 288                 ECParameterSpec params = decodeParameters(attributes[1].getByteArray());
 289                 return new ECPrivateKeySpec(attributes[0].getBigInteger(), params);
 290             } catch (IOException e) {
 291                 throw new InvalidKeySpecException("Could not parse key", e);
 292             }
 293         } else { // PKCS#8 handled in superclass
 294             throw new InvalidKeySpecException("Only ECPrivateKeySpec "
 295                 + "and PKCS8EncodedKeySpec supported for EC private keys");
 296         }
 297     }
 298 
 299     KeyFactory implGetSoftwareFactory() throws GeneralSecurityException {
 300         return sun.security.ec.ECKeyFactory.INSTANCE;
 301     }
 302 
 303 }