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