Path: blob/master/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java
67760 views
/*1* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.rsa;2627import java.io.IOException;28import java.math.BigInteger;2930import java.security.*;31import java.security.spec.*;32import java.security.interfaces.*;33import java.util.Arrays;3435import sun.security.util.*;3637import sun.security.pkcs.PKCS8Key;3839import sun.security.rsa.RSAUtil.KeyType;4041/**42* RSA private key implementation for "RSA", "RSASSA-PSS" algorithms in CRT form.43* For non-CRT private keys, see RSAPrivateKeyImpl. We need separate classes44* to ensure correct behavior in instanceof checks, etc.45*46* Note: RSA keys must be at least 512 bits long47*48* @see RSAPrivateKeyImpl49* @see RSAKeyFactory50*51* @since 1.552* @author Andreas Sterbenz53*/54public final class RSAPrivateCrtKeyImpl55extends PKCS8Key implements RSAPrivateCrtKey {5657@java.io.Serial58private static final long serialVersionUID = -1326088454257084918L;5960private BigInteger n; // modulus61private BigInteger e; // public exponent62private BigInteger d; // private exponent63private BigInteger p; // prime p64private BigInteger q; // prime q65private BigInteger pe; // prime exponent p66private BigInteger qe; // prime exponent q67private BigInteger coeff; // CRT coeffcient6869private transient KeyType type;7071// Optional parameters associated with this RSA key72// specified in the encoding of its AlgorithmId.73// Must be null for "RSA" keys.74private transient AlgorithmParameterSpec keyParams;7576/**77* Generate a new RSAPrivate(Crt)Key from the specified type,78* format and encoding. Returns a CRT key if possible and a non-CRT79* key otherwise.80* Also used by SunPKCS11 provider.81*/82public static RSAPrivateKey newKey(KeyType type, String format,83byte[] encoded) throws InvalidKeyException {84if (encoded == null || encoded.length == 0) {85throw new InvalidKeyException("Missing key encoding");86}87switch (format) {88case "PKCS#8":89RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded);90RSAKeyFactory.checkKeyAlgo(key, type.keyAlgo);91// check all CRT-specific components are available, if any one92// missing, return a non-CRT key instead93if (checkComponents(key)) {94return key;95} else {96return new RSAPrivateKeyImpl(key.type, key.keyParams,97key.getModulus(), key.getPrivateExponent());98}99case "PKCS#1":100try {101BigInteger[] comps = parseASN1(encoded);102if ((comps[1].signum() == 0) || (comps[3].signum() == 0) ||103(comps[4].signum() == 0) || (comps[5].signum() == 0) ||104(comps[6].signum() == 0) || (comps[7].signum() == 0)) {105return new RSAPrivateKeyImpl(type, null, comps[0],106comps[2]);107} else {108return new RSAPrivateCrtKeyImpl(type, null, comps[0],109comps[1], comps[2], comps[3], comps[4], comps[5],110comps[6], comps[7]);111}112} catch (IOException ioe) {113throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe);114}115default:116throw new InvalidKeyException("Unsupported RSA Private(Crt)Key "117+ "format: " + format);118}119}120121/**122* Validate if all CRT-specific components are available.123*/124static boolean checkComponents(RSAPrivateCrtKey key) {125return !((key.getPublicExponent().signum() == 0) ||126(key.getPrimeExponentP().signum() == 0) ||127(key.getPrimeExponentQ().signum() == 0) ||128(key.getPrimeP().signum() == 0) ||129(key.getPrimeQ().signum() == 0) ||130(key.getCrtCoefficient().signum() == 0));131}132133/**134* Generate a new key from the specified type and components.135* Returns a CRT key if possible and a non-CRT key otherwise.136* Used by SunPKCS11 provider.137*/138public static RSAPrivateKey newKey(KeyType type,139AlgorithmParameterSpec params,140BigInteger n, BigInteger e, BigInteger d,141BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,142BigInteger coeff) throws InvalidKeyException {143RSAPrivateKey key;144if ((e.signum() == 0) || (p.signum() == 0) ||145(q.signum() == 0) || (pe.signum() == 0) ||146(qe.signum() == 0) || (coeff.signum() == 0)) {147// if any component is missing, return a non-CRT key148return new RSAPrivateKeyImpl(type, params, n, d);149} else {150return new RSAPrivateCrtKeyImpl(type, params, n, e, d,151p, q, pe, qe, coeff);152}153}154155/**156* Construct a key from its encoding. Called from newKey above.157*/158private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {159super(encoded);160parseKeyBits();161RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);162try {163// check the validity of oid and params164Object[] o = RSAUtil.getTypeAndParamSpec(algid);165this.type = (KeyType) o[0];166this.keyParams = (AlgorithmParameterSpec) o[1];167} catch (ProviderException e) {168throw new InvalidKeyException(e);169}170}171172/**173* Construct a RSA key from its components. Used by the174* RSAKeyFactory and the RSAKeyPairGenerator.175*/176RSAPrivateCrtKeyImpl(KeyType type, AlgorithmParameterSpec keyParams,177BigInteger n, BigInteger e, BigInteger d,178BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,179BigInteger coeff) throws InvalidKeyException {180RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);181182this.n = n;183this.e = e;184this.d = d;185this.p = p;186this.q = q;187this.pe = pe;188this.qe = qe;189this.coeff = coeff;190191try {192// validate and generate the algid encoding193algid = RSAUtil.createAlgorithmId(type, keyParams);194} catch (ProviderException exc) {195throw new InvalidKeyException(exc);196}197198this.type = type;199this.keyParams = keyParams;200201try {202byte[][] nbytes = new byte[8][];203nbytes[0] = n.toByteArray();204nbytes[1] = e.toByteArray();205nbytes[2] = d.toByteArray();206nbytes[3] = p.toByteArray();207nbytes[4] = q.toByteArray();208nbytes[5] = pe.toByteArray();209nbytes[6] = qe.toByteArray();210nbytes[7] = coeff.toByteArray();211212// Initiate with a big enough size so there's no need to213// reallocate memory later and thus can be cleaned up214// reliably.215DerOutputStream out = new DerOutputStream(216nbytes[0].length + nbytes[1].length +217nbytes[2].length + nbytes[3].length +218nbytes[4].length + nbytes[5].length +219nbytes[6].length + nbytes[7].length +220100); // Enough for version(3) and 8 tag+length(3 or 4)221out.putInteger(0); // version must be 0222out.putInteger(nbytes[0]);223out.putInteger(nbytes[1]);224out.putInteger(nbytes[2]);225out.putInteger(nbytes[3]);226out.putInteger(nbytes[4]);227out.putInteger(nbytes[5]);228out.putInteger(nbytes[6]);229out.putInteger(nbytes[7]);230// Private values from [2] on.231Arrays.fill(nbytes[2], (byte)0);232Arrays.fill(nbytes[3], (byte)0);233Arrays.fill(nbytes[4], (byte)0);234Arrays.fill(nbytes[5], (byte)0);235Arrays.fill(nbytes[6], (byte)0);236Arrays.fill(nbytes[7], (byte)0);237DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);238key = val.toByteArray();239val.clear();240} catch (IOException exc) {241// should never occur242throw new InvalidKeyException(exc);243}244}245246// see JCA doc247@Override248public String getAlgorithm() {249return type.keyAlgo;250}251252// see JCA doc253@Override254public BigInteger getModulus() {255return n;256}257258// see JCA doc259@Override260public BigInteger getPublicExponent() {261return e;262}263264// see JCA doc265@Override266public BigInteger getPrivateExponent() {267return d;268}269270// see JCA doc271@Override272public BigInteger getPrimeP() {273return p;274}275276// see JCA doc277@Override278public BigInteger getPrimeQ() {279return q;280}281282// see JCA doc283@Override284public BigInteger getPrimeExponentP() {285return pe;286}287288// see JCA doc289@Override290public BigInteger getPrimeExponentQ() {291return qe;292}293294// see JCA doc295@Override296public BigInteger getCrtCoefficient() {297return coeff;298}299300// see JCA doc301@Override302public AlgorithmParameterSpec getParams() {303return keyParams;304}305306// return a string representation of this key for debugging307@Override308public String toString() {309return "SunRsaSign " + type.keyAlgo + " private CRT key, "310+ n.bitLength() + " bits" + "\n params: " + keyParams311+ "\n modulus: " + n + "\n private exponent: " + d;312}313314// utility method for parsing DER encoding of RSA private keys in PKCS#1315// format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n,316// e, d, p, q, pe, qe, and coeff, and return the parsed components.317private static BigInteger[] parseASN1(byte[] raw) throws IOException {318DerValue derValue = new DerValue(raw);319try {320if (derValue.tag != DerValue.tag_Sequence) {321throw new IOException("Not a SEQUENCE");322}323int version = derValue.data.getInteger();324if (version != 0) {325throw new IOException("Version must be 0");326}327328BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff329/*330* Some implementations do not correctly encode ASN.1 INTEGER values331* in 2's complement format, resulting in a negative integer when332* decoded. Correct the error by converting it to a positive integer.333*334* See CR 6255949335*/336for (int i = 0; i < result.length; i++) {337result[i] = derValue.data.getPositiveBigInteger();338}339if (derValue.data.available() != 0) {340throw new IOException("Extra data available");341}342return result;343} finally {344derValue.clear();345}346}347348private void parseKeyBits() throws InvalidKeyException {349try {350BigInteger[] comps = parseASN1(key);351n = comps[0];352e = comps[1];353d = comps[2];354p = comps[3];355q = comps[4];356pe = comps[5];357qe = comps[6];358coeff = comps[7];359} catch (IOException e) {360throw new InvalidKeyException("Invalid RSA private key", e);361}362}363}364365366