1746a236e2be5dee62c482e27f4c682496d071d8bKenny Root/* 2746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Copyright (C) 2012 The Android Open Source Project 3746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 4746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Licensed under the Apache License, Version 2.0 (the "License"); 5746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * you may not use this file except in compliance with the License. 6746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * You may obtain a copy of the License at 7746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 8746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * http://www.apache.org/licenses/LICENSE-2.0 9746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * 10746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * Unless required by applicable law or agreed to in writing, software 11746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * distributed under the License is distributed on an "AS IS" BASIS, 12746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * See the License for the specific language governing permissions and 14746a236e2be5dee62c482e27f4c682496d071d8bKenny Root * limitations under the License. 15746a236e2be5dee62c482e27f4c682496d071d8bKenny Root */ 16746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 1738375a4d0b3d34e2babbd2f6a013976c7c439696Kenny Rootpackage org.conscrypt; 18746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 19d3df366d3fd59237f1fbf099e979e6843047032cKenny Rootimport java.io.IOException; 20d3df366d3fd59237f1fbf099e979e6843047032cKenny Rootimport java.io.NotSerializableException; 21d3df366d3fd59237f1fbf099e979e6843047032cKenny Rootimport java.io.ObjectInputStream; 22d3df366d3fd59237f1fbf099e979e6843047032cKenny Rootimport java.io.ObjectOutputStream; 23746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.math.BigInteger; 24746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.InvalidKeyException; 25746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.interfaces.DSAParams; 26746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.interfaces.DSAPublicKey; 27746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.DSAPublicKeySpec; 28746a236e2be5dee62c482e27f4c682496d071d8bKenny Rootimport java.security.spec.InvalidKeySpecException; 29746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 300731d6d00c5e30c05e035d3ae96327029d07a606Kenny Rootpublic class OpenSSLDSAPublicKey implements DSAPublicKey, OpenSSLKeyHolder { 31d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root private static final long serialVersionUID = 5238609500353792232L; 32d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 33d3df366d3fd59237f1fbf099e979e6843047032cKenny Root private transient OpenSSLKey key; 34746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 35d3df366d3fd59237f1fbf099e979e6843047032cKenny Root private transient OpenSSLDSAParams params; 36746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 37746a236e2be5dee62c482e27f4c682496d071d8bKenny Root OpenSSLDSAPublicKey(OpenSSLKey key) { 38746a236e2be5dee62c482e27f4c682496d071d8bKenny Root this.key = key; 39746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 40746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 410731d6d00c5e30c05e035d3ae96327029d07a606Kenny Root @Override 420731d6d00c5e30c05e035d3ae96327029d07a606Kenny Root public OpenSSLKey getOpenSSLKey() { 4391bb5fbe55b854df891ff7720e30d42081dbcd58Kenny Root return key; 4491bb5fbe55b854df891ff7720e30d42081dbcd58Kenny Root } 4591bb5fbe55b854df891ff7720e30d42081dbcd58Kenny Root 46746a236e2be5dee62c482e27f4c682496d071d8bKenny Root OpenSSLDSAPublicKey(DSAPublicKeySpec dsaKeySpec) throws InvalidKeySpecException { 47746a236e2be5dee62c482e27f4c682496d071d8bKenny Root try { 48746a236e2be5dee62c482e27f4c682496d071d8bKenny Root key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( 49746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaKeySpec.getP().toByteArray(), 50746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaKeySpec.getQ().toByteArray(), 51746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaKeySpec.getG().toByteArray(), 52746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaKeySpec.getY().toByteArray(), 53746a236e2be5dee62c482e27f4c682496d071d8bKenny Root null)); 54746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } catch (Exception e) { 55746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeySpecException(e); 56746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 57746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 58746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 59746a236e2be5dee62c482e27f4c682496d071d8bKenny Root private void ensureReadParams() { 60746a236e2be5dee62c482e27f4c682496d071d8bKenny Root if (params == null) { 61746a236e2be5dee62c482e27f4c682496d071d8bKenny Root params = new OpenSSLDSAParams(key); 62746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 63746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 64746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 65746a236e2be5dee62c482e27f4c682496d071d8bKenny Root static OpenSSLKey getInstance(DSAPublicKey dsaPublicKey) throws InvalidKeyException { 66746a236e2be5dee62c482e27f4c682496d071d8bKenny Root try { 67746a236e2be5dee62c482e27f4c682496d071d8bKenny Root final DSAParams dsaParams = dsaPublicKey.getParams(); 68746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( 69746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaParams.getP().toByteArray(), 70746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaParams.getQ().toByteArray(), 71746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaParams.getG().toByteArray(), 72746a236e2be5dee62c482e27f4c682496d071d8bKenny Root dsaPublicKey.getY().toByteArray(), 73746a236e2be5dee62c482e27f4c682496d071d8bKenny Root null)); 74746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } catch (Exception e) { 75746a236e2be5dee62c482e27f4c682496d071d8bKenny Root throw new InvalidKeyException(e); 76746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 77746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 78746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 79746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 80746a236e2be5dee62c482e27f4c682496d071d8bKenny Root public DSAParams getParams() { 81746a236e2be5dee62c482e27f4c682496d071d8bKenny Root ensureReadParams(); 82fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root 83fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root /* 84fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root * DSA keys can lack parameters if they're part of a certificate 85fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root * chain. In this case, we just return null. 86fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root */ 87fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root if (!params.hasParams()) { 88fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root return null; 89fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root } 90fc5480d13eb8b32c325ba79ba4221df2145727b7Kenny Root 91746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return params; 92746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 93746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 94746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 95746a236e2be5dee62c482e27f4c682496d071d8bKenny Root public String getAlgorithm() { 96746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return "DSA"; 97746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 98746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 99746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 100746a236e2be5dee62c482e27f4c682496d071d8bKenny Root public String getFormat() { 101746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return "X.509"; 102746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 103746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 104746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 105746a236e2be5dee62c482e27f4c682496d071d8bKenny Root public byte[] getEncoded() { 106746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return NativeCrypto.i2d_PUBKEY(key.getPkeyContext()); 107746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 108746a236e2be5dee62c482e27f4c682496d071d8bKenny Root 109746a236e2be5dee62c482e27f4c682496d071d8bKenny Root @Override 110746a236e2be5dee62c482e27f4c682496d071d8bKenny Root public BigInteger getY() { 111746a236e2be5dee62c482e27f4c682496d071d8bKenny Root ensureReadParams(); 112746a236e2be5dee62c482e27f4c682496d071d8bKenny Root return params.getY(); 113746a236e2be5dee62c482e27f4c682496d071d8bKenny Root } 114d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 115d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root @Override 116d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root public boolean equals(Object o) { 117d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root if (o == this) { 118d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return true; 119d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 120d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 121d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root if (o instanceof OpenSSLDSAPublicKey) { 122d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root OpenSSLDSAPublicKey other = (OpenSSLDSAPublicKey) o; 123d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 124d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root /* 125d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root * We can shortcut the true case, but it still may be equivalent but 126d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root * different copies. 127d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root */ 128d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root if (key.equals(other.getOpenSSLKey())) { 129d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return true; 130d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 131d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 132d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 133d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root if (!(o instanceof DSAPublicKey)) { 134d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return false; 135d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 136d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 137d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root ensureReadParams(); 138d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 139d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root DSAPublicKey other = (DSAPublicKey) o; 140d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return params.getY().equals(other.getY()) && params.equals(other.getParams()); 141d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 142d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 143d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root @Override 144d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root public int hashCode() { 145d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root ensureReadParams(); 146d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 147d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return params.getY().hashCode() ^ params.hashCode(); 148d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 149d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 150d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root @Override 151d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root public String toString() { 152d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root ensureReadParams(); 153d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 154d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root final StringBuilder sb = new StringBuilder("OpenSSLDSAPublicKey{"); 155d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append("Y="); 156d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append(params.getY().toString(16)); 157d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append(','); 158d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append("params="); 159d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append(params.toString()); 160d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root sb.append('}'); 161d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root 162d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root return sb.toString(); 163d036721c2ecd146acef9f36408c7a397dd0a0785Kenny Root } 164d3df366d3fd59237f1fbf099e979e6843047032cKenny Root 165d3df366d3fd59237f1fbf099e979e6843047032cKenny Root private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { 166d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.defaultReadObject(); 167d3df366d3fd59237f1fbf099e979e6843047032cKenny Root 168d3df366d3fd59237f1fbf099e979e6843047032cKenny Root final BigInteger g = (BigInteger) stream.readObject(); 169d3df366d3fd59237f1fbf099e979e6843047032cKenny Root final BigInteger p = (BigInteger) stream.readObject(); 170d3df366d3fd59237f1fbf099e979e6843047032cKenny Root final BigInteger q = (BigInteger) stream.readObject(); 171d3df366d3fd59237f1fbf099e979e6843047032cKenny Root final BigInteger y = (BigInteger) stream.readObject(); 172d3df366d3fd59237f1fbf099e979e6843047032cKenny Root 173d3df366d3fd59237f1fbf099e979e6843047032cKenny Root key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA( 174d3df366d3fd59237f1fbf099e979e6843047032cKenny Root p.toByteArray(), 175d3df366d3fd59237f1fbf099e979e6843047032cKenny Root q.toByteArray(), 176d3df366d3fd59237f1fbf099e979e6843047032cKenny Root g.toByteArray(), 177d3df366d3fd59237f1fbf099e979e6843047032cKenny Root y.toByteArray(), 178d3df366d3fd59237f1fbf099e979e6843047032cKenny Root null)); 179d3df366d3fd59237f1fbf099e979e6843047032cKenny Root } 180d3df366d3fd59237f1fbf099e979e6843047032cKenny Root 181d3df366d3fd59237f1fbf099e979e6843047032cKenny Root private void writeObject(ObjectOutputStream stream) throws IOException { 182d3df366d3fd59237f1fbf099e979e6843047032cKenny Root if (getOpenSSLKey().isEngineBased()) { 183d3df366d3fd59237f1fbf099e979e6843047032cKenny Root throw new NotSerializableException("engine-based keys can not be serialized"); 184d3df366d3fd59237f1fbf099e979e6843047032cKenny Root } 185d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.defaultWriteObject(); 186d3df366d3fd59237f1fbf099e979e6843047032cKenny Root 187d3df366d3fd59237f1fbf099e979e6843047032cKenny Root ensureReadParams(); 188d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.writeObject(params.getG()); 189d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.writeObject(params.getP()); 190d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.writeObject(params.getQ()); 191d3df366d3fd59237f1fbf099e979e6843047032cKenny Root stream.writeObject(params.getY()); 192d3df366d3fd59237f1fbf099e979e6843047032cKenny Root } 193746a236e2be5dee62c482e27f4c682496d071d8bKenny Root} 194