• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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