1 // Copyright 2018 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 //////////////////////////////////////////////////////////////////////////////// 16 17 package com.google.crypto.tink.subtle; 18 19 import static java.nio.charset.StandardCharsets.UTF_8; 20 import static org.junit.Assert.assertEquals; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.assertTrue; 23 import static org.junit.Assert.fail; 24 25 import com.google.crypto.tink.PublicKeySign; 26 import com.google.crypto.tink.PublicKeyVerify; 27 import com.google.crypto.tink.config.TinkFips; 28 import com.google.crypto.tink.config.internal.TinkFipsUtil; 29 import com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey; 30 import com.google.crypto.tink.signature.RsaSsaPkcs1PublicKey; 31 import com.google.crypto.tink.signature.internal.testing.RsaSsaPkcs1TestUtil; 32 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 33 import com.google.crypto.tink.subtle.Enums.HashType; 34 import com.google.crypto.tink.testing.TestUtil; 35 import java.security.GeneralSecurityException; 36 import java.security.KeyPair; 37 import java.security.KeyPairGenerator; 38 import java.security.Security; 39 import java.security.Signature; 40 import java.security.interfaces.RSAPrivateCrtKey; 41 import java.security.interfaces.RSAPublicKey; 42 import java.util.TreeSet; 43 import org.conscrypt.Conscrypt; 44 import org.junit.Assume; 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.experimental.theories.DataPoints; 48 import org.junit.experimental.theories.FromDataPoints; 49 import org.junit.experimental.theories.Theories; 50 import org.junit.experimental.theories.Theory; 51 import org.junit.runner.RunWith; 52 53 /** Unit tests for RsaSsaPkcs1SignJce. */ 54 @RunWith(Theories.class) 55 public class RsaSsaPkcs1SignJceTest { 56 57 @Before useConscrypt()58 public void useConscrypt() throws Exception { 59 // If Tink is build in FIPS-only mode, then we register Conscrypt for the tests. 60 if (TinkFips.useOnlyFips()) { 61 try { 62 Conscrypt.checkAvailability(); 63 Security.addProvider(Conscrypt.newProvider()); 64 } catch (Throwable cause) { 65 throw new IllegalStateException( 66 "Cannot test RSA PKCS1.5 sign in FIPS-mode without Conscrypt Provider", cause); 67 } 68 } 69 } 70 71 @Test testConstructorExceptions()72 public void testConstructorExceptions() throws Exception { 73 Assume.assumeTrue(!TinkFips.useOnlyFips()); // Only 3072-bit modulus is supported in FIPS. 74 75 int keySize = 2048; 76 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 77 keyGen.initialize(keySize); 78 79 RSAPrivateCrtKey priv = (RSAPrivateCrtKey) keyGen.generateKeyPair().getPrivate(); 80 GeneralSecurityException e = 81 assertThrows( 82 GeneralSecurityException.class, () -> new RsaSsaPkcs1SignJce(priv, HashType.SHA1)); 83 TestUtil.assertExceptionContains(e, "Unsupported hash: SHA1"); 84 } 85 86 @Test testBasicAgainstJce()87 public void testBasicAgainstJce() throws Exception { 88 Assume.assumeTrue(!TinkFips.useOnlyFips()); // Only 3072-bit modulus is supported in FIPS. 89 90 int keySize = 2048; 91 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 92 keyGen.initialize(keySize); 93 KeyPair keyPair = keyGen.generateKeyPair(); 94 RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic(); 95 RSAPrivateCrtKey priv = (RSAPrivateCrtKey) keyPair.getPrivate(); 96 97 // Sign with RsaSsaPkcs1SignJce. 98 String message = "Hello"; 99 RsaSsaPkcs1SignJce signer = new RsaSsaPkcs1SignJce(priv, HashType.SHA256); 100 byte[] signature = signer.sign(message.getBytes(UTF_8)); 101 102 // Verify with JCE's Signature. 103 Signature verifier = Signature.getInstance("SHA256withRSA"); 104 verifier.initVerify(pub); 105 verifier.update(message.getBytes(UTF_8)); 106 assertTrue(verifier.verify(signature)); 107 } 108 109 @Test testBasicAgainstJce3072()110 public void testBasicAgainstJce3072() throws Exception { 111 Assume.assumeTrue(!TinkFips.useOnlyFips() || TinkFipsUtil.fipsModuleAvailable()); 112 113 int keySize = 3072; 114 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 115 keyGen.initialize(keySize); 116 KeyPair keyPair = keyGen.generateKeyPair(); 117 RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic(); 118 RSAPrivateCrtKey priv = (RSAPrivateCrtKey) keyPair.getPrivate(); 119 120 // Sign with RsaSsaPkcs1SignJce. 121 String message = "Hello"; 122 RsaSsaPkcs1SignJce signer = new RsaSsaPkcs1SignJce(priv, HashType.SHA256); 123 byte[] signature = signer.sign(message.getBytes(UTF_8)); 124 125 // Verify with JCE's Signature. 126 Signature verifier = Signature.getInstance("SHA256withRSA"); 127 verifier.initVerify(pub); 128 verifier.update(message.getBytes(UTF_8)); 129 assertTrue(verifier.verify(signature)); 130 } 131 132 @Test testSignWithTheSameMessage()133 public void testSignWithTheSameMessage() throws Exception { 134 Assume.assumeTrue(!TinkFips.useOnlyFips()); // Only 3072-bit modulus is supported in FIPS. 135 Assume.assumeFalse( 136 TestUtil 137 .isTsan()); // This test times out when running under thread sanitizer, so we just skip. 138 139 int keySize = 4096; 140 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 141 keyGen.initialize(keySize); 142 KeyPair keyPair = keyGen.generateKeyPair(); 143 RSAPrivateCrtKey priv = (RSAPrivateCrtKey) keyPair.getPrivate(); 144 RSAPublicKey pub = (RSAPublicKey) keyPair.getPublic(); 145 146 byte[] msg = Random.randBytes(20); 147 TreeSet<String> allSignatures = new TreeSet<String>(); 148 RsaSsaPkcs1SignJce signer = new RsaSsaPkcs1SignJce(priv, HashType.SHA512); 149 for (int i = 0; i < 100; i++) { 150 byte[] sig = signer.sign(msg); 151 allSignatures.add(Hex.encode(sig)); 152 // Verify with JCE's Signature. 153 Signature verifier = Signature.getInstance("SHA512WithRSA"); 154 verifier.initVerify(pub); 155 verifier.update(msg); 156 if (!verifier.verify(sig)) { 157 fail( 158 String.format( 159 "\n\nMessage: %s\nSignature: %s\nPrivateKey: %s\nPublicKey: %s\n", 160 Hex.encode(msg), 161 Hex.encode(sig), 162 Hex.encode(priv.getEncoded()), 163 Hex.encode(pub.getEncoded()))); 164 } 165 } 166 // RSA SSA PKCS1 is deterministic, expect a unique signature for the same message. 167 assertEquals(1, allSignatures.size()); 168 } 169 170 @Test testFailIfFipsModuleNotAvailable()171 public void testFailIfFipsModuleNotAvailable() throws Exception { 172 Assume.assumeTrue(TinkFips.useOnlyFips() && !TinkFipsUtil.fipsModuleAvailable()); 173 174 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); 175 keyGen.initialize(3072); 176 KeyPair keyPair = keyGen.generateKeyPair(); 177 RSAPrivateCrtKey priv = (RSAPrivateCrtKey) keyPair.getPrivate(); 178 179 assertThrows( 180 GeneralSecurityException.class, () -> new RsaSsaPkcs1SignJce(priv, HashType.SHA512)); 181 } 182 183 @Theory test_validateSignatureInTestVector( @romDataPoints"allTests") SignatureTestVector testVector)184 public void test_validateSignatureInTestVector( 185 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 186 PublicKeyVerify verifier = 187 RsaSsaPkcs1VerifyJce.create( 188 (RsaSsaPkcs1PublicKey) testVector.getPrivateKey().getPublicKey()); 189 verifier.verify(testVector.getSignature(), testVector.getMessage()); 190 } 191 192 @Theory test_computeAndValidateFreshSignatureWithTestVector( @romDataPoints"allTests") SignatureTestVector testVector)193 public void test_computeAndValidateFreshSignatureWithTestVector( 194 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 195 PublicKeySign signer = 196 RsaSsaPkcs1SignJce.create((RsaSsaPkcs1PrivateKey) testVector.getPrivateKey()); 197 byte[] signature = signer.sign(testVector.getMessage()); 198 PublicKeyVerify verifier = 199 RsaSsaPkcs1VerifyJce.create( 200 (RsaSsaPkcs1PublicKey) testVector.getPrivateKey().getPublicKey()); 201 verifier.verify(signature, testVector.getMessage()); 202 } 203 204 @Theory test_validateSignatureInTestVectorWithWrongMessage_throws( @romDataPoints"allTests") SignatureTestVector testVector)205 public void test_validateSignatureInTestVectorWithWrongMessage_throws( 206 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 207 PublicKeyVerify verifier = 208 RsaSsaPkcs1VerifyJce.create( 209 (RsaSsaPkcs1PublicKey) testVector.getPrivateKey().getPublicKey()); 210 byte[] modifiedMessage = Bytes.concat(testVector.getMessage(), new byte[] {0x01}); 211 assertThrows( 212 GeneralSecurityException.class, 213 () -> verifier.verify(testVector.getSignature(), modifiedMessage)); 214 } 215 216 @DataPoints("allTests") 217 public static final SignatureTestVector[] ALL_TEST_VECTORS = 218 RsaSsaPkcs1TestUtil.createRsaSsaPkcs1TestVectors(); 219 } 220