1/*
2 * Copyright (c) 2003, 2017, 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
26package sun.security.rsa;
27
28import java.io.IOException;
29import java.math.BigInteger;
30
31import java.security.*;
32import java.security.interfaces.*;
33
34import sun.security.util.*;
35import sun.security.x509.AlgorithmId;
36import sun.security.pkcs.PKCS8Key;
37
38/**
39 * Key implementation for RSA private keys, CRT form. For non-CRT private
40 * keys, see RSAPrivateKeyImpl. We need separate classes to ensure
41 * correct behavior in instanceof checks, etc.
42 *
43 * Note: RSA keys must be at least 512 bits long
44 *
45 * @see RSAPrivateKeyImpl
46 * @see RSAKeyFactory
47 *
48 * @since   1.5
49 * @author  Andreas Sterbenz
50 */
51public final class RSAPrivateCrtKeyImpl
52        extends PKCS8Key implements RSAPrivateCrtKey {
53
54    private static final long serialVersionUID = -1326088454257084918L;
55
56    private BigInteger n;       // modulus
57    private BigInteger e;       // public exponent
58    private BigInteger d;       // private exponent
59    private BigInteger p;       // prime p
60    private BigInteger q;       // prime q
61    private BigInteger pe;      // prime exponent p
62    private BigInteger qe;      // prime exponent q
63    private BigInteger coeff;   // CRT coeffcient
64
65    // algorithmId used to identify RSA keys
66    static final AlgorithmId rsaId =
67        new AlgorithmId(AlgorithmId.RSAEncryption_oid);
68
69    /**
70     * Generate a new key from its encoding. Returns a CRT key if possible
71     * and a non-CRT key otherwise. Used by RSAKeyFactory.
72     */
73    public static RSAPrivateKey newKey(byte[] encoded)
74            throws InvalidKeyException {
75        RSAPrivateCrtKeyImpl key = new RSAPrivateCrtKeyImpl(encoded);
76        if (key.getPublicExponent().signum() == 0) {
77            // public exponent is missing, return a non-CRT key
78            return new RSAPrivateKeyImpl(
79                key.getModulus(),
80                key.getPrivateExponent()
81            );
82        } else {
83            return key;
84        }
85    }
86
87    /**
88     * Construct a key from its encoding. Called from newKey above.
89     */
90    RSAPrivateCrtKeyImpl(byte[] encoded) throws InvalidKeyException {
91        decode(encoded);
92        RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
93    }
94
95    /**
96     * Construct a key from its components. Used by the
97     * RSAKeyFactory and the RSAKeyPairGenerator.
98     */
99    RSAPrivateCrtKeyImpl(BigInteger n, BigInteger e, BigInteger d,
100            BigInteger p, BigInteger q, BigInteger pe, BigInteger qe,
101            BigInteger coeff) throws InvalidKeyException {
102        this.n = n;
103        this.e = e;
104        this.d = d;
105        this.p = p;
106        this.q = q;
107        this.pe = pe;
108        this.qe = qe;
109        this.coeff = coeff;
110        RSAKeyFactory.checkRSAProviderKeyLengths(n.bitLength(), e);
111
112        // generate the encoding
113        algid = rsaId;
114        try {
115            DerOutputStream out = new DerOutputStream();
116            out.putInteger(0); // version must be 0
117            out.putInteger(n);
118            out.putInteger(e);
119            out.putInteger(d);
120            out.putInteger(p);
121            out.putInteger(q);
122            out.putInteger(pe);
123            out.putInteger(qe);
124            out.putInteger(coeff);
125            DerValue val =
126                new DerValue(DerValue.tag_Sequence, out.toByteArray());
127            key = val.toByteArray();
128        } catch (IOException exc) {
129            // should never occur
130            throw new InvalidKeyException(exc);
131        }
132    }
133
134    // see JCA doc
135    public String getAlgorithm() {
136        return "RSA";
137    }
138
139    // see JCA doc
140    public BigInteger getModulus() {
141        return n;
142    }
143
144    // see JCA doc
145    public BigInteger getPublicExponent() {
146        return e;
147    }
148
149    // see JCA doc
150    public BigInteger getPrivateExponent() {
151        return d;
152    }
153
154    // see JCA doc
155    public BigInteger getPrimeP() {
156        return p;
157    }
158
159    // see JCA doc
160    public BigInteger getPrimeQ() {
161        return q;
162    }
163
164    // see JCA doc
165    public BigInteger getPrimeExponentP() {
166        return pe;
167    }
168
169    // see JCA doc
170    public BigInteger getPrimeExponentQ() {
171        return qe;
172    }
173
174    // see JCA doc
175    public BigInteger getCrtCoefficient() {
176        return coeff;
177    }
178
179    /**
180     * Parse the key. Called by PKCS8Key.
181     */
182    protected void parseKeyBits() throws InvalidKeyException {
183        try {
184            DerInputStream in = new DerInputStream(key);
185            DerValue derValue = in.getDerValue();
186            if (derValue.tag != DerValue.tag_Sequence) {
187                throw new IOException("Not a SEQUENCE");
188            }
189            DerInputStream data = derValue.data;
190            int version = data.getInteger();
191            if (version != 0) {
192                throw new IOException("Version must be 0");
193            }
194
195            /*
196             * Some implementations do not correctly encode ASN.1 INTEGER values
197             * in 2's complement format, resulting in a negative integer when
198             * decoded. Correct the error by converting it to a positive integer.
199             *
200             * See CR 6255949
201             */
202            n = data.getPositiveBigInteger();
203            e = data.getPositiveBigInteger();
204            d = data.getPositiveBigInteger();
205            p = data.getPositiveBigInteger();
206            q = data.getPositiveBigInteger();
207            pe = data.getPositiveBigInteger();
208            qe = data.getPositiveBigInteger();
209            coeff = data.getPositiveBigInteger();
210            if (derValue.data.available() != 0) {
211                throw new IOException("Extra data available");
212            }
213        } catch (IOException e) {
214            throw new InvalidKeyException("Invalid RSA private key", e);
215        }
216    }
217}
218