15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright (C) 2012 The Android Open Source Project
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License");
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you may not use this file except in compliance with the License.
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * You may obtain a copy of the License at
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *      http://www.apache.org/licenses/LICENSE-2.0
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Unless required by applicable law or agreed to in writing, software
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS,
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * See the License for the specific language governing permissions and
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * limitations under the License.
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.conscrypt;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.IOException;
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.NotSerializableException;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.ObjectInputStream;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.io.ObjectOutputStream;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.math.BigInteger;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.InvalidKeyException;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.interfaces.RSAPrivateCrtKey;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.interfaces.RSAPrivateKey;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.spec.InvalidKeySpecException;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.security.spec.RSAPrivateCrtKeySpec;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)public class OpenSSLRSAPrivateCrtKey extends OpenSSLRSAPrivateKey implements RSAPrivateCrtKey {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final long serialVersionUID = 3785291944868707197L;
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger publicExponent;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger primeP;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger primeQ;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger primeExponentP;
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger primeExponentQ;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private BigInteger crtCoefficient;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OpenSSLRSAPrivateCrtKey(OpenSSLKey key) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        super(key);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    OpenSSLRSAPrivateCrtKey(OpenSSLKey key, byte[][] params) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        super(key, params);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public OpenSSLRSAPrivateCrtKey(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        super(init(rsaKeySpec));
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static OpenSSLKey init(RSAPrivateCrtKeySpec rsaKeySpec) throws InvalidKeySpecException {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BigInteger modulus = rsaKeySpec.getModulus();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BigInteger privateExponent = rsaKeySpec.getPrivateExponent();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (modulus == null) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new InvalidKeySpecException("modulus == null");
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } else if (privateExponent == null) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new InvalidKeySpecException("privateExponent == null");
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /*
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * OpenSSL uses the public modulus to do RSA blinding. If
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * the public modulus is not available, the call to
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * EVP_PKEY_new_RSA will turn off blinding for this key
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * instance.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             */
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger publicExponent = rsaKeySpec.getPublicExponent();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeP = rsaKeySpec.getPrimeP();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeQ = rsaKeySpec.getPrimeQ();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeExponentP = rsaKeySpec.getPrimeExponentP();
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeExponentQ = rsaKeySpec.getPrimeExponentQ();
79b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            final BigInteger crtCoefficient = rsaKeySpec.getCrtCoefficient();
80b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
81b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
82b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    modulus.toByteArray(),
83b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    publicExponent == null ? null : publicExponent.toByteArray(),
84b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    privateExponent.toByteArray(),
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    primeP == null ? null : primeP.toByteArray(),
86b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    primeQ == null ? null : primeQ.toByteArray(),
87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    primeExponentP == null ? null : primeExponentP.toByteArray(),
88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                    primeExponentQ == null ? null : primeExponentQ.toByteArray(),
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    crtCoefficient == null ? null : crtCoefficient.toByteArray()));
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } catch (Exception e) {
91b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            throw new InvalidKeySpecException(e);
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static OpenSSLKey getInstance(RSAPrivateCrtKey rsaPrivateKey) throws InvalidKeyException {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * If the key is not encodable (PKCS11-like key), then wrap it and use
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * JNI upcalls to satisfy requests.
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (rsaPrivateKey.getFormat() == null) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return wrapPlatformKey(rsaPrivateKey);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
104b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        BigInteger modulus = rsaPrivateKey.getModulus();
105eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        BigInteger privateExponent = rsaPrivateKey.getPrivateExponent();
106eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (modulus == null) {
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            throw new InvalidKeyException("modulus == null");
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        } else if (privateExponent == null) {
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch            throw new InvalidKeyException("privateExponent == null");
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            /*
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * OpenSSL uses the public modulus to do RSA blinding. If
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * the public modulus is not available, the call to
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * EVP_PKEY_new_RSA will turn off blinding for this key
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             * instance.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)             */
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger publicExponent = rsaPrivateKey.getPublicExponent();
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeP = rsaPrivateKey.getPrimeP();
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeQ = rsaPrivateKey.getPrimeQ();
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeExponentP = rsaPrivateKey.getPrimeExponentP();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger primeExponentQ = rsaPrivateKey.getPrimeExponentQ();
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            final BigInteger crtCoefficient = rsaPrivateKey.getCrtCoefficient();
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    modulus.toByteArray(),
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    publicExponent == null ? null : publicExponent.toByteArray(),
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    privateExponent.toByteArray(),
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    primeP == null ? null : primeP.toByteArray(),
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    primeQ == null ? null : primeQ.toByteArray(),
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    primeExponentP == null ? null : primeExponentP.toByteArray(),
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    primeExponentQ == null ? null : primeExponentQ.toByteArray(),
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    crtCoefficient == null ? null : crtCoefficient.toByteArray()));
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } catch (Exception e) {
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            throw new InvalidKeyException(e);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
140b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
141b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    @Override
142b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    synchronized void readParams(byte[][] params) {
143b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        super.readParams(params);
144b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        // params[0] read in super.readParams
145b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        if (params[1] != null) {
146b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            publicExponent = new BigInteger(params[1]);
147b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        }
148b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        // params[2] read in super.readParams
149b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        if (params[3] != null) {
150b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            primeP = new BigInteger(params[3]);
151b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        }
152b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        if (params[4] != null) {
153b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            primeQ = new BigInteger(params[4]);
154b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        }
155b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        if (params[5] != null) {
156b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            primeExponentP = new BigInteger(params[5]);
157b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        }
158b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        if (params[6] != null) {
159b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)            primeExponentQ = new BigInteger(params[6]);
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
161        if (params[7] != null) {
162            crtCoefficient = new BigInteger(params[7]);
163        }
164    }
165
166    @Override
167    public BigInteger getPublicExponent() {
168        ensureReadParams();
169        return publicExponent;
170    }
171
172    @Override
173    public BigInteger getPrimeP() {
174        ensureReadParams();
175        return primeP;
176    }
177
178    @Override
179    public BigInteger getPrimeQ() {
180        ensureReadParams();
181        return primeQ;
182    }
183
184    @Override
185    public BigInteger getPrimeExponentP() {
186        ensureReadParams();
187        return primeExponentP;
188    }
189
190    @Override
191    public BigInteger getPrimeExponentQ() {
192        ensureReadParams();
193        return primeExponentQ;
194    }
195
196    @Override
197    public BigInteger getCrtCoefficient() {
198        ensureReadParams();
199        return crtCoefficient;
200    }
201
202    @Override
203    public boolean equals(Object o) {
204        if (o == this) {
205            return true;
206        }
207
208        if (o instanceof OpenSSLRSAPrivateKey) {
209            OpenSSLRSAPrivateKey other = (OpenSSLRSAPrivateKey) o;
210            return getOpenSSLKey().equals(other.getOpenSSLKey());
211        }
212
213        if (o instanceof RSAPrivateCrtKey) {
214            ensureReadParams();
215            RSAPrivateCrtKey other = (RSAPrivateCrtKey) o;
216
217            if (getOpenSSLKey().isEngineBased()) {
218                return getModulus().equals(other.getModulus())
219                        && publicExponent.equals(other.getPublicExponent());
220            } else {
221                return getModulus().equals(other.getModulus())
222                        && publicExponent.equals(other.getPublicExponent())
223                        && getPrivateExponent().equals(other.getPrivateExponent())
224                        && primeP.equals(other.getPrimeP()) && primeQ.equals(other.getPrimeQ())
225                        && primeExponentP.equals(other.getPrimeExponentP())
226                        && primeExponentQ.equals(other.getPrimeExponentQ())
227                        && crtCoefficient.equals(other.getCrtCoefficient());
228            }
229        } else if (o instanceof RSAPrivateKey) {
230            ensureReadParams();
231            RSAPrivateKey other = (RSAPrivateKey) o;
232
233            if (getOpenSSLKey().isEngineBased()) {
234                return getModulus().equals(other.getModulus());
235            } else {
236                return getModulus().equals(other.getModulus())
237                        && getPrivateExponent().equals(other.getPrivateExponent());
238            }
239        }
240
241        return false;
242    }
243
244    @Override
245    public final int hashCode() {
246        int hashCode = super.hashCode();
247        if (publicExponent != null) {
248            hashCode ^= publicExponent.hashCode();
249        }
250        return hashCode;
251    }
252
253    @Override
254    public String toString() {
255        final StringBuilder sb = new StringBuilder("OpenSSLRSAPrivateCrtKey{");
256
257        final boolean engineBased = getOpenSSLKey().isEngineBased();
258        if (engineBased) {
259            sb.append("key=");
260            sb.append(getOpenSSLKey());
261            sb.append('}');
262        }
263
264        ensureReadParams();
265        sb.append("modulus=");
266        sb.append(getModulus().toString(16));
267        sb.append(',');
268
269        if (publicExponent != null) {
270            sb.append("publicExponent=");
271            sb.append(publicExponent.toString(16));
272            sb.append(',');
273        }
274
275        if (!engineBased) {
276            sb.append("privateExponent=");
277            sb.append(getPrivateExponent().toString(16));
278            sb.append(',');
279        }
280
281        if (primeP != null) {
282            sb.append("primeP=");
283            sb.append(primeP.toString(16));
284            sb.append(',');
285        }
286
287        if (primeQ != null) {
288            sb.append("primeQ=");
289            sb.append(primeQ.toString(16));
290            sb.append(',');
291        }
292
293        if (primeExponentP != null) {
294            sb.append("primeExponentP=");
295            sb.append(primeExponentP.toString(16));
296            sb.append(',');
297        }
298
299        if (primeExponentQ != null) {
300            sb.append("primeExponentQ=");
301            sb.append(primeExponentQ.toString(16));
302            sb.append(',');
303        }
304
305        if (crtCoefficient != null) {
306            sb.append("crtCoefficient=");
307            sb.append(crtCoefficient.toString(16));
308            sb.append(',');
309        }
310
311        return sb.toString();
312    }
313
314    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
315        stream.defaultReadObject();
316
317        key = new OpenSSLKey(NativeCrypto.EVP_PKEY_new_RSA(
318                modulus.toByteArray(),
319                publicExponent == null ? null : publicExponent.toByteArray(),
320                privateExponent.toByteArray(),
321                primeP == null ? null : primeP.toByteArray(),
322                primeQ == null ? null : primeQ.toByteArray(),
323                primeExponentP == null ? null : primeExponentP.toByteArray(),
324                primeExponentQ == null ? null : primeExponentQ.toByteArray(),
325                crtCoefficient == null ? null : crtCoefficient.toByteArray()));
326        fetchedParams = true;
327    }
328
329    private void writeObject(ObjectOutputStream stream) throws IOException {
330        if (getOpenSSLKey().isEngineBased()) {
331            throw new NotSerializableException("engine-based keys can not be serialized");
332        }
333
334        ensureReadParams();
335        stream.defaultWriteObject();
336    }
337}
338