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