1 /* 2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.rsa; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 31 import java.security.*; 32 import java.security.spec.*; 33 import java.security.interfaces.*; 34 35 import sun.security.util.*; 36 37 import sun.security.x509.AlgorithmId; 38 import sun.security.pkcs.PKCS8Key; 39 40 import static sun.security.rsa.RSAUtil.KeyType; 41 42 /** 43 * RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in CRT form. 44 * For non-CRT private keys, see RSAPrivateKeyImpl. We need separate classes 45 * to ensure correct behavior in instanceof checks, etc. 46 * 47 * Note: RSA keys must be at least 512 bits long 48 * 49 * @see RSAPrivateKeyImpl 50 * @see RSAKeyFactory 51 * 52 * @since 1.5 53 * @author Andreas Sterbenz 54 */ 55 public final class RSAPrivateCrtKeyImpl 56 extends PKCS8Key implements RSAPrivateCrtKey { 57 58 private static final long serialVersionUID = -1326088454257084918L; 59 60 private BigInteger n; // modulus 61 private BigInteger e; // public exponent 62 private BigInteger d; // private exponent 63 private BigInteger p; // prime p 64 private BigInteger q; // prime q 65 private BigInteger pe; // prime exponent p 66 private BigInteger qe; // prime exponent q 67 private BigInteger coeff; // CRT coeffcient 68 69 // Optional parameters associated with this RSA key 70 // specified in the encoding of its AlgorithmId. 71 // Must be null for "RSA" keys. 72 private AlgorithmParameterSpec keyParams; 73 74 /** 75 * Generate a new key from its encoding. Returns a CRT key if possible 76 * and a non-CRT key otherwise. Used by RSAKeyFactory. 77 */ 78 public static RSAPrivateKey newKey(byte[] encoded) 79 throws InvalidKeyException { 80 RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded); 81 // check all CRT-specific components are available, if any one 82 // missing, return a non-CRT key instead 83 if ((key.getPublicExponent().signum() == 0) || 84 (key.getPrimeExponentP().signum() == 0) || 85 (key.getPrimeExponentQ().signum() == 0) || 86 (key.getPrimeP().signum() == 0) || 87 (key.getPrimeQ().signum() == 0) || 88 (key.getCrtCoefficient().signum() == 0)) { 89 return new RSAPrivateKeyImpl( 90 key.algid, 91 key.getModulus(), 92 key.getPrivateExponent() 93 ); 94 } else { 95 return key; 96 } 97 } 98 99 /** 100 * Generate a new key from the specified type and components. 101 * Returns a CRT key if possible and a non-CRT key otherwise. 102 * Used by SunPKCS11 provider. 103 */ 104 public static RSAPrivateKey newKey(KeyType type, 105 AlgorithmParameterSpec params, 106 BigInteger n, BigInteger e, BigInteger d, 107 BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, 108 BigInteger coeff) throws InvalidKeyException { 109 RSAPrivateKey key; 110 AlgorithmId rsaId = RSAUtil.createAlgorithmId(type, params); 111 if ((e.signum() == 0) || (p.signum() == 0) || 112 (q.signum() == 0) || (pe.signum() == 0) || 113 (qe.signum() == 0) || (coeff.signum() == 0)) { 114 // if any component is missing, return a non-CRT key 115 return new RSAPrivateKeyImpl(rsaId, n, d); 116 } else { 117 return new RSAPrivateCrtKeyImpl(rsaId, n, e, d, 118 p, q, pe, qe, coeff); 119 } 120 } 121 122 /** 123 * Construct a key from its encoding. Called from newKey above. 124 */ 125 RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException { 126 decode(encoded); 127 RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); 128 try { 129 // this will check the validity of params 130 this.keyParams = RSAUtil.getParamSpec(algid); 131 } catch (ProviderException e) { 132 throw new InvalidKeyException(e); 133 } 134 } 135 136 /** 137 * Construct a RSA key from its components. Used by the 138 * RSAKeyFactory and the RSAKeyPairGenerator. 139 */ 140 RSAPrivateCrtKeyImpl(AlgorithmId rsaId, 141 BigInteger n, BigInteger e, BigInteger d, 142 BigInteger p, BigInteger q, BigInteger pe, BigInteger qe, 143 BigInteger coeff) throws InvalidKeyException { 144 RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e); 145 146 this.n = n; 147 this.e = e; 148 this.d = d; 149 this.p = p; 150 this.q = q; 151 this.pe = pe; 152 this.qe = qe; 153 this.coeff = coeff; 154 this.keyParams = RSAUtil.getParamSpec(rsaId); 155 156 // generate the encoding 157 algid = rsaId; 158 try { 159 DerOutputStream out = new DerOutputStream(); 160 out.putInteger(0); // version must be 0 161 out.putInteger(n); 162 out.putInteger(e); 163 out.putInteger(d); 164 out.putInteger(p); 165 out.putInteger(q); 166 out.putInteger(pe); 167 out.putInteger(qe); 168 out.putInteger(coeff); 169 DerValue val = 170 new DerValue(DerValue.tag_Sequence, out.toByteArray()); 171 key = val.toByteArray(); 172 } catch (IOException exc) { 173 // should never occur 174 throw new InvalidKeyException(exc); 175 } 176 } 177 178 // see JCA doc 179 @Override 180 public String getAlgorithm() { 181 return algid.getName(); 182 } 183 184 // see JCA doc 185 @Override 186 public BigInteger getModulus() { 187 return n; 188 } 189 190 // see JCA doc 191 @Override 192 public BigInteger getPublicExponent() { 193 return e; 194 } 195 196 // see JCA doc 197 @Override 198 public BigInteger getPrivateExponent() { 199 return d; 200 } 201 202 // see JCA doc 203 @Override 204 public BigInteger getPrimeP() { 205 return p; 206 } 207 208 // see JCA doc 209 @Override 210 public BigInteger getPrimeQ() { 211 return q; 212 } 213 214 // see JCA doc 215 @Override 216 public BigInteger getPrimeExponentP() { 217 return pe; 218 } 219 220 // see JCA doc 221 @Override 222 public BigInteger getPrimeExponentQ() { 223 return qe; 224 } 225 226 // see JCA doc 227 @Override 228 public BigInteger getCrtCoefficient() { 229 return coeff; 230 } 231 232 // see JCA doc 233 @Override 234 public AlgorithmParameterSpec getParams() { 235 return keyParams; 236 } 237 238 // return a string representation of this key for debugging 239 @Override 240 public String toString() { 241 return "SunRsaSign " + getAlgorithm() + " private CRT key, " + n.bitLength() 242 + " bits" + "\n params: " + keyParams + "\n modulus: " + n 243 + "\n private exponent: " + d; 244 } 245 246 /** 247 * Parse the key. Called by PKCS8Key. 248 */ 249 protected void parseKeyBits() throws InvalidKeyException { 250 try { 251 DerInputStream in = new DerInputStream(key); 252 DerValue derValue = in.getDerValue(); 253 if (derValue.tag != DerValue.tag_Sequence) { 254 throw new IOException("Not a SEQUENCE"); 255 } 256 DerInputStream data = derValue.data; 257 int version = data.getInteger(); 258 if (version != 0) { 259 throw new IOException("Version must be 0"); 260 } 261 262 /* 263 * Some implementations do not correctly encode ASN.1 INTEGER values 264 * in 2's complement format, resulting in a negative integer when 265 * decoded. Correct the error by converting it to a positive integer. 266 * 267 * See CR 6255949 268 */ 269 n = data.getPositiveBigInteger(); 270 e = data.getPositiveBigInteger(); 271 d = data.getPositiveBigInteger(); 272 p = data.getPositiveBigInteger(); 273 q = data.getPositiveBigInteger(); 274 pe = data.getPositiveBigInteger(); 275 qe = data.getPositiveBigInteger(); 276 coeff = data.getPositiveBigInteger(); 277 if (derValue.data.available() != 0) { 278 throw new IOException("Extra data available"); 279 } 280 } catch (IOException e) { 281 throw new InvalidKeyException("Invalid RSA private key", e); 282 } 283 } 284 }