1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. 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 distributed under the License 10 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 * or implied. See the License for the specific language governing permissions and limitations under 12 * the License. 13 */ 14 15 package android.keystore.cts; 16 17 import static org.junit.Assert.assertEquals; 18 import static org.junit.Assert.assertNotNull; 19 import static org.junit.Assert.assertTrue; 20 import static org.junit.Assert.fail; 21 22 import java.security.InvalidKeyException; 23 import java.security.KeyPair; 24 import java.security.PrivateKey; 25 import java.security.Provider; 26 import java.security.PublicKey; 27 import java.security.Security; 28 import java.security.Signature; 29 import java.security.SignatureException; 30 import java.security.interfaces.RSAKey; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.Collection; 34 import java.util.List; 35 36 import android.content.Context; 37 import android.keystore.cts.R; 38 import android.keystore.cts.util.ImportedKey; 39 import android.keystore.cts.util.TestUtils; 40 import android.security.keystore.KeyProperties; 41 import android.security.keystore.KeyProtection; 42 import androidx.test.InstrumentationRegistry; 43 import androidx.test.runner.AndroidJUnit4; 44 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 @RunWith(AndroidJUnit4.class) 49 public class RSASignatureTest { 50 51 private static final String EXPECTED_PROVIDER_NAME = SignatureTest.EXPECTED_PROVIDER_NAME; 52 53 private static final String[] SIGNATURE_ALGORITHMS; 54 55 static { 56 List<String> sigAlgs = new ArrayList<>(); 57 for (String algorithm : SignatureTest.EXPECTED_SIGNATURE_ALGORITHMS) { 58 String keyAlgorithm = TestUtils.getSignatureAlgorithmKeyAlgorithm(algorithm); 59 if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) { 60 sigAlgs.add(algorithm); 61 } 62 } 63 SIGNATURE_ALGORITHMS = sigAlgs.toArray(new String[sigAlgs.size()]); 64 } 65 getContext()66 private Context getContext() { 67 return InstrumentationRegistry.getInstrumentation().getTargetContext(); 68 } 69 70 @Test testMaxMessageSizeWhenNoDigestUsed()71 public void testMaxMessageSizeWhenNoDigestUsed() throws Exception { 72 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 73 assertNotNull(provider); 74 75 for (ImportedKey keyPair : importKatKeyPairs("NONEwithRSA")) { 76 PublicKey publicKey = keyPair.getKeystoreBackedKeyPair().getPublic(); 77 PrivateKey privateKey = keyPair.getKeystoreBackedKeyPair().getPrivate(); 78 int modulusSizeBits = ((RSAKey) publicKey).getModulus().bitLength(); 79 try { 80 int modulusSizeBytes = (modulusSizeBits + 7) / 8; 81 // PKCS#1 signature padding must be at least 11 bytes long (00 || 01 || PS || 00) 82 // where PS must be at least 8 bytes long). 83 int expectedMaxMessageSizeBytes = modulusSizeBytes - 11; 84 byte[] msg = new byte[expectedMaxMessageSizeBytes + 1]; 85 Arrays.fill(msg, (byte) 0xf0); 86 87 // Assert that a message of expected maximum length is accepted 88 Signature signature = Signature.getInstance("NONEwithRSA", provider); 89 signature.initSign(privateKey); 90 signature.update(msg, 0, expectedMaxMessageSizeBytes); 91 byte[] sigBytes = signature.sign(); 92 93 signature.initVerify(publicKey); 94 signature.update(msg, 0, expectedMaxMessageSizeBytes); 95 assertTrue(signature.verify(sigBytes)); 96 97 // Assert that a message longer than expected maximum length is rejected 98 signature = Signature.getInstance(signature.getAlgorithm(), provider); 99 signature.initSign(privateKey); 100 try { 101 signature.update(msg, 0, expectedMaxMessageSizeBytes + 1); 102 signature.sign(); 103 fail(); 104 } catch (SignatureException expected) { 105 } 106 107 signature.initVerify(publicKey); 108 try { 109 signature.update(msg, 0, expectedMaxMessageSizeBytes + 1); 110 if (signature.verify(sigBytes)) { 111 fail(); 112 } 113 } catch (SignatureException expected) { 114 } 115 } catch (Throwable e) { 116 throw new RuntimeException("Failed for " + modulusSizeBits + " bit key", e); 117 } 118 } 119 } 120 121 @Test testSmallKeyRejected()122 public void testSmallKeyRejected() throws Exception { 123 // Use a 512 bit key which should prevent the use of any digests larger than SHA-256 124 // because the padded form of the digested message will be larger than modulus size. 125 Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME); 126 assertNotNull(provider); 127 128 for (String algorithm : SIGNATURE_ALGORITHMS) { 129 try { 130 String digest = TestUtils.getSignatureAlgorithmDigest(algorithm); 131 if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) { 132 // Ignore signature algorithms without digest -- this is tested in a separate 133 // test above. 134 continue; 135 } 136 int digestOutputSizeBits = TestUtils.getDigestOutputSizeBits(digest); 137 if (digestOutputSizeBits <= 256) { 138 // 256-bit and shorter digests are short enough to work with a 512 bit key. 139 continue; 140 } 141 142 KeyPair keyPair = TestUtils.importIntoAndroidKeyStore("test1", 143 getContext(), 144 R.raw.rsa_key5_512_pkcs8, 145 R.raw.rsa_key5_512_cert, 146 TestUtils.getMinimalWorkingImportParametersForSigningingWith(algorithm)) 147 .getKeystoreBackedKeyPair(); 148 assertEquals(512, ((RSAKey) keyPair.getPrivate()).getModulus().bitLength()); 149 assertEquals(512, ((RSAKey) keyPair.getPublic()).getModulus().bitLength()); 150 151 Signature signature = Signature.getInstance(algorithm, provider); 152 // Assert that either initSign or sign fails. We don't expect all keymaster 153 // implementations to fail early, during initSign. 154 try { 155 signature.initSign(keyPair.getPrivate()); 156 signature.update("A message".getBytes("UTF-8")); 157 byte[] sigBytes = signature.sign(); 158 fail("Unexpectedly generated a signature (" + sigBytes.length + " bytes): " 159 + HexEncoding.encode(sigBytes)); 160 } catch (InvalidKeyException | SignatureException expected) { 161 } 162 } catch (Throwable e) { 163 throw new RuntimeException("Failed for " + algorithm, e); 164 } 165 } 166 } 167 importKatKeyPairs(String signatureAlgorithm)168 private Collection<ImportedKey> importKatKeyPairs(String signatureAlgorithm) 169 throws Exception { 170 KeyProtection params = 171 TestUtils.getMinimalWorkingImportParametersForSigningingWith(signatureAlgorithm); 172 return importKatKeyPairs(getContext(), params); 173 } 174 importKatKeyPairs( Context context, KeyProtection importParams)175 static Collection<ImportedKey> importKatKeyPairs( 176 Context context, KeyProtection importParams) throws Exception { 177 return Arrays.asList(new ImportedKey[] { 178 TestUtils.importIntoAndroidKeyStore("testRSA512", context, 179 R.raw.rsa_key5_512_pkcs8, R.raw.rsa_key5_512_cert, importParams), 180 TestUtils.importIntoAndroidKeyStore("testRSA768", context, 181 R.raw.rsa_key6_768_pkcs8, R.raw.rsa_key6_768_cert, importParams), 182 TestUtils.importIntoAndroidKeyStore("testRSA1024", context, 183 R.raw.rsa_key3_1024_pkcs8, R.raw.rsa_key3_1024_cert, importParams), 184 TestUtils.importIntoAndroidKeyStore("testRSA2048", context, 185 R.raw.rsa_key8_2048_pkcs8, R.raw.rsa_key8_2048_cert, importParams), 186 TestUtils.importIntoAndroidKeyStore("testRSA3072", context, 187 R.raw.rsa_key7_3072_pksc8, R.raw.rsa_key7_3072_cert, importParams), 188 TestUtils.importIntoAndroidKeyStore("testRSA4096", context, 189 R.raw.rsa_key4_4096_pkcs8, R.raw.rsa_key4_4096_cert, importParams), 190 }); 191 } 192 } 193