18b7521eb38878822be3817270cc074ee1e22095dKenny Root/* 28b7521eb38878822be3817270cc074ee1e22095dKenny Root * Copyright (C) 2012 The Android Open Source Project 38b7521eb38878822be3817270cc074ee1e22095dKenny Root * 48b7521eb38878822be3817270cc074ee1e22095dKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 58b7521eb38878822be3817270cc074ee1e22095dKenny Root * you may not use this file except in compliance with the License. 68b7521eb38878822be3817270cc074ee1e22095dKenny Root * You may obtain a copy of the License at 78b7521eb38878822be3817270cc074ee1e22095dKenny Root * 88b7521eb38878822be3817270cc074ee1e22095dKenny Root * http://www.apache.org/licenses/LICENSE-2.0 98b7521eb38878822be3817270cc074ee1e22095dKenny Root * 108b7521eb38878822be3817270cc074ee1e22095dKenny Root * Unless required by applicable law or agreed to in writing, software 118b7521eb38878822be3817270cc074ee1e22095dKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 128b7521eb38878822be3817270cc074ee1e22095dKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138b7521eb38878822be3817270cc074ee1e22095dKenny Root * See the License for the specific language governing permissions and 148b7521eb38878822be3817270cc074ee1e22095dKenny Root * limitations under the License. 158b7521eb38878822be3817270cc074ee1e22095dKenny Root */ 168b7521eb38878822be3817270cc074ee1e22095dKenny Root 17860d2707ce126ef8f66e3eac7ceeab6d24218cd8Kenny Rootpackage org.conscrypt; 188b7521eb38878822be3817270cc074ee1e22095dKenny Root 198b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.io.IOException; 208b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.io.NotSerializableException; 218b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.io.ObjectInputStream; 228b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.io.ObjectOutputStream; 238b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.math.BigInteger; 24f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Rootimport java.security.InvalidAlgorithmParameterException; 258b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.security.InvalidKeyException; 268b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.security.interfaces.ECPrivateKey; 278b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.security.spec.ECParameterSpec; 2811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.ECPrivateKeySpec; 2911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Rootimport java.security.spec.InvalidKeySpecException; 308b7521eb38878822be3817270cc074ee1e22095dKenny Rootimport java.util.Arrays; 318b7521eb38878822be3817270cc074ee1e22095dKenny Root 3247cc520bd63c1eabfdef23cbab10457701f2a395Kenny Rootpublic final class OpenSSLECPrivateKey implements ECPrivateKey, OpenSSLKeyHolder { 338b7521eb38878822be3817270cc074ee1e22095dKenny Root private static final long serialVersionUID = -4036633595001083922L; 348b7521eb38878822be3817270cc074ee1e22095dKenny Root 358b7521eb38878822be3817270cc074ee1e22095dKenny Root private static final String ALGORITHM = "EC"; 368b7521eb38878822be3817270cc074ee1e22095dKenny Root 378b7521eb38878822be3817270cc074ee1e22095dKenny Root protected transient OpenSSLKey key; 388b7521eb38878822be3817270cc074ee1e22095dKenny Root 398b7521eb38878822be3817270cc074ee1e22095dKenny Root protected transient OpenSSLECGroupContext group; 408b7521eb38878822be3817270cc074ee1e22095dKenny Root 418b7521eb38878822be3817270cc074ee1e22095dKenny Root public OpenSSLECPrivateKey(OpenSSLECGroupContext group, OpenSSLKey key) { 428b7521eb38878822be3817270cc074ee1e22095dKenny Root this.group = group; 438b7521eb38878822be3817270cc074ee1e22095dKenny Root this.key = key; 448b7521eb38878822be3817270cc074ee1e22095dKenny Root } 458b7521eb38878822be3817270cc074ee1e22095dKenny Root 4647cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root public OpenSSLECPrivateKey(OpenSSLKey key) { 4738c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 4847cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root this.group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 4947cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root this.key = key; 5047cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root } 5147cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root 5211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root public OpenSSLECPrivateKey(ECPrivateKeySpec ecKeySpec) throws InvalidKeySpecException { 5311b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root try { 54d4600d69dba0f1df24e8df7328fa473632c32822Kenny Root group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); 5511b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root final BigInteger privKey = ecKeySpec.getS(); 5611b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 0, 5711b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root privKey.toByteArray())); 5811b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } catch (Exception e) { 5911b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root throw new InvalidKeySpecException(e); 6011b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 6111b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root } 6211b3e7025853f061e2f0e0ce1e248e730eca721eKenny Root 63f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root public static OpenSSLKey wrapPlatformKey(ECPrivateKey ecPrivateKey) throws InvalidKeyException { 64f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root OpenSSLECGroupContext group; 65f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root try { 66f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root group = OpenSSLECGroupContext.getInstance(ecPrivateKey.getParams()); 67f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } catch (InvalidAlgorithmParameterException e) { 68f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root throw new InvalidKeyException("Unknown group parameters", e); 69f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 70f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return wrapPlatformKey(ecPrivateKey, group); 71f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 72f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 73dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root private static OpenSSLKey wrapPlatformKey(ECPrivateKey ecPrivateKey, 74dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root OpenSSLECGroupContext group) throws InvalidKeyException { 75dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root return new OpenSSLKey(NativeCrypto.getECPrivateKeyWrapper(ecPrivateKey, 76dac92c69d3a147ea57bc7bd28c96b6365c1988e2Kenny Root group.getContext()), true); 77f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 78f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 798b7521eb38878822be3817270cc074ee1e22095dKenny Root public static OpenSSLKey getInstance(ECPrivateKey ecPrivateKey) throws InvalidKeyException { 808b7521eb38878822be3817270cc074ee1e22095dKenny Root try { 818b7521eb38878822be3817270cc074ee1e22095dKenny Root OpenSSLECGroupContext group = OpenSSLECGroupContext.getInstance(ecPrivateKey 828b7521eb38878822be3817270cc074ee1e22095dKenny Root .getParams()); 83f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 84f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root /** 85f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * If the key is not encodable (PKCS11-like key), then wrap it and 86f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root * use JNI upcalls to satisfy requests. 87f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root */ 88f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root if (ecPrivateKey.getFormat() == null) { 89f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root return wrapPlatformKey(ecPrivateKey, group); 90f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root } 91f24ba0620d88b7d71ddb089b97d29fb1b073718dKenny Root 928b7521eb38878822be3817270cc074ee1e22095dKenny Root final BigInteger privKey = ecPrivateKey.getS(); 938b7521eb38878822be3817270cc074ee1e22095dKenny Root return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 0, 948b7521eb38878822be3817270cc074ee1e22095dKenny Root privKey.toByteArray())); 958b7521eb38878822be3817270cc074ee1e22095dKenny Root } catch (Exception e) { 968b7521eb38878822be3817270cc074ee1e22095dKenny Root throw new InvalidKeyException(e); 978b7521eb38878822be3817270cc074ee1e22095dKenny Root } 988b7521eb38878822be3817270cc074ee1e22095dKenny Root } 998b7521eb38878822be3817270cc074ee1e22095dKenny Root 1008b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1018b7521eb38878822be3817270cc074ee1e22095dKenny Root public String getAlgorithm() { 1028b7521eb38878822be3817270cc074ee1e22095dKenny Root return ALGORITHM; 1038b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1048b7521eb38878822be3817270cc074ee1e22095dKenny Root 1058b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1068b7521eb38878822be3817270cc074ee1e22095dKenny Root public String getFormat() { 107ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root /* 108ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * If we're using an OpenSSL ENGINE, there's no guarantee we can export 109ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * the key. Returning {@code null} tells the caller that there's no 110ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * encoded format. 111ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root */ 112ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root if (key.isEngineBased()) { 113ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root return null; 114ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root } 115ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root 1168b7521eb38878822be3817270cc074ee1e22095dKenny Root return "PKCS#8"; 1178b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1188b7521eb38878822be3817270cc074ee1e22095dKenny Root 1198b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1208b7521eb38878822be3817270cc074ee1e22095dKenny Root public byte[] getEncoded() { 121ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root /* 122ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * If we're using an OpenSSL ENGINE, there's no guarantee we can export 123ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * the key. Returning {@code null} tells the caller that there's no 124ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root * encoded format. 125ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root */ 126ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root if (key.isEngineBased()) { 127ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root return null; 128ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root } 129ba1ea0caa5d6059e73b67068819e5948cfa1bc95Kenny Root 1308b7521eb38878822be3817270cc074ee1e22095dKenny Root return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext()); 1318b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1328b7521eb38878822be3817270cc074ee1e22095dKenny Root 1338b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1348b7521eb38878822be3817270cc074ee1e22095dKenny Root public ECParameterSpec getParams() { 1358b7521eb38878822be3817270cc074ee1e22095dKenny Root return group.getECParameterSpec(); 1368b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1378b7521eb38878822be3817270cc074ee1e22095dKenny Root 1388b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1398b7521eb38878822be3817270cc074ee1e22095dKenny Root public BigInteger getS() { 140f42ec17cfa43a002814e901d63ae8a93d77f7fc3Kenny Root if (key.isEngineBased()) { 141f42ec17cfa43a002814e901d63ae8a93d77f7fc3Kenny Root throw new UnsupportedOperationException("private key value S cannot be extracted"); 142f42ec17cfa43a002814e901d63ae8a93d77f7fc3Kenny Root } 143f42ec17cfa43a002814e901d63ae8a93d77f7fc3Kenny Root 1448b7521eb38878822be3817270cc074ee1e22095dKenny Root return getPrivateKey(); 1458b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1468b7521eb38878822be3817270cc074ee1e22095dKenny Root 1478b7521eb38878822be3817270cc074ee1e22095dKenny Root private BigInteger getPrivateKey() { 1488b7521eb38878822be3817270cc074ee1e22095dKenny Root return new BigInteger(NativeCrypto.EC_KEY_get_private_key(key.getPkeyContext())); 1498b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1508b7521eb38878822be3817270cc074ee1e22095dKenny Root 15147cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root @Override 15247cc520bd63c1eabfdef23cbab10457701f2a395Kenny Root public OpenSSLKey getOpenSSLKey() { 1538b7521eb38878822be3817270cc074ee1e22095dKenny Root return key; 1548b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1558b7521eb38878822be3817270cc074ee1e22095dKenny Root 1568b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1578b7521eb38878822be3817270cc074ee1e22095dKenny Root public boolean equals(Object o) { 1588b7521eb38878822be3817270cc074ee1e22095dKenny Root if (o == this) { 1598b7521eb38878822be3817270cc074ee1e22095dKenny Root return true; 1608b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1618b7521eb38878822be3817270cc074ee1e22095dKenny Root 1628b7521eb38878822be3817270cc074ee1e22095dKenny Root if (o instanceof OpenSSLECPrivateKey) { 1638b7521eb38878822be3817270cc074ee1e22095dKenny Root OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o; 1648b7521eb38878822be3817270cc074ee1e22095dKenny Root return key.equals(other.key); 1658b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1668b7521eb38878822be3817270cc074ee1e22095dKenny Root 1678b7521eb38878822be3817270cc074ee1e22095dKenny Root if (!(o instanceof ECPrivateKey)) { 1688b7521eb38878822be3817270cc074ee1e22095dKenny Root return false; 1698b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1708b7521eb38878822be3817270cc074ee1e22095dKenny Root 1718b7521eb38878822be3817270cc074ee1e22095dKenny Root final ECPrivateKey other = (ECPrivateKey) o; 1728b7521eb38878822be3817270cc074ee1e22095dKenny Root if (!getPrivateKey().equals(other.getS())) { 1738b7521eb38878822be3817270cc074ee1e22095dKenny Root return false; 1748b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1758b7521eb38878822be3817270cc074ee1e22095dKenny Root 1768b7521eb38878822be3817270cc074ee1e22095dKenny Root final ECParameterSpec spec = getParams(); 1778b7521eb38878822be3817270cc074ee1e22095dKenny Root final ECParameterSpec otherSpec = other.getParams(); 1788b7521eb38878822be3817270cc074ee1e22095dKenny Root 1798b7521eb38878822be3817270cc074ee1e22095dKenny Root return spec.getCurve().equals(otherSpec.getCurve()) 1808b7521eb38878822be3817270cc074ee1e22095dKenny Root && spec.getGenerator().equals(otherSpec.getGenerator()) 1818b7521eb38878822be3817270cc074ee1e22095dKenny Root && spec.getOrder().equals(otherSpec.getOrder()) 1828b7521eb38878822be3817270cc074ee1e22095dKenny Root && spec.getCofactor() == otherSpec.getCofactor(); 1838b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1848b7521eb38878822be3817270cc074ee1e22095dKenny Root 1858b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1868b7521eb38878822be3817270cc074ee1e22095dKenny Root public int hashCode() { 1878b7521eb38878822be3817270cc074ee1e22095dKenny Root return Arrays.hashCode(NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext())); 1888b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1898b7521eb38878822be3817270cc074ee1e22095dKenny Root 1908b7521eb38878822be3817270cc074ee1e22095dKenny Root @Override 1918b7521eb38878822be3817270cc074ee1e22095dKenny Root public String toString() { 1928b7521eb38878822be3817270cc074ee1e22095dKenny Root return NativeCrypto.EVP_PKEY_print_private(key.getPkeyContext()); 1938b7521eb38878822be3817270cc074ee1e22095dKenny Root } 1948b7521eb38878822be3817270cc074ee1e22095dKenny Root 1958b7521eb38878822be3817270cc074ee1e22095dKenny Root private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 1968b7521eb38878822be3817270cc074ee1e22095dKenny Root stream.defaultReadObject(); 1978b7521eb38878822be3817270cc074ee1e22095dKenny Root 1985b36f6cc5f013574dc453e8938fcae13185c7732Kenny Root byte[] encoded = (byte[]) stream.readObject(); 1998b7521eb38878822be3817270cc074ee1e22095dKenny Root 2005b36f6cc5f013574dc453e8938fcae13185c7732Kenny Root key = new OpenSSLKey(NativeCrypto.d2i_PKCS8_PRIV_KEY_INFO(encoded)); 2018b7521eb38878822be3817270cc074ee1e22095dKenny Root 20238c70d393f14cf0963a289caefb72e6ac14e23d3Joel Dice final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 2035b36f6cc5f013574dc453e8938fcae13185c7732Kenny Root group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 2048b7521eb38878822be3817270cc074ee1e22095dKenny Root } 2058b7521eb38878822be3817270cc074ee1e22095dKenny Root 2068b7521eb38878822be3817270cc074ee1e22095dKenny Root private void writeObject(ObjectOutputStream stream) throws IOException { 2078b7521eb38878822be3817270cc074ee1e22095dKenny Root if (key.isEngineBased()) { 2088b7521eb38878822be3817270cc074ee1e22095dKenny Root throw new NotSerializableException("engine-based keys can not be serialized"); 2098b7521eb38878822be3817270cc074ee1e22095dKenny Root } 2108b7521eb38878822be3817270cc074ee1e22095dKenny Root 2118b7521eb38878822be3817270cc074ee1e22095dKenny Root stream.defaultWriteObject(); 2125b36f6cc5f013574dc453e8938fcae13185c7732Kenny Root stream.writeObject(getEncoded()); 2138b7521eb38878822be3817270cc074ee1e22095dKenny Root } 2148b7521eb38878822be3817270cc074ee1e22095dKenny Root} 215