Home | History | Annotate | Download | only in conscrypt
      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.conscrypt;
     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.RSAPrivateCrtKey;
     26 import java.security.interfaces.RSAPrivateKey;
     27 import java.security.spec.InvalidKeySpecException;
     28 import java.security.spec.RSAPrivateCrtKeySpec;
     29 
     30 public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey {
     31     private static final long serialVersionUID = 3785291944868707197L;
     32 
     33     private BigInteger publicExponent;
     34 
     35     private BigInteger primeP;
     36 
     37     private BigInteger primeQ;
     38 
     39     private BigInteger primeExponentP;
     40 
     41     private BigInteger primeExponentQ;
     42 
     43     private BigInteger crtCoefficient;
     44 
     45     OpenSSLRSAPrivateCrtKey(OpenSSLKey key) {
     46         super(key);
     47     }
     48 
     49     OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) {
     50         super(key, params);
     51     }
     52 
     53     public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
     54         super(init(rsaKeySpec));
     55     }
     56 
     57     private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
     58         BigInteger modulus = rsaKeySpec.getModulus();
     59         BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
     60 
     61         if (modulus == null) {
     62             throw new InvalidKeySpecException("modulus == null");
     63         } else if (privateExponent == null) {
     64             throw new InvalidKeySpecException("privateExponent == null");
     65         }
     66 
     67         try {
     68             /*
     69              * OpenSSL uses the public modulus to do RSA blinding. If
     70              * the public modulus is not available, the call to
     71              * EVP_PKEY_new_RSA will turn off blinding for this key
     72              * instance.
     73              */
     74             final BigInteger publicExponent = rsaKeySpec.getPublicExponent();
     75             final BigInteger primeP = rsaKeySpec.getPrimeP();
     76             final BigInteger primeQ = rsaKeySpec.getPrimeQ();
     77             final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP();
     78             final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ();
     79             final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient();
     80 
     81             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
     82                     modulus.toByteArray(),
     83                     publicExponent == null ? null : publicExponent.toByteArray(),
     84                     privateExponent.toByteArray(),
     85                     primeP == null ? null : primeP.toByteArray(),
     86                     primeQ == null ? null : primeQ.toByteArray(),
     87                     primeExponentP == null ? null : primeExponentP.toByteArray(),
     88                     primeExponentQ == null ? null : primeExponentQ.toByteArray(),
     89                     crtCoefficient == null ? null : crtCoefficient.toByteArray()));
     90         } catch (Exception e) {
     91             throw new InvalidKeySpecException(e);
     92         }
     93     }
     94 
     95     static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException {
     96         /**
     97          * If the key is not encodable (PKCS11-like key), then wrap it and use
     98          * JNI upcalls to satisfy requests.
     99          */
    100         if (rsaPrivateKey.getFormat() == null) {
    101             return wrapPlatformKey(rsaPrivateKey);
    102         }
    103 
    104         BigInteger modulus = rsaPrivateKey.getModulus();
    105         BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
    106 
    107         if (modulus == null) {
    108             throw new InvalidKeyException("modulus == null");
    109         } else if (privateExponent == null) {
    110             throw new InvalidKeyException("privateExponent == null");
    111         }
    112 
    113         try {
    114             /*
    115              * OpenSSL uses the public modulus to do RSA blinding. If
    116              * the public modulus is not available, the call to
    117              * EVP_PKEY_new_RSA will turn off blinding for this key
    118              * instance.
    119              */
    120             final BigInteger publicExponent = rsaPrivateKey.getPublicExponent();
    121             final BigInteger primeP = rsaPrivateKey.getPrimeP();
    122             final BigInteger primeQ = rsaPrivateKey.getPrimeQ();
    123             final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP();
    124             final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ();
    125             final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient();
    126 
    127             return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
    128                     modulus.toByteArray(),
    129                     publicExponent == null ? null : publicExponent.toByteArray(),
    130                     privateExponent.toByteArray(),
    131                     primeP == null ? null : primeP.toByteArray(),
    132                     primeQ == null ? null : primeQ.toByteArray(),
    133                     primeExponentP == null ? null : primeExponentP.toByteArray(),
    134                     primeExponentQ == null ? null : primeExponentQ.toByteArray(),
    135                     crtCoefficient == null ? null : crtCoefficient.toByteArray()));
    136         } catch (Exception e) {
    137             throw new InvalidKeyException(e);
    138         }
    139     }
    140 
    141     @Override
    142     synchronized void readParams(byte[][] params) {
    143         super.readParams(params);
    144         // params[0] read in super.readParams
    145         if (params[1] != null) {
    146             publicExponent = new BigInteger(params[1]);
    147         }
    148         // params[2] read in super.readParams
    149         if (params[3] != null) {
    150             primeP = new BigInteger(params[3]);
    151         }
    152         if (params[4] != null) {
    153             primeQ = new BigInteger(params[4]);
    154         }
    155         if (params[5] != null) {
    156             primeExponentP = new BigInteger(params[5]);
    157         }
    158         if (params[6] != null) {
    159             primeExponentQ = new BigInteger(params[6]);
    160         }
    161         if (params[7] != null) {
    162             crtCoefficient = new BigInteger(params[7]);
    163         }
    164     }
    165 
    166     @Override
    167     public BigInteger getPublicExponent() {
    168         ensureReadParams();
    169         return publicExponent;
    170     }
    171 
    172     @Override
    173     public BigInteger getPrimeP() {
    174         ensureReadParams();
    175         return primeP;
    176     }
    177 
    178     @Override
    179     public BigInteger getPrimeQ() {
    180         ensureReadParams();
    181         return primeQ;
    182     }
    183 
    184     @Override
    185     public BigInteger getPrimeExponentP() {
    186         ensureReadParams();
    187         return primeExponentP;
    188     }
    189 
    190     @Override
    191     public BigInteger getPrimeExponentQ() {
    192         ensureReadParams();
    193         return primeExponentQ;
    194     }
    195 
    196     @Override
    197     public BigInteger getCrtCoefficient() {
    198         ensureReadParams();
    199         return crtCoefficient;
    200     }
    201 
    202     @Override
    203     public boolean equals(Object o) {
    204         if (o == this) {
    205             return true;
    206         }
    207 
    208         if (o instanceof OpenSSLRSAPrivateKey) {
    209             OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
    210             return getOpenSSLKey().equals(other.getOpenSSLKey());
    211         }
    212 
    213         if (o instanceof RSAPrivateCrtKey) {
    214             ensureReadParams();
    215             RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
    216 
    217             if (getOpenSSLKey().isEngineBased()) {
    218                 return getModulus().equals(other.getModulus())
    219                         && publicExponent.equals(other.getPublicExponent());
    220             } else {
    221                 return getModulus().equals(other.getModulus())
    222                         && publicExponent.equals(other.getPublicExponent())
    223                         && getPrivateExponent().equals(other.getPrivateExponent())
    224                         && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
    225                         && primeExponentP.equals(other.getPrimeExponentP())
    226                         && primeExponentQ.equals(other.getPrimeExponentQ())
    227                         && crtCoefficient.equals(other.getCrtCoefficient());
    228             }
    229         } else if (o instanceof RSAPrivateKey) {
    230             ensureReadParams();
    231             RSAPrivateKey other = (RSAPrivateKey) o;
    232 
    233             if (getOpenSSLKey().isEngineBased()) {
    234                 return getModulus().equals(other.getModulus());
    235             } else {
    236                 return getModulus().equals(other.getModulus())
    237                         && getPrivateExponent().equals(other.getPrivateExponent());
    238             }
    239         }
    240 
    241         return false;
    242     }
    243 
    244     @Override
    245     public final int hashCode() {
    246         int hashCode = super.hashCode();
    247         if (publicExponent != null) {
    248             hashCode ^= publicExponent.hashCode();
    249         }
    250         return hashCode;
    251     }
    252 
    253     @Override
    254     public String toString() {
    255         final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{");
    256 
    257         final boolean engineBased = getOpenSSLKey().isEngineBased();
    258         if (engineBased) {
    259             sb.append("key=");
    260             sb.append(getOpenSSLKey());
    261             sb.append('}');
    262         }
    263 
    264         ensureReadParams();
    265         sb.append("modulus=");
    266         sb.append(getModulus().toString(16));
    267         sb.append(',');
    268 
    269         if (publicExponent != null) {
    270             sb.append("publicExponent=");
    271             sb.append(publicExponent.toString(16));
    272             sb.append(',');
    273         }
    274 
    275         if (!engineBased) {
    276             sb.append("privateExponent=");
    277             sb.append(getPrivateExponent().toString(16));
    278             sb.append(',');
    279         }
    280 
    281         if (primeP != null) {
    282             sb.append("primeP=");
    283             sb.append(primeP.toString(16));
    284             sb.append(',');
    285         }
    286 
    287         if (primeQ != null) {
    288             sb.append("primeQ=");
    289             sb.append(primeQ.toString(16));
    290             sb.append(',');
    291         }
    292 
    293         if (primeExponentP != null) {
    294             sb.append("primeExponentP=");
    295             sb.append(primeExponentP.toString(16));
    296             sb.append(',');
    297         }
    298 
    299         if (primeExponentQ != null) {
    300             sb.append("primeExponentQ=");
    301             sb.append(primeExponentQ.toString(16));
    302             sb.append(',');
    303         }
    304 
    305         if (crtCoefficient != null) {
    306             sb.append("crtCoefficient=");
    307             sb.append(crtCoefficient.toString(16));
    308             sb.append(',');
    309         }
    310 
    311         return sb.toString();
    312     }
    313 
    314     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
    315         stream.defaultReadObject();
    316 
    317         key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
    318                 modulus.toByteArray(),
    319                 publicExponent == null ? null : publicExponent.toByteArray(),
    320                 privateExponent.toByteArray(),
    321                 primeP == null ? null : primeP.toByteArray(),
    322                 primeQ == null ? null : primeQ.toByteArray(),
    323                 primeExponentP == null ? null : primeExponentP.toByteArray(),
    324                 primeExponentQ == null ? null : primeExponentQ.toByteArray(),
    325                 crtCoefficient == null ? null : crtCoefficient.toByteArray()));
    326         fetchedParams = true;
    327     }
    328 
    329     private void writeObject(ObjectOutputStream stream) throws IOException {
    330         if (getOpenSSLKey().isEngineBased()) {
    331             throw new NotSerializableException("engine-based keys can not be serialized");
    332         }
    333 
    334         ensureReadParams();
    335         stream.defaultWriteObject();
    336     }
    337 }
    338