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.RsaSsaPkcs1TestUtil; 32 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 33 import com.google.crypto.tink.subtle.Hex; 34 import com.google.crypto.tink.testing.TestUtil; 35 import java.math.BigInteger; 36 import java.util.Set; 37 import java.util.TreeSet; 38 import javax.annotation.Nullable; 39 import org.junit.BeforeClass; 40 import org.junit.Test; 41 import org.junit.experimental.theories.DataPoints; 42 import org.junit.experimental.theories.FromDataPoints; 43 import org.junit.experimental.theories.Theories; 44 import org.junit.experimental.theories.Theory; 45 import org.junit.runner.RunWith; 46 47 /** Unit tests for RsaSsaPkcs1SignKeyManager. */ 48 @RunWith(Theories.class) 49 public class RsaSsaPkcs1SignKeyManagerTest { 50 51 @BeforeClass beforeClass()52 public static void beforeClass() throws Exception { 53 RsaSsaPkcs1SignKeyManager.registerPair(/* newKeyAllowed= */ true); 54 PublicKeySignWrapper.register(); 55 PublicKeyVerifyWrapper.register(); 56 } 57 58 @Test createKey_smallKey_works()59 public void createKey_smallKey_works() throws Exception { 60 if (TestUtil.isTsan()) { 61 // factory.createKey is too slow in Tsan. 62 return; 63 } 64 RsaSsaPkcs1Parameters parameters = 65 RsaSsaPkcs1Parameters.builder() 66 .setModulusSizeBits(2048) 67 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 68 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA256) 69 .setVariant(RsaSsaPkcs1Parameters.Variant.NO_PREFIX) 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.RsaSsaPkcs1PrivateKey.class); 74 com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey privateKey = 75 (com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey) key; 76 77 assertThat(privateKey.getPublicKey().getParameters()).isEqualTo(parameters); 78 assertThat(privateKey.getPublicKey().getModulus().bitLength()).isEqualTo(2048); 79 } 80 81 @Test createKey_alwaysNewElement()82 public void createKey_alwaysNewElement() throws Exception { 83 if (TestUtil.isTsan()) { 84 // factory.createKey is too slow in Tsan. 85 return; 86 } 87 88 RsaSsaPkcs1Parameters parameters = 89 RsaSsaPkcs1Parameters.builder() 90 .setModulusSizeBits(2048) 91 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 92 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA256) 93 .setVariant(RsaSsaPkcs1Parameters.Variant.TINK) 94 .build(); 95 Set<BigInteger> primes = new TreeSet<>(); 96 // Calls newKey multiple times and make sure that they generate different keys -- takes about a 97 // second per key. 98 int numTests = 5; 99 for (int i = 0; i < numTests; i++) { 100 KeysetHandle handle = KeysetHandle.generateNew(parameters); 101 assertThat(handle.size()).isEqualTo(1); 102 com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey key = 103 (com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey) handle.getAt(0).getKey(); 104 primes.add(key.getPrimeP().getBigInteger(InsecureSecretKeyAccess.get())); 105 primes.add(key.getPrimeQ().getBigInteger(InsecureSecretKeyAccess.get())); 106 } 107 assertThat(primes).hasSize(2 * numTests); 108 } 109 110 @Test testRsa3072SsaPkcs1Sha256F4Template()111 public void testRsa3072SsaPkcs1Sha256F4Template() throws Exception { 112 KeyTemplate template = RsaSsaPkcs1SignKeyManager.rsa3072SsaPkcs1Sha256F4Template(); 113 assertThat(template.toParameters()) 114 .isEqualTo( 115 RsaSsaPkcs1Parameters.builder() 116 .setModulusSizeBits(3072) 117 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 118 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA256) 119 .setVariant(RsaSsaPkcs1Parameters.Variant.TINK) 120 .build()); 121 } 122 123 @Test testRawRsa3072SsaPkcs1Sha256F4Template()124 public void testRawRsa3072SsaPkcs1Sha256F4Template() throws Exception { 125 KeyTemplate template = RsaSsaPkcs1SignKeyManager.rawRsa3072SsaPkcs1Sha256F4Template(); 126 assertThat(template.toParameters()) 127 .isEqualTo( 128 RsaSsaPkcs1Parameters.builder() 129 .setModulusSizeBits(3072) 130 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 131 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA256) 132 .setVariant(RsaSsaPkcs1Parameters.Variant.NO_PREFIX) 133 .build()); 134 } 135 136 @Test testRsa4096SsaPkcs1Sha512F4Template()137 public void testRsa4096SsaPkcs1Sha512F4Template() throws Exception { 138 KeyTemplate template = RsaSsaPkcs1SignKeyManager.rsa4096SsaPkcs1Sha512F4Template(); 139 assertThat(template.toParameters()) 140 .isEqualTo( 141 RsaSsaPkcs1Parameters.builder() 142 .setModulusSizeBits(4096) 143 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 144 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA512) 145 .setVariant(RsaSsaPkcs1Parameters.Variant.TINK) 146 .build()); 147 } 148 149 @Test testRawRsa4096SsaPkcs1Sha512F4Template()150 public void testRawRsa4096SsaPkcs1Sha512F4Template() throws Exception { 151 KeyTemplate template = RsaSsaPkcs1SignKeyManager.rawRsa4096SsaPkcs1Sha512F4Template(); 152 assertThat(template.toParameters()) 153 .isEqualTo( 154 RsaSsaPkcs1Parameters.builder() 155 .setModulusSizeBits(4096) 156 .setPublicExponent(RsaSsaPkcs1Parameters.F4) 157 .setHashType(RsaSsaPkcs1Parameters.HashType.SHA512) 158 .setVariant(RsaSsaPkcs1Parameters.Variant.NO_PREFIX) 159 .build()); 160 } 161 162 @Test testRsa3072SsaPkcs1Sha256F4TemplateWithManager()163 public void testRsa3072SsaPkcs1Sha256F4TemplateWithManager() throws Exception { 164 if (TestUtil.isTsan()) { 165 // factory.createKey is too slow in Tsan. 166 return; 167 } 168 Parameters p = RsaSsaPkcs1SignKeyManager.rsa3072SsaPkcs1Sha256F4Template().toParameters(); 169 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 170 } 171 172 @Test testRawRsa3072SsaPkcs1Sha256F4TemplateWithManager()173 public void testRawRsa3072SsaPkcs1Sha256F4TemplateWithManager() throws Exception { 174 if (TestUtil.isTsan()) { 175 // factory.createKey is too slow in Tsan. 176 return; 177 } 178 Parameters p = RsaSsaPkcs1SignKeyManager.rawRsa3072SsaPkcs1Sha256F4Template().toParameters(); 179 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 180 } 181 182 @Test testRsa4096SsaPkcs1Sha512F4TemplateWithManager()183 public void testRsa4096SsaPkcs1Sha512F4TemplateWithManager() throws Exception { 184 if (TestUtil.isTsan()) { 185 // factory.createKey is too slow in Tsan. 186 return; 187 } 188 Parameters p = RsaSsaPkcs1SignKeyManager.rsa4096SsaPkcs1Sha512F4Template().toParameters(); 189 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 190 } 191 192 @Test testRawRsa4096SsaPkcs1Sha512F4TemplateWithManager()193 public void testRawRsa4096SsaPkcs1Sha512F4TemplateWithManager() throws Exception { 194 if (TestUtil.isTsan()) { 195 // factory.createKey is too slow in Tsan. 196 return; 197 } 198 Parameters p = RsaSsaPkcs1SignKeyManager.rawRsa4096SsaPkcs1Sha512F4Template().toParameters(); 199 assertThat(KeysetHandle.generateNew(p).getAt(0).getKey().getParameters()).isEqualTo(p); 200 } 201 202 @DataPoints("templateNames") 203 public static final String[] KEY_TEMPLATES = 204 new String[] { 205 "RSA_SSA_PKCS1_3072_SHA256_F4", 206 "RSA_SSA_PKCS1_3072_SHA256_F4_RAW", 207 "RSA_SSA_PKCS1_4096_SHA512_F4", 208 "RSA_SSA_PKCS1_4096_SHA512_F4_RAW", 209 "RSA_SSA_PKCS1_3072_SHA256_F4_WITHOUT_PREFIX" 210 }; 211 212 @Theory testTemplates(@romDataPoints"templateNames") String templateName)213 public void testTemplates(@FromDataPoints("templateNames") String templateName) throws Exception { 214 if (TestUtil.isTsan()) { 215 // factory.createKey is too slow in Tsan. 216 return; 217 } 218 KeysetHandle h = KeysetHandle.generateNew(KeyTemplates.get(templateName)); 219 assertThat(h.size()).isEqualTo(1); 220 assertThat(h.getAt(0).getKey().getParameters()) 221 .isEqualTo(KeyTemplates.get(templateName).toParameters()); 222 } 223 224 @DataPoints("testVectors") 225 public static final SignatureTestVector[] SIGNATURE_TEST_VECTORS = 226 RsaSsaPkcs1TestUtil.createRsaSsaPkcs1TestVectors(); 227 228 @Theory test_computeSignatureInTestVector( @romDataPoints"testVectors") SignatureTestVector v)229 public void test_computeSignatureInTestVector( 230 @FromDataPoints("testVectors") SignatureTestVector v) throws Exception { 231 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getPrivateKey()).makePrimary(); 232 @Nullable Integer id = v.getPrivateKey().getIdRequirementOrNull(); 233 if (id == null) { 234 entry.withRandomId(); 235 } else { 236 entry.withFixedId(id); 237 } 238 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 239 PublicKeySign signer = handle.getPrimitive(RegistryConfiguration.get(), PublicKeySign.class); 240 byte[] signature = signer.sign(v.getMessage()); 241 assertThat(Hex.encode(signature)).isEqualTo(Hex.encode(v.getSignature())); 242 } 243 244 @Theory test_validateSignatureInTestVector( @romDataPoints"testVectors") SignatureTestVector v)245 public void test_validateSignatureInTestVector( 246 @FromDataPoints("testVectors") SignatureTestVector v) throws Exception { 247 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(v.getPrivateKey()).makePrimary(); 248 @Nullable Integer id = v.getPrivateKey().getIdRequirementOrNull(); 249 if (id == null) { 250 entry.withRandomId(); 251 } else { 252 entry.withFixedId(id); 253 } 254 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 255 PublicKeyVerify verifier = 256 handle 257 .getPublicKeysetHandle() 258 .getPrimitive(RegistryConfiguration.get(), PublicKeyVerify.class); 259 verifier.verify(v.getSignature(), v.getMessage()); 260 } 261 262 @Test test_serializeAndParse_works()263 public void test_serializeAndParse_works() throws Exception { 264 SignatureTestVector testVector = SIGNATURE_TEST_VECTORS[0]; 265 com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey key = 266 (com.google.crypto.tink.signature.RsaSsaPkcs1PrivateKey) testVector.getPrivateKey(); 267 KeysetHandle.Builder.Entry entry = KeysetHandle.importKey(key).withFixedId(1216).makePrimary(); 268 KeysetHandle handle = KeysetHandle.newBuilder().addEntry(entry).build(); 269 270 byte[] serializedHandle = 271 TinkProtoKeysetFormat.serializeKeyset(handle, InsecureSecretKeyAccess.get()); 272 KeysetHandle parsedHandle = 273 TinkProtoKeysetFormat.parseKeyset(serializedHandle, InsecureSecretKeyAccess.get()); 274 assertThat(parsedHandle.equalsKeyset(handle)).isTrue(); 275 } 276 277 @Test testKeyManagerRegistered()278 public void testKeyManagerRegistered() throws Exception { 279 assertThat( 280 KeyManagerRegistry.globalInstance() 281 .getKeyManager( 282 "type.googleapis.com/google.crypto.tink.RsaSsaPkcs1PrivateKey", 283 PublicKeySign.class)) 284 .isNotNull(); 285 } 286 } 287