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