1 /*
2  * Copyright (c) 2021, Amazon.com, Inc. 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.math.BigInteger;
25 import java.security.KeyFactory;
26 import java.security.KeyPair;
27 import java.security.KeyPairGenerator;
28 import java.security.Provider;
29 import java.security.PrivateKey;
30 import java.security.interfaces.RSAPrivateKey;
31 import java.security.interfaces.RSAPrivateCrtKey;
32 import java.security.spec.*;
33 
34 /**
35  * @test
36  * @bug 8263404
37  * @summary RSAPrivateCrtKeySpec is prefered for CRT keys even when a RsaPrivateKeySpec is requested.
38  * @summary Also checks to ensure that sensitive RSA keys are correctly not exposed
39  * @library /test/lib ..
40  * @run main/othervm TestP11KeyFactoryGetRSAKeySpec
41  * @run main/othervm TestP11KeyFactoryGetRSAKeySpec sm rsakeys.ks.policy
42  * @run main/othervm -DCUSTOM_P11_CONFIG_NAME=p11-nss-sensitive.txt -DNO_DEIMOS=true -DNO_DEFAULT=true TestP11KeyFactoryGetRSAKeySpec
43  * @modules jdk.crypto.cryptoki
44  */
45 
46 public class TestP11KeyFactoryGetRSAKeySpec extends PKCS11Test {
47     private static boolean testingSensitiveKeys = false;
main(String[] args)48     public static void main(String[] args) throws Exception {
49         testingSensitiveKeys = "p11-nss-sensitive.txt".equals(System.getProperty("CUSTOM_P11_CONFIG_NAME"));
50         main(new TestP11KeyFactoryGetRSAKeySpec(), args);
51     }
52 
53     @Override
main(Provider p)54     public void main(Provider p) throws Exception {
55         KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA", p);
56         kg.initialize(2048);
57         KeyPair pair = kg.generateKeyPair();
58         PrivateKey privKey = pair.getPrivate();
59 
60         KeyFactory factory = KeyFactory.getInstance("RSA", p);
61 
62         // If this is a sensitive key, then it shouldn't implement the RSAPrivateKey interface as that exposes sensitive fields
63         boolean keyExposesSensitiveFields = privKey instanceof RSAPrivateKey;
64         if (keyExposesSensitiveFields == testingSensitiveKeys) {
65             throw new Exception("Key of type " + privKey.getClass() + " returned when testing sensitive keys is " + testingSensitiveKeys);
66         }
67 
68         if (!testingSensitiveKeys) {
69             // The remaining tests require that the PKCS #11 token actually generated a CRT key.
70             // This is the normal and expected case, but we add an assertion here to detect a broken test due to bad assumptions.
71             if (!(privKey instanceof RSAPrivateCrtKey)) {
72                 throw new Exception("Test assumption violated: PKCS #11 token did not generate a CRT key.");
73             }
74         }
75 
76         // === Case 1: private key is RSAPrivateCrtKey, keySpec is RSAPrivateKeySpec
77         // === Expected: return RSAPrivateCrtKeySpec
78         // Since RSAPrivateCrtKeySpec inherits from RSAPrivateKeySpec, we'd expect this next line to return an instance of RSAPrivateKeySpec
79         // (because the private key has CRT parts).
80         testKeySpec(factory, privKey, RSAPrivateKeySpec.class);
81 
82         // === Case 2: private key is RSAPrivateCrtKey, keySpec is RSAPrivateCrtKeySpec
83         // === Expected: return RSAPrivateCrtKeySpec
84         testKeySpec(factory, privKey, RSAPrivateCrtKeySpec.class);
85     }
86 
testKeySpec(KeyFactory factory, PrivateKey key, Class<? extends KeySpec> specClass)87     private static void testKeySpec(KeyFactory factory, PrivateKey key, Class<? extends KeySpec> specClass) throws Exception {
88         try {
89             KeySpec spec = factory.getKeySpec(key, RSAPrivateKeySpec.class);
90             if (testingSensitiveKeys) {
91                 throw new Exception("Able to retrieve spec from sensitive key");
92             }
93             if (!(spec instanceof RSAPrivateCrtKeySpec)) {
94                 throw new Exception("Spec should be an instance of RSAPrivateCrtKeySpec");
95             }
96         } catch (final InvalidKeySpecException ex) {
97             if (testingSensitiveKeys) {
98                 // Expected exception so swallow it
99                 System.err.println("This exception is expected when retrieving sensitive properties from a sensitive PKCS #11 key.");
100                 ex.printStackTrace();
101             } else {
102                 throw ex;
103             }
104         }
105     }
106 }
107