1 // Copyright 2018 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 21 import com.google.crypto.tink.InsecureSecretKeyAccess; 22 import com.google.crypto.tink.KeyTemplate; 23 import com.google.crypto.tink.KeyTemplates; 24 import com.google.crypto.tink.KeysetHandle; 25 import com.google.crypto.tink.Parameters; 26 import com.google.crypto.tink.PublicKeySign; 27 import com.google.crypto.tink.PublicKeyVerify; 28 import com.google.crypto.tink.RegistryConfiguration; 29 import com.google.crypto.tink.TinkProtoKeysetFormat; 30 import com.google.crypto.tink.internal.KeyManagerRegistry; 31 import com.google.crypto.tink.signature.internal.testing.RsaSsaPssTestUtil; 32 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 33 import com.google.crypto.tink.testing.TestUtil; 34 import java.math.BigInteger; 35 import java.util.Set; 36 import java.util.TreeSet; 37 import javax.annotation.Nullable; 38 import org.junit.BeforeClass; 39 import org.junit.Test; 40 import org.junit.experimental.theories.DataPoints; 41 import org.junit.experimental.theories.FromDataPoints; 42 import org.junit.experimental.theories.Theories; 43 import org.junit.experimental.theories.Theory; 44 import org.junit.runner.RunWith; 45 46 /** Unit tests for RsaSsaPssSignKeyManager. */ 47 @RunWith(Theories.class) 48 public class RsaSsaPssSignKeyManagerTest { 49 @BeforeClass beforeClass()50 public static void beforeClass() throws Exception { 51 RsaSsaPssSignKeyManager.registerPair(/* newKeyAllowed= */ true); 52 PublicKeySignWrapper.register(); 53 PublicKeyVerifyWrapper.register(); 54 } 55 56 @Test createSmallKeyUsingParameters_works()57 public void createSmallKeyUsingParameters_works() throws Exception { 58 if (TestUtil.isTsan()) { 59 // factory.createKey is too slow in Tsan. 60 return; 61 } 62 RsaSsaPssParameters parameters = 63 RsaSsaPssParameters.builder() 64 .setModulusSizeBits(3072) 65 .setPublicExponent(RsaSsaPssParameters.F4) 66 .setSigHashType(RsaSsaPssParameters.HashType.SHA256) 67 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256) 68 .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX) 69 .setSaltLengthBytes(32) 70 .build(); 71 KeysetHandle handle = KeysetHandle.generateNew(parameters); 72 com.google.crypto.tink.Key key = handle.getAt(0).getKey(); 73 assertThat(key).isInstanceOf(com.google.crypto.tink.signature.RsaSsaPssPrivateKey.class); 74 com.google.crypto.tink.signature.RsaSsaPssPrivateKey privateKey = 75 (com.google.crypto.tink.signature.RsaSsaPssPrivateKey) key; 76 77 assertThat(privateKey.getPublicKey().getParameters()).isEqualTo(parameters); 78 assertThat(privateKey.getPublicKey().getModulus().bitLength()).isEqualTo(3072); 79 } 80 81 82 @Test createKey_alwaysNewElement()83 public void createKey_alwaysNewElement() throws Exception { 84 if (TestUtil.isTsan()) { 85 // factory.createKey is too slow in Tsan. 86 return; 87 } 88 RsaSsaPssParameters parameters = 89 RsaSsaPssParameters.builder() 90 .setModulusSizeBits(2048) 91 .setPublicExponent(RsaSsaPssParameters.F4) 92 .setSigHashType(RsaSsaPssParameters.HashType.SHA256) 93 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256) 94 .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX) 95 .setSaltLengthBytes(32) 96 .build(); 97 Set<BigInteger> primes = new TreeSet<>(); 98 // Calls newKey multiple times and make sure that they generate different keys -- takes about a 99 // second per key. 100 int numTests = 5; 101 for (int i = 0; i < numTests; i++) { 102 KeysetHandle handle = KeysetHandle.generateNew(parameters); 103 assertThat(handle.size()).isEqualTo(1); 104 com.google.crypto.tink.signature.RsaSsaPssPrivateKey key = 105 (com.google.crypto.tink.signature.RsaSsaPssPrivateKey) handle.getAt(0).getKey(); 106 primes.add(key.getPrimeP().getBigInteger(InsecureSecretKeyAccess.get())); 107 primes.add(key.getPrimeQ().getBigInteger(InsecureSecretKeyAccess.get())); 108 } 109 assertThat(primes).hasSize(2 * numTests); 110 } 111 112 113 @Test testRsa3072PssSha256F4Template()114 public void testRsa3072PssSha256F4Template() throws Exception { 115 KeyTemplate template = RsaSsaPssSignKeyManager.rsa3072PssSha256F4Template(); 116 assertThat(template.toParameters()) 117 .isEqualTo( 118 RsaSsaPssParameters.builder() 119 .setSigHashType(RsaSsaPssParameters.HashType.SHA256) 120 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256) 121 .setSaltLengthBytes(32) 122 .setModulusSizeBits(3072) 123 .setPublicExponent(RsaSsaPssParameters.F4) 124 .setVariant(RsaSsaPssParameters.Variant.TINK) 125 .build()); 126 } 127 128 @Test testRawRsa3072PssSha256F4Template()129 public void testRawRsa3072PssSha256F4Template() throws Exception { 130 KeyTemplate template = RsaSsaPssSignKeyManager.rawRsa3072PssSha256F4Template(); 131 assertThat(template.toParameters()) 132 .isEqualTo( 133 RsaSsaPssParameters.builder() 134 .setSigHashType(RsaSsaPssParameters.HashType.SHA256) 135 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA256) 136 .setSaltLengthBytes(32) 137 .setModulusSizeBits(3072) 138 .setPublicExponent(RsaSsaPssParameters.F4) 139 .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX) 140 .build()); 141 } 142 143 @Test testRsa4096PssSha512F4Template()144 public void testRsa4096PssSha512F4Template() throws Exception { 145 KeyTemplate template = RsaSsaPssSignKeyManager.rsa4096PssSha512F4Template(); 146 assertThat(template.toParameters()) 147 .isEqualTo( 148 RsaSsaPssParameters.builder() 149 .setSigHashType(RsaSsaPssParameters.HashType.SHA512) 150 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA512) 151 .setSaltLengthBytes(64) 152 .setModulusSizeBits(4096) 153 .setPublicExponent(RsaSsaPssParameters.F4) 154 .setVariant(RsaSsaPssParameters.Variant.TINK) 155 .build()); 156 } 157 158 @Test testRawRsa4096PssSha512F4Template()159 public void testRawRsa4096PssSha512F4Template() throws Exception { 160 KeyTemplate template = RsaSsaPssSignKeyManager.rawRsa4096PssSha512F4Template(); 161 assertThat(template.toParameters()) 162 .isEqualTo( 163 RsaSsaPssParameters.builder() 164 .setSigHashType(RsaSsaPssParameters.HashType.SHA512) 165 .setMgf1HashType(RsaSsaPssParameters.HashType.SHA512) 166 .setSaltLengthBytes(64) 167 .setModulusSizeBits(4096) 168 .setPublicExponent(RsaSsaPssParameters.F4) 169 .setVariant(RsaSsaPssParameters.Variant.NO_PREFIX) 170 .build()); 171 } 172 173 @Test testRsa3072PssSha256F4TemplateWithManager()174 public void testRsa3072PssSha256F4TemplateWithManager() throws Exception { 175 if (TestUtil.isTsan()) { 176 return; // too slow for tsan 177 } 178 Parameters p = RsaSsaPssSignKeyManager.rsa3072PssSha256F4Template().toParameters(); 179 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 180 } 181 182 @Test testRawRsa3072PssSha256F4TemplateWithManager()183 public void testRawRsa3072PssSha256F4TemplateWithManager() throws Exception { 184 if (TestUtil.isTsan()) { 185 return; // too slow for tsan 186 } 187 Parameters p = RsaSsaPssSignKeyManager.rawRsa3072PssSha256F4Template().toParameters(); 188 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 189 } 190 191 @Test testRsa4096PssSha512F4TemplateWithManager()192 public void testRsa4096PssSha512F4TemplateWithManager() throws Exception { 193 if (TestUtil.isTsan()) { 194 return; // too slow for tsan 195 } 196 Parameters p = RsaSsaPssSignKeyManager.rsa4096PssSha512F4Template().toParameters(); 197 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 198 } 199 200 @Test testRawRsa4096PssSha512F4TemplateWithManager()201 public void testRawRsa4096PssSha512F4TemplateWithManager() throws Exception { 202 if (TestUtil.isTsan()) { 203 return; // too slow for tsan 204 } 205 Parameters p = RsaSsaPssSignKeyManager.rawRsa4096PssSha512F4Template().toParameters(); 206 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 207 } 208 209 @DataPoints("templateNames") 210 public static final String[] KEY_TEMPLATES = 211 new String[] { 212 "RSA_SSA_PSS_3072_SHA256_F4", 213 "RSA_SSA_PSS_3072_SHA256_F4_RAW", 214 "RSA_SSA_PSS_3072_SHA256_SHA256_32_F4", 215 "RSA_SSA_PSS_4096_SHA512_F4", 216 "RSA_SSA_PSS_4096_SHA512_F4_RAW", 217 "RSA_SSA_PSS_4096_SHA512_SHA512_64_F4", 218 }; 219 220 @Theory testTemplates(@romDataPoints"templateNames") String templateName)221 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 222 if (TestUtil.isTsan()) { 223 // factory.createKey is too slow in Tsan. 224 return; 225 } 226 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 227 assertThat(h.size()).isEqualTo(1); 228 assertThat(h.getAt(0).getKey().getParameters()) 229 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 230 } 231 232 /** 233 * Tests that the verifier can verify a the signature for the message and key in the test vector. 234 */ 235 @Theory test_validateSignatureInTestVector( @romDataPoints"allTests") SignatureTestVector testVector)236 public void test_validateSignatureInTestVector( 237 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 238 com.google.crypto.tink.signature.RsaSsaPssPrivateKey key = 239 (com.google.crypto.tink.signature.RsaSsaPssPrivateKey) testVector.getPrivateKey(); 240 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).makePrimary(); 241 @Nullable Integer id = key.getIdRequirementOrNull(); 242 if (id == null) { 243 entry.withRandomId(); 244 } else { 245 entry.withFixedId(id); 246 } 247 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 248 PublicKeyVerify verifier = 249 handle 250 .getPublicKeysetHandle() 251 .getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class); 252 verifier.verify(testVector.getSignature(), testVector.getMessage()); 253 } 254 255 /** 256 * Tests that the verifier can verify a newly generated signature for the message and key in the 257 * test vector. 258 */ 259 @Theory test_computeAndValidateFreshSignatureWithTestVector( @romDataPoints"allTests") SignatureTestVector testVector)260 public void test_computeAndValidateFreshSignatureWithTestVector( 261 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 262 com.google.crypto.tink.signature.RsaSsaPssPrivateKey key = 263 (com.google.crypto.tink.signature.RsaSsaPssPrivateKey) testVector.getPrivateKey(); 264 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).makePrimary(); 265 @Nullable Integer id = key.getIdRequirementOrNull(); 266 if (id == null) { 267 entry.withRandomId(); 268 } else { 269 entry.withFixedId(id); 270 } 271 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 272 PublicKeySign signer = handle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class); 273 byte[] signature = signer.sign(testVector.getMessage()); 274 PublicKeyVerify verifier = 275 handle 276 .getPublicKeysetHandle() 277 .getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class); 278 verifier.verify(signature, testVector.getMessage()); 279 } 280 281 @DataPoints("allTests") 282 public static final SignatureTestVector[] ALL_TEST_VECTORS = 283 RsaSsaPssTestUtil.createRsaPssTestVectors(); 284 285 @Test test_serializeAndParse_works()286 public void test_serializeAndParse_works() throws Exception { 287 SignatureTestVector testVector = ALL_TEST_VECTORS[0]; 288 com.google.crypto.tink.signature.RsaSsaPssPrivateKey key = 289 (com.google.crypto.tink.signature.RsaSsaPssPrivateKey) testVector.getPrivateKey(); 290 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).withFixedId(1216).makePrimary(); 291 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 292 293 byte[] serializedHandle = 294 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 295 KeysetHandle parsedHandle = 296 TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get()); 297 assertThat(parsedHandle.equalsKeyset(handle)).isTrue(); 298 } 299 300 @Test testKeyManagerRegistered()301 public void testKeyManagerRegistered() throws Exception { 302 assertThat( 303 KeyManagerRegistry.globalInstance() 304 .getKeyManager( 305 "type.googleapis.com/google.crypto.tink.RsaSsaPssPrivateKey", 306 PublicKeySign.class)) 307 .isNotNull(); 308 } 309 } 310