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