• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 Google LLC
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.signature;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.assertThrows;
21 
22 import com.google.crypto.tink.internal.KeyTester;
23 import com.google.crypto.tink.subtle.Hex;
24 import com.google.crypto.tink.util.Bytes;
25 import java.math.BigInteger;
26 import java.security.GeneralSecurityException;
27 import org.junit.Test;
28 import org.junit.runner.RunWith;
29 import org.junit.runners.JUnit4;
30 
31 @RunWith(JUnit4.class)
32 public final class RsaSsaPssPublicKeyTest {
33 
34   // Test vector from
35   // https://github.com/google/wycheproof/blob/master/testvectors/rsa_pss_2048_sha256_mgf1_32_test.json
36   static final BigInteger MODULUS =
37       new BigInteger(
38           "00a2b451a07d0aa5f96e455671513550514a8a5b462ebef717094fa1fee82224e637f9746d3f7cafd31878d8"
39               + "0325b6ef5a1700f65903b469429e89d6eac8845097b5ab393189db92512ed8a7711a1253facd20f79c"
40               + "15e8247f3d3e42e46e48c98e254a2fe9765313a03eff8f17e1a029397a1fa26a8dce26f490ed812996"
41               + "15d9814c22da610428e09c7d9658594266f5c021d0fceca08d945a12be82de4d1ece6b4c03145b5d34"
42               + "95d4ed5411eb878daf05fd7afc3e09ada0f1126422f590975a1969816f48698bcbba1b4d9cae79d460"
43               + "d8f9f85e7975005d9bc22c4e5ac0f7c1a45d12569a62807d3b9a02e5a530e773066f453d1f5b4c2e9c"
44               + "f7820283f742b9d5",
45           16);
46   static final BigInteger EXPONENT = BigInteger.valueOf(65537);
47 
48   @Test
buildNoPrefixVariantAndGetProperties()49   public void buildNoPrefixVariantAndGetProperties() throws Exception {
50     RsaSsaPssParameters parameters =
51         RsaSsaPssParameters.builder()
52             .setModulusSizeBits(2048)
53             .setPublicExponent(EXPONENT)
54             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
55             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
56             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
57             .setSaltLengthBytes(32)
58             .build();
59     assertThat(parameters.hasIdRequirement()).isFalse();
60     RsaSsaPssPublicKey key =
61         RsaSsaPssPublicKey.builder().setParameters(parameters).setModulus(MODULUS).build();
62     assertThat(key.getParameters()).isEqualTo(parameters);
63     assertThat(key.getModulus()).isEqualTo(MODULUS);
64     assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(new byte[] {}));
65     assertThat(key.getIdRequirementOrNull()).isNull();
66   }
67 
68   @Test
buildTinkVariantAndGetProperties()69   public void buildTinkVariantAndGetProperties() throws Exception {
70     RsaSsaPssParameters parameters =
71         RsaSsaPssParameters.builder()
72             .setModulusSizeBits(2048)
73             .setPublicExponent(EXPONENT)
74             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
75             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
76             .setVariant(RsaSsaPssParameters.Variant.TINK)
77             .setSaltLengthBytes(32)
78             .build();
79     assertThat(parameters.hasIdRequirement()).isTrue();
80     RsaSsaPssPublicKey key =
81         RsaSsaPssPublicKey.builder()
82             .setParameters(parameters)
83             .setModulus(MODULUS)
84             .setIdRequirement(0x66AABBCC)
85             .build();
86     assertThat(key.getParameters()).isEqualTo(parameters);
87     assertThat(key.getModulus()).isEqualTo(MODULUS);
88     assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(Hex.decode("0166AABBCC")));
89     assertThat(key.getIdRequirementOrNull()).isEqualTo(0x66AABBCC);
90   }
91 
92   @Test
buildLegacyVariantAndGetProperties()93   public void buildLegacyVariantAndGetProperties() throws Exception {
94     RsaSsaPssParameters parameters =
95         RsaSsaPssParameters.builder()
96             .setModulusSizeBits(2048)
97             .setPublicExponent(EXPONENT)
98             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
99             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
100             .setVariant(RsaSsaPssParameters.Variant.LEGACY)
101             .setSaltLengthBytes(32)
102             .build();
103     assertThat(parameters.hasIdRequirement()).isTrue();
104     RsaSsaPssPublicKey key =
105         RsaSsaPssPublicKey.builder()
106             .setParameters(parameters)
107             .setModulus(MODULUS)
108             .setIdRequirement(0x66AABBCC)
109             .build();
110     assertThat(key.getParameters()).isEqualTo(parameters);
111     assertThat(key.getModulus()).isEqualTo(MODULUS);
112     assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(Hex.decode("0066AABBCC")));
113     assertThat(key.getIdRequirementOrNull()).isEqualTo(0x66AABBCC);
114   }
115 
116   @Test
buildCrunchyVariantAndGetProperties()117   public void buildCrunchyVariantAndGetProperties() throws Exception {
118     RsaSsaPssParameters parameters =
119         RsaSsaPssParameters.builder()
120             .setModulusSizeBits(2048)
121             .setPublicExponent(EXPONENT)
122             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
123             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
124             .setVariant(RsaSsaPssParameters.Variant.CRUNCHY)
125             .setSaltLengthBytes(32)
126             .build();
127     assertThat(parameters.hasIdRequirement()).isTrue();
128     RsaSsaPssPublicKey key =
129         RsaSsaPssPublicKey.builder()
130             .setParameters(parameters)
131             .setModulus(MODULUS)
132             .setIdRequirement(0x66AABBCC)
133             .build();
134     assertThat(key.getParameters()).isEqualTo(parameters);
135     assertThat(key.getModulus()).isEqualTo(MODULUS);
136     assertThat(key.getOutputPrefix()).isEqualTo(Bytes.copyFrom(Hex.decode("0066AABBCC")));
137     assertThat(key.getIdRequirementOrNull()).isEqualTo(0x66AABBCC);
138   }
139 
140   @Test
emptyBuild_fails()141   public void emptyBuild_fails() throws Exception {
142     assertThrows(GeneralSecurityException.class, () -> RsaSsaPssPublicKey.builder().build());
143   }
144 
145   @Test
buildWithoutParameters_fails()146   public void buildWithoutParameters_fails() throws Exception {
147     assertThrows(
148         GeneralSecurityException.class,
149         () -> RsaSsaPssPublicKey.builder().setModulus(MODULUS).build());
150   }
151 
152   @Test
buildWithoutPublicPoint_fails()153   public void buildWithoutPublicPoint_fails() throws Exception {
154     RsaSsaPssParameters parameters =
155         RsaSsaPssParameters.builder()
156             .setModulusSizeBits(2048)
157             .setPublicExponent(EXPONENT)
158             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
159             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
160             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
161             .setSaltLengthBytes(32)
162             .build();
163     assertThrows(
164         GeneralSecurityException.class,
165         () -> RsaSsaPssPublicKey.builder().setParameters(parameters).build());
166   }
167 
168   @Test
parametersRequireIdButIdIsNotSetInBuild_fails()169   public void parametersRequireIdButIdIsNotSetInBuild_fails() throws Exception {
170     RsaSsaPssParameters parametersWithIdRequirement =
171         RsaSsaPssParameters.builder()
172             .setModulusSizeBits(2048)
173             .setPublicExponent(EXPONENT)
174             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
175             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
176             .setVariant(RsaSsaPssParameters.Variant.TINK)
177             .setSaltLengthBytes(32)
178             .build();
179     assertThat(parametersWithIdRequirement.hasIdRequirement()).isTrue();
180     assertThrows(
181         GeneralSecurityException.class,
182         () ->
183             RsaSsaPssPublicKey.builder()
184                 .setParameters(parametersWithIdRequirement)
185                 .setModulus(MODULUS)
186                 .build());
187   }
188 
189   @Test
parametersDoesNotRequireIdButIdIsSetInBuild_fails()190   public void parametersDoesNotRequireIdButIdIsSetInBuild_fails() throws Exception {
191     RsaSsaPssParameters parametersWithoutIdRequirement =
192         RsaSsaPssParameters.builder()
193             .setModulusSizeBits(2048)
194             .setPublicExponent(EXPONENT)
195             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
196             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
197             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
198             .setSaltLengthBytes(32)
199             .build();
200     assertThat(parametersWithoutIdRequirement.hasIdRequirement()).isFalse();
201     assertThrows(
202         GeneralSecurityException.class,
203         () ->
204             RsaSsaPssPublicKey.builder()
205                 .setParameters(parametersWithoutIdRequirement)
206                 .setModulus(MODULUS)
207                 .setIdRequirement(0x66AABBCC)
208                 .build());
209   }
210 
211   @Test
modulusSizeIsValidated()212   public void modulusSizeIsValidated() throws Exception {
213     RsaSsaPssParameters parameters =
214         RsaSsaPssParameters.builder()
215             .setModulusSizeBits(3456)
216             .setPublicExponent(EXPONENT)
217             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
218             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
219             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
220             .setSaltLengthBytes(32)
221             .build();
222     // Modulus between 2^3455 and 2^3456 are valid.
223     BigInteger tooSmall = BigInteger.valueOf(2).pow(3455).subtract(BigInteger.ONE);
224     BigInteger smallest = BigInteger.valueOf(2).pow(3455).add(BigInteger.ONE);
225     BigInteger biggest = BigInteger.valueOf(2).pow(3456).subtract(BigInteger.ONE);
226     BigInteger tooBig = BigInteger.valueOf(2).pow(3456).add(BigInteger.ONE);
227     assertThrows(
228         GeneralSecurityException.class,
229         () -> RsaSsaPssPublicKey.builder().setParameters(parameters).setModulus(tooSmall).build());
230     RsaSsaPssPublicKey publicKeyWithSmallestModulus =
231         RsaSsaPssPublicKey.builder().setParameters(parameters).setModulus(smallest).build();
232     assertThat(publicKeyWithSmallestModulus.getModulus()).isEqualTo(smallest);
233     RsaSsaPssPublicKey publicKeyWithBiggestModulus =
234         RsaSsaPssPublicKey.builder().setParameters(parameters).setModulus(biggest).build();
235     assertThat(publicKeyWithBiggestModulus.getModulus()).isEqualTo(biggest);
236     assertThrows(
237         GeneralSecurityException.class,
238         () -> RsaSsaPssPublicKey.builder().setParameters(parameters).setModulus(tooBig).build());
239   }
240 
241   @Test
testEqualities()242   public void testEqualities() throws Exception {
243     RsaSsaPssParameters noPrefixParameters =
244         RsaSsaPssParameters.builder()
245             .setModulusSizeBits(2048)
246             .setPublicExponent(EXPONENT)
247             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
248             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
249             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
250             .setSaltLengthBytes(32)
251             .build();
252     RsaSsaPssParameters noPrefixParametersCopy =
253         RsaSsaPssParameters.builder()
254             .setModulusSizeBits(2048)
255             .setPublicExponent(EXPONENT)
256             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
257             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
258             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
259             .setSaltLengthBytes(32)
260             .build();
261     RsaSsaPssParameters tinkPrefixParameters =
262         RsaSsaPssParameters.builder()
263             .setModulusSizeBits(2048)
264             .setPublicExponent(EXPONENT)
265             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
266             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
267             .setVariant(RsaSsaPssParameters.Variant.TINK)
268             .setSaltLengthBytes(32)
269             .build();
270     RsaSsaPssParameters legacyPrefixParameters =
271         RsaSsaPssParameters.builder()
272             .setModulusSizeBits(2048)
273             .setPublicExponent(EXPONENT)
274             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
275             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
276             .setVariant(RsaSsaPssParameters.Variant.LEGACY)
277             .setSaltLengthBytes(32)
278             .build();
279     RsaSsaPssParameters crunchyPrefixParameters =
280         RsaSsaPssParameters.builder()
281             .setModulusSizeBits(2048)
282             .setPublicExponent(EXPONENT)
283             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
284             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
285             .setVariant(RsaSsaPssParameters.Variant.CRUNCHY)
286             .setSaltLengthBytes(32)
287             .build();
288     RsaSsaPssParameters noPrefixParametersExponent65539 =
289         RsaSsaPssParameters.builder()
290             .setModulusSizeBits(2048)
291             .setPublicExponent(BigInteger.valueOf(65539))
292             .setSigHashType(RsaSsaPssParameters.HashType.SHA256)
293             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256)
294             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
295             .setSaltLengthBytes(32)
296             .build();
297     RsaSsaPssParameters noPrefixParametersSha512 =
298         RsaSsaPssParameters.builder()
299             .setModulusSizeBits(2048)
300             .setPublicExponent(EXPONENT)
301             .setSigHashType(RsaSsaPssParameters.HashType.SHA512)
302             .setMgf1HashType(RsaSsaPssParameters.HashType.SHA512)
303             .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX)
304             .setSaltLengthBytes(32)
305             .build();
306     new KeyTester()
307         .addEqualityGroup(
308             "No prefix, P256",
309             RsaSsaPssPublicKey.builder()
310                 .setParameters(noPrefixParameters)
311                 .setModulus(MODULUS)
312                 .build(),
313             // the same key built twice must be equal
314             RsaSsaPssPublicKey.builder()
315                 .setParameters(noPrefixParametersCopy)
316                 .setModulus(MODULUS)
317                 .build(),
318             // setting id requirement to null is equal to not setting it
319             RsaSsaPssPublicKey.builder()
320                 .setParameters(noPrefixParameters)
321                 .setModulus(MODULUS)
322                 .setIdRequirement(null)
323                 .build())
324         // This group checks that keys with different key bytes are not equal
325         .addEqualityGroup(
326             "No prefix, different modulus",
327             RsaSsaPssPublicKey.builder()
328                 .setParameters(noPrefixParameters)
329                 .setModulus(MODULUS.add(BigInteger.ONE))
330                 .build())
331         // These groups checks that keys with different parameters are not equal
332         .addEqualityGroup(
333             "No prefix, e=65539",
334             RsaSsaPssPublicKey.builder()
335                 .setParameters(noPrefixParametersExponent65539)
336                 .setModulus(MODULUS)
337                 .build())
338         .addEqualityGroup(
339             "No prefix, SHA512",
340             RsaSsaPssPublicKey.builder()
341                 .setParameters(noPrefixParametersSha512)
342                 .setModulus(MODULUS)
343                 .build())
344         .addEqualityGroup(
345             "Tink with key id 1907",
346             RsaSsaPssPublicKey.builder()
347                 .setParameters(tinkPrefixParameters)
348                 .setModulus(MODULUS)
349                 .setIdRequirement(1907)
350                 .build())
351         // This group checks that keys with different key ids are not equal
352         .addEqualityGroup(
353             "Tink with key id 1908",
354             RsaSsaPssPublicKey.builder()
355                 .setParameters(tinkPrefixParameters)
356                 .setModulus(MODULUS)
357                 .setIdRequirement(1908)
358                 .build())
359         // These 2 groups check that keys with different output prefix types are not equal
360         .addEqualityGroup(
361             "Legacy with key id 1907",
362             RsaSsaPssPublicKey.builder()
363                 .setParameters(legacyPrefixParameters)
364                 .setModulus(MODULUS)
365                 .setIdRequirement(1907)
366                 .build())
367         .addEqualityGroup(
368             "Crunchy with key id 1907",
369             RsaSsaPssPublicKey.builder()
370                 .setParameters(crunchyPrefixParameters)
371                 .setModulus(MODULUS)
372                 .setIdRequirement(1907)
373                 .build())
374         .doTests();
375   }
376 }
377