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