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.apache.harmony.xnet.provider.jsse; 18 19 import java.io.IOException; 20 import java.io.NotSerializableException; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectOutputStream; 23 import java.math.BigInteger; 24 import java.security.InvalidAlgorithmParameterException; 25 import java.security.InvalidKeyException; 26 import java.security.interfaces.ECPublicKey; 27 import java.security.spec.ECParameterSpec; 28 import java.security.spec.ECPoint; 29 import java.security.spec.ECPublicKeySpec; 30 import java.security.spec.InvalidKeySpecException; 31 import java.util.Arrays; 32 33 public final class OpenSSLECPublicKey implements ECPublicKey, OpenSSLKeyHolder { 34 private static final long serialVersionUID = 3215842926808298020L; 35 36 private static final String ALGORITHM = "EC"; 37 38 protected transient OpenSSLKey key; 39 40 protected transient OpenSSLECGroupContext group; 41 42 public OpenSSLECPublicKey(OpenSSLECGroupContext group, OpenSSLKey key) { 43 this.group = group; 44 this.key = key; 45 } 46 47 public OpenSSLECPublicKey(OpenSSLKey key) { 48 final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 49 this.group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 50 this.key = key; 51 } 52 53 public OpenSSLECPublicKey(ECPublicKeySpec ecKeySpec) throws InvalidKeySpecException { 54 try { 55 group = OpenSSLECGroupContext.getInstance(ecKeySpec.getParams()); 56 OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( 57 NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecKeySpec.getW()); 58 key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 59 pubKey.getContext(), null)); 60 } catch (Exception e) { 61 throw new InvalidKeySpecException(e); 62 } 63 } 64 65 public static OpenSSLKey getInstance(ECPublicKey ecPublicKey) throws InvalidKeyException { 66 try { 67 OpenSSLECGroupContext group = OpenSSLECGroupContext 68 .getInstance(ecPublicKey.getParams()); 69 OpenSSLECPointContext pubKey = OpenSSLECPointContext.getInstance( 70 NativeCrypto.get_EC_GROUP_type(group.getContext()), group, ecPublicKey.getW()); 71 return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_EC_KEY(group.getContext(), 72 pubKey.getContext(), null)); 73 } catch (Exception e) { 74 throw new InvalidKeyException(e); 75 } 76 } 77 78 @Override 79 public String getAlgorithm() { 80 return ALGORITHM; 81 } 82 83 @Override 84 public String getFormat() { 85 return "X.509"; 86 } 87 88 @Override 89 public byte[] getEncoded() { 90 return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); 91 } 92 93 @Override 94 public ECParameterSpec getParams() { 95 return group.getECParameterSpec(); 96 } 97 98 private ECPoint getPublicKey() { 99 final OpenSSLECPointContext pubKey = new OpenSSLECPointContext(group, 100 NativeCrypto.EC_KEY_get_public_key(key.getPkeyContext())); 101 102 return pubKey.getECPoint(); 103 } 104 105 @Override 106 public ECPoint getW() { 107 return getPublicKey(); 108 } 109 110 @Override 111 public OpenSSLKey getOpenSSLKey() { 112 return key; 113 } 114 115 @Override 116 public boolean equals(Object o) { 117 if (o == this) { 118 return true; 119 } 120 121 if (o instanceof OpenSSLECPrivateKey) { 122 OpenSSLECPrivateKey other = (OpenSSLECPrivateKey) o; 123 return key.equals(other.key); 124 } 125 126 if (!(o instanceof ECPublicKey)) { 127 return false; 128 } 129 130 final ECPublicKey other = (ECPublicKey) o; 131 if (!getPublicKey().equals(other.getW())) { 132 return false; 133 } 134 135 final ECParameterSpec spec = getParams(); 136 final ECParameterSpec otherSpec = other.getParams(); 137 138 return spec.getCurve().equals(otherSpec.getCurve()) 139 && spec.getGenerator().equals(otherSpec.getGenerator()) 140 && spec.getOrder().equals(otherSpec.getOrder()) 141 && spec.getCofactor() == otherSpec.getCofactor(); 142 } 143 144 @Override 145 public int hashCode() { 146 return Arrays.hashCode(NativeCrypto.i2d_PUBKEY(key.getPkeyContext())); 147 } 148 149 @Override 150 public String toString() { 151 return NativeCrypto.EVP_PKEY_print_public(key.getPkeyContext()); 152 } 153 154 private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 155 stream.defaultReadObject(); 156 157 byte[] encoded = (byte[]) stream.readObject(); 158 159 key = new OpenSSLKey(NativeCrypto.d2i_PUBKEY(encoded)); 160 161 final long origGroup = NativeCrypto.EC_KEY_get0_group(key.getPkeyContext()); 162 group = new OpenSSLECGroupContext(NativeCrypto.EC_GROUP_dup(origGroup)); 163 } 164 165 private void writeObject(ObjectOutputStream stream) throws IOException { 166 if (key.isEngineBased()) { 167 throw new NotSerializableException("engine-based keys can not be serialized"); 168 } 169 170 stream.defaultWriteObject(); 171 stream.writeObject(getEncoded()); 172 } 173 } 174