1 /*
   2  * Copyright (c) 2019, 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.
   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 8216039
  27  * @summary Ensure the BC provider-reselection workaround in Signature class
  28  *     functions correctly
  29  * @modules java.base/sun.security.util
  30  * @run main/othervm SignatureGetInstance
  31  */
  32 import java.security.*;
  33 import java.security.interfaces.*;
  34 import java.security.spec.*;
  35 import sun.security.util.SignatureUtil;
  36 
  37 public class SignatureGetInstance {
  38 
  39     private static final String SIGALG = "RSASSA-PSS";
  40 
  41     public static void main(String[] args) throws Exception {
  42         Provider testProvider = new TestProvider();
  43         // put test provider before SunRsaSign provider
  44         Security.insertProviderAt(testProvider, 1);
  45         //Security.addProvider(testProvider);
  46         KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
  47         KeyPair kp = kpg.generateKeyPair();
  48 
  49         MyPrivKey testPriv = new MyPrivKey();
  50         MyPubKey testPub = new MyPubKey();
  51 
  52         testDblInit(testPriv, testPub, true, "TestProvider");
  53         testDblInit(kp.getPrivate(), kp.getPublic(), true, "SunRsaSign");
  54         testDblInit(testPriv, kp.getPublic(), false, null);
  55         testDblInit(kp.getPrivate(), testPub, false, null);
  56 
  57         testSetAndInit(null, testPriv, true);
  58         testSetAndInit(null, testPub, true);
  59         testSetAndInit(null, kp.getPrivate(), true);
  60         testSetAndInit(null, kp.getPublic(), true);
  61 
  62         String provName = "SunRsaSign";
  63         testSetAndInit(provName, testPriv, false);
  64         testSetAndInit(provName, testPub, false);
  65         testSetAndInit(provName, kp.getPrivate(), true);
  66         testSetAndInit(provName, kp.getPublic(), true);
  67 
  68         provName = "TestProvider";
  69         testSetAndInit(provName, testPriv, true);
  70         testSetAndInit(provName, testPub, true);
  71         testSetAndInit(provName, kp.getPrivate(), false);
  72         testSetAndInit(provName, kp.getPublic(), false);
  73 
  74         System.out.println("Test Passed");
  75     }
  76 
  77     private static void checkName(Signature s, String name) {
  78         if (name != null &&
  79             !(name.equals(s.getProvider().getName()))) {
  80             throw new RuntimeException("Fail: provider name mismatch");
  81         }
  82     }
  83 
  84     private static void testDblInit(PrivateKey key1, PublicKey key2,
  85             boolean shouldPass, String expectedProvName) throws Exception {
  86         Signature sig = Signature.getInstance(SIGALG);
  87         SignatureUtil.initSignWithParam(sig, key1, PSSParameterSpec.DEFAULT, null);
  88         try {
  89             sig.initVerify(key2);
  90             if (!shouldPass) {
  91                 throw new RuntimeException("Fail: should throw InvalidKeyException");
  92             }
  93             checkName(sig, expectedProvName);
  94         } catch (InvalidKeyException ike) {
  95             if (shouldPass) {
  96                 System.out.println("Fail: Unexpected InvalidKeyException");
  97                 throw ike;
  98             }
  99         }
 100     }
 101 
 102     private static void testSetAndInit(String provName, Key key,
 103             boolean shouldPass) throws Exception {
 104         Signature sig;
 105         if (provName == null) {
 106             sig = Signature.getInstance(SIGALG);
 107         } else {
 108             sig = Signature.getInstance(SIGALG, provName);
 109         }
 110         AlgorithmParameterSpec params = PSSParameterSpec.DEFAULT;
 111         boolean doSign = (key instanceof PrivateKey);
 112         try {
 113             if (doSign) {
 114                 SignatureUtil.initSignWithParam(sig, (PrivateKey)key, params, null);
 115             } else {
 116                 SignatureUtil.initVerifyWithParam(sig, (PublicKey)key, params);
 117             }
 118             if (!shouldPass) {
 119                 throw new RuntimeException("Fail: should throw InvalidKeyException");
 120             }
 121             checkName(sig, provName);
 122             // check that the earlier parameter is still there
 123             if (sig.getParameters() == null) {
 124                 throw new RuntimeException("Fail: parameters not preserved");
 125             }
 126         } catch (InvalidKeyException ike) {
 127             if (shouldPass) {
 128                 System.out.println("Fail: Unexpected InvalidKeyException");
 129                 throw ike;
 130             }
 131         }
 132     }
 133 
 134     // Test provider which only accepts its own Key objects
 135     // Registered to be more preferred than SunRsaSign provider
 136     // for testing deferred provider selection
 137     public static class TestProvider extends Provider {
 138         TestProvider() {
 139             super("TestProvider", "1.0", "provider for SignatureGetInstance");
 140             put("Signature.RSASSA-PSS",
 141                 "SignatureGetInstance$MySigImpl");
 142         }
 143     }
 144 
 145     public static class MyPrivKey implements PrivateKey {
 146         public String getAlgorithm() { return "RSASSA-PSS"; }
 147         public String getFormat() { return "MyOwn"; }
 148         public byte[] getEncoded() { return null; }
 149     }
 150 
 151     public static class MyPubKey implements PublicKey {
 152         public String getAlgorithm() { return "RSASSA-PSS"; }
 153         public String getFormat() { return "MyOwn"; }
 154         public byte[] getEncoded() { return null; }
 155     }
 156 
 157     public static class MySigImpl extends SignatureSpi {
 158         // simulate BC behavior of only using params set before init calls
 159         AlgorithmParameterSpec initParamSpec = null;
 160         AlgorithmParameterSpec paramSpec = null;
 161 
 162         public MySigImpl() {
 163             super();
 164         }
 165 
 166         @Override
 167         protected void engineInitVerify(PublicKey publicKey)
 168                 throws InvalidKeyException {
 169             if (!(publicKey instanceof MyPubKey)) {
 170                 throw new InvalidKeyException("Must be MyPubKey");
 171             }
 172             initParamSpec = paramSpec;
 173         }
 174 
 175         @Override
 176         protected void engineInitSign(PrivateKey privateKey)
 177                 throws InvalidKeyException {
 178             if (!(privateKey instanceof MyPrivKey)) {
 179                 throw new InvalidKeyException("Must be MyPrivKey");
 180             }
 181             initParamSpec = paramSpec;
 182         }
 183 
 184         @Override
 185         protected void engineUpdate(byte b) throws SignatureException {
 186         }
 187 
 188         @Override
 189         protected void engineUpdate(byte[] b, int off, int len)
 190                 throws SignatureException {
 191         }
 192 
 193         @Override
 194         protected byte[] engineSign()
 195                 throws SignatureException {
 196             return new byte[0];
 197         }
 198 
 199         @Override
 200         protected boolean engineVerify(byte[] sigBytes)
 201                 throws SignatureException {
 202             return false;
 203         }
 204 
 205         @Override
 206         @Deprecated
 207         protected void engineSetParameter(String param, Object value)
 208                 throws InvalidParameterException {
 209         }
 210 
 211         @Override
 212         protected void engineSetParameter(AlgorithmParameterSpec params)
 213                 throws InvalidAlgorithmParameterException {
 214             paramSpec = params;
 215         }
 216 
 217         @Override
 218         @Deprecated
 219         protected AlgorithmParameters engineGetParameter(String param)
 220                 throws InvalidParameterException {
 221             return null;
 222         }
 223 
 224         @Override
 225         protected AlgorithmParameters engineGetParameters() {
 226             if (initParamSpec != null) {
 227                 try {
 228                     AlgorithmParameters ap =
 229                         AlgorithmParameters.getInstance("RSASSA-PSS");
 230                     ap.init(initParamSpec);
 231                     return ap;
 232                 } catch (Exception e) {
 233                     throw new RuntimeException(e);
 234                 }
 235             }
 236             return null;
 237         }
 238     }
 239 }