• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 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 org.junit.Assert.assertThrows;
20 
21 import com.google.crypto.tink.KeysetHandle;
22 import com.google.crypto.tink.PublicKeySign;
23 import com.google.crypto.tink.PublicKeyVerify;
24 import com.google.crypto.tink.config.internal.TinkFipsUtil;
25 import com.google.crypto.tink.internal.Util;
26 import com.google.crypto.tink.signature.internal.EcdsaProtoSerialization;
27 import com.google.crypto.tink.signature.internal.Ed25519ProtoSerialization;
28 import com.google.crypto.tink.signature.internal.RsaSsaPkcs1ProtoSerialization;
29 import com.google.crypto.tink.signature.internal.RsaSsaPssProtoSerialization;
30 import com.google.crypto.tink.signature.internal.testing.EcdsaTestUtil;
31 import com.google.crypto.tink.signature.internal.testing.Ed25519TestUtil;
32 import com.google.crypto.tink.signature.internal.testing.RsaSsaPkcs1TestUtil;
33 import com.google.crypto.tink.signature.internal.testing.RsaSsaPssTestUtil;
34 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector;
35 import java.security.GeneralSecurityException;
36 import java.util.Arrays;
37 import java.util.stream.Stream;
38 import javax.annotation.Nullable;
39 import org.junit.Assume;
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 import org.junit.experimental.theories.DataPoints;
43 import org.junit.experimental.theories.FromDataPoints;
44 import org.junit.experimental.theories.Theories;
45 import org.junit.experimental.theories.Theory;
46 import org.junit.runner.RunWith;
47 
48 @RunWith(Theories.class)
49 public class SignatureConfigurationV0Test {
50   @BeforeClass
setUp()51   public static void setUp() throws Exception {
52     EcdsaProtoSerialization.register();
53     RsaSsaPssProtoSerialization.register();
54     RsaSsaPkcs1ProtoSerialization.register();
55     Ed25519ProtoSerialization.register();
56   }
57 
58   @Test
config_throwsIfInFipsMode()59   public void config_throwsIfInFipsMode() throws Exception {
60     Assume.assumeTrue(TinkFipsUtil.useOnlyFips());
61 
62     assertThrows(GeneralSecurityException.class, SignatureConfigurationV0::get);
63   }
64 
65   /**
66    * Tests that when using the public API of Tink, signatures in the test vector can be verified.
67    * This additionally ensures that all the expected algorithms (Ecdsa, RsaSsaPss, RsaSsaPkcs1,
68    * Ed25519 for {@code PublicKeyVerify}) are present in the SignatureConfigurationV0.
69    */
70   @Theory
test_validateSignatureInTestVector( @romDataPoints"signatureTests") SignatureTestVector testVector)71   public void test_validateSignatureInTestVector(
72       @FromDataPoints("signatureTests") SignatureTestVector testVector) throws Exception {
73     Assume.assumeFalse(TinkFipsUtil.useOnlyFips());
74     @Nullable Integer apiLevel = Util.getAndroidApiLevel();
75     if (apiLevel != null && apiLevel == 19) {
76       // Android API 19 is slower than the others in this.
77       return;
78     }
79     SignaturePrivateKey key = testVector.getPrivateKey();
80     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).makePrimary();
81     @Nullable Integer id = key.getIdRequirementOrNull();
82     if (id == null) {
83       entry.withRandomId();
84     } else {
85       entry.withFixedId(id);
86     }
87     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
88 
89     PublicKeyVerify verifier =
90         handle
91             .getPublicKeysetHandle()
92             .getPrimitive(SignatureConfigurationV0.get(), PublicKeyVerify.class);
93 
94     verifier.verify(testVector.getSignature(), testVector.getMessage());
95   }
96 
97   /**
98    * Tests that when using the public API of Tink, newly created signatures can be verified. This
99    * additionally ensures that all the expected algorithms (Ecdsa, RsaSsaPss, RsaSsaPkcs1, Ed25519
100    * for {@code PublicKeySign}) are present in the SignatureConfigurationV0.
101    */
102   @Theory
test_computeAndValidateFreshSignatureWithTestVector( @romDataPoints"signatureTests") SignatureTestVector testVector)103   public void test_computeAndValidateFreshSignatureWithTestVector(
104       @FromDataPoints("signatureTests") SignatureTestVector testVector) throws Exception {
105     Assume.assumeFalse(TinkFipsUtil.useOnlyFips());
106     @Nullable Integer apiLevel = Util.getAndroidApiLevel();
107     if (apiLevel != null && apiLevel == 19) {
108       // Android API 19 is slower than the others in this.
109       return;
110     }
111     SignaturePrivateKey key = testVector.getPrivateKey();
112     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).makePrimary();
113     @Nullable Integer id = key.getIdRequirementOrNull();
114     if (id == null) {
115       entry.withRandomId();
116     } else {
117       entry.withFixedId(id);
118     }
119     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
120 
121     PublicKeySign signer = handle.getPrimitive(SignatureConfigurationV0.get(), PublicKeySign.class);
122     byte[] signature = signer.sign(testVector.getMessage());
123     PublicKeyVerify verifier =
124         handle
125             .getPublicKeysetHandle()
126             .getPrimitive(SignatureConfigurationV0.get(), PublicKeyVerify.class);
127 
128     verifier.verify(signature, testVector.getMessage());
129   }
130 
modifyInput(byte[] message)131   private static byte[] modifyInput(byte[] message) {
132     if (message.length == 0) {
133       return new byte[] {1};
134     }
135     byte[] copy = Arrays.copyOf(message, message.length);
136     copy[0] ^= 1;
137     return copy;
138   }
139 
140   /**
141    * Ensures correctness in the faulty scenario of the Sign/Verify primitives obtained through the
142    * public API of Tink.
143    */
144   @Theory
test_computeFreshSignatureWithTestVector_throwsWithWrongMessage( @romDataPoints"signatureTests") SignatureTestVector testVector)145   public void test_computeFreshSignatureWithTestVector_throwsWithWrongMessage(
146       @FromDataPoints("signatureTests") SignatureTestVector testVector) throws Exception {
147     Assume.assumeFalse(TinkFipsUtil.useOnlyFips());
148     @Nullable Integer apiLevel = Util.getAndroidApiLevel();
149     if (apiLevel != null && apiLevel == 19) {
150       // Android API 19 is slower than the others in this.
151       return;
152     }
153     SignaturePrivateKey key = testVector.getPrivateKey();
154     KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).makePrimary();
155     @Nullable Integer id = key.getIdRequirementOrNull();
156     if (id == null) {
157       entry.withRandomId();
158     } else {
159       entry.withFixedId(id);
160     }
161     KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build();
162 
163     PublicKeySign signer = handle.getPrimitive(SignatureConfigurationV0.get(), PublicKeySign.class);
164     byte[] signature = signer.sign(testVector.getMessage());
165     PublicKeyVerify verifier =
166         handle
167             .getPublicKeysetHandle()
168             .getPrimitive(SignatureConfigurationV0.get(), PublicKeyVerify.class);
169 
170     assertThrows(
171         GeneralSecurityException.class,
172         () -> verifier.verify(signature, modifyInput(testVector.getMessage())));
173   }
174 
175   @DataPoints("signatureTests")
176   public static final SignatureTestVector[] signatureTestVectors =
177       Stream.concat(
178               Stream.concat(
179                   Arrays.stream(EcdsaTestUtil.createEcdsaTestVectors()),
180                   Arrays.stream(RsaSsaPssTestUtil.createRsaPssTestVectors())),
181               Stream.concat(
182                   Arrays.stream(RsaSsaPkcs1TestUtil.createRsaSsaPkcs1TestVectors()),
183                   Arrays.stream(Ed25519TestUtil.createEd25519TestVectors())))
184           .toArray(SignatureTestVector[]::new);
185 }
186