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 /** 25 * @test 26 * @bug 8254717 8263404 27 * @summary isAssignableFrom checks in KeyFactorySpi.engineGetKeySpec appear to be backwards. 28 * @author Greg Rubin, Ziyi Luo 29 */ 30 31 import java.math.BigInteger; 32 import java.security.KeyFactory; 33 import java.security.KeyPair; 34 import java.security.KeyPairGenerator; 35 import java.security.interfaces.RSAPrivateCrtKey; 36 import java.security.interfaces.RSAPrivateKey; 37 import java.security.spec.*; 38 39 public class KeyFactoryGetKeySpecForInvalidSpec { 40 41 // Test for 8263404: This method generates RSAPrivateKey (without Crt info) from a RSAPrivateCrtKey privateCrtToPrivate(RSAPrivateCrtKey crtKey)42 public static RSAPrivateKey privateCrtToPrivate(RSAPrivateCrtKey crtKey) { 43 return new RSAPrivateKey() { 44 @Override 45 public BigInteger getPrivateExponent() { 46 return crtKey.getPrivateExponent(); 47 } 48 49 @Override 50 public String getAlgorithm() { 51 return crtKey.getAlgorithm(); 52 } 53 54 @Override 55 public String getFormat() { 56 return crtKey.getFormat(); 57 } 58 59 @Override 60 public byte[] getEncoded() { 61 return crtKey.getEncoded(); 62 } 63 64 @Override 65 public BigInteger getModulus() { 66 return crtKey.getModulus(); 67 } 68 }; 69 } 70 71 public static void main(String[] args) throws Exception { 72 KeyPairGenerator kg = KeyPairGenerator.getInstance("RSA", "SunRsaSign"); 73 kg.initialize(2048); 74 KeyPair pair = kg.generateKeyPair(); 75 76 KeyFactory factory = KeyFactory.getInstance("RSA"); 77 78 // === Case 1: private key is RSAPrivateCrtKey, keySpec is RSAPrivateKeySpec 79 // === Expected: return RSAPrivateCrtKeySpec 80 // Since RSAPrivateCrtKeySpec inherits from RSAPrivateKeySpec, we'd expect this next line to return an instance of RSAPrivateKeySpec 81 // (because the private key has CRT parts). 82 KeySpec spec = factory.getKeySpec(pair.getPrivate(), RSAPrivateKeySpec.class); 83 if (!(spec instanceof RSAPrivateCrtKeySpec)) { 84 throw new Exception("Spec should be an instance of RSAPrivateCrtKeySpec"); 85 } 86 87 // === Case 2: private key is RSAPrivateCrtKey, keySpec is RSAPrivateCrtKeySpec 88 // === Expected: return RSAPrivateCrtKeySpec 89 spec = factory.getKeySpec(pair.getPrivate(), RSAPrivateCrtKeySpec.class); 90 if (!(spec instanceof RSAPrivateCrtKeySpec)) { 91 throw new Exception("Spec should be an instance of RSAPrivateCrtKeySpec"); 92 } 93 94 // === Case 3: private key is RSAPrivateKey, keySpec is RSAPrivateKeySpec 95 // === Expected: return RSAPrivateKeySpec not RSAPrivateCrtKeySpec 96 RSAPrivateKey notCrtKey = privateCrtToPrivate((RSAPrivateCrtKey)pair.getPrivate()); 97 // InvalidKeySpecException should not be thrown 98 KeySpec notCrtSpec = factory.getKeySpec(notCrtKey, RSAPrivateKeySpec.class); 99 if (notCrtSpec instanceof RSAPrivateCrtKeySpec) { 100 throw new Exception("Spec should be an instance of RSAPrivateKeySpec not RSAPrivateCrtKeySpec"); 101 } 102 if (!(notCrtSpec instanceof RSAPrivateKeySpec)) { 103 throw new Exception("Spec should be an instance of RSAPrivateKeySpec"); 104 } 105 106 // === Case 4: private key is RSAPrivateKey, keySpec is RSAPrivateCrtKeySpec 107 // === Expected: throw InvalidKeySpecException 108 try { 109 factory.getKeySpec(notCrtKey, RSAPrivateCrtKeySpec.class); 110 throw new Exception("InvalidKeySpecException is expected but not thrown"); 111 } catch (InvalidKeySpecException e) { 112 // continue; 113 } 114 115 // This next line should give an InvalidKeySpec exception 116 try { 117 spec = factory.getKeySpec(pair.getPublic(), FakeX509Spec.class); 118 throw new Exception("InvalidKeySpecException is expected but not thrown"); 119 } catch (final ClassCastException ex) { 120 throw new Exception("InvalidKeySpecException is expected ClassCastException is thrown", ex); 121 } catch (final InvalidKeySpecException ex) { 122 // Pass 123 } 124 } 125 126 public static class FakeX509Spec extends X509EncodedKeySpec { 127 public FakeX509Spec(byte[] encodedKey) { 128 super(encodedKey); 129 } 130 131 public FakeX509Spec(byte[] encodedKey, String algorithm) { 132 super(encodedKey, algorithm); 133 } 134 } 135 } 136