111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root/* 211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Copyright (C) 2013 The Android Open Source Project 311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * 411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * you may not use this file except in compliance with the License. 611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * You may obtain a copy of the License at 711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * 811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * http://www.apache.org/licenses/LICENSE-2.0 911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * 1011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * Unless required by applicable law or agreed to in writing, software 1111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 1211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * See the License for the specific language governing permissions and 1411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root * limitations under the License. 1511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root */ 1611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 1811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 1911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.math.BigInteger; 2011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.InvalidKeyException; 2111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.Key; 2211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.KeyFactorySpi; 2311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.PrivateKey; 2411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.PublicKey; 2511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.interfaces.ECPrivateKey; 2611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.interfaces.ECPublicKey; 2711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECParameterSpec; 2811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPoint; 2911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPrivateKeySpec; 3011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPublicKeySpec; 3111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.InvalidKeySpecException; 3211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.KeySpec; 3311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.PKCS8EncodedKeySpec; 3411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.X509EncodedKeySpec; 3511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 365070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root/** 3729916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittler * An implementation of a {@link KeyFactorySpi} for EC keys based on BoringSSL. 385070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root * 395070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root * @hide 405070bdfc6277af136b7eb5fe5d0d72ad2ff6a2ebKenny Root */ 41dbe082cb70a1ffbe1a693bd583a06ecad585f46dNathan Mittler@Internal 4229916ef38dc9cb4e4c6e3fdb87d4e921546d3ef4Nathan Mittlerpublic final class OpenSSLECKeyFactory extends KeyFactorySpi { 4311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 4411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root @Override 4511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException { 46d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (keySpec == null) { 47d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("keySpec == null"); 48d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 4911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 50d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (keySpec instanceof ECPublicKeySpec) { 51d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec); 5211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } else if (keySpec instanceof X509EncodedKeySpec) { 53f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC); 5411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 5511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was " 5611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root + keySpec.getClass().getName()); 5711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 5811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 5911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root @Override 6011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root protected PrivateKey engineGeneratePrivate(KeySpec keySpec) throws InvalidKeySpecException { 61d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (keySpec == null) { 62d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("keySpec == null"); 63d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 6411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 65d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (keySpec instanceof ECPrivateKeySpec) { 66d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root return new OpenSSLECPrivateKey((ECPrivateKeySpec) keySpec); 6711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } else if (keySpec instanceof PKCS8EncodedKeySpec) { 68d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root return OpenSSLKey.getPrivateKey((PKCS8EncodedKeySpec) keySpec, 69f79c90d56464e254ce8645f886ec0ca47573ced1Adam Langley NativeConstants.EVP_PKEY_EC); 7011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 719414cebabcf332fcca1f40fa629cc471cfbbc21cKenny Root throw new InvalidKeySpecException("Must use ECPrivateKeySpec or PKCS8EncodedKeySpec; was " 7211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root + keySpec.getClass().getName()); 7311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 7411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 7511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root @Override 7611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec) 7711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throws InvalidKeySpecException { 7811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root if (key == null) { 7911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeySpecException("key == null"); 8011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 8111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 8211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root if (keySpec == null) { 8311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeySpecException("keySpec == null"); 8411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 8511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 86d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (!"EC".equals(key.getAlgorithm())) { 87d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Key must be an EC key"); 88d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 8911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 90d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (key instanceof ECPublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 91d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root ECPublicKey ecKey = (ECPublicKey) key; 92d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") 93d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams()); 94d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 95d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (key instanceof PublicKey && ECPublicKeySpec.class.isAssignableFrom(keySpec)) { 96d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root final byte[] encoded = key.getEncoded(); 97d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (!"X.509".equals(key.getFormat()) || encoded == null) { 98d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Not a valid X.509 encoding"); 9911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 100d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root ECPublicKey ecKey = (ECPublicKey) engineGeneratePublic(new X509EncodedKeySpec(encoded)); 101d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") 102d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams()); 103d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 104d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (key instanceof ECPrivateKey 105d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 10611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECPrivateKey ecKey = (ECPrivateKey) key; 107d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") 108d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams()); 109d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 110d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (key instanceof PrivateKey && ECPrivateKeySpec.class.isAssignableFrom(keySpec)) { 111d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root final byte[] encoded = key.getEncoded(); 112d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (!"PKCS#8".equals(key.getFormat()) || encoded == null) { 113d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Not a valid PKCS#8 encoding"); 114d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 115d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root ECPrivateKey ecKey = 116d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root (ECPrivateKey) engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); 117d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") 118d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root T result = (T) new ECPrivateKeySpec(ecKey.getS(), ecKey.getParams()); 119d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 120d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (key instanceof PrivateKey 121d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root && PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) { 122d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root final byte[] encoded = key.getEncoded(); 123d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (!"PKCS#8".equals(key.getFormat())) { 124d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Encoding type must be PKCS#8; was " 125d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root + key.getFormat()); 126d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (encoded == null) { 127d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Key is not encodable"); 128d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 129d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") T result = (T) new PKCS8EncodedKeySpec(encoded); 130d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 131d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (key instanceof PublicKey && X509EncodedKeySpec.class.isAssignableFrom(keySpec)) { 132d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root final byte[] encoded = key.getEncoded(); 133d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root if (!"X.509".equals(key.getFormat())) { 134d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Encoding type must be X.509; was " 135d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root + key.getFormat()); 136d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } else if (encoded == null) { 137d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Key is not encodable"); 13811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 139d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root @SuppressWarnings("unchecked") T result = (T) new X509EncodedKeySpec(encoded); 140d5d2c11d5491e4e9192f9d0e7bae086d31a7d472Kenny Root return result; 14111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } else { 142d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeySpecException("Unsupported key type and key spec combination; key=" 143d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root + key.getClass().getName() + ", keySpec=" + keySpec.getName()); 14411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 14511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 14611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 14711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root @Override 14811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root protected Key engineTranslateKey(Key key) throws InvalidKeyException { 14911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root if (key == null) { 15011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeyException("key == null"); 15111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 1520c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin if ((key instanceof OpenSSLECPublicKey) || (key instanceof OpenSSLECPrivateKey)) { 1530c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin return key; 1540c1d455738a5d4b054b85d72d2c9f216b4f57291Alex Klyubin } else if (key instanceof ECPublicKey) { 15511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECPublicKey ecKey = (ECPublicKey) key; 15611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 15711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECPoint w = ecKey.getW(); 15811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 15911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECParameterSpec params = ecKey.getParams(); 16011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 16111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root try { 16211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root return engineGeneratePublic(new ECPublicKeySpec(w, params)); 16311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } catch (InvalidKeySpecException e) { 16411b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeyException(e); 16511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 16611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } else if (key instanceof ECPrivateKey) { 16711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECPrivateKey ecKey = (ECPrivateKey) key; 16811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 16911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root BigInteger s = ecKey.getS(); 17011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 17111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root ECParameterSpec params = ecKey.getParams(); 17211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 17311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root try { 1749414cebabcf332fcca1f40fa629cc471cfbbc21cKenny Root return engineGeneratePrivate(new ECPrivateKeySpec(s, params)); 17511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } catch (InvalidKeySpecException e) { 17611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeyException(e); 17711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 178724f18f3f9fdc2501bc21d05959f7bb774b7774dAlex Klyubin } else if ((key instanceof PrivateKey) && ("PKCS#8".equals(key.getFormat()))) { 1791d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin byte[] encoded = key.getEncoded(); 1801d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin if (encoded == null) { 1811d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin throw new InvalidKeyException("Key does not support encoding"); 1821d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin } 183d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root try { 1841d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin return engineGeneratePrivate(new PKCS8EncodedKeySpec(encoded)); 185d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } catch (InvalidKeySpecException e) { 186d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeyException(e); 187d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 188724f18f3f9fdc2501bc21d05959f7bb774b7774dAlex Klyubin } else if ((key instanceof PublicKey) && ("X.509".equals(key.getFormat()))) { 1891d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin byte[] encoded = key.getEncoded(); 1901d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin if (encoded == null) { 1911d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin throw new InvalidKeyException("Key does not support encoding"); 1921d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin } 193d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root try { 1941d0cdbb1aa7e0706b8bd7d43b1b585bcac2d8979Alex Klyubin return engineGeneratePublic(new X509EncodedKeySpec(encoded)); 195d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } catch (InvalidKeySpecException e) { 196d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeyException(e); 197d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root } 19811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } else { 199d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root throw new InvalidKeyException("Key must be EC public or private key; was " 200cb4e73b4fffb5c5608f320f0af1004ebcfad71c0Kenny Root + key.getClass().getName()); 20111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 20211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 20311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root} 204