1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.conscrypt; 18 19 import java.io.IOException; 20 import java.io.NotSerializableException; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.security.InvalidKeyException; 24 import java.security.interfaces.ECPublicKey; 25 import java.security.spec.ECParameterSpec; 26 import java.security.spec.ECPoint; 27 import java.security.spec.ECPublicKeySpec; 28 import java.security.spec.InvalidKeySpecException; 29 import java.util.Arrays; 30 31 public final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder { 32 private static final long serialVersionUID = 3215842926808298020L; 33 34 private static final String ALGORITHM = "EC"; 35 36 protected transient OpenSSLKey key; 37 38 protected transient OpenSSLECGroupContext group; 39 40 public OpenSSLECPublicKey(OpenSSLECGroupContext group, OpenSSLKey key) { 41 this.group = group; 42 this.key = key; 43 } 44 45 public OpenSSLECPublicKey(OpenSSLKey key) { 46 final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 47 this.group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 48 this.key = key; 49 } 50 51 public OpenSSLECPublicKey(ECPublicKeySpec ecKeySpec) throws InvalidKeySpecException { 52 try { 53 group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); 54 OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( 55 NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecKeySpec.getW()); 56 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 57 pubKey.getContext(), null)); 58 } catch (Exception e) { 59 throw new InvalidKeySpecException(e); 60 } 61 } 62 63 public static OpenSSLKey getInstance(ECPublicKey ecPublicKey) throws InvalidKeyException { 64 try { 65 OpenSSLECGroupContext group = OpenSSLECGroupContext 66 .getInstance(ecPublicKey.getParams()); 67 OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( 68 NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecPublicKey.getW()); 69 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 70 pubKey.getContext(), null)); 71 } catch (Exception e) { 72 throw new InvalidKeyException(e); 73 } 74 } 75 76 @Override 77 public String getAlgorithm() { 78 return ALGORITHM; 79 } 80 81 @Override 82 public String getFormat() { 83 return "X.509"; 84 } 85 86 @Override 87 public byte[] getEncoded() { 88 return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); 89 } 90 91 @Override 92 public ECParameterSpec getParams() { 93 return group.getECParameterSpec(); 94 } 95 96 private ECPoint getPublicKey() { 97 final OpenSSLECPointContext pubKey = new OpenSSLECPointContext(group, 98 NativeCrypto.EC_KEY_get_public_key(key.getPkeyContext())); 99 100 return pubKey.getECPoint(); 101 } 102 103 @Override 104 public ECPoint getW() { 105 return getPublicKey(); 106 } 107 108 @Override 109 public OpenSSLKey getOpenSSLKey() { 110 return key; 111 } 112 113 @Override 114 public boolean equals(Object o) { 115 if (o == this) { 116 return true; 117 } 118 119 if (o instanceof OpenSSLECPrivateKey) { 120 OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o; 121 return key.equals(other.key); 122 } 123 124 if (!(o instanceof ECPublicKey)) { 125 return false; 126 } 127 128 final ECPublicKey other = (ECPublicKey) o; 129 if (!getPublicKey().equals(other.getW())) { 130 return false; 131 } 132 133 final ECParameterSpec spec = getParams(); 134 final ECParameterSpec otherSpec = other.getParams(); 135 136 return spec.getCurve().equals(otherSpec.getCurve()) 137 && spec.getGenerator().equals(otherSpec.getGenerator()) 138 && spec.getOrder().equals(otherSpec.getOrder()) 139 && spec.getCofactor() == otherSpec.getCofactor(); 140 } 141 142 @Override 143 public int hashCode() { 144 return Arrays.hashCode(NativeCrypto.i2d_PUBKEY(key.getPkeyContext())); 145 } 146 147 @Override 148 public String toString() { 149 return NativeCrypto.EVP_PKEY_print_public(key.getPkeyContext()); 150 } 151 152 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 153 stream.defaultReadObject(); 154 155 byte[] encoded = (byte[]) stream.readObject(); 156 157 key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(encoded)); 158 159 final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 160 group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 161 } 162 163 private void writeObject(ObjectOutputStream stream) throws IOException { 164 if (key.isEngineBased()) { 165 throw new NotSerializableException("engine-based keys can not be serialized"); 166 } 167 168 stream.defaultWriteObject(); 169 stream.writeObject(getEncoded()); 170 } 171 } 172