Home | History | Annotate | Download | only in jsse
      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.InvalidKeyException;
     25 import java.security.interfaces.DSAParams;
     26 import java.security.interfaces.DSAPublicKey;
     27 import java.security.spec.DSAPublicKeySpec;
     28 import java.security.spec.InvalidKeySpecException;
     29 
     30 public class OpenSSLDSAPublicKey implements DSAPublicKey, OpenSSLKeyHolder {
     31     private static final long serialVersionUID = 5238609500353792232L;
     32 
     33     private transient OpenSSLKey key;
     34 
     35     private transient OpenSSLDSAParams params;
     36 
     37     OpenSSLDSAPublicKey(OpenSSLKey key) {
     38         this.key = key;
     39     }
     40 
     41     @Override
     42     public OpenSSLKey getOpenSSLKey() {
     43         return key;
     44     }
     45 
     46     OpenSSLDSAPublicKey(DSAPublicKeySpec dsaKeySpec) throws InvalidKeySpecException {
     47         try {
     48             key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
     49                     dsaKeySpec.getP().toByteArray(),
     50                     dsaKeySpec.getQ().toByteArray(),
     51                     dsaKeySpec.getG().toByteArray(),
     52                     dsaKeySpec.getY().toByteArray(),
     53                     null));
     54         } catch (Exception e) {
     55             throw new InvalidKeySpecException(e);
     56         }
     57     }
     58 
     59     private void ensureReadParams() {
     60         if (params == null) {
     61             params = new OpenSSLDSAParams(key);
     62         }
     63     }
     64 
     65     static OpenSSLKey getInstance(DSAPublicKey dsaPublicKey) throws InvalidKeyException {
     66         try {
     67             final DSAParams dsaParams = dsaPublicKey.getParams();
     68             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
     69                     dsaParams.getP().toByteArray(),
     70                     dsaParams.getQ().toByteArray(),
     71                     dsaParams.getG().toByteArray(),
     72                     dsaPublicKey.getY().toByteArray(),
     73                     null));
     74         } catch (Exception e) {
     75             throw new InvalidKeyException(e);
     76         }
     77     }
     78 
     79     @Override
     80     public DSAParams getParams() {
     81         ensureReadParams();
     82 
     83         /*
     84          * DSA keys can lack parameters if they're part of a certificate
     85          * chain. In this case, we just return null.
     86          */
     87         if (!params.hasParams()) {
     88             return null;
     89         }
     90 
     91         return params;
     92     }
     93 
     94     @Override
     95     public String getAlgorithm() {
     96         return "DSA";
     97     }
     98 
     99     @Override
    100     public String getFormat() {
    101         return "X.509";
    102     }
    103 
    104     @Override
    105     public byte[] getEncoded() {
    106         return NativeCrypto.i2d_PUBKEY(key.getPkeyContext());
    107     }
    108 
    109     @Override
    110     public BigInteger getY() {
    111         ensureReadParams();
    112         return params.getY();
    113     }
    114 
    115     @Override
    116     public boolean equals(Object o) {
    117         if (o == this) {
    118             return true;
    119         }
    120 
    121         if (o instanceof OpenSSLDSAPublicKey) {
    122             OpenSSLDSAPublicKey other = (OpenSSLDSAPublicKey) o;
    123 
    124             /*
    125              * We can shortcut the true case, but it still may be equivalent but
    126              * different copies.
    127              */
    128             if (key.equals(other.getOpenSSLKey())) {
    129                 return true;
    130             }
    131         }
    132 
    133         if (!(o instanceof DSAPublicKey)) {
    134             return false;
    135         }
    136 
    137         ensureReadParams();
    138 
    139         DSAPublicKey other = (DSAPublicKey) o;
    140         return params.getY().equals(other.getY()) && params.equals(other.getParams());
    141     }
    142 
    143     @Override
    144     public int hashCode() {
    145         ensureReadParams();
    146 
    147         return params.getY().hashCode() ^ params.hashCode();
    148     }
    149 
    150     @Override
    151     public String toString() {
    152         ensureReadParams();
    153 
    154         final StringBuilder sb = new StringBuilder("OpenSSLDSAPublicKey{");
    155         sb.append("Y=");
    156         sb.append(params.getY().toString(16));
    157         sb.append(',');
    158         sb.append("params=");
    159         sb.append(params.toString());
    160         sb.append('}');
    161 
    162         return sb.toString();
    163     }
    164 
    165     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    166         stream.defaultReadObject();
    167 
    168         final BigInteger g = (BigInteger) stream.readObject();
    169         final BigInteger p = (BigInteger) stream.readObject();
    170         final BigInteger q = (BigInteger) stream.readObject();
    171         final BigInteger y = (BigInteger) stream.readObject();
    172 
    173         key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_DSA(
    174                 p.toByteArray(),
    175                 q.toByteArray(),
    176                 g.toByteArray(),
    177                 y.toByteArray(),
    178                 null));
    179     }
    180 
    181     private void writeObject(ObjectOutputStream stream) throws IOException {
    182         if (getOpenSSLKey().isEngineBased()) {
    183             throw new NotSerializableException("engine-based keys can not be serialized");
    184         }
    185         stream.defaultWriteObject();
    186 
    187         ensureReadParams();
    188         stream.writeObject(params.getG());
    189         stream.writeObject(params.getP());
    190         stream.writeObject(params.getQ());
    191         stream.writeObject(params.getY());
    192     }
    193 }
    194