Path: blob/master/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java
41159 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 ((key.getPublicExponent().signum() == 0) ||94(key.getPrimeExponentP().signum() == 0) ||95(key.getPrimeExponentQ().signum() == 0) ||96(key.getPrimeP().signum() == 0) ||97(key.getPrimeQ().signum() == 0) ||98(key.getCrtCoefficient().signum() == 0)) {99return new RSAPrivateKeyImpl(key.type, key.keyParams,100key.getModulus(), key.getPrivateExponent());101} else {102return key;103}104case "PKCS#1":105try {106BigInteger[] comps = parseASN1(encoded);107if ((comps[1].signum() == 0) || (comps[3].signum() == 0) ||108(comps[4].signum() == 0) || (comps[5].signum() == 0) ||109(comps[6].signum() == 0) || (comps[7].signum() == 0)) {110return new RSAPrivateKeyImpl(type, null, comps[0],111comps[2]);112} else {113return new RSAPrivateCrtKeyImpl(type, null, comps[0],114comps[1], comps[2], comps[3], comps[4], comps[5],115comps[6], comps[7]);116}117} catch (IOException ioe) {118throw new InvalidKeyException("Invalid PKCS#1 encoding", ioe);119}120default:121throw new InvalidKeyException("Unsupported RSA Private(Crt)Key "122+ "format: " + format);123}124}125126/**127* Generate a new key from the specified type and components.128* Returns a CRT key if possible and a non-CRT key otherwise.129* Used by SunPKCS11 provider.130*/131public static RSAPrivateKey newKey(KeyType type,132AlgorithmParameterSpec params,133BigInteger n, BigInteger e, BigInteger d,134BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,135BigInteger coeff) throws InvalidKeyException {136RSAPrivateKey key;137if ((e.signum() == 0) || (p.signum() == 0) ||138(q.signum() == 0) || (pe.signum() == 0) ||139(qe.signum() == 0) || (coeff.signum() == 0)) {140// if any component is missing, return a non-CRT key141return new RSAPrivateKeyImpl(type, params, n, d);142} else {143return new RSAPrivateCrtKeyImpl(type, params, n, e, d,144p, q, pe, qe, coeff);145}146}147148/**149* Construct a key from its encoding. Called from newKey above.150*/151private RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {152super(encoded);153parseKeyBits();154RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);155try {156// check the validity of oid and params157Object[] o = RSAUtil.getTypeAndParamSpec(algid);158this.type = (KeyType) o[0];159this.keyParams = (AlgorithmParameterSpec) o[1];160} catch (ProviderException e) {161throw new InvalidKeyException(e);162}163}164165/**166* Construct a RSA key from its components. Used by the167* RSAKeyFactory and the RSAKeyPairGenerator.168*/169RSAPrivateCrtKeyImpl(KeyType type, AlgorithmParameterSpec keyParams,170BigInteger n, BigInteger e, BigInteger d,171BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,172BigInteger coeff) throws InvalidKeyException {173RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);174175this.n = n;176this.e = e;177this.d = d;178this.p = p;179this.q = q;180this.pe = pe;181this.qe = qe;182this.coeff = coeff;183184try {185// validate and generate the algid encoding186algid = RSAUtil.createAlgorithmId(type, keyParams);187} catch (ProviderException exc) {188throw new InvalidKeyException(exc);189}190191this.type = type;192this.keyParams = keyParams;193194try {195byte[][] nbytes = new byte[8][];196nbytes[0] = n.toByteArray();197nbytes[1] = e.toByteArray();198nbytes[2] = d.toByteArray();199nbytes[3] = p.toByteArray();200nbytes[4] = q.toByteArray();201nbytes[5] = pe.toByteArray();202nbytes[6] = qe.toByteArray();203nbytes[7] = coeff.toByteArray();204205// Initiate with a big enough size so there's no need to206// reallocate memory later and thus can be cleaned up207// reliably.208DerOutputStream out = new DerOutputStream(209nbytes[0].length + nbytes[1].length +210nbytes[2].length + nbytes[3].length +211nbytes[4].length + nbytes[5].length +212nbytes[6].length + nbytes[7].length +213100); // Enough for version(3) and 8 tag+length(3 or 4)214out.putInteger(0); // version must be 0215out.putInteger(nbytes[0]);216out.putInteger(nbytes[1]);217out.putInteger(nbytes[2]);218out.putInteger(nbytes[3]);219out.putInteger(nbytes[4]);220out.putInteger(nbytes[5]);221out.putInteger(nbytes[6]);222out.putInteger(nbytes[7]);223// Private values from [2] on.224Arrays.fill(nbytes[2], (byte)0);225Arrays.fill(nbytes[3], (byte)0);226Arrays.fill(nbytes[4], (byte)0);227Arrays.fill(nbytes[5], (byte)0);228Arrays.fill(nbytes[6], (byte)0);229Arrays.fill(nbytes[7], (byte)0);230DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);231key = val.toByteArray();232val.clear();233} catch (IOException exc) {234// should never occur235throw new InvalidKeyException(exc);236}237}238239// see JCA doc240@Override241public String getAlgorithm() {242return type.keyAlgo;243}244245// see JCA doc246@Override247public BigInteger getModulus() {248return n;249}250251// see JCA doc252@Override253public BigInteger getPublicExponent() {254return e;255}256257// see JCA doc258@Override259public BigInteger getPrivateExponent() {260return d;261}262263// see JCA doc264@Override265public BigInteger getPrimeP() {266return p;267}268269// see JCA doc270@Override271public BigInteger getPrimeQ() {272return q;273}274275// see JCA doc276@Override277public BigInteger getPrimeExponentP() {278return pe;279}280281// see JCA doc282@Override283public BigInteger getPrimeExponentQ() {284return qe;285}286287// see JCA doc288@Override289public BigInteger getCrtCoefficient() {290return coeff;291}292293// see JCA doc294@Override295public AlgorithmParameterSpec getParams() {296return keyParams;297}298299// return a string representation of this key for debugging300@Override301public String toString() {302return "SunRsaSign " + type.keyAlgo + " private CRT key, "303+ n.bitLength() + " bits" + "\n params: " + keyParams304+ "\n modulus: " + n + "\n private exponent: " + d;305}306307// utility method for parsing DER encoding of RSA private keys in PKCS#1308// format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n,309// e, d, p, q, pe, qe, and coeff, and return the parsed components.310private static BigInteger[] parseASN1(byte[] raw) throws IOException {311DerValue derValue = new DerValue(raw);312try {313if (derValue.tag != DerValue.tag_Sequence) {314throw new IOException("Not a SEQUENCE");315}316int version = derValue.data.getInteger();317if (version != 0) {318throw new IOException("Version must be 0");319}320321BigInteger[] result = new BigInteger[8]; // n, e, d, p, q, pe, qe, coeff322/*323* Some implementations do not correctly encode ASN.1 INTEGER values324* in 2's complement format, resulting in a negative integer when325* decoded. Correct the error by converting it to a positive integer.326*327* See CR 6255949328*/329for (int i = 0; i < result.length; i++) {330result[i] = derValue.data.getPositiveBigInteger();331}332if (derValue.data.available() != 0) {333throw new IOException("Extra data available");334}335return result;336} finally {337derValue.clear();338}339}340341private void parseKeyBits() throws InvalidKeyException {342try {343BigInteger[] comps = parseASN1(key);344n = comps[0];345e = comps[1];346d = comps[2];347p = comps[3];348q = comps[4];349pe = comps[5];350qe = comps[6];351coeff = comps[7];352} catch (IOException e) {353throw new InvalidKeyException("Invalid RSA private key", e);354}355}356}357358359