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.apache.harmony.xnet.provider.jsse; 18 19import java.math.BigInteger; 20import java.security.InvalidKeyException; 21import java.security.interfaces.RSAPrivateKey; 22import java.security.spec.InvalidKeySpecException; 23import java.security.spec.RSAPrivateKeySpec; 24 25public 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 public String getPkeyAlias() { 184 return key.getAlias(); 185 } 186 187 @Override 188 public boolean equals(Object o) { 189 if (o == this) { 190 return true; 191 } 192 193 if (o instanceof OpenSSLRSAPrivateKey) { 194 OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o; 195 196 /* 197 * We can shortcut the true case, but it still may be equivalent but 198 * different copies. 199 */ 200 if (key.equals(other.getOpenSSLKey())) { 201 return true; 202 } 203 204 return NativeCrypto.EVP_PKEY_cmp(getPkeyContext(), other.getPkeyContext()) == 1; 205 } 206 207 if (o instanceof RSAPrivateKey) { 208 ensureReadParams(); 209 RSAPrivateKey other = (RSAPrivateKey) o; 210 211 return modulus.equals(other.getModulus()) 212 && privateExponent.equals(other.getPrivateExponent()); 213 } 214 215 return false; 216 } 217 218 @Override 219 public int hashCode() { 220 ensureReadParams(); 221 int hash = 1; 222 223 hash = hash * 3 + modulus.hashCode(); 224 if (privateExponent != null) { 225 hash = hash * 7 + privateExponent.hashCode(); 226 } 227 228 return hash; 229 } 230 231 @Override 232 public String toString() { 233 final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateKey{"); 234 235 final boolean engineBased = key.isEngineBased(); 236 if (engineBased) { 237 sb.append("key="); 238 sb.append(key); 239 sb.append('}'); 240 } 241 242 ensureReadParams(); 243 sb.append("modulus="); 244 sb.append(modulus.toString(16)); 245 sb.append(','); 246 247 if (!engineBased) { 248 sb.append("privateExponent="); 249 sb.append(privateExponent.toString(16)); 250 sb.append(','); 251 } 252 253 return sb.toString(); 254 } 255} 256