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