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.RSAPrivateKey;
     26 import java.security.spec.InvalidKeySpecException;
     27 import java.security.spec.RSAPrivateKeySpec;
     28 
     29 public class OpenSSLRSAPrivateKey implements RSAPrivateKey, OpenSSLKeyHolder {
     30     private static final long serialVersionUID = 4872170254439578735L;
     31 
     32     protected transient OpenSSLKey key;
     33 
     34     protected transient boolean fetchedParams;
     35 
     36     protected BigInteger modulus;
     37 
     38     protected BigInteger privateExponent;
     39 
     40     OpenSSLRSAPrivateKey(OpenSSLKey key) {
     41         this.key = key;
     42     }
     43 
     44     OpenSSLRSAPrivateKey(OpenSSLKey key, byte[][] params) {
     45         this(key);
     46         readParams(params);
     47         fetchedParams = true;
     48     }
     49 
     50     @Override
     51     public OpenSSLKey getOpenSSLKey() {
     52         return key;
     53     }
     54 
     55     public OpenSSLRSAPrivateKey(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
     56         this(init(rsaKeySpec));
     57     }
     58 
     59     private static OpenSSLKey init(RSAPrivateKeySpec rsaKeySpec) throws InvalidKeySpecException {
     60         final BigInteger modulus = rsaKeySpec.getModulus();
     61         final BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
     62 
     63         if (modulus == null) {
     64             throw new InvalidKeySpecException("modulus == null");
     65         } else if (privateExponent == null) {
     66             throw new InvalidKeySpecException("privateExponent == null");
     67         }
     68 
     69         try {
     70             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
     71                     modulus.toByteArray(),
     72                     null,
     73                     privateExponent.toByteArray(),
     74                     null,
     75                     null,
     76                     null,
     77                     null,
     78                     null));
     79         } catch (Exception e) {
     80             throw new InvalidKeySpecException(e);
     81         }
     82     }
     83 
     84     static OpenSSLRSAPrivateKey getInstance(OpenSSLKey key) {
     85       byte[][] params = NativeCrypto.get_RSA_private_params(key.getPkeyContext());
     86       if (params[1] != null) {
     87           return new OpenSSLRSAPrivateCrtKey(key, params);
     88       }
     89       return new OpenSSLRSAPrivateKey(key, params);
     90     }
     91 
     92     static OpenSSLKey getInstance(RSAPrivateKey rsaPrivateKey) throws InvalidKeyException {
     93         final BigInteger modulus = rsaPrivateKey.getModulus();
     94         final BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
     95 
     96         if (modulus == null) {
     97             throw new InvalidKeyException("modulus == null");
     98         } else if (privateExponent == null) {
     99             throw new InvalidKeyException("privateExponent == null");
    100         }
    101 
    102         try {
    103             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
    104                     modulus.toByteArray(),
    105                     null,
    106                     privateExponent.toByteArray(),
    107                     null,
    108                     null,
    109                     null,
    110                     null,
    111                     null));
    112         } catch (Exception e) {
    113             throw new InvalidKeyException(e);
    114         }
    115     }
    116 
    117     synchronized final void ensureReadParams() {
    118         if (fetchedParams) {
    119             return;
    120         }
    121         readParams(NativeCrypto.get_RSA_private_params(key.getPkeyContext()));
    122         fetchedParams = true;
    123     }
    124 
    125     void readParams(byte[][] params) {
    126         if (params[0] == null) {
    127             throw new NullPointerException("modulus == null");
    128         } else if (params[2] == null && !key.isEngineBased()) {
    129             throw new NullPointerException("privateExponent == null");
    130         }
    131 
    132         modulus = new BigInteger(params[0]);
    133 
    134         // ENGINE-based keys are not guaranteed to have a private exponent.
    135         if (params[2] != null) {
    136             privateExponent = new BigInteger(params[2]);
    137         }
    138     }
    139 
    140     @Override
    141     public final BigInteger getPrivateExponent() {
    142         if (key.isEngineBased()) {
    143             throw new UnsupportedOperationException("private exponent cannot be extracted");
    144         }
    145 
    146         ensureReadParams();
    147         return privateExponent;
    148     }
    149 
    150     @Override
    151     public final BigInteger getModulus() {
    152         ensureReadParams();
    153         return modulus;
    154     }
    155 
    156     @Override
    157     public final byte[] getEncoded() {
    158         /*
    159          * If we're using an OpenSSL ENGINE, there's no guarantee we can export
    160          * the key. Returning {@code null} tells the caller that there's no
    161          * encoded format.
    162          */
    163         if (key.isEngineBased()) {
    164             return null;
    165         }
    166 
    167         return NativeCrypto.i2d_PKCS8_PRIV_KEY_INFO(key.getPkeyContext());
    168     }
    169 
    170     public final String getFormat() {
    171         /*
    172          * If we're using an OpenSSL ENGINE, there's no guarantee we can export
    173          * the key. Returning {@code null} tells the caller that there's no
    174          * encoded format.
    175          */
    176         if (key.isEngineBased()) {
    177             return null;
    178         }
    179 
    180         return "PKCS#8";
    181     }
    182 
    183     @Override
    184     public final String getAlgorithm() {
    185         return "RSA";
    186     }
    187 
    188     @Override
    189     public boolean equals(Object o) {
    190         if (o == this) {
    191             return true;
    192         }
    193 
    194         if (o instanceof OpenSSLRSAPrivateKey) {
    195             OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
    196             return key.equals(other.getOpenSSLKey());
    197         }
    198 
    199         if (o instanceof RSAPrivateKey) {
    200             ensureReadParams();
    201             RSAPrivateKey other = (RSAPrivateKey) o;
    202 
    203             return modulus.equals(other.getModulus())
    204                     && privateExponent.equals(other.getPrivateExponent());
    205         }
    206 
    207         return false;
    208     }
    209 
    210     @Override
    211     public int hashCode() {
    212         ensureReadParams();
    213         int hash = 1;
    214 
    215         hash = hash * 3 + modulus.hashCode();
    216         if (privateExponent != null) {
    217             hash = hash * 7 + privateExponent.hashCode();
    218         }
    219 
    220         return hash;
    221     }
    222 
    223     @Override
    224     public String toString() {
    225         final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{");
    226 
    227         final boolean engineBased = key.isEngineBased();
    228         if (engineBased) {
    229             sb.append("key=");
    230             sb.append(key);
    231             sb.append('}');
    232         }
    233 
    234         ensureReadParams();
    235         sb.append("modulus=");
    236         sb.append(modulus.toString(16));
    237         sb.append(',');
    238 
    239         if (!engineBased) {
    240             sb.append("privateExponent=");
    241             sb.append(privateExponent.toString(16));
    242             sb.append(',');
    243         }
    244 
    245         return sb.toString();
    246     }
    247 
    248     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    249         stream.defaultReadObject();
    250 
    251         key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
    252                 modulus.toByteArray(),
    253                 null,
    254                 privateExponent.toByteArray(),
    255                 null,
    256                 null,
    257                 null,
    258                 null,
    259                 null));
    260         fetchedParams = true;
    261     }
    262 
    263     private void writeObject(ObjectOutputStream stream) throws IOException {
    264         if (getOpenSSLKey().isEngineBased()) {
    265             throw new NotSerializableException("engine-based keys can not be serialized");
    266         }
    267 
    268         ensureReadParams();
    269         stream.defaultWriteObject();
    270     }
    271 }
    272