1 // Copyright 2018 Google Inc. 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.subtle; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.junit.Assert.assertThrows; 21 22 import com.google.crypto.tink.AccessesPartialKey; 23 import com.google.crypto.tink.PublicKeyVerify; 24 import com.google.crypto.tink.internal.Util; 25 import com.google.crypto.tink.signature.RsaSsaPkcs1Parameters; 26 import com.google.crypto.tink.signature.RsaSsaPkcs1PublicKey; 27 import com.google.crypto.tink.signature.internal.testing.RsaSsaPkcs1TestUtil; 28 import com.google.crypto.tink.signature.internal.testing.SignatureTestVector; 29 import com.google.crypto.tink.subtle.Enums.HashType; 30 import com.google.crypto.tink.testing.WycheproofTestUtil; 31 import com.google.gson.JsonArray; 32 import com.google.gson.JsonObject; 33 import java.math.BigInteger; 34 import java.security.GeneralSecurityException; 35 import java.security.KeyFactory; 36 import java.security.Provider; 37 import java.security.Security; 38 import java.security.interfaces.RSAPublicKey; 39 import java.security.spec.RSAPublicKeySpec; 40 import org.conscrypt.Conscrypt; 41 import org.junit.Assume; 42 import org.junit.Before; 43 import org.junit.Test; 44 import org.junit.experimental.theories.DataPoints; 45 import org.junit.experimental.theories.FromDataPoints; 46 import org.junit.experimental.theories.Theories; 47 import org.junit.experimental.theories.Theory; 48 import org.junit.runner.RunWith; 49 50 /** Unit tests for RsaSsaPkcs1VerifyJce. */ 51 @RunWith(Theories.class) 52 public class RsaSsaPkcs1VerifyJceTest { 53 54 @DataPoints("allTests") 55 public static final SignatureTestVector[] ALL_TEST_VECTORS = 56 RsaSsaPkcs1TestUtil.createRsaSsaPkcs1TestVectors(); 57 getSubtleHashType(RsaSsaPkcs1Parameters.HashType hash)58 private static HashType getSubtleHashType(RsaSsaPkcs1Parameters.HashType hash) 59 throws GeneralSecurityException { 60 if (hash == RsaSsaPkcs1Parameters.HashType.SHA256) { 61 return HashType.SHA256; 62 } else if (hash == RsaSsaPkcs1Parameters.HashType.SHA384) { 63 return HashType.SHA384; 64 } else if (hash == RsaSsaPkcs1Parameters.HashType.SHA512) { 65 return HashType.SHA512; 66 } else { 67 throw new GeneralSecurityException("Unsupported hash: " + hash); 68 } 69 } 70 71 @Before useConscrypt()72 public void useConscrypt() throws Exception { 73 if (!Util.isAndroid()) { 74 Conscrypt.checkAvailability(); 75 Security.addProvider(Conscrypt.newProvider()); 76 } 77 } 78 79 @Theory create_verifySignatureInTestVector_works( @romDataPoints"allTests") SignatureTestVector testVector)80 public void create_verifySignatureInTestVector_works( 81 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 82 PublicKeyVerify verify = 83 RsaSsaPkcs1VerifyJce.create( 84 (RsaSsaPkcs1PublicKey) testVector.getPrivateKey().getPublicKey()); 85 verify.verify(testVector.getSignature(), testVector.getMessage()); 86 assertThrows( 87 GeneralSecurityException.class, 88 () -> verify.verify(testVector.getSignature(), new byte[] {1, 2, 3})); 89 } 90 91 @AccessesPartialKey 92 @Theory constructor_verifySignatureInTestVector_works( @romDataPoints"allTests") SignatureTestVector testVector)93 public void constructor_verifySignatureInTestVector_works( 94 @FromDataPoints("allTests") SignatureTestVector testVector) throws Exception { 95 RsaSsaPkcs1PublicKey testPublicKey = 96 (RsaSsaPkcs1PublicKey) testVector.getPrivateKey().getPublicKey(); 97 if (testPublicKey.getParameters().getVariant() != RsaSsaPkcs1Parameters.Variant.NO_PREFIX) { 98 // Constructor only supports NO_PREFIX variant. 99 return; 100 } 101 KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance("RSA"); 102 RSAPublicKey publicKey = 103 (RSAPublicKey) 104 keyFactory.generatePublic( 105 new RSAPublicKeySpec( 106 testPublicKey.getModulus(), testPublicKey.getParameters().getPublicExponent())); 107 RsaSsaPkcs1VerifyJce verify = 108 new RsaSsaPkcs1VerifyJce( 109 publicKey, getSubtleHashType(testPublicKey.getParameters().getHashType())); 110 verify.verify(testVector.getSignature(), testVector.getMessage()); 111 assertThrows( 112 GeneralSecurityException.class, 113 () -> verify.verify(testVector.getSignature(), new byte[] {1, 2, 3})); 114 } 115 116 @Test sha1IsNotSupported()117 public void sha1IsNotSupported() throws Exception { 118 RsaSsaPkcs1PublicKey testPublicKey = 119 (RsaSsaPkcs1PublicKey) ALL_TEST_VECTORS[0].getPrivateKey().getPublicKey(); 120 KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance("RSA"); 121 RSAPublicKey publicKey = 122 (RSAPublicKey) 123 keyFactory.generatePublic( 124 new RSAPublicKeySpec( 125 testPublicKey.getModulus(), testPublicKey.getParameters().getPublicExponent())); 126 assertThrows( 127 GeneralSecurityException.class, () -> new RsaSsaPkcs1VerifyJce(publicKey, HashType.SHA1)); 128 } 129 130 @Test constructorWithSmallExponent_throws()131 public void constructorWithSmallExponent_throws() throws Exception { 132 RsaSsaPkcs1PublicKey testPublicKey = 133 (RsaSsaPkcs1PublicKey) ALL_TEST_VECTORS[0].getPrivateKey().getPublicKey(); 134 KeyFactory keyFactory = EngineFactory.KEY_FACTORY.getInstance("RSA"); 135 RSAPublicKey publicKey = 136 (RSAPublicKey) 137 keyFactory.generatePublic( 138 new RSAPublicKeySpec(testPublicKey.getModulus(), BigInteger.valueOf(3))); 139 assertThrows( 140 GeneralSecurityException.class, () -> new RsaSsaPkcs1VerifyJce(publicKey, HashType.SHA256)); 141 } 142 getHashType(String sha)143 private static RsaSsaPkcs1Parameters.HashType getHashType(String sha) { 144 switch (sha) { 145 case "SHA-256": 146 return RsaSsaPkcs1Parameters.HashType.SHA256; 147 case "SHA-512": 148 return RsaSsaPkcs1Parameters.HashType.SHA512; 149 default: 150 throw new IllegalArgumentException("Unsupported hash: " + sha); 151 } 152 } 153 154 @DataPoints("wycheproofTestVectorPaths") 155 public static final String[] WYCHEPROOF_TEST_VECTORS_PATHS = 156 new String[] { 157 "../wycheproof/testvectors/rsa_signature_2048_sha256_test.json", 158 "../wycheproof/testvectors/rsa_signature_3072_sha512_test.json", 159 "../wycheproof/testvectors/rsa_signature_4096_sha512_test.json" 160 }; 161 162 @AccessesPartialKey 163 @Theory wycheproofVectors(@romDataPoints"wycheproofTestVectorPaths") String path)164 public void wycheproofVectors(@FromDataPoints("wycheproofTestVectorPaths") String path) 165 throws Exception { 166 JsonObject jsonObj = WycheproofTestUtil.readJson(path); 167 168 int errors = 0; 169 JsonArray testGroups = jsonObj.getAsJsonArray("testGroups"); 170 for (int i = 0; i < testGroups.size(); i++) { 171 JsonObject group = testGroups.get(i).getAsJsonObject(); 172 BigInteger modulus = new BigInteger(group.get("n").getAsString(), 16); 173 BigInteger exponent = new BigInteger(1, Hex.decode(group.get("e").getAsString())); 174 RsaSsaPkcs1Parameters.HashType hashType = getHashType(group.get("sha").getAsString()); 175 JsonArray tests = group.getAsJsonArray("tests"); 176 for (int j = 0; j < tests.size(); j++) { 177 JsonObject testcase = tests.get(j).getAsJsonObject(); 178 // Do not perform the Wycheproof test if the RSA public exponent is small. 179 if (WycheproofTestUtil.checkFlags(testcase, "SmallPublicKey")) { 180 continue; 181 } 182 String tcId = 183 String.format( 184 "testcase %d (%s)", 185 testcase.get("tcId").getAsInt(), testcase.get("comment").getAsString()); 186 RsaSsaPkcs1Parameters parameters = 187 RsaSsaPkcs1Parameters.builder() 188 .setModulusSizeBits(modulus.bitLength()) 189 .setPublicExponent(exponent) 190 .setHashType(hashType) 191 .setVariant(RsaSsaPkcs1Parameters.Variant.NO_PREFIX) 192 .build(); 193 RsaSsaPkcs1PublicKey publicKey = 194 RsaSsaPkcs1PublicKey.builder().setParameters(parameters).setModulus(modulus).build(); 195 PublicKeyVerify verifier = RsaSsaPkcs1VerifyJce.create(publicKey); 196 byte[] msg = getMessage(testcase); 197 byte[] sig = Hex.decode(testcase.get("sig").getAsString()); 198 String result = testcase.get("result").getAsString(); 199 try { 200 verifier.verify(sig, msg); 201 if (result.equals("invalid")) { 202 System.out.printf("FAIL %s: accepting invalid signature%n", tcId); 203 errors++; 204 } 205 } catch (GeneralSecurityException ex) { 206 if (result.equals("valid")) { 207 System.out.printf("FAIL %s: rejecting valid signature, exception: %s%n", tcId, ex); 208 errors++; 209 } 210 } 211 } 212 } 213 assertThat(errors).isEqualTo(0); 214 } 215 getMessage(JsonObject testcase)216 private static byte[] getMessage(JsonObject testcase) { 217 // Previous version of Wycheproof test vectors uses "message" while the new one uses "msg". 218 if (testcase.has("msg")) { 219 return Hex.decode(testcase.get("msg").getAsString()); 220 } else { 221 return Hex.decode(testcase.get("message").getAsString()); 222 } 223 } 224 225 @Test usesConscryptImplementationIfInstalled()226 public void usesConscryptImplementationIfInstalled() throws Exception { 227 Assume.assumeFalse(Util.isAndroid()); 228 229 RsaSsaPkcs1PublicKey testPublicKey = 230 (RsaSsaPkcs1PublicKey) ALL_TEST_VECTORS[0].getPrivateKey().getPublicKey(); 231 232 // Conscrypt is already installed, so RsaSsaPkcs1VerifyConscrypt is used. 233 PublicKeyVerify verifier = RsaSsaPkcs1VerifyJce.create(testPublicKey); 234 assertThat(verifier.getClass().getSimpleName()).isEqualTo("RsaSsaPkcs1VerifyConscrypt"); 235 236 Provider conscrypt = Conscrypt.newProvider(); 237 Security.removeProvider(conscrypt.getName()); 238 239 PublicKeyVerify verifier2 = RsaSsaPkcs1VerifyJce.create(testPublicKey); 240 assertThat(verifier2.getClass().getSimpleName()).isEqualTo("InternalJavaImpl"); 241 242 Security.addProvider(conscrypt); 243 } 244 } 245