1/*
2 * Copyright (c) 2003, 2013, 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.pkcs11;
27
28import java.math.BigInteger;
29
30import java.security.*;
31import java.security.interfaces.*;
32import java.security.spec.*;
33
34import static sun.security.pkcs11.TemplateManager.*;
35import sun.security.pkcs11.wrapper.*;
36import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
37
38import sun.security.rsa.RSAKeyFactory;
39
40/**
41 * RSA KeyFactory implementation.
42 *
43 * @author  Andreas Sterbenz
44 * @since   1.5
45 */
46final class P11RSAKeyFactory extends P11KeyFactory {
47
48    P11RSAKeyFactory(Token token, String algorithm) {
49        super(token, algorithm);
50    }
51
52    PublicKey implTranslatePublicKey(PublicKey key) throws InvalidKeyException {
53        try {
54            if (key instanceof RSAPublicKey) {
55                RSAPublicKey rsaKey = (RSAPublicKey)key;
56                return generatePublic(
57                    rsaKey.getModulus(),
58                    rsaKey.getPublicExponent()
59                );
60            } else if ("X.509".equals(key.getFormat())) {
61                // let SunRsaSign provider parse for us, then recurse
62                byte[] encoded = key.getEncoded();
63                key = new sun.security.rsa.RSAPublicKeyImpl(encoded);
64                return implTranslatePublicKey(key);
65            } else {
66                throw new InvalidKeyException("PublicKey must be instance "
67                        + "of RSAPublicKey or have X.509 encoding");
68            }
69        } catch (PKCS11Exception e) {
70            throw new InvalidKeyException("Could not create RSA public key", e);
71        }
72    }
73
74    PrivateKey implTranslatePrivateKey(PrivateKey key)
75            throws InvalidKeyException {
76        try {
77            if (key instanceof RSAPrivateCrtKey) {
78                RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key;
79                return generatePrivate(
80                    rsaKey.getModulus(),
81                    rsaKey.getPublicExponent(),
82                    rsaKey.getPrivateExponent(),
83                    rsaKey.getPrimeP(),
84                    rsaKey.getPrimeQ(),
85                    rsaKey.getPrimeExponentP(),
86                    rsaKey.getPrimeExponentQ(),
87                    rsaKey.getCrtCoefficient()
88                );
89            } else if (key instanceof RSAPrivateKey) {
90                RSAPrivateKey rsaKey = (RSAPrivateKey)key;
91                return generatePrivate(
92                    rsaKey.getModulus(),
93                    rsaKey.getPrivateExponent()
94                );
95            } else if ("PKCS#8".equals(key.getFormat())) {
96                // let SunRsaSign provider parse for us, then recurse
97                byte[] encoded = key.getEncoded();
98                key = sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded);
99                return implTranslatePrivateKey(key);
100            } else {
101                throw new InvalidKeyException("Private key must be instance "
102                        + "of RSAPrivate(Crt)Key or have PKCS#8 encoding");
103            }
104        } catch (PKCS11Exception e) {
105            throw new InvalidKeyException("Could not create RSA private key", e);
106        }
107    }
108
109    // see JCA spec
110    protected PublicKey engineGeneratePublic(KeySpec keySpec)
111            throws InvalidKeySpecException {
112        token.ensureValid();
113        if (keySpec instanceof X509EncodedKeySpec) {
114            try {
115                byte[] encoded = ((X509EncodedKeySpec)keySpec).getEncoded();
116                PublicKey key = new sun.security.rsa.RSAPublicKeyImpl(encoded);
117                return implTranslatePublicKey(key);
118            } catch (InvalidKeyException e) {
119                throw new InvalidKeySpecException
120                        ("Could not create RSA public key", e);
121            }
122        }
123        if (keySpec instanceof RSAPublicKeySpec == false) {
124            throw new InvalidKeySpecException("Only RSAPublicKeySpec and "
125                + "X509EncodedKeySpec supported for RSA public keys");
126        }
127        try {
128            RSAPublicKeySpec rs = (RSAPublicKeySpec)keySpec;
129            return generatePublic(
130                rs.getModulus(),
131                rs.getPublicExponent()
132            );
133        } catch (PKCS11Exception | InvalidKeyException e) {
134            throw new InvalidKeySpecException
135                ("Could not create RSA public key", e);
136        }
137    }
138
139    // see JCA spec
140    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
141            throws InvalidKeySpecException {
142        token.ensureValid();
143        if (keySpec instanceof PKCS8EncodedKeySpec) {
144            try {
145                byte[] encoded = ((PKCS8EncodedKeySpec)keySpec).getEncoded();
146                PrivateKey key =
147                        sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(encoded);
148                return implTranslatePrivateKey(key);
149            } catch (GeneralSecurityException e) {
150                throw new InvalidKeySpecException
151                        ("Could not create RSA private key", e);
152            }
153        }
154        try {
155            if (keySpec instanceof RSAPrivateCrtKeySpec) {
156                RSAPrivateCrtKeySpec rs = (RSAPrivateCrtKeySpec)keySpec;
157                return generatePrivate(
158                    rs.getModulus(),
159                    rs.getPublicExponent(),
160                    rs.getPrivateExponent(),
161                    rs.getPrimeP(),
162                    rs.getPrimeQ(),
163                    rs.getPrimeExponentP(),
164                    rs.getPrimeExponentQ(),
165                    rs.getCrtCoefficient()
166                );
167            } else if (keySpec instanceof RSAPrivateKeySpec) {
168                RSAPrivateKeySpec rs = (RSAPrivateKeySpec)keySpec;
169                return generatePrivate(
170                    rs.getModulus(),
171                    rs.getPrivateExponent()
172                );
173            } else {
174                throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
175                    + "and PKCS8EncodedKeySpec supported for RSA private keys");
176            }
177        } catch (PKCS11Exception | InvalidKeyException e) {
178            throw new InvalidKeySpecException
179                ("Could not create RSA private key", e);
180        }
181    }
182
183    private PublicKey generatePublic(BigInteger n, BigInteger e)
184            throws PKCS11Exception, InvalidKeyException {
185        RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
186        CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
187            new CK_ATTRIBUTE(CKA_CLASS, CKO_PUBLIC_KEY),
188            new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
189            new CK_ATTRIBUTE(CKA_MODULUS, n),
190            new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, e),
191        };
192        attributes = token.getAttributes
193                (O_IMPORT, CKO_PUBLIC_KEY, CKK_RSA, attributes);
194        Session session = null;
195        try {
196            session = token.getObjSession();
197            long keyID = token.p11.C_CreateObject(session.id(), attributes);
198            return P11Key.publicKey
199                (session, keyID, "RSA", n.bitLength(), attributes);
200        } finally {
201            token.releaseSession(session);
202        }
203    }
204
205    private PrivateKey generatePrivate(BigInteger n, BigInteger d)
206            throws PKCS11Exception, InvalidKeyException {
207        RSAKeyFactory.checkKeyLengths(n.bitLength(), null, -1, 64 * 1024);
208        CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
209            new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
210            new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
211            new CK_ATTRIBUTE(CKA_MODULUS, n),
212            new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, d),
213        };
214        attributes = token.getAttributes
215                (O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attributes);
216        Session session = null;
217        try {
218            session = token.getObjSession();
219            long keyID = token.p11.C_CreateObject(session.id(), attributes);
220            return P11Key.privateKey
221                (session,  keyID, "RSA", n.bitLength(), attributes);
222        } finally {
223            token.releaseSession(session);
224        }
225    }
226
227    private PrivateKey generatePrivate(BigInteger n, BigInteger e,
228            BigInteger d, BigInteger p, BigInteger q, BigInteger pe,
229            BigInteger qe, BigInteger coeff) throws PKCS11Exception,
230            InvalidKeyException {
231        RSAKeyFactory.checkKeyLengths(n.bitLength(), e, -1, 64 * 1024);
232        CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
233            new CK_ATTRIBUTE(CKA_CLASS, CKO_PRIVATE_KEY),
234            new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_RSA),
235            new CK_ATTRIBUTE(CKA_MODULUS, n),
236            new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, e),
237            new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT, d),
238            new CK_ATTRIBUTE(CKA_PRIME_1, p),
239            new CK_ATTRIBUTE(CKA_PRIME_2, q),
240            new CK_ATTRIBUTE(CKA_EXPONENT_1, pe),
241            new CK_ATTRIBUTE(CKA_EXPONENT_2, qe),
242            new CK_ATTRIBUTE(CKA_COEFFICIENT, coeff),
243        };
244        attributes = token.getAttributes
245                (O_IMPORT, CKO_PRIVATE_KEY, CKK_RSA, attributes);
246        Session session = null;
247        try {
248            session = token.getObjSession();
249            long keyID = token.p11.C_CreateObject(session.id(), attributes);
250            return P11Key.privateKey
251                (session, keyID, "RSA", n.bitLength(), attributes);
252        } finally {
253            token.releaseSession(session);
254        }
255    }
256
257    <T extends KeySpec> T implGetPublicKeySpec(P11Key key, Class<T> keySpec,
258            Session[] session) throws PKCS11Exception, InvalidKeySpecException {
259        if (RSAPublicKeySpec.class.isAssignableFrom(keySpec)) {
260            session[0] = token.getObjSession();
261            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
262                new CK_ATTRIBUTE(CKA_MODULUS),
263                new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
264            };
265            token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes);
266            KeySpec spec = new RSAPublicKeySpec(
267                attributes[0].getBigInteger(),
268                attributes[1].getBigInteger()
269            );
270            return keySpec.cast(spec);
271        } else { // X.509 handled in superclass
272            throw new InvalidKeySpecException("Only RSAPublicKeySpec and "
273                + "X509EncodedKeySpec supported for RSA public keys");
274        }
275    }
276
277    <T extends KeySpec> T implGetPrivateKeySpec(P11Key key, Class<T> keySpec,
278            Session[] session) throws PKCS11Exception, InvalidKeySpecException {
279        if (RSAPrivateCrtKeySpec.class.isAssignableFrom(keySpec)) {
280            session[0] = token.getObjSession();
281            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
282                new CK_ATTRIBUTE(CKA_MODULUS),
283                new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT),
284                new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
285                new CK_ATTRIBUTE(CKA_PRIME_1),
286                new CK_ATTRIBUTE(CKA_PRIME_2),
287                new CK_ATTRIBUTE(CKA_EXPONENT_1),
288                new CK_ATTRIBUTE(CKA_EXPONENT_2),
289                new CK_ATTRIBUTE(CKA_COEFFICIENT),
290            };
291            token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes);
292            KeySpec spec = new RSAPrivateCrtKeySpec(
293                attributes[0].getBigInteger(),
294                attributes[1].getBigInteger(),
295                attributes[2].getBigInteger(),
296                attributes[3].getBigInteger(),
297                attributes[4].getBigInteger(),
298                attributes[5].getBigInteger(),
299                attributes[6].getBigInteger(),
300                attributes[7].getBigInteger()
301            );
302            return keySpec.cast(spec);
303        } else if (RSAPrivateKeySpec.class.isAssignableFrom(keySpec)) {
304            session[0] = token.getObjSession();
305            CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {
306                new CK_ATTRIBUTE(CKA_MODULUS),
307                new CK_ATTRIBUTE(CKA_PRIVATE_EXPONENT),
308            };
309            token.p11.C_GetAttributeValue(session[0].id(), key.keyID, attributes);
310            KeySpec spec = new RSAPrivateKeySpec(
311                attributes[0].getBigInteger(),
312                attributes[1].getBigInteger()
313            );
314            return keySpec.cast(spec);
315        } else { // PKCS#8 handled in superclass
316            throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
317                + "and PKCS8EncodedKeySpec supported for RSA private keys");
318        }
319    }
320
321    KeyFactory implGetSoftwareFactory() throws GeneralSecurityException {
322        return KeyFactory.getInstance("RSA", P11Util.getSunRsaSignProvider());
323    }
324
325}
326