1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package sun.security.ec; 28 29 import java.security.*; 30 import java.security.interfaces.*; 31 import java.security.spec.*; 32 33 /** 34 * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey 35 * and getAlgorithm() must return "EC". For such keys, it supports conversion 36 * between the following: 37 * 38 * For public keys: 39 * . PublicKey with an X.509 encoding 40 * . ECPublicKey 41 * . ECPublicKeySpec 42 * . X509EncodedKeySpec 43 * 44 * For private keys: 45 * . PrivateKey with a PKCS#8 encoding 46 * . ECPrivateKey 47 * . ECPrivateKeySpec 48 * . PKCS8EncodedKeySpec 49 * 50 * @since 1.6 51 * @author Andreas Sterbenz 52 */ 53 public final class ECKeyFactory extends KeyFactorySpi { 54 55 // Used by translateKey() and the SunPKCS11 provider 56 public final static KeyFactory INSTANCE; 57 58 // Internal provider object we can obtain the KeyFactory and 59 // AlgorithmParameters from. Used by ECParameters and AlgorithmId. 60 // This can go away once we have EC always available in the SUN provider. 61 // Used by ECParameters and AlgorithmId. 62 public final static Provider ecInternalProvider; 63 64 static { 65 final Provider p = new Provider("SunEC-Internal", 1.0d, null) {}; AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { p.put("KeyFactory.EC", ECKeyFactory.class.getName()); p.put("AlgorithmParameters.EC", ECParameters.class.getName()); p.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC"); return null; } })66 AccessController.doPrivileged(new PrivilegedAction<Void>() { 67 public Void run() { 68 // Android changed : replace string reference with class name. It 69 // makes no difference in this case since these classes are already 70 // in direct use here. 71 p.put("KeyFactory.EC", ECKeyFactory.class.getName()); 72 p.put("AlgorithmParameters.EC", ECParameters.class.getName()); 73 p.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC"); 74 return null; 75 } 76 }); 77 try { 78 INSTANCE = KeyFactory.getInstance("EC", p); 79 } catch (NoSuchAlgorithmException e) { 80 throw new RuntimeException(e); 81 } 82 ecInternalProvider = p; 83 } 84 ECKeyFactory()85 public ECKeyFactory() { 86 // empty 87 } 88 89 /** 90 * Static method to convert Key into a useable instance of 91 * ECPublicKey or ECPrivateKey. Check the key and convert it 92 * to a Sun key if necessary. If the key is not an EC key 93 * or cannot be used, throw an InvalidKeyException. 94 * 95 * The difference between this method and engineTranslateKey() is that 96 * we do not convert keys of other providers that are already an 97 * instance of ECPublicKey or ECPrivateKey. 98 * 99 * To be used by future Java ECDSA and ECDH implementations. 100 */ toECKey(Key key)101 public static ECKey toECKey(Key key) throws InvalidKeyException { 102 if (key instanceof ECKey) { 103 ECKey ecKey = (ECKey)key; 104 checkKey(ecKey); 105 return ecKey; 106 } else { 107 return (ECKey)INSTANCE.translateKey(key); 108 } 109 } 110 111 /** 112 * Check that the given EC key is valid. 113 */ checkKey(ECKey key)114 private static void checkKey(ECKey key) throws InvalidKeyException { 115 // check for subinterfaces, omit additional checks for our keys 116 if (key instanceof ECPublicKey) { 117 if (key instanceof ECPublicKeyImpl) { 118 return; 119 } 120 } else if (key instanceof ECPrivateKey) { 121 if (key instanceof ECPrivateKeyImpl) { 122 return; 123 } 124 } else { 125 throw new InvalidKeyException("Neither a public nor a private key"); 126 } 127 // ECKey does not extend Key, so we need to do a cast 128 String keyAlg = ((Key)key).getAlgorithm(); 129 if (keyAlg.equals("EC") == false) { 130 throw new InvalidKeyException("Not an EC key: " + keyAlg); 131 } 132 // XXX further sanity checks about whether this key uses supported 133 // fields, point formats, etc. would go here 134 } 135 136 /** 137 * Translate an EC key into a Sun EC key. If conversion is 138 * not possible, throw an InvalidKeyException. 139 * See also JCA doc. 140 */ engineTranslateKey(Key key)141 protected Key engineTranslateKey(Key key) throws InvalidKeyException { 142 if (key == null) { 143 throw new InvalidKeyException("Key must not be null"); 144 } 145 String keyAlg = key.getAlgorithm(); 146 if (keyAlg.equals("EC") == false) { 147 throw new InvalidKeyException("Not an EC key: " + keyAlg); 148 } 149 if (key instanceof PublicKey) { 150 return implTranslatePublicKey((PublicKey)key); 151 } else if (key instanceof PrivateKey) { 152 return implTranslatePrivateKey((PrivateKey)key); 153 } else { 154 throw new InvalidKeyException("Neither a public nor a private key"); 155 } 156 } 157 158 // see JCA doc engineGeneratePublic(KeySpec keySpec)159 protected PublicKey engineGeneratePublic(KeySpec keySpec) 160 throws InvalidKeySpecException { 161 try { 162 return implGeneratePublic(keySpec); 163 } catch (InvalidKeySpecException e) { 164 throw e; 165 } catch (GeneralSecurityException e) { 166 throw new InvalidKeySpecException(e); 167 } 168 } 169 170 // see JCA doc engineGeneratePrivate(KeySpec keySpec)171 protected PrivateKey engineGeneratePrivate(KeySpec keySpec) 172 throws InvalidKeySpecException { 173 try { 174 return implGeneratePrivate(keySpec); 175 } catch (InvalidKeySpecException e) { 176 throw e; 177 } catch (GeneralSecurityException e) { 178 throw new InvalidKeySpecException(e); 179 } 180 } 181 182 // internal implementation of translateKey() for public keys. See JCA doc implTranslatePublicKey(PublicKey key)183 private PublicKey implTranslatePublicKey(PublicKey key) 184 throws InvalidKeyException { 185 if (key instanceof ECPublicKey) { 186 if (key instanceof ECPublicKeyImpl) { 187 return key; 188 } 189 ECPublicKey ecKey = (ECPublicKey)key; 190 return new ECPublicKeyImpl( 191 ecKey.getW(), 192 ecKey.getParams() 193 ); 194 } else if ("X.509".equals(key.getFormat())) { 195 byte[] encoded = key.getEncoded(); 196 return new ECPublicKeyImpl(encoded); 197 } else { 198 throw new InvalidKeyException("Public keys must be instance " 199 + "of ECPublicKey or have X.509 encoding"); 200 } 201 } 202 203 // internal implementation of translateKey() for private keys. See JCA doc implTranslatePrivateKey(PrivateKey key)204 private PrivateKey implTranslatePrivateKey(PrivateKey key) 205 throws InvalidKeyException { 206 if (key instanceof ECPrivateKey) { 207 if (key instanceof ECPrivateKeyImpl) { 208 return key; 209 } 210 ECPrivateKey ecKey = (ECPrivateKey)key; 211 return new ECPrivateKeyImpl( 212 ecKey.getS(), 213 ecKey.getParams() 214 ); 215 } else if ("PKCS#8".equals(key.getFormat())) { 216 return new ECPrivateKeyImpl(key.getEncoded()); 217 } else { 218 throw new InvalidKeyException("Private keys must be instance " 219 + "of ECPrivateKey or have PKCS#8 encoding"); 220 } 221 } 222 223 // internal implementation of generatePublic. See JCA doc implGeneratePublic(KeySpec keySpec)224 private PublicKey implGeneratePublic(KeySpec keySpec) 225 throws GeneralSecurityException { 226 if (keySpec instanceof X509EncodedKeySpec) { 227 X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec; 228 return new ECPublicKeyImpl(x509Spec.getEncoded()); 229 } else if (keySpec instanceof ECPublicKeySpec) { 230 ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec; 231 return new ECPublicKeyImpl( 232 ecSpec.getW(), 233 ecSpec.getParams() 234 ); 235 } else { 236 throw new InvalidKeySpecException("Only ECPublicKeySpec " 237 + "and X509EncodedKeySpec supported for EC public keys"); 238 } 239 } 240 241 // internal implementation of generatePrivate. See JCA doc implGeneratePrivate(KeySpec keySpec)242 private PrivateKey implGeneratePrivate(KeySpec keySpec) 243 throws GeneralSecurityException { 244 if (keySpec instanceof PKCS8EncodedKeySpec) { 245 PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec; 246 return new ECPrivateKeyImpl(pkcsSpec.getEncoded()); 247 } else if (keySpec instanceof ECPrivateKeySpec) { 248 ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec; 249 return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams()); 250 } else { 251 throw new InvalidKeySpecException("Only ECPrivateKeySpec " 252 + "and PKCS8EncodedKeySpec supported for EC private keys"); 253 } 254 } 255 engineGetKeySpec(Key key, Class<T> keySpec)256 protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) 257 throws InvalidKeySpecException { 258 try { 259 // convert key to one of our keys 260 // this also verifies that the key is a valid EC key and ensures 261 // that the encoding is X.509/PKCS#8 for public/private keys 262 key = engineTranslateKey(key); 263 } catch (InvalidKeyException e) { 264 throw new InvalidKeySpecException(e); 265 } 266 if (key instanceof ECPublicKey) { 267 ECPublicKey ecKey = (ECPublicKey)key; 268 if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 269 return (T) new ECPublicKeySpec( 270 ecKey.getW(), 271 ecKey.getParams() 272 ); 273 } else if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { 274 return (T) new X509EncodedKeySpec(key.getEncoded()); 275 } else { 276 throw new InvalidKeySpecException 277 ("KeySpec must be ECPublicKeySpec or " 278 + "X509EncodedKeySpec for EC public keys"); 279 } 280 } else if (key instanceof ECPrivateKey) { 281 if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { 282 return (T) new PKCS8EncodedKeySpec(key.getEncoded()); 283 } else if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 284 ECPrivateKey ecKey = (ECPrivateKey)key; 285 return (T) new ECPrivateKeySpec( 286 ecKey.getS(), 287 ecKey.getParams() 288 ); 289 } else { 290 throw new InvalidKeySpecException 291 ("KeySpec must be ECPrivateKeySpec or " 292 + "PKCS8EncodedKeySpec for EC private keys"); 293 } 294 } else { 295 // should not occur, caught in engineTranslateKey() 296 throw new InvalidKeySpecException("Neither public nor private key"); 297 } 298 } 299 } 300